diff --git a/src/86box.h b/src/86box.h index b3956ea10..2f03791e5 100644 --- a/src/86box.h +++ b/src/86box.h @@ -92,7 +92,6 @@ extern int vid_cga_contrast, /* (C) video */ force_43, /* (C) video */ gfxcard; /* (C) graphics/video card */ extern int serial_enabled[], /* (C) enable serial ports */ - lpt_enabled, /* (C) enable LPT ports */ bugger_enabled, /* (C) enable ISAbugger */ isamem_type[], /* (C) enable ISA mem cards */ isartc_type; /* (C) enable ISA RTC card */ @@ -129,7 +128,9 @@ extern int nic_do_log; extern wchar_t exe_path[1024]; /* path (dir) of executable */ extern wchar_t usr_path[1024]; /* path (dir) of user data */ extern wchar_t cfg_path[1024]; /* full path of config file */ +#ifndef USE_NEW_DYNAREC extern FILE *stdlog; /* file to log output to */ +#endif extern int scrnsz_x, /* current screen size, X */ scrnsz_y; /* current screen size, Y */ extern int efscrnsz_y; @@ -164,6 +165,16 @@ extern void pc_thread(void *param); extern void pc_start(void); extern void pc_onesec(void); +extern uint16_t get_last_addr(void); + +/* This is for external subtraction of cycles; + should be in cpu.c but I put it here to avoid + having to include cpu.c everywhere. */ +extern void sub_cycles(int c); + +extern double isa_timing; +extern int io_delay; + #ifdef __cplusplus } #endif diff --git a/src/Makefile.local b/src/Makefile.local index 93cb032a0..6b7bee698 100644 --- a/src/Makefile.local +++ b/src/Makefile.local @@ -10,7 +10,7 @@ # settings, so we can avoid changing the main one for all of # our local setups. # -# Version: @(#)Makefile.local 1.0.20 2018/11/18 +# Version: @(#)Makefile.local 1.0.21 2019/03/03 # # Author: Fred N. van Kempen, # @@ -70,8 +70,8 @@ STUFF := # -DENABLE_HDC_LOG=N sets logging level at N. # -DENABLE_HDD_IMAGE_LOG=N sets logging level at N. # -DENABLE_IDE_LOG=N sets logging level at N. -# -DENABLE_MFM_AT_LOG=N sets logging level at N. -# -DENABLE_MFM_XT_LOG=N sets logging level at N. +# -DENABLE_ST506_AT_LOG=N sets logging level at N. +# -DENABLE_ST506_XT_LOG=N sets logging level at N. # -DENABLE_XTA_LOG=N sets logging level at N. # -DENABLE_ZIP_LOG=N sets logging level at N. # floppy/ logging: @@ -123,6 +123,10 @@ STUFF := # -DENABLE_ATI28800_LOG=N sets logging level at N. # -DENABLE_MACH64_LOG=N sets logging level at N. # -DENABLE_ET4000W32_LOG=N sets logging level at N. +# -DENABLE_HT216_LOG=N sets logging level at N. +# -DENABLE_ICD2061_LOG=N sets logging level at N. +# -DENABLE_IM1024_LOG=N sets logging level at N. +# -DENABLE_PGC_LOG=N sets logging level at N. # -DENABLE_S3_VIRGE_LOG=N sets logging level at N. # -DENABLE_VID_TABLE_LOG=N sets logging level at N. # -DENABLE_VOODOO_LOG=N sets logging level at N. diff --git a/src/apm.c b/src/apm.c new file mode 100644 index 000000000..1ec2fb6de --- /dev/null +++ b/src/apm.c @@ -0,0 +1,149 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Advanced Power Management emulation. + * + * Version: @(#)apm.c 1.0.0 2019/05/12 + * + * Authors: Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu/cpu.h" +#include "device.h" +#include "io.h" + + +typedef struct +{ + uint8_t cmd, + stat; +} apm_t; + + +#ifdef ENABLE_APM_LOG +int apm_do_log = ENABLE_APM_LOG; + + +static void +apm_log(const char *fmt, ...) +{ + va_list ap; + + if (apm_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define apm_log(fmt, ...) +#endif + + +static void +apm_out(uint16_t port, uint8_t val, void *p) +{ + apm_t *apm = (apm_t *) p; + + apm_log("[%04X:%08X] APM write: %04X = %02X (BX = %04X, CX = %04X)\n", CS, cpu_state.pc, port, val, BX, CX); + + port &= 0x0001; + + if (port == 0x0000) { + apm->cmd = val; + + switch (apm->cmd) { + case 0x07: /* Set Power State */ + if (CH == 0x00) switch (CX) { + case 0x0000: +#ifdef ENABLE_APM_LOG + apm_log("APM Set Power State: APM Enabled\n"); +#endif + break; + case 0x0001: +#ifdef ENABLE_APM_LOG + apm_log("APM Set Power State: Standby\n"); +#endif + break; + case 0x0002: +#ifdef ENABLE_APM_LOG + apm_log("APM Set Power State: Suspend\n"); +#endif + break; + case 0x0003: /* Off */ +#ifdef ENABLE_APM_LOG + apm_log("APM Set Power State: Off\n"); +#endif + exit(-1); + break; + } + break; + } + } else + apm->stat = val; +} + + +static uint8_t +apm_in(uint16_t port, void *p) +{ + apm_t *apm = (apm_t *) p; + + apm_log("[%04X:%08X] APM read: %04X = FF\n", CS, cpu_state.pc, port); + + port &= 0x0001; + + if (port == 0x0000) + return apm->cmd; + else + return apm->stat; +} + + +static void +apm_close(void *p) +{ + apm_t *dev = (apm_t *)p; + + free(dev); +} + + +static void +*apm_init(const device_t *info) +{ + apm_t *apm = (apm_t *) malloc(sizeof(apm_t)); + memset(apm, 0, sizeof(apm_t)); + + io_sethandler(0x00b2, 0x0002, apm_in, NULL, NULL, apm_out, NULL, NULL, apm); + + return apm; +} + + +const device_t apm_device = +{ + "Advanced Power Management", + 0, + 0, + apm_init, + apm_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/apm.h b/src/apm.h new file mode 100644 index 000000000..3f0e34780 --- /dev/null +++ b/src/apm.h @@ -0,0 +1,43 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the ISA Bus (de)Bugger expansion card + * sold as a DIY kit in the late 1980's in The Netherlands. + * This card was a assemble-yourself 8bit ISA addon card for + * PC and AT systems that had several tools to aid in low- + * level debugging (mostly for faulty BIOSes, bootloaders + * and system kernels...) + * + * Definitions for the Advanced Power Management emulation. + * + * Version: @(#)apm.h 1.0.0 2019/05/12 + * + * Authors: Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#ifndef APM_H +# define APM_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global variables. */ +extern const device_t apm_device; + + +/* Functions. */ + +#ifdef __cplusplus +} +#endif + + +#endif /*APM_H*/ diff --git a/src/cassette/cassette.c b/src/cassette/cassette.c new file mode 100644 index 000000000..b9ba8a7ca --- /dev/null +++ b/src/cassette/cassette.c @@ -0,0 +1,203 @@ +/************************************************************************ + + PCEM: IBM 5150 Cassette support + + Copyright (C) 2019 John Elliott + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*************************************************************************/ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../ppi.h" +#include "../ui.h" +#include "../plat.h" +#include "pzx.h" +#include "cassette.h" + +typedef struct cassette_t +{ + uint8_t motor; /* Motor status */ + pzxfile_t pzx; + int cycles_last; /* Cycle count at last cassette poll */ + +} cassette_t; + +wchar_t cassettefn[256]; + +static cassette_t *st_cas; + + +#ifdef ENABLE_CASSETTE_LOG +int cassette_do_log = ENABLE_CASSETTE_LOG; + + +static void +cassette_log(const char *fmt, ...) +{ + va_list ap; + + if (cassette_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define cassette_log(fmt, ...) +#endif + + +/* The PCEM CPU uses IBM cycles (4.77MHz). PZX uses Spectrum cycles (3.5MHz) + * so scale accordingly. */ +static int32_t +pzx_cycles(int32_t pc) +{ + double d = pc; + + return (int32_t)(((d * 3.5) / 4.772728) + 0.5); +} + +void +cassette_eject(void) +{ + if (st_cas->pzx.input) { + pzx_close(&st_cas->pzx); + } + cassettefn[0] = 0; +} + +void +cassette_load(wchar_t *fn) +{ + FILE *fp; + unsigned char magic[8]; + + if (!fn) + return; + + fp = plat_fopen(fn, L"rb"); + if (!fp) { + /* Warn user? */ + cassette_log("Failed to open cassette input %s\n", fn); + return; + } + memset(magic, 0, sizeof(magic)); + fread(magic, 1, sizeof(magic), fp); + + /* Check for PZX signature. In due course support could be added for + * other formats like TZX */ + if (!memcmp(magic, "PZXT", 4)) { + wchar_t *result; + + result = pzx_open(&st_cas->pzx, fp); + + if (result) { + cassette_log("Failed to open %s as PZX: %s\n", + fn, result); + fclose(fp); + return; + } + wcscpy(cassettefn, fn); + } +} + + +uint8_t +cassette_input(void) +{ + int ticks; + + /* While motor is off, result is loopback */ + if (!st_cas->motor) + return ppispeakon; + /* If there is no tapefile open don't try to extract data */ + if (st_cas->pzx.input == NULL) + return 0; + /* Otherwise see how many ticks there have been since the last input */ + if (st_cas->cycles_last == -1) + st_cas->cycles_last = cycles; + if (cycles <= st_cas->cycles_last) + ticks = (st_cas->cycles_last - cycles); + else + ticks = (st_cas->cycles_last + (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed / 100) - cycles); + st_cas->cycles_last = cycles; + + return pzx_advance(&st_cas->pzx, pzx_cycles(ticks)); +} + + + +void +cassette_set_motor(uint8_t on) +{ + if (on && !st_cas->motor) { + cassette_log("Start cassette motor\n"); + st_cas->cycles_last = -1; + } + if (st_cas->motor && !on) { + cassette_log("Stop cassette motor\n"); + st_cas->cycles_last = -1; + } + st_cas->motor = on; +} + + +static void +*cassette_init(const device_t *info) +{ + cassette_t *cas = (cassette_t *)malloc(sizeof(cassette_t)); + memset(cas, 0, sizeof(cassette_t)); + pzx_init(&cas->pzx); + + st_cas = cas; + return cas; +} + + +static void +cassette_close(void *p) +{ + cassette_t *cas = (cassette_t *)p; + + pzx_close(&cas->pzx); + + free(cas); +} + + +const device_t cassette_device = { + "IBM PC 5150 Cassette", + 0, + 0, + cassette_init, + cassette_close, + NULL, + NULL, + NULL, + NULL +}; + diff --git a/src/cassette/cassette.h b/src/cassette/cassette.h new file mode 100644 index 000000000..cf7712811 --- /dev/null +++ b/src/cassette/cassette.h @@ -0,0 +1,30 @@ +/************************************************************************ + + PCEM: IBM 5150 cassette support + + Copyright (C) 2019 John Elliott + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*************************************************************************/ + +extern wchar_t cassettefn[256]; + +extern const device_t cassette_device; + +uint8_t cassette_input(void); +void cassette_set_motor(uint8_t on); +void cassette_eject(void); +void cassette_load(wchar_t *filename); diff --git a/src/cassette/pzx.c b/src/cassette/pzx.c new file mode 100644 index 000000000..c7d16d36e --- /dev/null +++ b/src/cassette/pzx.c @@ -0,0 +1,414 @@ +/************************************************************************ + + PCEM: IBM 5150 Cassette support + + Copyright (C) 2019 John Elliott + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*************************************************************************/ + +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../ui.h" +#include "pzx.h" + +/* This module is intended to abstract all the details of a PZX file and + * emit its contents as a bitstream in a form suitable for PCEM. Similar + * modules could be written to add support for other tape formats such as TZX, + * TAP or CSW. */ + + +#ifdef ENABLE_PZX_LOG +int pzx_do_log = ENABLE_PZX_LOG; + + +static void +pzx_log(const char *fmt, ...) +{ + va_list ap; + + if (pzx_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pzx_log(fmt, ...) +#endif + +static uint32_t +peek2(uint8_t *data) +{ + return (((uint32_t)data[1]) << 8) | data[0]; +} + +static uint32_t +peek4(uint8_t *data) +{ + return (((uint32_t)data[3]) << 24) | + (((uint32_t)data[2]) << 16) | + (((uint32_t)data[1]) << 8) | data[0]; +} + +/* Cue up the next pulse definition from the current PULS block. */ +static void +pzx_parse_pulse(pzxfile_t *pzx) +{ + pzx->puls_duration = peek2(pzx->curblock + pzx->puls_ptr); + pzx->puls_ptr += 2; + if (pzx->puls_duration > 0x8000) { + pzx->puls_count = pzx->puls_duration & 0x7FFF; + pzx->puls_duration = peek2(pzx->curblock + pzx->puls_ptr); + pzx->puls_ptr += 2; + } + if (pzx->puls_duration >= 0x8000) { + pzx->puls_duration &= 0x7FFF; + pzx->puls_duration <<= 16; + pzx->puls_duration |= peek2(pzx->curblock + pzx->puls_ptr); + pzx->puls_ptr += 2; + } + if (!pzx->puls_count) pzx->puls_count = 1; +} + + +void +pzx_init(pzxfile_t *pzx) +{ + memset(pzx, 0, sizeof(pzxfile_t)); + pzx->state = PZX_CLOSED; +} + +/* Load the next block from a PZX-format file. + * + * Returns block if successful, NULL if end of file or error + * Caller must free the block with free(). */ +uint8_t +*pzx_load_block(FILE *fp) +{ + uint8_t block_header[8]; + uint8_t *block_data; + uint32_t block_len; + + /* The first 8 bytes of a PZX block are fixed: the first 4 give + * the ID, the second 4 the length (excluding the header itself) */ + if (fread(block_header, 1, 8, fp) < 8) + return NULL; /* EoF */ + + block_len = peek4(block_header + 4); + block_data = malloc(8 + block_len); + if (!block_data) return NULL; + memcpy(block_data, block_header, 8); + if (!block_len) { /* Block is only the header */ +/* CAS_LOG(("Loaded PZX block: %-4.4s\n", block_data)); */ + return block_data; + } + if (fread(block_data + 8, 1, block_len, fp) < block_len) { + free(block_data); /* Unexpected EoF */ + return NULL; + } +/* CAS_LOG(("Loaded PZX block: %-4.4s\n", block_data)); */ + return block_data; +} + + +/* Search the current file for PZX version headers and check they're all 1.x */ +static wchar_t +*pzx_check_version(FILE *fp) +{ + uint8_t *block; + static wchar_t message[80]; + + rewind(fp); + while ((block = pzx_load_block(fp))) { + if (!memcmp(block, "PZXT", 4)) { + pzx_log("PZX version %d.%d\n", block[8], block[9]); + if (block[8] != 1) { + swprintf(message, 80, L"Unsupported PZX version %d.%d\n", block[8], block[9]); + free(block); + return message; + } + } + free(block); + } + rewind(fp); + return NULL; +} + + +wchar_t +*pzx_open(pzxfile_t *pzx, FILE *fp) +{ + wchar_t *result; + + rewind(fp); + /* Check that this file is compatible */ + result = pzx_check_version(fp); + if (result) + return result; + + pzx->level = 0; + pzx->state = PZX_IDLE; + pzx->input = fp; + return NULL; +} + +void +pzx_close(pzxfile_t *pzx) +{ + if (pzx->input) { + fclose(pzx->input); + pzx->input = NULL; + } + if (pzx->curblock) { + free(pzx->curblock); + pzx->curblock = NULL; + } + pzx->state = PZX_CLOSED; +} + +/* Read the next block of type DATA, PAUS or PULS */ +int +pzx_next_block(pzxfile_t *pzx) +{ + long pos; + + pos = ftell(pzx->input); + while (pzx->state == PZX_IDLE) { + uint8_t *blk; + + /* In idle state there should be no current block. But + * make sure of that */ + if (pzx->curblock) { + free(pzx->curblock); + pzx->curblock = NULL; + } + + /* Load the next block */ + blk = pzx_load_block(pzx->input); + + /* If that didn't load we've reached the end of file; wrap to + * beginning. */ + if (!blk) { + rewind(pzx->input); + blk = pzx_load_block(pzx->input); + if (!blk) { /* Couldn't even load first block */ + pzx_close(pzx); + return 0; + } + /* Have we read the whole file and come back to where + * we were? */ + if (ftell(pzx->input) == pos) { + free(blk); + pzx_close(pzx); + return 0; + } + } + /* We have loaded the next block. What is it? */ + if (!memcmp(blk, "PULS", 4)) { + pzx->state = PZX_IN_PULS; + pzx->curblock = blk; + pzx->puls_len = 8 + peek4(blk + 4); + pzx->puls_ptr = 8; + pzx->puls_count = 0; + pzx->puls_remain = 0; + pzx->puls_duration = 0; + pzx->level = 0; + pzx_log("Beginning PULS block\n"); + } + else if (!memcmp(blk, "PAUS", 4)) { + pzx->state = PZX_IN_PAUS; + pzx->curblock = blk; + pzx->paus_remain = peek4(blk + 8); + pzx->level = (pzx->paus_remain >> 31); + pzx->paus_remain &= 0x7FFFFFFF; + pzx_log("Beginning PAUS block, duration=%d\n", + pzx->paus_remain); + } + else if (!memcmp(blk, "DATA", 4)) { + pzx->state = PZX_IN_DATA; + pzx->curblock = blk; + pzx->data_bits = peek4(blk + 8); + pzx->level = (pzx->data_bits >> 31); + pzx->data_bits &= 0x7FFFFFFF; + pzx->data_tail = peek2(blk + 12); + pzx->data_p0 = blk[14]; + pzx->data_p1 = blk[15]; + pzx->data_p = 0; + pzx->data_w = 16; + pzx->data_remain = 0; + pzx->data_ptr = 16 + 2 * (pzx->data_p0 + pzx->data_p1); + pzx->data_mask = 0x80; + pzx_log("Beginning DATA block, length=%d p0=%d p1=%d" + " data_ptr=%d\n", + pzx->data_bits, + pzx->data_p0, pzx->data_p1, + pzx->data_ptr); + } + } + return 1; +} + +static void +pzx_endblock(pzxfile_t *pzx) +{ + if (pzx->curblock) + free(pzx->curblock); + pzx->curblock = NULL; + pzx->state = PZX_IDLE; +} + +/* PAUS is easy - just run the timer down */ +static int +pzx_advance_paus(pzxfile_t *pzx, int time) +{ + if (pzx->paus_remain > time) { + pzx->paus_remain -= time; + return 0; + } + time -= pzx->paus_remain; + pzx_endblock(pzx); + return time; +} + +static int +pzx_advance_puls(pzxfile_t *pzx, int time) +{ + /* At the start of a pulse sequence? */ + if (pzx->puls_count == 0) { + pzx_parse_pulse(pzx); + pzx->puls_remain = pzx->puls_duration; + } + /* Does sample trigger a pulse change? If not, that's easy. */ + if (time < pzx->puls_remain) { + pzx->puls_remain -= time; + return 0; + } + /* Sample does trigger a pulse change */ + time -= pzx->puls_remain; + /* If there's another pulse in the current sequence, that's + * straightforward; just flip the level and continue */ + --pzx->puls_count; + pzx->level = !pzx->level; + if (pzx->puls_count) { + pzx->puls_remain = pzx->puls_duration; + return time; + } + /* If we've reached the end of the pulse sequence, there may be + * another one */ + if (pzx->puls_ptr < pzx->puls_len) { + return time; + } + /* If there isn't another one, it's the end of the block */ + pzx_endblock(pzx); + return time; +} + +/* Decode a DATA block */ +static int +pzx_advance_data(pzxfile_t *pzx, int time) +{ + uint8_t bit; + + /* Reached end of data? */ + if (pzx->data_bits == 0) { + /* Time interval is covered by the tail bit */ + if (pzx->data_tail > time) { + pzx->data_tail -= time; + return 0; + } + /* Have run out of block */ + time -= pzx->data_tail; + pzx_endblock(pzx); + return time; + } + /* No more time remaining on the current bit? */ + if (pzx->data_p < 1 && !pzx->data_remain) { + bit = pzx->curblock[pzx->data_ptr] & pzx->data_mask; + pzx->data_mask >>= 1; + if (!pzx->data_mask) { + pzx->data_mask = 0x80; + ++pzx->data_ptr; + } + --pzx->data_bits; + + if (bit) { + pzx->data_p = pzx->data_p1; + pzx->data_w = 16 + 2 * pzx->data_p0; + pzx->data_remain = 0; + } else { + pzx->data_p = pzx->data_p0; + pzx->data_w = 16; + pzx->data_remain = 0; + } + } + /* See if we've started processing the current waveform. If not, + * load its first element (assuming that there is one) */ + if (!pzx->data_remain) { + if (pzx->data_p) { + pzx->data_remain = peek2(pzx->curblock + pzx->data_w); + pzx->data_w += 2; + pzx->data_p--; + } + } + if (pzx->data_remain > time) { + /* Time advance is contained within current wave */ + pzx->data_remain -= time; + return 0; + } else { /* Move on to next element of wave / next bit / next block */ + time -= pzx->data_remain; + pzx->data_remain = 0; + pzx->level = !pzx->level; + } + + return time; +} + +int +pzx_advance(pzxfile_t *pzx, int time) +{ + if (pzx->state == PZX_CLOSED) + return 0; /* No tape loaded */ + + while (time) { + switch (pzx->state) + { + case PZX_IDLE: + if (!pzx_next_block(pzx)) return 0; + break; + case PZX_IN_PULS: + time = pzx_advance_puls(pzx, time); + break; + case PZX_IN_PAUS: + time = pzx_advance_paus(pzx, time); + break; + case PZX_IN_DATA: + time = pzx_advance_data(pzx, time); + break; + } + } + return pzx->level; +} + + + diff --git a/src/cassette/pzx.h b/src/cassette/pzx.h new file mode 100644 index 000000000..a642a0688 --- /dev/null +++ b/src/cassette/pzx.h @@ -0,0 +1,71 @@ +/************************************************************************ + + PCEM: IBM 5150 cassette support + + Copyright (C) 2019 John Elliott + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*************************************************************************/ + +typedef enum +{ + PZX_CLOSED, /* File is not open */ + PZX_IDLE, /* File is open, no block loaded */ + PZX_IN_PULS, /* File is open, current block is a PULS block */ + PZX_IN_DATA, /* File is open, current block is a DATA block */ + PZX_IN_PAUS, /* File is open, current block is a PAUS block */ +} PZX_STATE; + + +typedef struct pzxfile_t +{ + FILE *input; /* Input PZX file */ + uint8_t *curblock; /* Currently-loaded block, if any */ + int level; /* Current signal level */ + PZX_STATE state; /* State machine current status */ +/* State variables for PULS */ + uint32_t puls_ptr; /* Pointer within PULS block */ + uint32_t puls_len; /* Length of PULS block */ + uint32_t puls_count; /* Count of pulses */ + uint32_t puls_duration; /* Duration of each pulse */ + uint32_t puls_remain; /* Time remaining in this pulse */ +/* State variables for PAUS */ + uint32_t paus_remain; /* Time remaining in this pause */ +/* State variables for DATA */ + uint32_t data_ptr; /* Pointer within DATA block */ + uint32_t data_bits; /* Count of bits */ + uint16_t data_tail; /* Length of pulse after last bit */ + uint8_t data_mask; /* Mask for current bit */ + uint8_t data_p0; /* Length of 0 encoding */ + uint8_t data_p1; /* Length of 1 encoding */ + int data_p; /* Current sequence being emitted */ + uint32_t data_w; /* Current waveform */ + uint32_t data_remain; /* Current data pulse time remaining */ +} pzxfile_t; + +uint8_t *pzx_load_block(FILE *fp); + +/* Initialise structure */ +void pzx_init(pzxfile_t *pzx); + +/* Open file for input */ +wchar_t *pzx_open(pzxfile_t *pzx, FILE *fp); + +/* Close file */ +void pzx_close(pzxfile_t *pzx); + +/* Advance by 'time' samples (3.5MHz sample rate) and return current state */ +int pzx_advance(pzxfile_t *pzx, int time); diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index f6639dab1..3bd86f710 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -359,7 +359,7 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) { uint8_t ret; subchannel_t subc; - int pos = 0; + int pos = 1; dev->ops->get_subchannel(dev, dev->seek_pos, &subc); cdrom_log("CD-ROM %i: Returned subchannel at %02i:%02i.%02i\n", subc.abs_m, subc.abs_s, subc.abs_f); @@ -375,6 +375,9 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) ret = 0x13; } + if (b[pos] > 1) + return ret; + b[pos++] = subc.attr; b[pos++] = subc.track; b[pos++] = subc.index; @@ -1003,6 +1006,7 @@ cdrom_hard_reset(void) switch(dev->bus_type) { case CDROM_BUS_ATAPI: case CDROM_BUS_SCSI: + case CDROM_BUS_SCSI_CHINON: scsi_cdrom_drive_reset(i); break; diff --git a/src/cdrom/cdrom.h b/src/cdrom/cdrom.h index 92e947af3..b38868135 100644 --- a/src/cdrom/cdrom.h +++ b/src/cdrom/cdrom.h @@ -58,6 +58,7 @@ enum { CDROM_BUS_DISABLED = 0, CDROM_BUS_ATAPI = 4, CDROM_BUS_SCSI, + CDROM_BUS_SCSI_CHINON, CDROM_BUS_USB }; diff --git a/src/cdrom/cdrom_dosbox.cpp b/src/cdrom/cdrom_dosbox.cpp index 6bd8fd955..0087dedcf 100644 --- a/src/cdrom/cdrom_dosbox.cpp +++ b/src/cdrom/cdrom_dosbox.cpp @@ -1,664 +1,873 @@ /* - * Copyright (C) 2002-2015 The DOSBox Team + * 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 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 file is part of the VARCem Project. * - * 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. + * CD-ROM image file handling module. * - * 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. + * 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.11 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. */ - -/* Modified for use with PCem by bit */ - #define _LARGEFILE_SOURCE #define _LARGEFILE64_SOURCE -#ifdef _WIN32 -//FIXME: should not be needed. */ -# define _GNU_SOURCE -#endif +#define __STDC_FORMAT_MACROS +#include +#include +#include #include #include - -#include -#include -#include -#include -#include -#include -#include //GCC 2.95 -#include +#include +#ifdef _WIN32 +# include +#else +# include +#endif +#include #include -#include +#define HAVE_STDARG_H +#include "../86box.h" #include "../plat.h" #include "cdrom_dosbox.h" -#ifndef _WIN32 -# include -#else -# include -#endif - using namespace std; + #define MAX_LINE_LENGTH 512 #define MAX_FILENAME_LENGTH 256 #define CROSS_LEN 512 -#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0) -CDROM_Interface_Image::BinaryFile::BinaryFile(const char *filename, bool &error) + +#ifdef ENABLE_CDROM_DOSBOX_LOG +int cdrom_dosbox_do_log = ENABLE_CDROM_DOSBOX_LOG; + + +void +cdrom_dosbox_log(const char *fmt, ...) { - memset(fn, 0, sizeof(fn)); - strcpy(fn, filename); - file = fopen64(fn, "rb"); - if (file == NULL) - error = true; - else - error = false; + 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() + +CDROM_Interface_Image::BinaryFile::~BinaryFile(void) { + if (file != NULL) { fclose(file); file = NULL; - memset(fn, 0, sizeof(fn)); + } + memset(fn, 0x00, sizeof(fn)); } -bool CDROM_Interface_Image::BinaryFile::read(Bit8u *buffer, uint64_t seek, uint64_t count) + +bool +CDROM_Interface_Image::BinaryFile::read(uint8_t *buffer, uint64_t seek, size_t count) { - fseeko64(file, seek, SEEK_SET); - fread(buffer, 1, count, file); - return 1; -} + cdrom_dosbox_log("CDROM: binary_read(%08lx, pos=%" PRIu64 " count=%lu\n", + file, seek, count); + if (file == NULL) return 0; -uint64_t CDROM_Interface_Image::BinaryFile::getLength() -{ - fseeko64(file, 0, SEEK_END); - return ftello64(file); -} - -CDROM_Interface_Image::CDROM_Interface_Image() -{ - // printf("CDROM_Interface_Image constructor\n"); -} - -CDROM_Interface_Image::~CDROM_Interface_Image() -{ - // printf("CDROM_Interface_Image destructor\n"); - ClearTracks(); -} - -void CDROM_Interface_Image::InitNewMedia() -{ -} - -bool CDROM_Interface_Image::SetDevice(char* path, int forceCD) -{ - (void)forceCD; - if (LoadCueSheet(path)) return true; - if (LoadIsoFile(path)) return true; - - // print error message on dosbox console - //printf("Could not load image file: %s\n", path); - return false; -} - -bool CDROM_Interface_Image::GetUPC(unsigned char& attr, char* upc) -{ - attr = 0; - strcpy(upc, this->mcn.c_str()); - return true; -} - -bool CDROM_Interface_Image::GetAudioTracks(int& stTrack, int& end, TMSF& leadOut) -{ - stTrack = 1; - end = (int)(tracks.size() - 1); - FRAMES_TO_MSF(tracks[tracks.size() - 1].start + 150, &leadOut.min, &leadOut.sec, &leadOut.fr); - return true; -} - -bool CDROM_Interface_Image::GetAudioTrackInfo(int track, int& track_number, TMSF& start, unsigned char& attr) -{ - if (track < 1 || track > (int)tracks.size()) return false; - FRAMES_TO_MSF(tracks[track - 1].start + 150, &start.min, &start.sec, &start.fr); - track_number = tracks[track - 1].track_number; - attr = tracks[track - 1].attr; - return true; -} - -bool CDROM_Interface_Image::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, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) -{ - int cur_track = GetTrack(sector); - if (cur_track < 1) return false; - track = (unsigned char)cur_track; - attr = tracks[track - 1].attr; - index = 1; - FRAMES_TO_MSF(sector + 150, &absPos.min, &absPos.sec, &absPos.fr); - /* FRAMES_TO_MSF(sector - tracks[track - 1].start + 150, &relPos.min, &relPos.sec, &relPos.fr); */ - /* Note by Kotori: Yes, the absolute position should be adjusted by 150, but not the relative position. */ - FRAMES_TO_MSF(sector - tracks[track - 1].start, &relPos.min, &relPos.sec, &relPos.fr); - return true; -} - -bool CDROM_Interface_Image::GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen) -{ - mediaPresent = true; - mediaChanged = false; - trayOpen = false; - return true; -} - -bool CDROM_Interface_Image::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num) -{ - int sectorSize = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; - Bitu buflen = num * sectorSize; - Bit8u* buf = new Bit8u[buflen]; - - bool success = true; //Gobliiins reads 0 sectors - for(unsigned long i = 0; i < num; i++) { - success = ReadSector(&buf[i * sectorSize], raw, sector + i); - if (!success) break; - } - - memcpy((void*)buffer, buf, buflen); - delete[] buf; - - return success; -} - -bool CDROM_Interface_Image::LoadUnloadMedia(bool unload) -{ - (void)unload; - return true; -} - -int CDROM_Interface_Image::GetTrack(unsigned int sector) -{ - vector::iterator i = tracks.begin(); - vector::iterator end = tracks.end() - 1; - - while(i != end) { - Track &curr = *i; - Track &next = *(i + 1); - if (curr.start <= sector && sector < next.start) return curr.number; - i++; - } - return -1; -} - -bool CDROM_Interface_Image::ReadSector(Bit8u *buffer, bool raw, unsigned long sector) -{ - uint64_t length; - - int track = GetTrack(sector) - 1; - if (track < 0) return false; - - uint64_t s = (uint64_t) sector; - uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize); - if (tracks[track].mode2) - length = (raw ? RAW_SECTOR_SIZE : 2336); - else - length = (raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE); - if (tracks[track].sectorSize != RAW_SECTOR_SIZE && raw) return false; - if (tracks[track].sectorSize == RAW_SECTOR_SIZE && !tracks[track].mode2 && !raw) seek += 16; - if (tracks[track].mode2 && !raw) seek += 24; - - return tracks[track].file->read(buffer, seek, length); -} - -bool CDROM_Interface_Image::ReadSectorSub(Bit8u *buffer, unsigned long sector) -{ - int track = GetTrack(sector) - 1; - if (track < 0) return false; - - uint64_t s = (uint64_t) sector; - uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize); - if (tracks[track].sectorSize != 2448) return false; - - return tracks[track].file->read(buffer, seek, 2448); -} - -int CDROM_Interface_Image::GetSectorSize(unsigned long sector) -{ - int track = GetTrack(sector) - 1; - if (track < 0) return 0; - - return tracks[track].sectorSize; -} - -bool CDROM_Interface_Image::IsMode2(unsigned long sector) -{ - int track = GetTrack(sector) - 1; - if (track < 0) return false; - - if (tracks[track].mode2) - { - return true; - } - else - { - return false; - } -} - -int CDROM_Interface_Image::GetMode2Form(unsigned long sector) -{ - int track = GetTrack(sector) - 1; - if (track < 0) return false; - - return tracks[track].form; -} - -bool CDROM_Interface_Image::LoadIsoFile(char* filename) -{ - tracks.clear(); - - // data track - Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL}; - bool error; - track.file = new BinaryFile(filename, error); - if (error) { - delete track.file; - return false; - } - track.number = 1; - track.track_number = 1;//IMPORTANT: This is needed. - track.attr = DATA_TRACK;//data - track.form = 0; - - // try to detect iso type - if (CanReadPVD(track.file, COOKED_SECTOR_SIZE, false)) { - track.sectorSize = COOKED_SECTOR_SIZE; - track.mode2 = false; - } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, false)) { - track.sectorSize = RAW_SECTOR_SIZE; - track.mode2 = false; - } else if (CanReadPVD(track.file, 2324, true)) { - track.sectorSize = 2324; - track.form = 2; - track.mode2 = true; - } else if (CanReadPVD(track.file, 2336, true)) { - track.sectorSize = 2336; - track.mode2 = true; - } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, true)) { - track.sectorSize = RAW_SECTOR_SIZE; - track.mode2 = true; - } else { - /* Unknown mode: Assume regular 2048-byte sectors, this is needed so Apple Rhapsody ISO's can be mounted. */ - track.sectorSize = COOKED_SECTOR_SIZE; - track.mode2 = false; - } - - track.length = track.file->getLength() / track.sectorSize; - tracks.push_back(track); - - // leadout track - track.number = 2; - track.track_number = 0xAA; - track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ - track.start = track.length; - track.length = 0; - track.file = NULL; - tracks.push_back(track); - - return true; -} - -bool CDROM_Interface_Image::CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2) -{ - Bit8u pvd[COOKED_SECTOR_SIZE]; - uint64_t seek = 16 * sectorSize; // first vd is located at sector 16 - if (sectorSize == RAW_SECTOR_SIZE && !mode2) seek += 16; - if (mode2) seek += 24; - file->read(pvd, seek, COOKED_SECTOR_SIZE); - // pvd[0] = descriptor type, pvd[1..5] = standard identifier, pvd[6] = iso version (+8 for High Sierra) - return ((pvd[0] == 1 && !strncmp((char*)(&pvd[1]), "CD001", 5) && pvd[6] == 1) || - (pvd[8] == 1 && !strncmp((char*)(&pvd[9]), "CDROM", 5) && pvd[14] == 1)); -} - -#ifdef _WIN32 -static string dirname(char * file) { - char * sep = strrchr(file, '\\'); - if (sep == NULL) - sep = strrchr(file, '/'); - if (sep == NULL) - return ""; - else { - int len = (int)(sep - file); - char tmp[MAX_FILENAME_LENGTH]; - safe_strncpy(tmp, file, len+1); - return tmp; - } -} + 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; + } -bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) -{ - Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL}; - tracks.clear(); - uint64_t shift = 0; - uint64_t currPregap = 0; - uint64_t totalPregap = 0; - uint64_t prestart = 0; - bool success; - bool canAddTrack = false; - char tmp[MAX_FILENAME_LENGTH]; // dirname can change its argument - safe_strncpy(tmp, cuefile, MAX_FILENAME_LENGTH); - string pathname(dirname(tmp)); - ifstream in; - in.open(cuefile, ios::in); - if (in.fail()) return false; - - while(!in.eof()) { - // get next line - char buf[MAX_LINE_LENGTH]; - in.getline(buf, MAX_LINE_LENGTH); - if (in.fail() && !in.eof()) return false; // probably a binary file - istringstream line(buf); - - string command; - GetCueKeyword(command, line); - - if (command == "TRACK") { - if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); - else success = true; - - track.start = 0; - track.skip = 0; - currPregap = 0; - prestart = 0; - - line >> track.number; - track.track_number = track.number; - string type; - GetCueKeyword(type, line); - - track.form = 0; - - if (type == "AUDIO") { - track.sectorSize = RAW_SECTOR_SIZE; - track.attr = AUDIO_TRACK; - track.mode2 = false; - } else if (type == "MODE1/2048") { - track.sectorSize = COOKED_SECTOR_SIZE; - track.attr = DATA_TRACK; - track.mode2 = false; - } else if (type == "MODE1/2352") { - track.sectorSize = RAW_SECTOR_SIZE; - track.attr = DATA_TRACK; - track.mode2 = false; - } else if (type == "MODE2/2048") { - track.form = 1; - track.sectorSize = 2048; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "MODE2/2324") { - track.form = 2; - track.sectorSize = 2324; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "MODE2/2336") { - track.sectorSize = 2336; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "MODE2/2352") { - track.form = 1; /* Assume this is XA Mode 2 Form 1. */ - track.sectorSize = RAW_SECTOR_SIZE; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "CDG/2448") { - track.sectorSize = 2448; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "CDI/2336") { - track.sectorSize = 2336; - track.attr = DATA_TRACK; - track.mode2 = true; - } else if (type == "CDI/2352") { - track.sectorSize = RAW_SECTOR_SIZE; - track.attr = DATA_TRACK; - track.mode2 = true; - } else success = false; - - canAddTrack = true; - } - else if (command == "INDEX") { - uint64_t index; - line >> index; - uint64_t frame; - success = GetCueFrame(frame, line); - - if (index == 1) track.start = frame; - else if (index == 0) prestart = frame; - // ignore other indices - } - else if (command == "FILE") { - if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); - else success = true; - canAddTrack = false; - - string filename; - GetCueString(filename, line); - GetRealFileName(filename, pathname); - string type; - GetCueKeyword(type, line); - - track.file = NULL; - bool error = true; - if (type == "BINARY") { - track.file = new BinaryFile(filename.c_str(), error); - } - if (error) { - delete track.file; - success = false; - } - } - else if (command == "PREGAP") success = GetCueFrame(currPregap, line); - else if (command == "CATALOG") success = GetCueString(mcn, line); - // ignored commands - else if (command == "CDTEXTFILE" || command == "FLAGS" || command == "ISRC" - || command == "PERFORMER" || command == "POSTGAP" || command == "REM" - || command == "SONGWRITER" || command == "TITLE" || command == "") success = true; - // failure - else success = false; - - if (!success) return false; - } - // add last track - if (!AddTrack(track, shift, prestart, totalPregap, currPregap)) return false; - - // add leadout track - track.number++; - track.track_number = 0xAA; - // track.attr = 0;//sync with load iso - track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ - // track.attr = last_attr | 0x02; - track.start = 0; - track.length = 0; - track.file = NULL; - if(!AddTrack(track, shift, 0, totalPregap, 0)) return false; - - return true; + return 1; } -bool CDROM_Interface_Image::AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap) + +uint64_t +CDROM_Interface_Image::BinaryFile::getLength(void) { - // 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; + 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; - // 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; - } + 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; - Track &prev = *(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; - // current track consumes data from the same file as the previous - if (prev.file == curr.file) { - curr.start += shift; - prev.length = curr.start + totalPregap - prev.start - skip; - curr.skip += prev.skip + (prev.length * prev.sectorSize) + (skip * curr.sectorSize); - totalPregap += currPregap; - curr.start += totalPregap; - // current track uses a different file as the previous track - } else { - uint64_t tmp = prev.file->getLength() - ((uint64_t) prev.skip); - prev.length = tmp / ((uint64_t) prev.sectorSize); - if (tmp % prev.sectorSize != 0) prev.length++; // padding - - curr.start += prev.start + prev.length + currPregap; - curr.skip = skip * curr.sectorSize; - shift += prev.start + prev.length; - totalPregap = currPregap; - } - - // error checks - if (curr.number <= 1) return false; - if (prev.number + 1 != curr.number) return false; - if (curr.start < prev.start + prev.length) return false; + if (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 - /* curr.length is unsigned, so... --FvK */ - if (curr.length < 0) return false; + 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; + 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 (fgets(buf, sizeof(buf), fp) == NULL || ferror(fp) || feof(fp)) + break; + 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, 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) + +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; + //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) + +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; + for (track_it it = tracks.begin(); it != tracks.end(); it++) { + if ((*it).attr == AUDIO_TRACK) return true; + } + return false; } -bool CDROM_Interface_Image::GetRealFileName(string &filename, string &pathname) +void +CDROM_Interface_Image::ClearTracks(void) { - // check if file exists - struct stat test; - if (stat(filename.c_str(), &test) == 0) return true; + vector::iterator i = tracks.begin(); + vector::iterator end = tracks.end(); - // check if file with path relative to cue file exists - string tmpstr(pathname + "/" + filename); - if (stat(tmpstr.c_str(), &test) == 0) { - filename = tmpstr; - return true; + TrackFile* last = NULL; + while(i != end) { + Track &curr = *i; + if (curr.file != last) { + delete curr.file; + last = curr.file; } -#if defined (_WIN32) || defined(OS2) - //Nothing -#else - //Consider the possibility that the filename has a windows directory seperator (inside the CUE file) - //which is common for some commercial rereleases of DOS games using DOSBox - - string copy = filename; - size_t l = copy.size(); - for (size_t i = 0; i < l;i++) { - if(copy[i] == '\\') copy[i] = '/'; - } - - if (stat(copy.c_str(), &test) == 0) { - filename = copy; - return true; - } - - tmpstr = pathname + "/" + copy; - if (stat(tmpstr.c_str(), &test) == 0) { - filename = tmpstr; - return true; - } - -#endif - return false; -} - -bool CDROM_Interface_Image::GetCueKeyword(string &keyword, istream &in) -{ - in >> keyword; - for(Bitu i = 0; i < keyword.size(); i++) keyword[i] = toupper(keyword[i]); - - return true; -} - -bool CDROM_Interface_Image::GetCueFrame(uint64_t &frames, istream &in) -{ - string msf; - in >> msf; - int min, sec, fr; - bool success = sscanf(msf.c_str(), "%d:%d:%d", &min, &sec, &fr) == 3; - frames = MSF_TO_FRAMES(min, sec, fr); - - return success; -} - -bool CDROM_Interface_Image::GetCueString(string &str, istream &in) -{ - int pos = (int)in.tellg(); - in >> str; - if (str[0] == '\"') { - if (str[str.size() - 1] == '\"') { - str.assign(str, 1, str.size() - 2); - } else { - in.seekg(pos, ios::beg); - char buffer[MAX_FILENAME_LENGTH]; - in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); // skip - in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); - str = buffer; - } - } - return true; -} - -void CDROM_Interface_Image::ClearTracks() -{ - vector::iterator i = tracks.begin(); - vector::iterator end = tracks.end(); - - TrackFile* last = NULL; - while(i != end) { - Track &curr = *i; - if (curr.file != last) { - delete curr.file; - last = curr.file; - } - i++; - } - tracks.clear(); + i++; + } + tracks.clear(); } diff --git a/src/cdrom/cdrom_dosbox.cpp.ok b/src/cdrom/cdrom_dosbox.cpp.ok new file mode 100644 index 000000000..6bd8fd955 --- /dev/null +++ b/src/cdrom/cdrom_dosbox.cpp.ok @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2002-2015 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Modified for use with PCem by bit */ + +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#ifdef _WIN32 +//FIXME: should not be needed. */ +# define _GNU_SOURCE +#endif +#include +#include + +#include +#include +#include +#include +#include +#include +#include //GCC 2.95 +#include +#include +#include +#include "../plat.h" +#include "cdrom_dosbox.h" + +#ifndef _WIN32 +# include +#else +# include +#endif + +using namespace std; + +#define MAX_LINE_LENGTH 512 +#define MAX_FILENAME_LENGTH 256 +#define CROSS_LEN 512 + +#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0) + +CDROM_Interface_Image::BinaryFile::BinaryFile(const char *filename, bool &error) +{ + memset(fn, 0, sizeof(fn)); + strcpy(fn, filename); + file = fopen64(fn, "rb"); + if (file == NULL) + error = true; + else + error = false; +} + +CDROM_Interface_Image::BinaryFile::~BinaryFile() +{ + fclose(file); + file = NULL; + memset(fn, 0, sizeof(fn)); +} + +bool CDROM_Interface_Image::BinaryFile::read(Bit8u *buffer, uint64_t seek, uint64_t count) +{ + fseeko64(file, seek, SEEK_SET); + fread(buffer, 1, count, file); + return 1; +} + +uint64_t CDROM_Interface_Image::BinaryFile::getLength() +{ + fseeko64(file, 0, SEEK_END); + return ftello64(file); +} + +CDROM_Interface_Image::CDROM_Interface_Image() +{ + // printf("CDROM_Interface_Image constructor\n"); +} + +CDROM_Interface_Image::~CDROM_Interface_Image() +{ + // printf("CDROM_Interface_Image destructor\n"); + ClearTracks(); +} + +void CDROM_Interface_Image::InitNewMedia() +{ +} + +bool CDROM_Interface_Image::SetDevice(char* path, int forceCD) +{ + (void)forceCD; + if (LoadCueSheet(path)) return true; + if (LoadIsoFile(path)) return true; + + // print error message on dosbox console + //printf("Could not load image file: %s\n", path); + return false; +} + +bool CDROM_Interface_Image::GetUPC(unsigned char& attr, char* upc) +{ + attr = 0; + strcpy(upc, this->mcn.c_str()); + return true; +} + +bool CDROM_Interface_Image::GetAudioTracks(int& stTrack, int& end, TMSF& leadOut) +{ + stTrack = 1; + end = (int)(tracks.size() - 1); + FRAMES_TO_MSF(tracks[tracks.size() - 1].start + 150, &leadOut.min, &leadOut.sec, &leadOut.fr); + return true; +} + +bool CDROM_Interface_Image::GetAudioTrackInfo(int track, int& track_number, TMSF& start, unsigned char& attr) +{ + if (track < 1 || track > (int)tracks.size()) return false; + FRAMES_TO_MSF(tracks[track - 1].start + 150, &start.min, &start.sec, &start.fr); + track_number = tracks[track - 1].track_number; + attr = tracks[track - 1].attr; + return true; +} + +bool CDROM_Interface_Image::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, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) +{ + int cur_track = GetTrack(sector); + if (cur_track < 1) return false; + track = (unsigned char)cur_track; + attr = tracks[track - 1].attr; + index = 1; + FRAMES_TO_MSF(sector + 150, &absPos.min, &absPos.sec, &absPos.fr); + /* FRAMES_TO_MSF(sector - tracks[track - 1].start + 150, &relPos.min, &relPos.sec, &relPos.fr); */ + /* Note by Kotori: Yes, the absolute position should be adjusted by 150, but not the relative position. */ + FRAMES_TO_MSF(sector - tracks[track - 1].start, &relPos.min, &relPos.sec, &relPos.fr); + return true; +} + +bool CDROM_Interface_Image::GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen) +{ + mediaPresent = true; + mediaChanged = false; + trayOpen = false; + return true; +} + +bool CDROM_Interface_Image::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num) +{ + int sectorSize = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; + Bitu buflen = num * sectorSize; + Bit8u* buf = new Bit8u[buflen]; + + bool success = true; //Gobliiins reads 0 sectors + for(unsigned long i = 0; i < num; i++) { + success = ReadSector(&buf[i * sectorSize], raw, sector + i); + if (!success) break; + } + + memcpy((void*)buffer, buf, buflen); + delete[] buf; + + return success; +} + +bool CDROM_Interface_Image::LoadUnloadMedia(bool unload) +{ + (void)unload; + return true; +} + +int CDROM_Interface_Image::GetTrack(unsigned int sector) +{ + vector::iterator i = tracks.begin(); + vector::iterator end = tracks.end() - 1; + + while(i != end) { + Track &curr = *i; + Track &next = *(i + 1); + if (curr.start <= sector && sector < next.start) return curr.number; + i++; + } + return -1; +} + +bool CDROM_Interface_Image::ReadSector(Bit8u *buffer, bool raw, unsigned long sector) +{ + uint64_t length; + + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + uint64_t s = (uint64_t) sector; + uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize); + if (tracks[track].mode2) + length = (raw ? RAW_SECTOR_SIZE : 2336); + else + length = (raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE); + if (tracks[track].sectorSize != RAW_SECTOR_SIZE && raw) return false; + if (tracks[track].sectorSize == RAW_SECTOR_SIZE && !tracks[track].mode2 && !raw) seek += 16; + if (tracks[track].mode2 && !raw) seek += 24; + + return tracks[track].file->read(buffer, seek, length); +} + +bool CDROM_Interface_Image::ReadSectorSub(Bit8u *buffer, unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + uint64_t s = (uint64_t) sector; + uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize); + if (tracks[track].sectorSize != 2448) return false; + + return tracks[track].file->read(buffer, seek, 2448); +} + +int CDROM_Interface_Image::GetSectorSize(unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return 0; + + return tracks[track].sectorSize; +} + +bool CDROM_Interface_Image::IsMode2(unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + if (tracks[track].mode2) + { + return true; + } + else + { + return false; + } +} + +int CDROM_Interface_Image::GetMode2Form(unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + return tracks[track].form; +} + +bool CDROM_Interface_Image::LoadIsoFile(char* filename) +{ + tracks.clear(); + + // data track + Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL}; + bool error; + track.file = new BinaryFile(filename, error); + if (error) { + delete track.file; + return false; + } + track.number = 1; + track.track_number = 1;//IMPORTANT: This is needed. + track.attr = DATA_TRACK;//data + track.form = 0; + + // try to detect iso type + if (CanReadPVD(track.file, COOKED_SECTOR_SIZE, false)) { + track.sectorSize = COOKED_SECTOR_SIZE; + track.mode2 = false; + } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, false)) { + track.sectorSize = RAW_SECTOR_SIZE; + track.mode2 = false; + } else if (CanReadPVD(track.file, 2324, true)) { + track.sectorSize = 2324; + track.form = 2; + track.mode2 = true; + } else if (CanReadPVD(track.file, 2336, true)) { + track.sectorSize = 2336; + track.mode2 = true; + } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, true)) { + track.sectorSize = RAW_SECTOR_SIZE; + track.mode2 = true; + } else { + /* Unknown mode: Assume regular 2048-byte sectors, this is needed so Apple Rhapsody ISO's can be mounted. */ + track.sectorSize = COOKED_SECTOR_SIZE; + track.mode2 = false; + } + + track.length = track.file->getLength() / track.sectorSize; + tracks.push_back(track); + + // leadout track + track.number = 2; + track.track_number = 0xAA; + track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ + track.start = track.length; + track.length = 0; + track.file = NULL; + tracks.push_back(track); + + return true; +} + +bool CDROM_Interface_Image::CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2) +{ + Bit8u pvd[COOKED_SECTOR_SIZE]; + uint64_t seek = 16 * sectorSize; // first vd is located at sector 16 + if (sectorSize == RAW_SECTOR_SIZE && !mode2) seek += 16; + if (mode2) seek += 24; + file->read(pvd, seek, COOKED_SECTOR_SIZE); + // pvd[0] = descriptor type, pvd[1..5] = standard identifier, pvd[6] = iso version (+8 for High Sierra) + return ((pvd[0] == 1 && !strncmp((char*)(&pvd[1]), "CD001", 5) && pvd[6] == 1) || + (pvd[8] == 1 && !strncmp((char*)(&pvd[9]), "CDROM", 5) && pvd[14] == 1)); +} + +#ifdef _WIN32 +static string dirname(char * file) { + char * sep = strrchr(file, '\\'); + if (sep == NULL) + sep = strrchr(file, '/'); + if (sep == NULL) + return ""; + else { + int len = (int)(sep - file); + char tmp[MAX_FILENAME_LENGTH]; + safe_strncpy(tmp, file, len+1); + return tmp; + } +} +#endif + +bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) +{ + Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL}; + tracks.clear(); + uint64_t shift = 0; + uint64_t currPregap = 0; + uint64_t totalPregap = 0; + uint64_t prestart = 0; + bool success; + bool canAddTrack = false; + char tmp[MAX_FILENAME_LENGTH]; // dirname can change its argument + safe_strncpy(tmp, cuefile, MAX_FILENAME_LENGTH); + string pathname(dirname(tmp)); + ifstream in; + in.open(cuefile, ios::in); + if (in.fail()) return false; + + while(!in.eof()) { + // get next line + char buf[MAX_LINE_LENGTH]; + in.getline(buf, MAX_LINE_LENGTH); + if (in.fail() && !in.eof()) return false; // probably a binary file + istringstream line(buf); + + string command; + GetCueKeyword(command, line); + + if (command == "TRACK") { + if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); + else success = true; + + track.start = 0; + track.skip = 0; + currPregap = 0; + prestart = 0; + + line >> track.number; + track.track_number = track.number; + string type; + GetCueKeyword(type, line); + + track.form = 0; + + if (type == "AUDIO") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = AUDIO_TRACK; + track.mode2 = false; + } else if (type == "MODE1/2048") { + track.sectorSize = COOKED_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = false; + } else if (type == "MODE1/2352") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = false; + } else if (type == "MODE2/2048") { + track.form = 1; + track.sectorSize = 2048; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "MODE2/2324") { + track.form = 2; + track.sectorSize = 2324; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "MODE2/2336") { + track.sectorSize = 2336; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "MODE2/2352") { + track.form = 1; /* Assume this is XA Mode 2 Form 1. */ + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "CDG/2448") { + track.sectorSize = 2448; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "CDI/2336") { + track.sectorSize = 2336; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "CDI/2352") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = true; + } else success = false; + + canAddTrack = true; + } + else if (command == "INDEX") { + uint64_t index; + line >> index; + uint64_t frame; + success = GetCueFrame(frame, line); + + if (index == 1) track.start = frame; + else if (index == 0) prestart = frame; + // ignore other indices + } + else if (command == "FILE") { + if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); + else success = true; + canAddTrack = false; + + string filename; + GetCueString(filename, line); + GetRealFileName(filename, pathname); + string type; + GetCueKeyword(type, line); + + track.file = NULL; + bool error = true; + if (type == "BINARY") { + track.file = new BinaryFile(filename.c_str(), error); + } + if (error) { + delete track.file; + success = false; + } + } + else if (command == "PREGAP") success = GetCueFrame(currPregap, line); + else if (command == "CATALOG") success = GetCueString(mcn, line); + // ignored commands + else if (command == "CDTEXTFILE" || command == "FLAGS" || command == "ISRC" + || command == "PERFORMER" || command == "POSTGAP" || command == "REM" + || command == "SONGWRITER" || command == "TITLE" || command == "") success = true; + // failure + else success = false; + + if (!success) return false; + } + // add last track + if (!AddTrack(track, shift, prestart, totalPregap, currPregap)) return false; + + // add leadout track + track.number++; + track.track_number = 0xAA; + // track.attr = 0;//sync with load iso + track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ + // track.attr = last_attr | 0x02; + track.start = 0; + track.length = 0; + track.file = NULL; + if(!AddTrack(track, shift, 0, totalPregap, 0)) return false; + + return true; +} + +bool CDROM_Interface_Image::AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap) +{ + // frames between index 0(prestart) and 1(curr.start) must be skipped + uint64_t skip; + if (prestart > 0) { + if (prestart > curr.start) return false; + skip = curr.start - prestart; + } else skip = 0; + + // first track (track number must be 1) + if (tracks.empty()) { + if (curr.number != 1) return false; + curr.skip = skip * curr.sectorSize; + curr.start += currPregap; + totalPregap = currPregap; + tracks.push_back(curr); + return true; + } + + Track &prev = *(tracks.end() - 1); + + // current track consumes data from the same file as the previous + if (prev.file == curr.file) { + curr.start += shift; + prev.length = curr.start + totalPregap - prev.start - skip; + curr.skip += prev.skip + (prev.length * prev.sectorSize) + (skip * curr.sectorSize); + totalPregap += currPregap; + curr.start += totalPregap; + // current track uses a different file as the previous track + } else { + uint64_t tmp = prev.file->getLength() - ((uint64_t) prev.skip); + prev.length = tmp / ((uint64_t) prev.sectorSize); + if (tmp % prev.sectorSize != 0) prev.length++; // padding + + curr.start += prev.start + prev.length + currPregap; + curr.skip = skip * curr.sectorSize; + shift += prev.start + prev.length; + totalPregap = currPregap; + } + + // error checks + if (curr.number <= 1) return false; + if (prev.number + 1 != curr.number) return false; + if (curr.start < prev.start + prev.length) return false; +#if 0 + /* curr.length is unsigned, so... --FvK */ + if (curr.length < 0) return false; +#endif + + tracks.push_back(curr); + return true; +} + +bool CDROM_Interface_Image::HasDataTrack(void) +{ + //Data track has attribute 0x14 + for(track_it it = tracks.begin(); it != tracks.end(); it++) { + if ((*it).attr == DATA_TRACK) return true; + } + return false; +} + +bool CDROM_Interface_Image::HasAudioTracks(void) +{ + for(track_it it = tracks.begin(); it != tracks.end(); it++) { + if ((*it).attr == AUDIO_TRACK) return true; + } + return false; +} + + +bool CDROM_Interface_Image::GetRealFileName(string &filename, string &pathname) +{ + // check if file exists + struct stat test; + if (stat(filename.c_str(), &test) == 0) return true; + + // check if file with path relative to cue file exists + string tmpstr(pathname + "/" + filename); + if (stat(tmpstr.c_str(), &test) == 0) { + filename = tmpstr; + return true; + } +#if defined (_WIN32) || defined(OS2) + //Nothing +#else + //Consider the possibility that the filename has a windows directory seperator (inside the CUE file) + //which is common for some commercial rereleases of DOS games using DOSBox + + string copy = filename; + size_t l = copy.size(); + for (size_t i = 0; i < l;i++) { + if(copy[i] == '\\') copy[i] = '/'; + } + + if (stat(copy.c_str(), &test) == 0) { + filename = copy; + return true; + } + + tmpstr = pathname + "/" + copy; + if (stat(tmpstr.c_str(), &test) == 0) { + filename = tmpstr; + return true; + } + +#endif + return false; +} + +bool CDROM_Interface_Image::GetCueKeyword(string &keyword, istream &in) +{ + in >> keyword; + for(Bitu i = 0; i < keyword.size(); i++) keyword[i] = toupper(keyword[i]); + + return true; +} + +bool CDROM_Interface_Image::GetCueFrame(uint64_t &frames, istream &in) +{ + string msf; + in >> msf; + int min, sec, fr; + bool success = sscanf(msf.c_str(), "%d:%d:%d", &min, &sec, &fr) == 3; + frames = MSF_TO_FRAMES(min, sec, fr); + + return success; +} + +bool CDROM_Interface_Image::GetCueString(string &str, istream &in) +{ + int pos = (int)in.tellg(); + in >> str; + if (str[0] == '\"') { + if (str[str.size() - 1] == '\"') { + str.assign(str, 1, str.size() - 2); + } else { + in.seekg(pos, ios::beg); + char buffer[MAX_FILENAME_LENGTH]; + in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); // skip + in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); + str = buffer; + } + } + return true; +} + +void CDROM_Interface_Image::ClearTracks() +{ + vector::iterator i = tracks.begin(); + vector::iterator end = tracks.end(); + + TrackFile* last = NULL; + while(i != end) { + Track &curr = *i; + if (curr.file != last) { + delete curr.file; + last = curr.file; + } + i++; + } + tracks.clear(); +} diff --git a/src/cdrom/cdrom_dosbox.h b/src/cdrom/cdrom_dosbox.h index e3d346031..93b80340f 100644 --- a/src/cdrom/cdrom_dosbox.h +++ b/src/cdrom/cdrom_dosbox.h @@ -1,26 +1,45 @@ /* - * Copyright (C) 2002-2015 The DOSBox Team + * 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 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 file is part of the VARCem Project. * - * 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. + * Definitions for the CD-ROM image file handling module. * - * 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. + * 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 -/* Modified for use with PCem by bit */ - -#ifndef __CDROM_INTERFACE__ -#define __CDROM_INTERFACE__ - +#include #include #include #include @@ -28,18 +47,17 @@ #include #include -#include -typedef signed int Bits; -typedef unsigned int Bitu; -typedef int8_t Bit8s; -typedef uint8_t Bit8u; -typedef int16_t Bit16s; -typedef uint16_t Bit16u; -typedef int32_t Bit32s; -typedef uint32_t Bit32u; +//typedef 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 @@ -48,130 +66,135 @@ typedef size_t PhysPt; #define CD_FPS 75 #define FRAMES_TO_MSF(f, M,S,F) { \ - int value = f; \ - *(F) = value%CD_FPS; \ + uint64_t value = f; \ + *(F) = (value%CD_FPS) & 0xff; \ value /= CD_FPS; \ - *(S) = value%60; \ + *(S) = (value%60) & 0xff; \ value /= 60; \ - *(M) = value; \ + *(M) = value & 0xff; \ } #define MSF_TO_FRAMES(M, S, F) ((M)*60*CD_FPS+(S)*CD_FPS+(F)) typedef struct SMSF { - unsigned char min; - unsigned char sec; - unsigned char fr; + uint8_t min; + uint8_t sec; + uint8_t fr; } TMSF; typedef struct SCtrl { - Bit8u out[4]; // output channel - Bit8u vol[4]; // channel volume + uint8_t out[4]; // output channel + uint8_t vol[4]; // channel volume } TCtrl; -extern int CDROM_GetMountType(char* path, int force); -class CDROM_Interface -{ +class CDROM_Interface { public: -// CDROM_Interface (void); - virtual ~CDROM_Interface (void) {}; +// CDROM_Interface(void); - virtual bool SetDevice (char* path, int forceCD) = 0; + virtual ~CDROM_Interface(void) {}; - virtual bool GetUPC (unsigned char& attr, char* upc) = 0; + virtual bool SetDevice(const wchar_t *path, int forceCD) = 0; - virtual bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut) = 0; - virtual bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr) = 0; - virtual bool GetAudioTrackEndInfo (int track, int& number, TMSF& start, unsigned char& attr) = 0; - virtual bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) = 0; - virtual bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen) = 0; + virtual bool GetUPC(uint8_t& attr, char* upc) = 0; - virtual bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num) = 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 LoadUnloadMedia (bool unload) = 0; + virtual bool ReadSectors(PhysPt buffer, bool raw, uint32_t sector, uint32_t num) = 0; - virtual void InitNewMedia (void) {}; + virtual bool LoadUnloadMedia(bool unload) = 0; + + virtual void InitNewMedia(void) {}; }; -class CDROM_Interface_Image : public CDROM_Interface -{ + +class CDROM_Interface_Image : public CDROM_Interface { private: - class TrackFile { + class TrackFile { public: - virtual bool read(Bit8u *buffer, uint64_t seek, uint64_t count) = 0; + virtual bool read(uint8_t *buffer, uint64_t seek, size_t count) = 0; virtual uint64_t getLength() = 0; virtual ~TrackFile() { }; - }; + }; - class BinaryFile : public TrackFile { + class BinaryFile : public TrackFile { public: - BinaryFile(const char *filename, bool &error); + BinaryFile(const wchar_t *filename, bool &error); ~BinaryFile(); - bool read(Bit8u *buffer, uint64_t seek, uint64_t count); + bool read(uint8_t *buffer, uint64_t seek, size_t count); uint64_t getLength(); private: BinaryFile(); - char fn[260]; + 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; - uint64_t sectorSize; - bool mode2; - TrackFile *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 (char* path, int forceCD); - bool GetUPC (unsigned char& attr, char* upc); - bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut); - bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr); - bool GetAudioTrackEndInfo (int track, int& number, TMSF& start, unsigned char& attr); - bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos); - bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen); - bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num); - bool LoadUnloadMedia (bool unload); - bool ReadSector (Bit8u *buffer, bool raw, unsigned long sector); - bool ReadSectorSub (Bit8u *buffer, unsigned long sector); - int GetSectorSize (unsigned long sector); - bool IsMode2 (unsigned long sector); - int GetMode2Form (unsigned long sector); - bool HasDataTrack (void); - bool HasAudioTracks (void); + 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); + int GetTrack(unsigned int sector); private: - // player -static void CDAudioCallBack(Bitu len); + // player + static void CDAudioCallBack(unsigned int len); - void ClearTracks(); - bool LoadIsoFile(char *filename); - bool CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2); - // cue sheet processing - bool LoadCueSheet(char *cuefile); - bool GetRealFileName(std::string& filename, std::string& pathname); - bool GetCueKeyword(std::string &keyword, std::istream &in); - bool GetCueFrame(uint64_t &frames, std::istream &in); - bool GetCueString(std::string &str, std::istream &in); - bool AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap); + void ClearTracks(); + bool IsoLoadFile(const wchar_t *filename); + bool CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2); - std::vector tracks; + // 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; + std::string mcn; }; -void cdrom_image_log(const char *format, ...); + +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_dosbox.h.ok b/src/cdrom/cdrom_dosbox.h.ok new file mode 100644 index 000000000..e3d346031 --- /dev/null +++ b/src/cdrom/cdrom_dosbox.h.ok @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2002-2015 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Modified for use with PCem by bit */ + +#ifndef __CDROM_INTERFACE__ +#define __CDROM_INTERFACE__ + +#include +#include +#include +#include +#include +#include + +#include +typedef signed int Bits; +typedef unsigned int Bitu; +typedef int8_t Bit8s; +typedef uint8_t Bit8u; +typedef int16_t Bit16s; +typedef uint16_t Bit16u; +typedef int32_t Bit32s; +typedef uint32_t Bit32u; + +typedef size_t PhysPt; + +#define RAW_SECTOR_SIZE 2352 +#define COOKED_SECTOR_SIZE 2048 + +#define DATA_TRACK 0x14 +#define AUDIO_TRACK 0x10 + +#define CD_FPS 75 +#define FRAMES_TO_MSF(f, M,S,F) { \ + int value = f; \ + *(F) = value%CD_FPS; \ + value /= CD_FPS; \ + *(S) = value%60; \ + value /= 60; \ + *(M) = value; \ +} +#define MSF_TO_FRAMES(M, S, F) ((M)*60*CD_FPS+(S)*CD_FPS+(F)) + + +typedef struct SMSF { + unsigned char min; + unsigned char sec; + unsigned char fr; +} TMSF; + +typedef struct SCtrl { + Bit8u out[4]; // output channel + Bit8u vol[4]; // channel volume +} TCtrl; + +extern int CDROM_GetMountType(char* path, int force); + +class CDROM_Interface +{ +public: +// CDROM_Interface (void); + virtual ~CDROM_Interface (void) {}; + + virtual bool SetDevice (char* path, int forceCD) = 0; + + virtual bool GetUPC (unsigned char& attr, char* upc) = 0; + + virtual bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut) = 0; + virtual bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr) = 0; + virtual bool GetAudioTrackEndInfo (int track, int& number, TMSF& start, unsigned char& attr) = 0; + virtual bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) = 0; + virtual bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen) = 0; + + virtual bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num) = 0; + + virtual bool LoadUnloadMedia (bool unload) = 0; + + virtual void InitNewMedia (void) {}; +}; + +class CDROM_Interface_Image : public CDROM_Interface +{ +private: + class TrackFile { + public: + virtual bool read(Bit8u *buffer, uint64_t seek, uint64_t count) = 0; + virtual uint64_t getLength() = 0; + virtual ~TrackFile() { }; + }; + + class BinaryFile : public TrackFile { + public: + BinaryFile(const char *filename, bool &error); + ~BinaryFile(); + bool read(Bit8u *buffer, uint64_t seek, uint64_t count); + uint64_t getLength(); + private: + BinaryFile(); + char fn[260]; + FILE *file; + }; + + struct Track { + int number; + int track_number; + int attr; + int form; + uint64_t start; + uint64_t length; + uint64_t skip; + uint64_t sectorSize; + bool mode2; + TrackFile *file; + }; + +public: + CDROM_Interface_Image (); + virtual ~CDROM_Interface_Image (void); + void InitNewMedia (void); + bool SetDevice (char* path, int forceCD); + bool GetUPC (unsigned char& attr, char* upc); + bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut); + bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr); + bool GetAudioTrackEndInfo (int track, int& number, TMSF& start, unsigned char& attr); + bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos); + bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen); + bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num); + bool LoadUnloadMedia (bool unload); + bool ReadSector (Bit8u *buffer, bool raw, unsigned long sector); + bool ReadSectorSub (Bit8u *buffer, unsigned long sector); + int GetSectorSize (unsigned long sector); + bool IsMode2 (unsigned long sector); + int GetMode2Form (unsigned long sector); + bool HasDataTrack (void); + bool HasAudioTracks (void); + + int GetTrack (unsigned int sector); + +private: + // player +static void CDAudioCallBack(Bitu len); + + void ClearTracks(); + bool LoadIsoFile(char *filename); + bool CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2); + // cue sheet processing + bool LoadCueSheet(char *cuefile); + bool GetRealFileName(std::string& filename, std::string& pathname); + bool GetCueKeyword(std::string &keyword, std::istream &in); + bool GetCueFrame(uint64_t &frames, std::istream &in); + bool GetCueString(std::string &str, std::istream &in); + bool AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap); + + std::vector tracks; +typedef std::vector::iterator track_it; + std::string mcn; +}; + +void cdrom_image_log(const char *format, ...); + +#endif /* __CDROM_INTERFACE__ */ diff --git a/src/cdrom/cdrom_image.cc b/src/cdrom/cdrom_image.cc index 94394a01b..4eb6c6499 100644 --- a/src/cdrom/cdrom_image.cc +++ b/src/cdrom/cdrom_image.cc @@ -8,15 +8,15 @@ * * CD-ROM image support. * - * Version: @(#)cdrom_image.cc 1.0.9 2019/02/01 + * Version: @(#)cdrom_image.cc 1.0.10 2019/03/06 * * Author: RichardG867, * Miran Grca, * bit, * - * Copyright 2015-2018 Richardg867. - * Copyright 2015-2018 Miran Grca. - * Copyright 2017,2018 bit. + * Copyright 2015-2019 Richardg867. + * Copyright 2015-2019 Miran Grca. + * Copyright 2017-2019 bit. */ #define __USE_LARGEFILE64 #define _LARGEFILE_SOURCE @@ -27,6 +27,8 @@ #include #include #include +#define HAVE_STDARG_H +#include "../86box.h" #include "../config.h" #include "../plat.h" #include "../scsi/scsi_device.h" @@ -108,7 +110,7 @@ image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) static int -image_get_last_block(cdrom_t *dev) +image_get_capacity(cdrom_t *dev) { CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; int first_track, last_track; @@ -250,7 +252,6 @@ image_open_abort(cdrom_t *dev) int cdrom_image_open(cdrom_t *dev, const wchar_t *fn) { - char temp[1024]; CDROM_Interface_Image *img; wcscpy(dev->image_path, fn); @@ -265,10 +266,8 @@ cdrom_image_open(cdrom_t *dev, const wchar_t *fn) dev->image = img; - /* Convert filename and open the image. */ - memset(temp, '\0', sizeof(temp)); - wcstombs(temp, fn, sizeof(temp)); - if (!img->SetDevice(temp, false)) + /* Open the image. */ + if (! img->SetDevice(fn, false)) return image_open_abort(dev); /* All good, reset state. */ @@ -278,7 +277,8 @@ cdrom_image_open(cdrom_t *dev, const wchar_t *fn) dev->cd_status = CD_STATUS_STOPPED; dev->seek_pos = 0; dev->cd_buflen = 0; - dev->cdrom_capacity = image_get_last_block(dev) + 1; + dev->cdrom_capacity = image_get_capacity(dev); + cdrom_image_log("CD-ROM capacity: %i sectors (%i bytes)\n", dev->cdrom_capacity, dev->cdrom_capacity << 11); /* Attach this handler to the drive. */ dev->ops = &cdrom_image_ops; diff --git a/src/chipset/acc2168.c b/src/chipset/acc2168.c new file mode 100644 index 000000000..aca29d4f2 --- /dev/null +++ b/src/chipset/acc2168.c @@ -0,0 +1,171 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the ACC 2168 chipset + * used by the Packard Bell Legend 760 Supreme (PB410A or PB430). + * + * Version: @(#)acc2168.c 1.0.0 2019/05/13 + * + * Authors: Sarah Walker, + * + * Copyright 2019 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../timer.h" +#include "../device.h" +#include "../keyboard.h" +#include "../io.h" +#include "../mem.h" +#include "../mouse.h" +#include "../port_92.h" +#include "../sio.h" +#include "../disk/hdc.h" +#include "../video/video.h" +#include "../video/vid_ht216.h" +#include "chipset.h" + + +typedef struct acc2168_t +{ + int reg_idx; + uint8_t regs[256]; + uint8_t port_78; +} acc2168_t; + + +static void +acc2168_shadow_recalc(acc2168_t *dev) +{ + if (dev->regs[0x02] & 8) { + switch (dev->regs[0x02] & 0x30) { + case 0x00: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x10: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x20: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 0x30: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + if (dev->regs[0x02] & 4) { + switch (dev->regs[0x02] & 0x30) { + case 0x00: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x10: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x20: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 0x30: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } else + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} + + +static void +acc2168_write(uint16_t addr, uint8_t val, void *p) +{ + acc2168_t *dev = (acc2168_t *)p; + + if (!(addr & 1)) + dev->reg_idx = val; + else { + dev->regs[dev->reg_idx] = val; + + switch (dev->reg_idx) { + case 0x02: + acc2168_shadow_recalc(dev); + break; + } + } +} + + +static uint8_t +acc2168_read(uint16_t addr, void *p) +{ + acc2168_t *dev = (acc2168_t *)p; + + if (!(addr & 1)) + return dev->reg_idx; + + return dev->regs[dev->reg_idx]; +} + + +/* + Bit 7 = Super I/O chip: 1 = enabled, 0 = disabled; + Bit 6 = Graphics card: 1 = standalone, 0 = on-board; + Bit 5 = ???? (if 1, siren and hangs). +*/ +static uint8_t +acc2168_port_78_read(uint16_t addr, void *p) +{ + acc2168_t *dev = (acc2168_t *)p; + + return dev->port_78; +} + + +static void +acc2168_close(void *priv) +{ + acc2168_t *dev = (acc2168_t *) priv; + + free(dev); +} + + +static void * +acc2168_init(const device_t *info) +{ + acc2168_t *dev = (acc2168_t *)malloc(sizeof(acc2168_t)); + memset(dev, 0, sizeof(acc2168_t)); + + io_sethandler(0x00f2, 0x0002, + acc2168_read, NULL, NULL, acc2168_write, NULL, NULL, dev); + io_sethandler(0x0078, 0x0001, + acc2168_port_78_read, NULL, NULL, NULL, NULL, NULL, dev); + + device_add(&port_92_inv_device); + + if (gfxcard != VID_INTERNAL) + dev->port_78 = 0x40; + else + dev->port_78 = 0; + + return dev; +} + + +const device_t acc2168_device = { + "ACC 2168", + 0, + 0, + acc2168_init, acc2168_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/acer_m3a.c b/src/chipset/acer_m3a.c new file mode 100644 index 000000000..0d8ab2052 --- /dev/null +++ b/src/chipset/acer_m3a.c @@ -0,0 +1,97 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Acer M3A and V35N ports EAh and EBh. + * + * Version: @(#)acer_m3a.c 1.0.0 2019/05/13 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../keyboard.h" +#include "chipset.h" + + +typedef struct +{ + int index; +} acerm3a_t; + + +static void +acerm3a_out(uint16_t port, uint8_t val, void *p) +{ + acerm3a_t *dev = (acerm3a_t *) p; + + if (port == 0xea) + dev->index = val; +} + + +static uint8_t +acerm3a_in(uint16_t port, void *p) +{ + acerm3a_t *dev = (acerm3a_t *) p; + + if (port == 0xeb) { + switch (dev->index) { + case 2: + return 0xfd; + } + } + return 0xff; +} + + +static void +acerm3a_close(void *p) +{ + acerm3a_t *dev = (acerm3a_t *)p; + + free(dev); +} + + +static void +*acerm3a_init(const device_t *info) +{ + acerm3a_t *acerm3a = (acerm3a_t *) malloc(sizeof(acerm3a_t)); + memset(acerm3a, 0, sizeof(acerm3a_t)); + + io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, acerm3a); + + return acerm3a; +} + + +const device_t acerm3a_device = +{ + "Acer M3A Register", + 0, + 0, + acerm3a_init, + acerm3a_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/chipset/ali1429.c b/src/chipset/ali1429.c new file mode 100644 index 000000000..e01a8d11b --- /dev/null +++ b/src/chipset/ali1429.c @@ -0,0 +1,146 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the ALi M-1429/1431 chipset. + * + * Version: @(#)ali1429.c 1.0.8 2019/04/08 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../timer.h" +#include "../io.h" +#include "../mem.h" +#include "../device.h" +#include "../keyboard.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../timer.h" +#include "../port_92.h" +#include "chipset.h" + + +typedef struct +{ + uint8_t cur_reg, + regs[256]; +} ali1429_t; + + +static void +ali1429_recalc(ali1429_t *dev) +{ + uint32_t base; + uint32_t i, shflags = 0; + + shadowbios = 0; + shadowbios_write = 0; + + for (i = 0; i < 8; i++) { + base = 0xc0000 + (i << 15); + + if (dev->regs[0x13] & (1 << i)) { + shadowbios |= (base >= 0xe8000) && !!(dev->regs[0x14] & 0x01); + shadowbios_write |= (base >= 0xe8000) && !!(dev->regs[0x14] & 0x02); + shflags = (dev->regs[0x14] & 0x01) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL; + shflags |= !(dev->regs[0x14] & 0x02) ? MEM_WRITE_EXTERNAL : MEM_WRITE_INTERNAL; + mem_set_mem_state(base, 0x8000, shflags); + } else + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + flushmmucache(); +} + + +static void +ali1429_write(uint16_t port, uint8_t val, void *priv) +{ + ali1429_t *dev = (ali1429_t *) priv; + + if (port & 1) { + dev->regs[dev->cur_reg] = val; + + switch (dev->cur_reg) { + case 0x13: + ali1429_recalc(dev); + break; + case 0x14: + ali1429_recalc(dev); + break; + } + } else + dev->cur_reg = val; +} + + +static uint8_t +ali1429_read(uint16_t port, void *priv) +{ + uint8_t ret = 0xff; + ali1429_t *dev = (ali1429_t *) priv; + + if (!(port & 1)) + ret = dev->cur_reg; + else if (((dev->cur_reg >= 0xc0) || (dev->cur_reg == 0x20)) && cpu_iscyrix) + ret = 0xff; /*Don't conflict with Cyrix config registers*/ + else + ret = dev->regs[dev->cur_reg]; + + return ret; +} + + +static void +ali1429_close(void *priv) +{ + ali1429_t *dev = (ali1429_t *) priv; + + free(dev); +} + + +static void * +ali1429_init(const device_t *info) +{ + ali1429_t *dev = (ali1429_t *) malloc(sizeof(ali1429_t)); + memset(dev, 0, sizeof(ali1429_t)); + + memset(dev->regs, 0xff, 256); + dev->regs[0x13] = dev->regs[0x14] = 0x00; + + io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, dev); + + ali1429_recalc(dev); + + device_add(&port_92_device); + + return dev; +} + + +const device_t ali1429_device = { + "ALi-M1429", + 0, + 0, + ali1429_init, ali1429_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/chipset.h b/src/chipset/chipset.h new file mode 100644 index 000000000..bf2cda160 --- /dev/null +++ b/src/chipset/chipset.h @@ -0,0 +1,68 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Handling of the emulated chipsets. + * + * Version: @(#)machine.h 1.0.0 2019/05/13 + * + * Authors: Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#ifndef EMU_CHIPSET_H +# define EMU_CHIPSET_H + + +/* ACC */ +extern const device_t acc2168_device; + +/* Acer M3A and V35N */ +extern const device_t acerm3a_device; + +/* ALi */ +extern const device_t ali1429_device; + +/* Headland */ +extern const device_t headland_device; +extern const device_t headland_386_device; + +/* Intel 4x0xX */ +extern const device_t i420tx_device; +extern const device_t i430lx_device; +extern const device_t i430nx_device; +extern const device_t i430fx_device; +extern const device_t i430fx_pb640_device; +extern const device_t i430hx_device; +extern const device_t i430vx_device; +#if defined(DEV_BRANCH) && defined(USE_I686) +extern const device_t i440fx_device; +#endif + +/* NEAT */ +extern const device_t neat_device; + +/* OPTi */ +extern const device_t opti495_device; + +/* SCAT */ +extern const device_t scat_device; +extern const device_t scat_4_device; +extern const device_t scat_sx_device; + +/* SiS */ +extern const device_t sis_85c471_device; +extern const device_t sis_85c496_device; +#if defined(DEV_BRANCH) && defined(USE_SIS_85C50X) +extern const device_t sis_85c50x_device; +#endif + +/* WD */ +extern const device_t wd76c10_device; + + +#endif /*EMU_CHIPSET_H*/ diff --git a/src/chipset/headland.c b/src/chipset/headland.c new file mode 100644 index 000000000..7bb14d391 --- /dev/null +++ b/src/chipset/headland.c @@ -0,0 +1,635 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the HEADLAND AT286 chipset. + * + * Version: @(#)headland.c 1.0.0 2019/05/14 + * + * Authors: Sarah Walker, + * Fred N. van Kempen, + * Original by GreatPsycho for PCem. + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2017,2018 Miran Grca. + * Copyright 2017,2018 GreatPsycho. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../cpu/x86.h" +#include "../timer.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../keyboard.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../port_92.h" +#include "chipset.h" + + +typedef struct { + uint8_t valid, pad; + uint16_t mr; + + struct headland_t * headland; +} headland_mr_t; + + +typedef struct headland_t { + uint8_t type; + + uint8_t cri; + uint8_t cr[8]; + + uint8_t indx; + uint8_t regs[256]; + + uint8_t ems_mar; + + headland_mr_t null_mr, + ems_mr[64]; + + rom_t vid_bios; + + mem_mapping_t low_mapping; + mem_mapping_t ems_mapping[64]; + mem_mapping_t mid_mapping; + mem_mapping_t high_mapping; + mem_mapping_t upper_mapping[24]; +} headland_t; + + +/* TODO - Headland chipset's memory address mapping emulation isn't fully implemented yet, + so memory configuration is hardcoded now. */ +static const int mem_conf_cr0[41] = { + 0x00, 0x00, 0x20, 0x40, 0x60, 0xA0, 0x40, 0xE0, + 0xA0, 0xC0, 0xE0, 0xE0, 0xC0, 0xE0, 0xE0, 0xE0, + 0xE0, 0x20, 0x40, 0x40, 0xA0, 0xC0, 0xE0, 0xE0, + 0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0x20, 0x40, 0x60, 0x60, 0xC0, 0xE0, 0xE0, 0xE0, + 0xE0 +}; +static const int mem_conf_cr1[41] = { + 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, + 0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x40 +}; + + +static uint32_t +get_addr(headland_t *dev, uint32_t addr, headland_mr_t *mr) +{ + if (mr && mr->valid && (dev->cr[0] & 2) && (mr->mr & 0x200)) { + addr = (addr & 0x3fff) | ((mr->mr & 0x1F) << 14); + if (dev->cr[1] & 0x40) { + if ((dev->cr[4] & 0x80) && (dev->cr[6] & 1)) { + if (dev->cr[0] & 0x80) { + addr |= (mr->mr & 0x60) << 14; + if (mr->mr & 0x100) + addr += ((mr->mr & 0xC00) << 13) + (((mr->mr & 0x80) + 0x80) << 15); + else + addr += (mr->mr & 0x80) << 14; + } else if (mr->mr & 0x100) + addr += ((mr->mr & 0xC00) << 13) + (((mr->mr & 0x80) + 0x20) << 15); + else + addr += (mr->mr & 0x80) << 12; + } else if (dev->cr[0] & 0x80) + addr |= (mr->mr & 0x100) ? ((mr->mr & 0x80) + 0x400) << 12 : (mr->mr & 0xE0) << 14; + else + addr |= (mr->mr & 0x100) ? ((mr->mr & 0xE0) + 0x40) << 14 : (mr->mr & 0x80) << 12; + } else { + if ((dev->cr[4] & 0x80) && (dev->cr[6] & 1)) { + if (dev->cr[0] & 0x80) { + addr |= ((mr->mr & 0x60) << 14); + if (mr->mr & 0x180) + addr += ((mr->mr & 0xC00) << 13) + (((mr->mr & 0x180) - 0x60) << 16); + } else + addr |= ((mr->mr & 0x60) << 14) | ((mr->mr & 0x180) << 16) | ((mr->mr & 0xC00) << 13); + } else if (dev->cr[0] & 0x80) + addr |= (mr->mr & 0x1E0) << 14; + else + addr |= (mr->mr & 0x180) << 12; + } + } else if ((mr == NULL) && ((dev->cr[0] & 4) == 0) && (mem_size >= 1024) && (addr >= 0x100000)) + addr -= 0x60000; + + return addr; +} + + +static void +set_global_EMS_state(headland_t *dev, int state) +{ + uint32_t base_addr, virt_addr; + int i; + + for (i = 0; i < 32; i++) { + base_addr = (i + 16) << 14; + if (i >= 24) + base_addr += 0x20000; + if ((state & 2) && (dev->ems_mr[((state & 1) << 5) | i].mr & 0x200)) { + virt_addr = get_addr(dev, base_addr, &dev->ems_mr[((state & 1) << 5) | i]); + if (i < 24) + mem_mapping_disable(&dev->upper_mapping[i]); + mem_mapping_disable(&dev->ems_mapping[(((state ^ 1) & 1) << 5) | i]); + mem_mapping_enable(&dev->ems_mapping[((state & 1) << 5) | i]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[((state & 1) << 5) | i], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[((state & 1) << 5) | i], NULL); + } else { + mem_mapping_set_exec(&dev->ems_mapping[((state & 1) << 5) | i], ram + base_addr); + mem_mapping_disable(&dev->ems_mapping[(((state ^ 1) & 1) << 5) | i]); + mem_mapping_disable(&dev->ems_mapping[((state & 1) << 5) | i]); + if (i < 24) + mem_mapping_enable(&dev->upper_mapping[i]); + } + } + + flushmmucache(); +} + + +static void +memmap_state_update(headland_t *dev) +{ + uint32_t addr; + int i; + + for (i = 0; i < 24; i++) { + addr = get_addr(dev, 0x40000 + (i << 14), NULL); + mem_mapping_set_exec(&dev->upper_mapping[i], addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + } + mem_set_mem_state(0xA0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + if (mem_size > 640) { + if ((dev->cr[0] & 4) == 0) { + mem_mapping_set_addr(&dev->mid_mapping, 0x100000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); + mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000); + if (mem_size > 1024) { + mem_mapping_set_addr(&dev->high_mapping, 0x160000, (mem_size - 1024) << 10); + mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000); + } + } else { + mem_mapping_set_addr(&dev->mid_mapping, 0xA0000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); + mem_mapping_set_exec(&dev->mid_mapping, ram + 0xA0000); + if (mem_size > 1024) { + mem_mapping_set_addr(&dev->high_mapping, 0x100000, (mem_size - 1024) << 10); + mem_mapping_set_exec(&dev->high_mapping, ram + 0x100000); + } + } + } + + set_global_EMS_state(dev, dev->cr[0] & 3); +} + + +static void +hl_write(uint16_t addr, uint8_t val, void *priv) +{ + headland_t *dev = (headland_t *)priv; + uint32_t base_addr, virt_addr; + uint8_t old_val, indx; + + switch(addr) { + case 0x0022: + dev->indx = val; + break; + + case 0x0023: + old_val = dev->regs[dev->indx]; + if ((dev->indx == 0xc1) && !is486) + val = 0; + dev->regs[dev->indx] = val; + if (dev->indx == 0x82) { + shadowbios = val & 0x10; + shadowbios_write = !(val & 0x10); + if (shadowbios) + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + } else if (dev->indx == 0x87) { + if ((val & 1) && !(old_val & 1)) + softresetx86(); + } + break; + + case 0x01ec: + dev->ems_mr[dev->ems_mar & 0x3f].mr = val | 0xff00; + indx = dev->ems_mar & 0x1f; + base_addr = (indx + 16) << 14; + if (indx >= 24) + base_addr += 0x20000; + if ((dev->cr[0] & 2) && ((dev->cr[0] & 1) == ((dev->ems_mar & 0x20) >> 5))) { + virt_addr = get_addr(dev, base_addr, &dev->ems_mr[dev->ems_mar & 0x3F]); + if (indx < 24) + mem_mapping_disable(&dev->upper_mapping[indx]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], NULL); + mem_mapping_enable(&dev->ems_mapping[dev->ems_mar & 0x3f]); + flushmmucache(); + } + if (dev->ems_mar & 0x80) + dev->ems_mar++; + break; + + case 0x01ed: + dev->cri = val; + break; + + case 0x01ee: + dev->ems_mar = val; + break; + + case 0x01ef: + old_val = dev->cr[dev->cri]; + switch(dev->cri) { + case 0: + dev->cr[0] = (val & 0x1f) | mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + mem_set_mem_state(0xe0000, 0x10000, (val & 8 ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL) | MEM_WRITE_DISABLED); + mem_set_mem_state(0xf0000, 0x10000, (val & 0x10 ? MEM_READ_INTERNAL: MEM_READ_EXTERNAL) | MEM_WRITE_DISABLED); + memmap_state_update(dev); + break; + + case 1: + dev->cr[1] = (val & 0xbf) | mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + memmap_state_update(dev); + break; + + case 2: + case 3: + case 5: + dev->cr[dev->cri] = val; + memmap_state_update(dev); + break; + + case 4: + dev->cr[4] = (dev->cr[4] & 0xf0) | (val & 0x0f); + if (val & 1) { + mem_mapping_set_addr(&bios_mapping, 0x000f0000, 0x10000); + mem_mapping_set_exec(&bios_mapping, &(rom[0x10000])); + } else { + mem_mapping_set_addr(&bios_mapping, 0x000e0000, 0x20000); + mem_mapping_set_exec(&bios_mapping, rom); + } + break; + + case 6: + if (dev->cr[4] & 0x80) { + dev->cr[dev->cri] = (val & 0xfe) | (mem_size > 8192 ? 1 : 0); + memmap_state_update(dev); + } + break; + + default: + break; + } + break; + + default: + break; + } +} + + +static void +hl_writew(uint16_t addr, uint16_t val, void *priv) +{ + headland_t *dev = (headland_t *)priv; + uint32_t base_addr, virt_addr; + uint8_t indx; + + switch(addr) { + case 0x01ec: + dev->ems_mr[dev->ems_mar & 0x3f].mr = val; + indx = dev->ems_mar & 0x1f; + base_addr = (indx + 16) << 14; + if (indx >= 24) + base_addr += 0x20000; + if ((dev->cr[0] & 2) && (dev->cr[0] & 1) == ((dev->ems_mar & 0x20) >> 5)) { + if (val & 0x200) { + virt_addr = get_addr(dev, base_addr, &dev->ems_mr[dev->ems_mar & 0x3f]); + if (indx < 24) + mem_mapping_disable(&dev->upper_mapping[indx]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], NULL); + mem_mapping_enable(&dev->ems_mapping[dev->ems_mar & 0x3f]); + } else { + mem_mapping_set_exec(&dev->ems_mapping[dev->ems_mar & 0x3f], ram + base_addr); + mem_mapping_disable(&dev->ems_mapping[dev->ems_mar & 0x3f]); + if (indx < 24) + mem_mapping_enable(&dev->upper_mapping[indx]); + } + flushmmucache(); + } + if (dev->ems_mar & 0x80) + dev->ems_mar++; + break; + + default: + break; + } +} + + +static uint8_t +hl_read(uint16_t addr, void *priv) +{ + headland_t *dev = (headland_t *)priv; + uint8_t ret = 0xff; + + switch(addr) { + case 0x0022: + ret = dev->indx; + break; + + case 0x0023: + if ((dev->indx >= 0xc0 || dev->indx == 0x20) && cpu_iscyrix) + ret = 0xff; /*Don't conflict with Cyrix config registers*/ + else + ret = dev->regs[dev->indx]; + break; + + case 0x01ec: + ret = (uint8_t)dev->ems_mr[dev->ems_mar & 0x3f].mr; + if (dev->ems_mar & 0x80) + dev->ems_mar++; + break; + + case 0x01ed: + ret = dev->cri; + break; + + case 0x01ee: + ret = dev->ems_mar; + break; + + case 0x01ef: + switch(dev->cri) { + case 0: + ret = (dev->cr[0] & 0x1f) | mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + break; + + case 1: + ret = (dev->cr[1] & 0xbf) | mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + break; + + case 6: + if (dev->cr[4] & 0x80) + ret = (dev->cr[6] & 0xfe) | (mem_size > 8192 ? 1 : 0); + else + ret = 0; + break; + + default: + ret = dev->cr[dev->cri]; + break; + } + break; + + default: + break; + } + + return ret; +} + + +static uint16_t +hl_readw(uint16_t addr, void *priv) +{ + headland_t *dev = (headland_t *)priv; + uint16_t ret = 0xffff; + + switch(addr) { + case 0x01ec: + ret = dev->ems_mr[dev->ems_mar & 0x3f].mr | ((dev->cr[4] & 0x80) ? 0xf000 : 0xfc00); + if (dev->ems_mar & 0x80) + dev->ems_mar++; + break; + + default: + break; + } + + return ret; +} + + +static uint8_t +mem_read_b(uint32_t addr, void *priv) +{ + headland_mr_t *mr = (headland_mr_t *) priv; + headland_t *dev = mr->headland; + uint8_t ret = 0xff; + + addr = get_addr(dev, addr, mr); + if (addr < ((uint32_t)mem_size << 10)) + ret = ram[addr]; + + return ret; +} + + +static uint16_t +mem_read_w(uint32_t addr, void *priv) +{ + headland_mr_t *mr = (headland_mr_t *) priv; + headland_t *dev = mr->headland; + uint16_t ret = 0xffff; + + addr = get_addr(dev, addr, mr); + if (addr < ((uint32_t)mem_size << 10)) + ret = *(uint16_t *)&ram[addr]; + + return ret; +} + + +static uint32_t +mem_read_l(uint32_t addr, void *priv) +{ + headland_mr_t *mr = (headland_mr_t *) priv; + headland_t *dev = mr->headland; + uint32_t ret = 0xffffffff; + + addr = get_addr(dev, addr, mr); + if (addr < ((uint32_t)mem_size << 10)) + ret = *(uint32_t *)&ram[addr]; + + return ret; +} + + +static void +mem_write_b(uint32_t addr, uint8_t val, void *priv) +{ + headland_mr_t *mr = (headland_mr_t *) priv; + headland_t *dev = mr->headland; + + addr = get_addr(dev, addr, mr); + if (addr < ((uint32_t)mem_size << 10)) + ram[addr] = val; +} + + +static void +mem_write_w(uint32_t addr, uint16_t val, void *priv) +{ + headland_mr_t *mr = (headland_mr_t *) priv; + headland_t *dev = mr->headland; + + addr = get_addr(dev, addr, mr); + if (addr < ((uint32_t)mem_size << 10)) + *(uint16_t *)&ram[addr] = val; +} + + +static void +mem_write_l(uint32_t addr, uint32_t val, void *priv) +{ + headland_mr_t *mr = (headland_mr_t *) priv; + headland_t *dev = mr->headland; + + addr = get_addr(dev, addr, mr); + if (addr < ((uint32_t)mem_size << 10)) + *(uint32_t *)&ram[addr] = val; +} + + +static void +headland_close(void *priv) +{ + headland_t *dev = (headland_t *)priv; + + free(dev); +} + + +static void * +headland_init(const device_t *info) +{ + headland_t *dev; + int ht386; + uint32_t i; + + dev = (headland_t *) malloc(sizeof(headland_t)); + memset(dev, 0x00, sizeof(headland_t)); + dev->type = info->local; + + ht386 = (dev->type == 32) ? 1 : 0; + + for (i = 0; i < 8; i++) + dev->cr[i] = 0x00; + dev->cr[0] = 0x04; + + if (ht386) { + dev->cr[4] = 0x20; + + device_add(&port_92_inv_device); + } else + dev->cr[4] = 0x00; + + io_sethandler(0x01ec, 1, + hl_read,hl_readw,NULL, hl_write,hl_writew,NULL, dev); + + io_sethandler(0x01ed, 3, hl_read,NULL,NULL, hl_write,NULL,NULL, dev); + + dev->ems_mr[i].valid = 0; + dev->ems_mr[i].mr = 0xff; + dev->ems_mr[i].headland = dev; + + for (i = 0; i < 64; i++) { + dev->ems_mr[i].valid = 1; + dev->ems_mr[i].mr = 0x00; + dev->ems_mr[i].headland = dev; + } + + /* Turn off mem.c mappings. */ + mem_mapping_disable(&ram_low_mapping); + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); + + mem_mapping_add(&dev->low_mapping, 0, 0x40000, + mem_read_b, mem_read_w, mem_read_l, + mem_write_b, mem_write_w, mem_write_l, + ram, MEM_MAPPING_INTERNAL, &dev->null_mr); + + if (mem_size > 640) { + mem_mapping_add(&dev->mid_mapping, 0xa0000, 0x60000, + mem_read_b, mem_read_w, mem_read_l, + mem_write_b, mem_write_w, mem_write_l, + ram + 0xa0000, MEM_MAPPING_INTERNAL, &dev->null_mr); + mem_mapping_enable(&dev->mid_mapping); + } + + if (mem_size > 1024) { + mem_mapping_add(&dev->high_mapping, 0x100000, ((mem_size-1024)*1024), + mem_read_b, mem_read_w, mem_read_l, + mem_write_b, mem_write_w, mem_write_l, + ram + 0x100000, MEM_MAPPING_INTERNAL, &dev->null_mr); + mem_mapping_enable(&dev->high_mapping); + } + + for (i = 0; i < 24; i++) { + mem_mapping_add(&dev->upper_mapping[i], + 0x40000 + (i << 14), 0x4000, + mem_read_b, mem_read_w, mem_read_l, + mem_write_b, mem_write_w, mem_write_l, + mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, + MEM_MAPPING_INTERNAL, &dev->null_mr); + mem_mapping_enable(&dev->upper_mapping[i]); + } + + for (i = 0; i < 64; i++) { + dev->ems_mr[i].mr = 0x00; + mem_mapping_add(&dev->ems_mapping[i], + ((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14, 0x04000, + mem_read_b, mem_read_w, mem_read_l, + mem_write_b, mem_write_w, mem_write_l, + ram + (((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14), + 0, &dev->ems_mr[i]); + } + + memmap_state_update(dev); + + return(dev); +} + + +const device_t headland_device = { + "Headland 286", + 0, + 0, + headland_init, headland_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t headland_386_device = { + "Headland 386", + 0, + 32, + headland_init, headland_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/intel_4x0.c b/src/chipset/intel_4x0.c new file mode 100644 index 000000000..c0653d154 --- /dev/null +++ b/src/chipset/intel_4x0.c @@ -0,0 +1,433 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the Intel PCISet chips from 420TX to 440FX. + * + * Version: @(#)intel_4x0.c 1.0.0 2019/05/13 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../keyboard.h" +#include "chipset.h" + + +enum +{ + INTEL_420TX, + INTEL_430LX, + INTEL_430NX, + INTEL_430FX, + INTEL_430FX_PB640, + INTEL_430HX, + INTEL_430VX +#if defined(DEV_BRANCH) && defined(USE_I686) + ,INTEL_440FX +#endif +}; + +typedef struct +{ + uint8_t regs[256]; + int type; +} i4x0_t; +static void +i4x0_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + + +static void +i4x0_write(int func, int addr, uint8_t val, void *priv) +{ + i4x0_t *dev = (i4x0_t *) priv; + + if (func) + return; + + if ((addr >= 0x10) && (addr < 0x4f)) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0e: + return; + + case 0x04: /*Command register*/ + if (dev->type >= INTEL_430FX) { + if (dev->type == INTEL_430FX_PB640) + val &= 0x06; + else + val &= 0x02; + } else + val &= 0x42; + val |= 0x04; + break; + case 0x05: + if (dev->type >= INTEL_430FX) + val = 0; + else + val &= 0x01; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + if (dev->type >= INTEL_430HX) { + val &= 0x80; + val |= 0x02; + } else { + val = 0x02; + if (dev->type == INTEL_430FX_PB640) + val |= 0x20; + } + break; + + case 0x59: /*PAM0*/ + if ((dev->regs[0x59] ^ val) & 0xf0) { + i4x0_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + break; + case 0x5a: /*PAM1*/ + if ((dev->regs[0x5a] ^ val) & 0x0f) + i4x0_map(0xc0000, 0x04000, val & 0xf); + if ((dev->regs[0x5a] ^ val) & 0xf0) + i4x0_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((dev->regs[0x5b] ^ val) & 0x0f) + i4x0_map(0xc8000, 0x04000, val & 0xf); + if ((dev->regs[0x5b] ^ val) & 0xf0) + i4x0_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((dev->regs[0x5c] ^ val) & 0x0f) + i4x0_map(0xd0000, 0x04000, val & 0xf); + if ((dev->regs[0x5c] ^ val) & 0xf0) + i4x0_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((dev->regs[0x5d] ^ val) & 0x0f) + i4x0_map(0xd8000, 0x04000, val & 0xf); + if ((dev->regs[0x5d] ^ val) & 0xf0) + i4x0_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((dev->regs[0x5e] ^ val) & 0x0f) + i4x0_map(0xe0000, 0x04000, val & 0xf); + if ((dev->regs[0x5e] ^ val) & 0xf0) + i4x0_map(0xe4000, 0x04000, val >> 4); + break; + case 0x5f: /*PAM6*/ + if ((dev->regs[0x5f] ^ val) & 0x0f) + i4x0_map(0xe8000, 0x04000, val & 0xf); + if ((dev->regs[0x5f] ^ val) & 0xf0) + i4x0_map(0xec000, 0x04000, val >> 4); + break; + case 0x72: /*SMRAM*/ + if ((dev->type >= INTEL_430FX) && ((dev->regs[0x72] ^ val) & 0x48)) + i4x0_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); + else if ((dev->type < INTEL_430FX) && ((dev->regs[0x72] ^ val) & 0x20)) + i4x0_map(0xa0000, 0x20000, ((val & 0x20) == 0x20) ? 3 : 0); + break; + } + + dev->regs[addr] = val; +} + + +static uint8_t +i4x0_read(int func, int addr, void *priv) +{ + i4x0_t *dev = (i4x0_t *) priv; + + if (func) + return 0xff; + + return dev->regs[addr]; +} + + +static void +i4x0_reset(void *priv) +{ + i4x0_t *i4x0 = (i4x0_t *)priv; + + i4x0_write(0, 0x59, 0x00, priv); + if (i4x0->type >= INTEL_430FX) + i4x0_write(0, 0x72, 0x02, priv); +} + + +static void +i4x0_close(void *p) +{ + i4x0_t *i4x0 = (i4x0_t *)p; + + free(i4x0); +} + + +static void +*i4x0_init(const device_t *info) +{ + i4x0_t *i4x0 = (i4x0_t *) malloc(sizeof(i4x0_t)); + memset(i4x0, 0, sizeof(i4x0_t)); + + i4x0->type = info->local; + + i4x0->regs[0x00] = 0x86; i4x0->regs[0x01] = 0x80; /*Intel*/ + switch(i4x0->type) { + case INTEL_420TX: + i4x0->regs[0x02] = 0x83; i4x0->regs[0x03] = 0x04; /*82424TX/ZX*/ + i4x0->regs[0x08] = 0x03; /*A3 stepping*/ + i4x0->regs[0x50] = 0x80; + i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/ + break; + case INTEL_430LX: + i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/ + i4x0->regs[0x08] = 0x03; /*A3 stepping*/ + i4x0->regs[0x50] = 0x80; + i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/ + break; + case INTEL_430NX: + i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/ + i4x0->regs[0x08] = 0x10; /*A0 stepping*/ + i4x0->regs[0x50] = 0xA0; + i4x0->regs[0x52] = 0x44; /*256kb PLB cache*/ + i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02; + break; + case INTEL_430FX: + case INTEL_430FX_PB640: + i4x0->regs[0x02] = 0x2d; i4x0->regs[0x03] = 0x12; /*SB82437FX-66*/ + if (i4x0->type == INTEL_430FX_PB640) + i4x0->regs[0x08] = 0x02; /*???? stepping*/ + else + i4x0->regs[0x08] = 0x00; /*A0 stepping*/ + i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/ + break; + case INTEL_430HX: + i4x0->regs[0x02] = 0x50; i4x0->regs[0x03] = 0x12; /*82439HX*/ + i4x0->regs[0x08] = 0x00; /*A0 stepping*/ + i4x0->regs[0x51] = 0x20; + i4x0->regs[0x52] = 0xB5; /*512kb cache*/ + i4x0->regs[0x56] = 0x52; /*DRAM control*/ + i4x0->regs[0x59] = 0x40; + i4x0->regs[0x5A] = i4x0->regs[0x5B] = i4x0->regs[0x5C] = i4x0->regs[0x5D] = 0x44; + i4x0->regs[0x5E] = i4x0->regs[0x5F] = 0x44; + i4x0->regs[0x65] = i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02; + i4x0->regs[0x68] = 0x11; + break; + case INTEL_430VX: + i4x0->regs[0x02] = 0x30; i4x0->regs[0x03] = 0x70; /*82437VX*/ + i4x0->regs[0x08] = 0x00; /*A0 stepping*/ + i4x0->regs[0x52] = 0x42; /*256kb PLB cache*/ + i4x0->regs[0x53] = 0x14; + i4x0->regs[0x56] = 0x52; /*DRAM control*/ + i4x0->regs[0x67] = 0x11; + i4x0->regs[0x69] = 0x03; + i4x0->regs[0x70] = 0x20; + i4x0->regs[0x74] = 0x0e; + i4x0->regs[0x78] = 0x23; + break; +#if defined(DEV_BRANCH) && defined(USE_I686) + case INTEL_440FX: + i4x0->regs[0x02] = 0x37; i4x0->regs[0x03] = 0x12; /*82441FX*/ + i4x0->regs[0x08] = 0x02; /*A0 stepping*/ + i4x0->regs[0x2c] = 0xf4; + i4x0->regs[0x2d] = 0x1a; + i4x0->regs[0x2f] = 0x11; + i4x0->regs[0x51] = 0x01; + i4x0->regs[0x53] = 0x80; + i4x0->regs[0x58] = 0x10; + i4x0->regs[0x5a] = i4x0->regs[0x5b] = i4x0->regs[0x5c] = i4x0->regs[0x5d] = 0x11; + i4x0->regs[0x5e] = 0x11; + i4x0->regs[0x5f] = 0x31; + break; +#endif + } + i4x0->regs[0x04] = 0x06; i4x0->regs[0x05] = 0x00; +#if defined(DEV_BRANCH) && defined(USE_I686) + if (i4x0->type == INTEL_440FX) + i4x0->regs[0x06] = 0x80; +#endif + if (i4x0->type == INTEL_430FX) + i4x0->regs[0x07] = 0x82; +#if defined(DEV_BRANCH) && defined(USE_I686) + else if (i4x0->type != INTEL_440FX) +#else + else +#endif + i4x0->regs[0x07] = 0x02; + i4x0->regs[0x0b] = 0x06; + if (i4x0->type >= INTEL_430FX) + i4x0->regs[0x57] = 0x01; + else + i4x0->regs[0x57] = 0x31; + i4x0->regs[0x60] = i4x0->regs[0x61] = i4x0->regs[0x62] = i4x0->regs[0x63] = 0x02; + i4x0->regs[0x64] = 0x02; + if (i4x0->type >= INTEL_430FX) + i4x0->regs[0x72] = 0x02; + + pci_add_card(0, i4x0_read, i4x0_write, i4x0); + + return i4x0; +} + + +const device_t i420tx_device = +{ + "Intel 82424TX", + DEVICE_PCI, + INTEL_420TX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430lx_device = +{ + "Intel 82434LX", + DEVICE_PCI, + INTEL_430LX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430nx_device = +{ + "Intel 82434NX", + DEVICE_PCI, + INTEL_430NX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430fx_device = +{ + "Intel SB82437FX-66", + DEVICE_PCI, + INTEL_430FX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430fx_pb640_device = +{ + "Intel SB82437FX-66 (PB640)", + DEVICE_PCI, + INTEL_430FX_PB640, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430hx_device = +{ + "Intel 82439HX", + DEVICE_PCI, + INTEL_430HX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430vx_device = +{ + "Intel 82437VX", + DEVICE_PCI, + INTEL_430VX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +#if defined(DEV_BRANCH) && defined(USE_I686) +const device_t i440fx_device = +{ + "Intel 82441FX", + DEVICE_PCI, + INTEL_440FX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; +#endif diff --git a/src/machine/m_at_neat.c b/src/chipset/neat.c similarity index 91% rename from src/machine/m_at_neat.c rename to src/chipset/neat.c index b37340d59..4f2524db9 100644 --- a/src/machine/m_at_neat.c +++ b/src/chipset/neat.c @@ -1,10 +1,10 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Emulation of C&T CS8121 ("NEAT") 82C206/211/212/215 chipset. * @@ -18,38 +18,7 @@ * Author: Fred N. van Kempen, * * Copyright 2018 Fred N. van Kempen. - * - * Redistribution and use in source and binary forms, with - or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the entire - * above notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names - * of its contributors may be used to endorse or promote - * products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - + */ #include #include #include @@ -57,13 +26,14 @@ #include #include "../86box.h" #include "../device.h" +#include "../timer.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "../keyboard.h" #include "../io.h" #include "../mem.h" #include "../nmi.h" -#include "machine.h" +#include "chipset.h" #define NEAT_DEBUG 0 @@ -259,6 +229,7 @@ typedef struct { emspage_t ems[EMS_MAXPAGE]; /* EMS page registers */ } neat_t; + #ifdef ENABLE_NEAT_LOG int neat_do_log = ENABLE_NEAT_LOG; @@ -279,6 +250,7 @@ neat_log(const char *fmt, ...) #define neat_log(fmt, ...) #endif + /* Read one byte from paged RAM. */ static uint8_t ems_readb(uint32_t addr, void *priv) @@ -442,7 +414,9 @@ ems_init(neat_t *dev, int en) ems_read,NULL,NULL, ems_write,NULL,NULL, dev); } +#ifdef ENABLE_NEAT_LOG neat_log("NEAT: EMS disabled\n"); +#endif return; } @@ -666,9 +640,10 @@ neat_write(uint16_t port, uint8_t val, void *priv) break; } dev->ems_pages = (dev->ems_size << 10) / EMS_PGSIZE; - if (dev->regs[REG_RB7] & RB7_EMSEN) + if (dev->regs[REG_RB7] & RB7_EMSEN) { neat_log("NEAT: EMS %iKB (%i pages)\n", dev->ems_size, dev->ems_pages); + } break; default: @@ -708,10 +683,17 @@ neat_read(uint16_t port, void *priv) } - - static void -neat_init(void) +neat_close(void *priv) +{ + neat_t *dev = (neat_t *) priv; + + free(dev); +} + + +static void * +neat_init(const device_t *info) { neat_t *dev; int i; @@ -857,34 +839,23 @@ neat_init(void) default: neat_log("NEAT: **INVALID DRAM SIZE %iKB !**\n", mem_size); } - if (i > 0) + if (i > 0) { neat_log("NEAT: using DRAM mode #%i (mem=%iKB)\n", i, mem_size); + } /* Set up an I/O handler for the chipset. */ io_sethandler(0x0022, 2, neat_read,NULL,NULL, neat_write,NULL,NULL, dev); + + return dev; } -void -machine_at_neat_init(const machine_t *model) -{ - machine_at_init(model); - - neat_init(); - - device_add(&fdc_at_device); -} - - -void -machine_at_neat_ami_init(const machine_t *model) -{ - machine_at_common_init(model); - - neat_init(); - - device_add(&keyboard_at_ami_device); - - device_add(&fdc_at_device); -} +const device_t neat_device = { + "C&T CS8121 (NEAT)", + 0, + 0, + neat_init, neat_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/machine/m_at_opti495.c b/src/chipset/opti495.c similarity index 80% rename from src/machine/m_at_opti495.c rename to src/chipset/opti495.c index d38e47066..3c77e242c 100644 --- a/src/machine/m_at_opti495.c +++ b/src/chipset/opti495.c @@ -254,94 +254,116 @@ SeeAlso: #P0178,#P0187 #include #include #include +#include #include #include #define HAVE_STDARG_H #include "../86box.h" #include "../cpu/cpu.h" +#include "../timer.h" #include "../io.h" #include "../device.h" #include "../keyboard.h" #include "../mem.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" -#include "machine.h" +#include "chipset.h" -static uint8_t optiregs[0x10]; -static int optireg; - - -static void opti495_write(uint16_t addr, uint8_t val, void *p) +typedef struct { - switch (addr) - { - case 0x22: - optireg=val; - break; - case 0x24: - if (optireg>=0x20 && optireg<=0x2C) - { - optiregs[optireg-0x20]=val; - if (optireg == 0x21) - { - cpu_cache_ext_enabled = val & 0x10; - cpu_update_waitstates(); - } - if (optireg == 0x22) - { - shadowbios = !(val & 0x80); - shadowbios_write = val & 0x80; - if (shadowbios) - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); - else - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - } - } - break; - } + uint8_t cur_reg, + regs[16], + scratch[2]; +} opti495_t; + + +static void +opti495_write(uint16_t addr, uint8_t val, void *priv) +{ + opti495_t *dev = (opti495_t *) priv; + + switch (addr) { + case 0x22: + dev->cur_reg = val; + break; + case 0x24: + if ((dev->cur_reg >= 0x20) && (dev->cur_reg <= 0x2C)) { + dev->regs[dev->cur_reg - 0x20] = val; + if (dev->cur_reg == 0x21) { + cpu_cache_ext_enabled = val & 0x10; + cpu_update_waitstates(); + } + if (dev->cur_reg == 0x22) { + if (!(val & 0x80)) + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + } + } + break; + case 0xe1: + case 0xe2: + dev->scratch[addr - 0xe1] = val; + break; + } } -static uint8_t opti495_read(uint16_t addr, void *p) +static uint8_t +opti495_read(uint16_t addr, void *priv) { - switch (addr) - { - case 0x24: - if (optireg>=0x20 && optireg<=0x2C) return optiregs[optireg-0x20]; - break; - } - return 0xFF; + uint8_t ret = 0xff; + opti495_t *dev = (opti495_t *) priv; + + switch (addr) { + case 0x24: + if ((dev->cur_reg >= 0x20) && (dev->cur_reg <= 0x2C)) + ret = dev->regs[dev->cur_reg - 0x20]; + break; + case 0xe1: + case 0xe2: + ret = dev->scratch[addr - 0xe1]; + break; + } + + return ret; } -static void opti495_init(void) +static void +opti495_close(void *priv) { - io_sethandler(0x0022, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, NULL); - io_sethandler(0x0024, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, NULL); - optiregs[0x22-0x20] = 0x80; + opti495_t *dev = (opti495_t *) priv; + + free(dev); } -void -machine_at_opti495_init(const machine_t *model) +static void * +opti495_init(const device_t *info) { - machine_at_common_ide_init(model); + opti495_t *dev = (opti495_t *) malloc(sizeof(opti495_t)); + memset(dev, 0, sizeof(opti495_t)); - device_add(&keyboard_at_device); - device_add(&fdc_at_device); + io_sethandler(0x0022, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); + io_sethandler(0x0024, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); - opti495_init(); + dev->scratch[0] = dev->scratch[1] = 0xff; + + io_sethandler(0x00e1, 0x0002, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); + + dev->regs[0x22 - 0x20] = 0x80; + + return dev; } -void -machine_at_opti495_ami_init(const machine_t *model) -{ - machine_at_common_ide_init(model); - - device_add(&keyboard_at_ami_device); - device_add(&fdc_at_device); - - opti495_init(); -} +const device_t opti495_device = { + "OPTi 82C495", + 0, + 0, + opti495_init, opti495_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/scat.c b/src/chipset/scat.c new file mode 100644 index 000000000..a1bbca168 --- /dev/null +++ b/src/chipset/scat.c @@ -0,0 +1,1630 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Chips&Technology's SCAT (82C235) chipset. + * + * Re-worked version based on the 82C235 datasheet and errata. + * + * Version: @(#)scat.c 1.0.0 2019/05/13 + * + * Authors: Original by GreatPsycho for PCem. + * Fred N. van Kempen, + * + * Copyright 2017-2019 GreatPsycho. + * Copyright 2017-2019 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#ifdef USE_NEW_DYNAREC +#include "../cpu_new/cpu.h" +#include "../cpu_new/x86.h" +#else +#include "../cpu/cpu.h" +#include "../cpu/x86.h" +#endif +#include "../timer.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../keyboard.h" +#include "../io.h" +#include "../mem.h" +#include "../nmi.h" +#include "../port_92.h" +#include "../rom.h" +#include "chipset.h" + + +#define SCAT_DMA_WAIT_STATE_CONTROL 0x01 +#define SCAT_VERSION 0x40 +#define SCAT_CLOCK_CONTROL 0x41 +#define SCAT_PERIPHERAL_CONTROL 0x44 +#define SCAT_MISCELLANEOUS_STATUS 0x45 +#define SCAT_POWER_MANAGEMENT 0x46 +#define SCAT_ROM_ENABLE 0x48 +#define SCAT_RAM_WRITE_PROTECT 0x49 +#define SCAT_SHADOW_RAM_ENABLE_1 0x4A +#define SCAT_SHADOW_RAM_ENABLE_2 0x4B +#define SCAT_SHADOW_RAM_ENABLE_3 0x4C +#define SCAT_DRAM_CONFIGURATION 0x4D +#define SCAT_EXTENDED_BOUNDARY 0x4E +#define SCAT_EMS_CONTROL 0x4F + +#define SCATSX_LAPTOP_FEATURES 0x60 +#define SCATSX_FAST_VIDEO_CONTROL 0x61 +#define SCATSX_FAST_VIDEORAM_ENABLE 0x62 +#define SCATSX_HIGH_PERFORMANCE_REFRESH 0x63 +#define SCATSX_CAS_TIMING_FOR_DMA 0x64 + + +typedef struct { + uint8_t valid, pad; + + uint8_t regs_2x8; + uint8_t regs_2x9; + + struct scat_t * scat; +} ems_page_t; + +typedef struct scat_t { + int type; + + int indx; + uint8_t regs[256]; + uint8_t reg_2xA; + + uint32_t xms_bound; + + int external_is_RAS; + + ems_page_t null_page, page[32]; + + mem_mapping_t low_mapping[32]; + mem_mapping_t high_mapping[16]; + mem_mapping_t remap_mapping[6]; + mem_mapping_t efff_mapping[44]; + mem_mapping_t romcs_mapping[8]; + mem_mapping_t bios_mapping[8]; + mem_mapping_t ems_mapping[32]; +} scat_t; + + +static const uint8_t max_map[32] = { + 0, 1, 1, 1, 2, 3, 4, 8, + 4, 8, 12, 16, 20, 24, 28, 32, + 0, 5, 9, 13, 6, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; +static const uint8_t max_map_sx[32] = { + 0, 1, 2, 1, 3, 4, 6, 10, + 5, 9, 13, 4, 8, 12, 16, 14, + 18, 22, 26, 20, 24, 28, 32, 18, + 20, 32, 0, 0, 0, 0, 0, 0 +}; +static const uint8_t scatsx_external_is_RAS[33] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0 +}; + + +static uint8_t scat_in(uint16_t port, void *priv); +static void scat_out(uint16_t port, uint8_t val, void *priv); + + +static void +romcs_state_update(scat_t *dev, uint8_t val) +{ + int i; + + for (i = 0; i < 4; i++) { + if (val & 1) { + mem_mapping_enable(&dev->romcs_mapping[i << 1]); + mem_mapping_enable(&dev->romcs_mapping[(i << 1) + 1]); + } else { + mem_mapping_disable(&dev->romcs_mapping[i << 1]); + mem_mapping_disable(&dev->romcs_mapping[(i << 1) + 1]); + } + val >>= 1; + } + + for (i = 0; i < 4; i++) { + if (val & 1) { + mem_mapping_enable(&dev->bios_mapping[i << 1]); + mem_mapping_enable(&dev->bios_mapping[(i << 1) + 1]); + } else { + mem_mapping_disable(&dev->bios_mapping[i << 1]); + mem_mapping_disable(&dev->bios_mapping[(i << 1) + 1]); + } + val >>= 1; + } +} + + +static void +shadow_state_update(scat_t *dev) +{ + int i, val; + + for (i = 0; i < 24; i++) { + val = ((dev->regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_READ_INTERNAL | MEM_WRITE_INTERNAL : MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL; + mem_set_mem_state((i + 40) << 14, 0x4000, val); + } + + flushmmucache(); +} + + +static void +set_xms_bound(scat_t *dev, uint8_t val) +{ + uint32_t xms_max = ((dev->regs[SCAT_VERSION] & 0xf0) != 0 && ((val & 0x10) != 0)) || (dev->regs[SCAT_VERSION] >= 4) ? 0xfe0000 : 0xfc0000; + int i; + + switch (val & 0x0f) { + case 1: + dev->xms_bound = 0x100000; + break; + + case 2: + dev->xms_bound = 0x140000; + break; + + case 3: + dev->xms_bound = 0x180000; + break; + + case 4: + dev->xms_bound = 0x200000; + break; + + case 5: + dev->xms_bound = 0x300000; + break; + + case 6: + dev->xms_bound = 0x400000; + break; + + case 7: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0x600000 : 0x500000; + break; + + case 8: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0x800000 : 0x700000; + break; + + case 9: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0xa00000 : 0x800000; + break; + + case 10: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0xc00000 : 0x900000; + break; + + case 11: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0xe00000 : 0xa00000; + break; + + case 12: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xb00000; + break; + + case 13: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xc00000; + break; + + case 14: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xd00000; + break; + + case 15: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xf00000; + break; + + default: + dev->xms_bound = xms_max; + break; + } + + if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && (val & 0x40) == 0 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) == 3) || + (((dev->regs[SCAT_VERSION] & 0xf0) != 0) && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 3)) { + if ((val & 0x0f) == 0 || dev->xms_bound > 0x160000) + dev->xms_bound = 0x160000; + + if (dev->xms_bound > 0x100000) + mem_set_mem_state(0x100000, dev->xms_bound - 0x100000, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + if (dev->xms_bound < 0x160000) + mem_set_mem_state(dev->xms_bound, 0x160000 - dev->xms_bound, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } else { + if (dev->xms_bound > xms_max) + dev->xms_bound = xms_max; + + if (dev->xms_bound > 0x100000) + mem_set_mem_state(0x100000, dev->xms_bound - 0x100000, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + if (dev->xms_bound < ((uint32_t)mem_size << 10)) + mem_set_mem_state(dev->xms_bound, (mem_size << 10) - dev->xms_bound, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + mem_mapping_set_addr(&dev->low_mapping[31], 0xf80000, + ((dev->regs[SCAT_VERSION] & 0xf0) != 0 && ((val & 0x10) != 0)) || + (dev->regs[SCAT_VERSION] >= 4) ? 0x60000 : 0x40000); + if (dev->regs[SCAT_VERSION] & 0xf0) { + for (i = 0; i < 8; i++) { + if (val & 0x10) + mem_mapping_disable(&dev->high_mapping[i]); + else + mem_mapping_enable(&dev->high_mapping[i]); + } + } +} + + +static uint32_t +get_addr(scat_t *dev, uint32_t addr, ems_page_t *p) +{ +#if 1 + int nbanks_2048k, nbanks_512k; + uint32_t addr2; + int nbank; +#else + uint32_t nbanks_2048k, nbanks_512k, addr2, nbank; +#endif + + if (p && p->valid && (dev->regs[SCAT_EMS_CONTROL] & 0x80) && (p->regs_2x9 & 0x80)) + addr = (addr & 0x3fff) | (((p->regs_2x9 & 3) << 8) | p->regs_2x8) << 14; + + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + switch((dev->regs[SCAT_EXTENDED_BOUNDARY] & ((dev->regs[SCAT_VERSION] & 0x0f) > 3 ? 0x40 : 0)) | (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f)) { + case 0x41: + nbank = addr >> 19; + if (nbank < 4) + nbank = 1; + else if (nbank == 4) + nbank = 0; + else + nbank -= 3; + break; + + case 0x42: + nbank = addr >> 19; + if (nbank < 8) + nbank = 1 + (nbank >> 2); + else if (nbank == 8) + nbank = 0; + else + nbank -= 6; + break; + + case 0x43: + nbank = addr >> 19; + if (nbank < 12) + nbank = 1 + (nbank >> 2); + else if (nbank == 12) + nbank = 0; + else + nbank -= 9; + break; + + case 0x44: + nbank = addr >> 19; + if (nbank < 4) + nbank = 2; + else if (nbank < 6) + nbank -= 4; + else + nbank -= 3; + break; + + case 0x45: + nbank = addr >> 19; + if (nbank < 8) + nbank = 2 + (nbank >> 2); + else if (nbank < 10) + nbank -= 8; + else + nbank -= 6; + break; + + default: + nbank = addr >> (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) < 8 && (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) ? 19 : 21); + break; + } + + nbank &= (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3; + + if ((dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0 && + (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) == 3 && + nbank == 2 && (addr & 0x7ffff) < 0x60000 && mem_size > 640) { + nbank = 1; + addr ^= 0x70000; + } + + if (dev->external_is_RAS && (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) { + if (nbank == 3) + nbank = 7; + else + return 0xffffffff; + } else if (!dev->external_is_RAS && dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) { + switch(nbank) { + case 7: + nbank = 3; + break; + + /* Note - In the following cases, the chipset accesses multiple memory banks + at the same time, so it's impossible to predict which memory bank + is actually accessed. */ + case 5: + case 1: + nbank = 1; + break; + + case 3: + nbank = 2; + break; + + default: + nbank = 0; + break; + } + } + + if ((dev->regs[SCAT_VERSION] & 0x0f) > 3 && (mem_size > 2048) && (mem_size & 1536)) { + if ((mem_size & 1536) == 512) { + if (nbank == 0) + addr &= 0x7ffff; + else + addr = 0x80000 + ((addr & 0x1fffff) | ((nbank - 1) << 21)); + } else { + if (nbank < 2) + addr = (addr & 0x7ffff) | (nbank << 19); + else + addr = 0x100000 + ((addr & 0x1fffff) | ((nbank - 2) << 21)); + } + } else { + if (mem_size <= ((dev->regs[SCAT_VERSION] & 0x0f) > 3 ? 2048 : 4096) && (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) < 8) || dev->external_is_RAS)) { + nbanks_2048k = 0; + nbanks_512k = mem_size >> 9; + } else { + nbanks_2048k = mem_size >> 11; + nbanks_512k = (mem_size & 1536) >> 9; + } + + if (nbank < nbanks_2048k || (nbanks_2048k > 0 && nbank >= nbanks_2048k + nbanks_512k + ((mem_size & 511) >> 7))) { + addr &= 0x1fffff; + addr |= (nbank << 21); + } else if (nbank < nbanks_2048k + nbanks_512k || nbank >= nbanks_2048k + nbanks_512k + ((mem_size & 511) >> 7)) { + addr &= 0x7ffff; + addr |= (nbanks_2048k << 21) | ((nbank - nbanks_2048k) << 19); + } else { + addr &= 0x1ffff; + addr |= (nbanks_2048k << 21) | (nbanks_512k << 19) | ((nbank - nbanks_2048k - nbanks_512k) << 17); + } + } + } else { + switch(dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) { + case 0x02: + case 0x04: + nbank = addr >> 19; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else + addr2 = addr >> 10; + break; + + case 0x03: + nbank = addr >> 19; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) == 2 && (addr & 0x7ffff) < 0x60000) { + addr ^= 0x1f0000; + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else + addr2 = addr >> 10; + break; + + case 0x05: + nbank = addr >> 19; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) { + nbank = (addr >> 10) & 3; + addr2 = addr >> 12; + } else + addr2 = addr >> 10; + break; + + case 0x06: + nbank = addr >> 19; + if (nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else { + nbank = 2 + ((addr - 0x100000) >> 21); + addr2 = (addr - 0x100000) >> 11; + } + break; + + case 0x07: + case 0x0f: + nbank = addr >> 19; + if (nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if (nbank < 10) { + nbank = 2 + (((addr - 0x100000) >> 11) & 1); + addr2 = (addr - 0x100000) >> 12; + } else { + nbank = 4 + ((addr - 0x500000) >> 21); + addr2 = (addr - 0x500000) >> 11; + } + break; + + case 0x08: + nbank = addr >> 19; + if (nbank < 4) { + nbank = 1; + addr2 = addr >> 11; + } else if (nbank == 4) { + nbank = 0; + addr2 = addr >> 10; + } else { + nbank -= 3; + addr2 = addr >> 10; + } + break; + + case 0x09: + nbank = addr >> 19; + if (nbank < 8) { + nbank = 1 + ((addr >> 11) & 1); + addr2 = addr >> 12; + } else if (nbank == 8) { + nbank = 0; + addr2 = addr >> 10; + } else { + nbank -= 6; + addr2 = addr >> 10; + } + break; + + case 0x0a: + nbank = addr >> 19; + if (nbank < 8) { + nbank = 1 + ((addr >> 11) & 1); + addr2 = addr >> 12; + } else if (nbank < 12) { + nbank = 3; + addr2 = addr >> 11; + } else if (nbank == 12) { + nbank = 0; + addr2 = addr >> 10; + } else { + nbank -= 9; + addr2 = addr >> 10; + } + break; + + case 0x0b: + nbank = addr >> 21; + addr2 = addr >> 11; + break; + + case 0x0c: + case 0x0d: + nbank = addr >> 21; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { + nbank = (addr >> 11) & 1; + addr2 = addr >> 12; + } else + addr2 = addr >> 11; + break; + + case 0x0e: + case 0x13: + nbank = addr >> 21; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) { + nbank = (addr >> 11) & 3; + addr2 = addr >> 13; + } else + addr2 = addr >> 11; + break; + + case 0x10: + case 0x11: + nbank = addr >> 19; + if (nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if (nbank < 10) { + nbank = 2 + (((addr - 0x100000) >> 11) & 1); + addr2 = (addr - 0x100000) >> 12; + } else if (nbank < 18) { + nbank = 4 + (((addr - 0x500000) >> 11) & 1); + addr2 = (addr - 0x500000) >> 12; + } else { + nbank = 6 + ((addr - 0x900000) >> 21); + addr2 = (addr - 0x900000) >> 11; + } + break; + + case 0x12: + nbank = addr >> 19; + if (nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if (nbank < 10) { + nbank = 2 + (((addr - 0x100000) >> 11) & 1); + addr2 = (addr - 0x100000) >> 12; + } else { + nbank = 4 + (((addr - 0x500000) >> 11) & 3); + addr2 = (addr - 0x500000) >> 13; + } + break; + + case 0x14: + case 0x15: + nbank = addr >> 21; + if ((nbank & 7) < 4) { + nbank = (addr >> 11) & 3; + addr2 = addr >> 13; + } else if ((nbank & 7) < 6) { + nbank = 4 + (((addr - 0x800000) >> 11) & 1); + addr2 = (addr - 0x800000) >> 12; + } else { + nbank = 6 + (((addr - 0xc00000) >> 11) & 3); + addr2 = (addr - 0xc00000) >> 13; + } + break; + + case 0x16: + nbank = ((addr >> 21) & 4) | ((addr >> 11) & 3); + addr2 = addr >> 13; + break; + + case 0x17: + if (dev->external_is_RAS && (addr & 0x800) == 0) + return 0xffffffff; + nbank = addr >> 19; + if (nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else { + nbank = 2 + ((addr - 0x100000) >> 23); + addr2 = (addr - 0x100000) >> 12; + } + break; + + case 0x18: + if (dev->external_is_RAS && (addr & 0x800) == 0) + return 0xffffffff; + nbank = addr >> 21; + if (nbank < 4) { + nbank = 1; + addr2 = addr >> 12; + } else if (nbank == 4) { + nbank = 0; + addr2 = addr >> 11; + } else { + nbank -= 3; + addr2 = addr >> 11; + } + break; + + case 0x19: + if (dev->external_is_RAS && (addr & 0x800) == 0) + return 0xffffffff; + nbank = addr >> 23; + if ((nbank & 3) < 2) { + nbank = (addr >> 12) & 1; + addr2 = addr >> 13; + } else + addr2 = addr >> 12; + break; + + default: + if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 6) { + nbank = addr >> 19; + addr2 = (addr >> 10) & 0x1ff; + } else if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 0x17) { + nbank = addr >> 21; + addr2 = (addr >> 11) & 0x3ff; + } else { + nbank = addr >> 23; + addr2 = (addr >> 12) & 0x7ff; + } + break; + } + + nbank &= (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3; + + if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) > 0x16 && nbank == 3) + return 0xffffffff; + + if (dev->external_is_RAS && (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) { + if (nbank == 3) + nbank = 7; + else + return 0xffffffff; + } else if (!dev->external_is_RAS && dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) { + switch(nbank) { + case 7: + nbank = 3; + break; + + /* Note - In the following cases, the chipset accesses multiple memory banks + at the same time, so it's impossible to predict which memory bank + is actually accessed. */ + case 5: + case 1: + nbank = 1; + break; + + case 3: + nbank = 2; + break; + + default: + nbank = 0; + break; + } + } + + switch(mem_size & ~511) { + case 1024: + case 1536: + addr &= 0x3ff; + if (nbank < 2) + addr |= (nbank << 10) | ((addr2 & 0x1ff) << 11); + else + addr |= ((addr2 & 0x1ff) << 10) | (nbank << 19); + break; + + case 2048: + if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 5) { + addr &= 0x3ff; + if (nbank < 4) + addr |= (nbank << 10) | ((addr2 & 0x1ff) << 12); + else + addr |= ((addr2 & 0x1ff) << 10) | (nbank << 19); + } else { + addr &= 0x7ff; + addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21); + } + break; + + case 2560: + if (nbank == 0) + addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10); + else { + addr &= 0x7ff; + addr2 &= 0x3ff; + addr = addr + 0x80000 + ((addr2 << 11) | ((nbank - 1) << 21)); + } + break; + + case 3072: + if (nbank < 2) + addr = (addr & 0x3ff) | (nbank << 10) | ((addr2 & 0x1ff) << 11); + else + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11) | ((nbank - 2) << 21)); + break; + + case 4096: + case 6144: + addr &= 0x7ff; + if (nbank < 2) + addr |= (nbank << 11) | ((addr2 & 0x3ff) << 12); + else + addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21); + break; + + case 4608: + if (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) >= 8 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) <= 0x0a) || ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 0x18)) { + if (nbank == 0) + addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10); + else if (nbank < 3) + addr = 0x80000 + ((addr & 0x7ff) | ((nbank - 1) << 11) | ((addr2 & 0x3ff) << 12)); + else + addr = 0x480000 + ((addr & 0x3ff) | ((addr2 & 0x1ff) << 10) | ((nbank - 3) << 19)); + } else if (nbank == 0) + addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10); + else { + addr &= 0x7ff; + addr2 &= 0x3ff; + addr = addr + 0x80000 + ((addr2 << 11) | ((nbank - 1) << 21)); + } + break; + + case 5120: + case 7168: + if (nbank < 2) + addr = (addr & 0x3ff) | (nbank << 10) | ((addr2 & 0x1ff) << 11); + else if (nbank < 4) + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 12) | ((nbank & 1) << 11)); + else + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11) | ((nbank - 2) << 21)); + break; + + case 6656: + if (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) >= 8 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) <= 0x0a) || ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 0x18)) { + if (nbank == 0) + addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10); + else if (nbank < 3) + addr = 0x80000 + ((addr & 0x7ff) | ((nbank - 1) << 11) | ((addr2 & 0x3ff) << 12)); + else if (nbank == 3) + addr = 0x480000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11)); + else + addr = 0x680000 + ((addr & 0x3ff) | ((addr2 & 0x1ff) << 10) | ((nbank - 4) << 19)); + } else if (nbank == 0) + addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10); + else if (nbank == 1) { + addr &= 0x7ff; + addr2 &= 0x3ff; + addr = addr + 0x80000 + (addr2 << 11); + } else { + addr &= 0x7ff; + addr2 &= 0x3ff; + addr = addr + 0x280000 + ((addr2 << 12) | ((nbank & 1) << 11) | (((nbank - 2) & 6) << 21)); + } + break; + + case 8192: + addr &= 0x7ff; + if (nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3ff) << 13); + else + addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21); + break; + + case 9216: + if (nbank < 2) + addr = (addr & 0x3ff) | (nbank << 10) | ((addr2 & 0x1ff) << 11); + else if (dev->external_is_RAS) { + if (nbank < 6) + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 12) | ((nbank & 1) << 11)); + else + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11) | ((nbank - 2) << 21)); + } else + addr = 0x100000 + ((addr & 0xfff) | ((addr2 & 0x7ff) << 12) | ((nbank - 2) << 23)); + break; + + case 10240: + if (dev->external_is_RAS) { + addr &= 0x7ff; + if (nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3ff) << 13); + else + addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21); + } else if (nbank == 0) + addr = (addr & 0x7ff) | ((addr2 & 0x3ff) << 11); + else { + addr &= 0xfff; + addr2 &= 0x7ff; + addr = addr + 0x200000 + ((addr2 << 12) | ((nbank - 1) << 23)); + } + break; + + case 11264: + if (nbank < 2) + addr = (addr & 0x3ff) | (nbank << 10) | ((addr2 & 0x1ff) << 11); + else if (nbank < 6) + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 12) | ((nbank & 1) << 11)); + else + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11) | ((nbank - 2) << 21)); + break; + + case 12288: + if (dev->external_is_RAS) { + addr &= 0x7ff; + if (nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3ff) << 13); + else if (nbank < 6) + addr |= ((nbank & 1) << 11) | ((addr2 & 0x3ff) << 12) | ((nbank & 4) << 21); + else + addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21); + } else { + if (nbank < 2) + addr = (addr & 0x7ff) | (nbank << 11) | ((addr2 & 0x3ff) << 12); + else + addr = 0x400000 + ((addr & 0xfff) | ((addr2 & 0x7ff) << 12) | ((nbank - 2) << 23)); + } + break; + + case 13312: + if (nbank < 2) + addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); + else if (nbank < 4) + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); + else + addr = 0x500000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 13) | ((nbank & 3) << 11)); + break; + + case 14336: + addr &= 0x7ff; + if (nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3ff) << 13); + else if (nbank < 6) + addr |= ((nbank & 1) << 11) | ((addr2 & 0x3ff) << 12) | ((nbank & 4) << 21); + else + addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21); + break; + + case 16384: + if (dev->external_is_RAS) { + addr &= 0x7ff; + addr2 &= 0x3ff; + addr |= ((nbank & 3) << 11) | (addr2 << 13) | ((nbank & 4) << 21); + } else { + addr &= 0xfff; + addr2 &= 0x7ff; + if (nbank < 2) + addr |= (addr2 << 13) | (nbank << 12); + else + addr |= (addr2 << 12) | (nbank << 23); + } + break; + + default: + if (mem_size < 2048 || ((mem_size & 1536) == 512) || (mem_size == 2048 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 6)) { + addr &= 0x3ff; + addr2 &= 0x1ff; + addr |= (addr2 << 10) | (nbank << 19); + } else if (mem_size < 8192 || (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 0x17) { + addr &= 0x7ff; + addr2 &= 0x3ff; + addr |= (addr2 << 11) | (nbank << 21); + } else { + addr &= 0xfff; + addr2 &= 0x7ff; + addr |= (addr2 << 12) | (nbank << 23); + } + break; + } + } + + return addr; +} + + +static void +set_global_EMS_state(scat_t *dev, int state) +{ + uint32_t base_addr, virt_addr; + int i, conf; + + for (i = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0 : 24; i < 32; i++) { + base_addr = (i + 16) << 14; + + if (i >= 24) + base_addr += 0x30000; + if (state && (dev->page[i].regs_2x9 & 0x80)) { + virt_addr = get_addr(dev, base_addr, &dev->page[i]); + if (i < 24) + mem_mapping_disable(&dev->efff_mapping[i]); + else + mem_mapping_disable(&dev->efff_mapping[i + 12]); + mem_mapping_enable(&dev->ems_mapping[i]); + + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[i], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[i], NULL); + } else { + mem_mapping_set_exec(&dev->ems_mapping[i], ram + base_addr); + mem_mapping_disable(&dev->ems_mapping[i]); + + conf = (dev->regs[SCAT_VERSION] & 0xf0) ? (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) + : (dev->regs[SCAT_DRAM_CONFIGURATION] & 0xf) | + ((dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2); + if (i < 24) { + if (conf > 1 || (conf == 1 && i < 16)) + mem_mapping_enable(&dev->efff_mapping[i]); + else + mem_mapping_disable(&dev->efff_mapping[i]); + } else if (conf > 3 || ((dev->regs[SCAT_VERSION] & 0xf0) != 0 && conf == 2)) + mem_mapping_enable(&dev->efff_mapping[i + 12]); + else + mem_mapping_disable(&dev->efff_mapping[i + 12]); + } + } + + flushmmucache(); +} + + +static void +memmap_state_update(scat_t *dev) +{ + uint32_t addr; + int i; + + for (i = (((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0 : 16); i < 44; i++) { + addr = get_addr(dev, 0x40000 + (i << 14), NULL); + mem_mapping_set_exec(&dev->efff_mapping[i], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + } + + addr = get_addr(dev, 0, NULL); + mem_mapping_set_exec(&dev->low_mapping[0], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + + addr = get_addr(dev, 0xf0000, NULL); + mem_mapping_set_exec(&dev->low_mapping[1], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + + for (i = 2; i < 32; i++) { + addr = get_addr(dev, i << 19, NULL); + mem_mapping_set_exec(&dev->low_mapping[i], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + } + + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + for (i = 0; i < max_map[(dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) | + ((dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2)]; i++) + mem_mapping_enable(&dev->low_mapping[i]); + + for (; i < 32; i++) + mem_mapping_disable(&dev->low_mapping[i]); + + for (i = 24; i < 36; i++) { + if (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) | (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40)) < 4) + mem_mapping_disable(&dev->efff_mapping[i]); + else + mem_mapping_enable(&dev->efff_mapping[i]); + } + } else { + for (i = 0; i < max_map_sx[dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f]; i++) + mem_mapping_enable(&dev->low_mapping[i]); + + for (; i < 32; i++) + mem_mapping_disable(&dev->low_mapping[i]); + + for(i = 24; i < 36; i++) { + if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 2 || (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 3) + mem_mapping_disable(&dev->efff_mapping[i]); + else + mem_mapping_enable(&dev->efff_mapping[i]); + } + } + + if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && + (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) || ((dev->regs[SCAT_VERSION] & 0xf0) != 0)) { + if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && + (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) == 3) || + (((dev->regs[SCAT_VERSION] & 0xf0) != 0) && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 3)) { + mem_mapping_disable(&dev->low_mapping[2]); + + for (i = 0; i < 6; i++) { + addr = get_addr(dev, 0x100000 + (i << 16), NULL); + mem_mapping_set_exec(&dev->remap_mapping[i], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + mem_mapping_enable(&dev->remap_mapping[i]); + } + } else { + for (i = 0; i < 6; i++) + mem_mapping_disable(&dev->remap_mapping[i]); + + if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && + (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) > 4) || + (((dev->regs[SCAT_VERSION] & 0xf0) != 0) && + (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) > 3)) + mem_mapping_enable(&dev->low_mapping[2]); + } + } else { + for (i = 0; i < 6; i++) + mem_mapping_disable(&dev->remap_mapping[i]); + + mem_mapping_enable(&dev->low_mapping[2]); + } + + set_global_EMS_state(dev, dev->regs[SCAT_EMS_CONTROL] & 0x80); +} + + +static void +scat_out(uint16_t port, uint8_t val, void *priv) +{ + scat_t *dev = (scat_t *)priv; + uint8_t reg_valid = 0, + shadow_update = 0, + map_update = 0, + indx; + uint32_t base_addr, virt_addr; + + switch (port) { + case 0x22: + dev->indx = val; + break; + + case 0x23: + switch (dev->indx) { + case SCAT_DMA_WAIT_STATE_CONTROL: + case SCAT_CLOCK_CONTROL: + case SCAT_PERIPHERAL_CONTROL: + reg_valid = 1; + break; + + case SCAT_EMS_CONTROL: + if (val & 0x40) { + if (val & 1) { + io_sethandler(0x0218, 3, scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + io_removehandler(0x0208, 3, scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + } else { + io_sethandler(0x0208, 3, scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + io_removehandler(0x0218, 3, scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + } + } else { + io_removehandler(0x0208, 0x0003, scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + io_removehandler(0x0218, 0x0003, scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + } + set_global_EMS_state(dev, val & 0x80); + reg_valid = 1; + break; + + case SCAT_POWER_MANAGEMENT: + /* TODO - Only use AUX parity disable bit for this version. + Other bits should be implemented later. */ + val &= (dev->regs[SCAT_VERSION] & 0xf0) == 0 ? 0x40 : 0x60; + reg_valid = 1; + break; + + case SCAT_DRAM_CONFIGURATION: + map_update = 1; + + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + cpu_waitstates = (val & 0x70) == 0 ? 1 : 2; + cpu_update_waitstates(); + } + + reg_valid = 1; + break; + + case SCAT_EXTENDED_BOUNDARY: + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + if (dev->regs[SCAT_VERSION] < 4) { + val &= 0xbf; + set_xms_bound(dev, val & 0x0f); + } else { + val = (val & 0x7f) | 0x80; + set_xms_bound(dev, val & 0x4f); + } + } else + set_xms_bound(dev, val & 0x1f); + + mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if ((val ^ dev->regs[SCAT_EXTENDED_BOUNDARY]) & 0xc0) + map_update = 1; + reg_valid = 1; + break; + + case SCAT_ROM_ENABLE: + romcs_state_update(dev, val); + reg_valid = 1; + break; + + case SCAT_RAM_WRITE_PROTECT: + reg_valid = 1; + flushmmucache_cr3(); + break; + + case SCAT_SHADOW_RAM_ENABLE_1: + case SCAT_SHADOW_RAM_ENABLE_2: + case SCAT_SHADOW_RAM_ENABLE_3: + reg_valid = 1; + shadow_update = 1; + break; + + case SCATSX_LAPTOP_FEATURES: + if ((dev->regs[SCAT_VERSION] & 0xf0) != 0) { + val = (val & ~8) | (dev->regs[SCATSX_LAPTOP_FEATURES] & 8); + reg_valid = 1; + } + break; + + case SCATSX_FAST_VIDEO_CONTROL: + case SCATSX_FAST_VIDEORAM_ENABLE: + case SCATSX_HIGH_PERFORMANCE_REFRESH: + case SCATSX_CAS_TIMING_FOR_DMA: + if ((dev->regs[SCAT_VERSION] & 0xf0) != 0) + reg_valid = 1; + break; + + default: + break; + } + + if (reg_valid) + dev->regs[dev->indx] = val; + + if (shadow_update) + shadow_state_update(dev); + + if (map_update) + memmap_state_update(dev); + break; + + case 0x208: + case 0x218: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + indx = dev->reg_2xA & 0x1f; + else + indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24; + dev->page[indx].regs_2x8 = val; + base_addr = (indx + 16) << 14; + if (indx >= 24) + base_addr += 0x30000; + + if ((dev->regs[SCAT_EMS_CONTROL] & 0x80) && (dev->page[indx].regs_2x9 & 0x80)) { + virt_addr = get_addr(dev, base_addr, &dev->page[indx]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[indx], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[indx], NULL); + flushmmucache(); + } + } + break; + + case 0x209: + case 0x219: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + indx = dev->reg_2xA & 0x1f; + else + indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24; + dev->page[indx].regs_2x9 = val; + base_addr = (indx + 16) << 14; + if (indx >= 24) + base_addr += 0x30000; + + if (dev->regs[SCAT_EMS_CONTROL] & 0x80) { + if (val & 0x80) { + virt_addr = get_addr(dev, base_addr, &dev->page[indx]); + if (indx < 24) + mem_mapping_disable(&dev->efff_mapping[indx]); + else + mem_mapping_disable(&dev->efff_mapping[indx + 12]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[indx], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[indx], NULL); + mem_mapping_enable(&dev->ems_mapping[indx]); + } else { + mem_mapping_set_exec(&dev->ems_mapping[indx], ram + base_addr); + mem_mapping_disable(&dev->ems_mapping[indx]); + if (indx < 24) + mem_mapping_enable(&dev->efff_mapping[indx]); + else + mem_mapping_enable(&dev->efff_mapping[indx + 12]); + } + + flushmmucache(); + } + + if (dev->reg_2xA & 0x80) + dev->reg_2xA = (dev->reg_2xA & 0xe0) | ((dev->reg_2xA + 1) & (((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0x1f : 3)); + } + break; + + case 0x20a: + case 0x21a: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) + dev->reg_2xA = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? val : val & 0xc3; + break; + } +} + + +static uint8_t +scat_in(uint16_t port, void *priv) +{ + scat_t *dev = (scat_t *)priv; + uint8_t ret = 0xff, indx; + + switch (port) { + case 0x23: + switch (dev->indx) { + case SCAT_MISCELLANEOUS_STATUS: + ret = (dev->regs[dev->indx] & 0x3f) | (~nmi_mask & 0x80) | ((mem_a20_key & 2) << 5); + break; + + case SCAT_DRAM_CONFIGURATION: + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + ret = (dev->regs[dev->indx] & 0x8f) | (cpu_waitstates == 1 ? 0 : 0x10); + else + ret = dev->regs[dev->indx]; + break; + + case SCAT_EXTENDED_BOUNDARY: + ret = dev->regs[dev->indx]; + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + if ((dev->regs[SCAT_VERSION] & 0x0f) >= 4) + ret |= 0x80; + else + ret &= 0xaf; + } + break; + + default: + ret = dev->regs[dev->indx]; + break; + } + break; + + case 0x208: + case 0x218: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + indx = dev->reg_2xA & 0x1f; + else + indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24; + ret = dev->page[indx].regs_2x8; + } + break; + + case 0x209: + case 0x219: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + indx = dev->reg_2xA & 0x1f; + else + indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24; + ret = dev->page[indx].regs_2x9; + } + break; + + case 0x20a: + case 0x21a: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) + ret = dev->reg_2xA; + break; + } + + return ret; +} + + +static uint8_t +mem_read_scatb(uint32_t addr, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + scat_t *dev = (scat_t *)page->scat; + uint8_t val = 0xff; + + addr = get_addr(dev, addr, page); + if (addr < ((uint32_t)mem_size << 10)) + val = ram[addr]; + + return val; +} + + +static uint16_t +mem_read_scatw(uint32_t addr, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + scat_t *dev = (scat_t *)page->scat; + uint16_t val = 0xffff; + + addr = get_addr(dev, addr, page); + if (addr < ((uint32_t)mem_size << 10)) + val = *(uint16_t *)&ram[addr]; + + return val; +} + + +static uint32_t +mem_read_scatl(uint32_t addr, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + scat_t *dev = (scat_t *)page->scat; + uint32_t val = 0xffffffff; + + addr = get_addr(dev, addr, page); + if (addr < ((uint32_t)mem_size << 10)) + val = *(uint32_t *)&ram[addr]; + + return val; +} + + +static void +mem_write_scatb(uint32_t addr, uint8_t val, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + scat_t *dev = (scat_t *)page->scat; + uint32_t oldaddr = addr, chkaddr; + + addr = get_addr(dev, addr, page); + chkaddr = page ? addr : oldaddr; + if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { + if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; + } + + if (addr < ((uint32_t)mem_size << 10)) + ram[addr] = val; +} + + +static void +mem_write_scatw(uint32_t addr, uint16_t val, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + scat_t *dev = (scat_t *)page->scat; + uint32_t oldaddr = addr, chkaddr; + + addr = get_addr(dev, addr, page); + chkaddr = page ? addr : oldaddr; + if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { + if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; + } + + if (addr < ((uint32_t)mem_size << 10)) + *(uint16_t *)&ram[addr] = val; +} + + +static void +mem_write_scatl(uint32_t addr, uint32_t val, void *priv) +{ + ems_page_t *page = (ems_page_t *)priv; + scat_t *dev = (scat_t *)page->scat; + uint32_t oldaddr = addr, chkaddr; + + addr = get_addr(dev, addr, page); + chkaddr = page ? addr : oldaddr; + if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { + if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; + } + if (addr < ((uint32_t)mem_size << 10)) + *(uint32_t *)&ram[addr] = val; +} + + +static void +scat_close(void *priv) +{ + scat_t *dev = (scat_t *)priv; + + free(dev); +} + + +static void * +scat_init(const device_t *info) +{ + scat_t *dev; + uint32_t i, k; + int sx; + + dev = (scat_t *)malloc(sizeof(scat_t)); + memset(dev, 0x00, sizeof(scat_t)); + dev->type = info->local; + + sx = (dev->type == 32) ? 1 : 0; + + for (i = 0; i < sizeof(dev->regs); i++) + dev->regs[i] = 0xff; + + if (sx) { + dev->regs[SCAT_VERSION] = 0x13; + dev->regs[SCAT_CLOCK_CONTROL] = 6; + dev->regs[SCAT_PERIPHERAL_CONTROL] = 0; + dev->regs[SCAT_DRAM_CONFIGURATION] = 1; + dev->regs[SCATSX_LAPTOP_FEATURES] = 0; + dev->regs[SCATSX_FAST_VIDEO_CONTROL] = 0; + dev->regs[SCATSX_FAST_VIDEORAM_ENABLE] = 0; + dev->regs[SCATSX_HIGH_PERFORMANCE_REFRESH] = 8; + dev->regs[SCATSX_CAS_TIMING_FOR_DMA] = 3; + } else { + switch(dev->type) { + case 4: + dev->regs[SCAT_VERSION] = 4; + break; + + default: + dev->regs[SCAT_VERSION] = 1; + break; + } + dev->regs[SCAT_CLOCK_CONTROL] = 2; + dev->regs[SCAT_PERIPHERAL_CONTROL] = 0x80; + dev->regs[SCAT_DRAM_CONFIGURATION] = cpu_waitstates == 1 ? 2 : 0x12; + } + dev->regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; + dev->regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; + dev->regs[SCAT_ROM_ENABLE] = 0xc0; + dev->regs[SCAT_RAM_WRITE_PROTECT] = 0; + dev->regs[SCAT_POWER_MANAGEMENT] = 0; + dev->regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; + dev->regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; + dev->regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; + dev->regs[SCAT_EXTENDED_BOUNDARY] = 0; + dev->regs[SCAT_EMS_CONTROL] = 0; + + /* Disable all system mappings, we will override them. */ + mem_mapping_disable(&ram_low_mapping); + if (! sx) + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); + mem_mapping_disable(&bios_mapping); + + k = (sx) ? 0x80000 : 0x40000; + + dev->null_page.valid = 0; + dev->null_page.regs_2x8 = 0xff; + dev->null_page.regs_2x9 = 0xff; + dev->null_page.scat = dev; + + mem_mapping_add(&dev->low_mapping[0], 0, k, + mem_read_scatb, mem_read_scatw, mem_read_scatl, + mem_write_scatb, mem_write_scatw, mem_write_scatl, + ram, MEM_MAPPING_INTERNAL, &dev->null_page); + + mem_mapping_add(&dev->low_mapping[1], 0xf0000, 0x10000, + mem_read_scatb, mem_read_scatw, mem_read_scatl, + mem_write_scatb, mem_write_scatw, mem_write_scatl, + ram + 0xf0000, MEM_MAPPING_INTERNAL, &dev->null_page); + + for (i = 2; i < 32; i++) { + mem_mapping_add(&dev->low_mapping[i], (i << 19), 0x80000, + mem_read_scatb, mem_read_scatw, mem_read_scatl, + mem_write_scatb, mem_write_scatw, mem_write_scatl, + ram + (i<<19), MEM_MAPPING_INTERNAL, &dev->null_page); + } + + if (sx) { + i = 16; + k = 0x40000; + } else { + i = 0; + k = (dev->regs[SCAT_VERSION] < 4) ? 0x40000 : 0x60000; + } + mem_mapping_set_addr(&dev->low_mapping[31], 0xf80000, k); + + for (; i < 44; i++) { + mem_mapping_add(&dev->efff_mapping[i], 0x40000 + (i << 14), 0x4000, + mem_read_scatb, mem_read_scatw, mem_read_scatl, + mem_write_scatb, mem_write_scatw, mem_write_scatl, + mem_size > (256 + (i << 4)) ? ram + 0x40000 + (i << 14) : NULL, + MEM_MAPPING_INTERNAL, &dev->null_page); + + if (sx) + mem_mapping_enable(&dev->efff_mapping[i]); + } + + for (i = 0; i < 8; i++) { + mem_mapping_add(&dev->romcs_mapping[i], 0xc0000 + (i << 14), 0x4000, + mem_read_bios, mem_read_biosw, mem_read_biosl, + mem_write_null, mem_write_nullw, mem_write_nulll, + rom + ((i << 14) & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, NULL); + mem_mapping_disable(&dev->romcs_mapping[i]); + } + + for (i = 0; i < 8; i++) { + mem_mapping_add(&dev->bios_mapping[i], 0xe0000 + (i << 14), 0x4000, + mem_read_bios, mem_read_biosw, mem_read_biosl, + mem_write_null, mem_write_nullw, mem_write_nulll, + rom + ((i << 14) & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, NULL); + if (i < 4) + mem_mapping_disable(&dev->bios_mapping[i]); + } + + if (sx) { + for (i = 24; i < 32; i++) { + dev->page[i].valid = 1; + dev->page[i].regs_2x8 = 0xff; + dev->page[i].regs_2x9 = 0x03; + dev->page[i].scat = dev; + mem_mapping_add(&dev->ems_mapping[i], (i + 28) << 14, 0x04000, + mem_read_scatb, mem_read_scatw, mem_read_scatl, + mem_write_scatb, mem_write_scatw, mem_write_scatl, + ram + ((i + 28) << 14), 0, &dev->page[i]); + mem_mapping_disable(&dev->ems_mapping[i]); + } + + for (i = 0; i < 16; i++) { + mem_mapping_add(&dev->high_mapping[i], (i << 14) + 0xfc0000, 0x04000, + mem_read_bios, mem_read_biosw, mem_read_biosl, + mem_write_null, mem_write_nullw, mem_write_nulll, + rom + ((i << 14) & biosmask), 0, NULL); + mem_mapping_enable(&dev->high_mapping[i]); + } + } else { + for (i = 0; i < 32; i++) { + dev->page[i].valid = 1; + dev->page[i].regs_2x8 = 0xff; + dev->page[i].regs_2x9 = 0x03; + dev->page[i].scat = dev; + mem_mapping_add(&dev->ems_mapping[i], (i + (i >= 24 ? 28 : 16)) << 14, 0x04000, + mem_read_scatb, mem_read_scatw, mem_read_scatl, + mem_write_scatb, mem_write_scatw, mem_write_scatl, + ram + ((i + (i >= 24 ? 28 : 16)) << 14), + 0, &dev->page[i]); + } + + for (i = (dev->regs[SCAT_VERSION] < 4 ? 0 : 8); i < 16; i++) { + mem_mapping_add(&dev->high_mapping[i], (i << 14) + 0xfc0000, 0x04000, + mem_read_bios, mem_read_biosw, mem_read_biosl, + mem_write_null, mem_write_nullw, mem_write_nulll, + rom + ((i << 14) & biosmask), 0, NULL); + mem_mapping_enable(&dev->high_mapping[i]); + } + } + + for (i = 0; i < 6; i++) { + mem_mapping_add(&dev->remap_mapping[i], 0x100000 + (i << 16), 0x10000, + mem_read_scatb, mem_read_scatw, mem_read_scatl, + mem_write_scatb, mem_write_scatw, mem_write_scatl, + mem_size >= 1024 ? ram + get_addr(dev, 0x100000 + (i << 16), NULL) : NULL, + MEM_MAPPING_INTERNAL, &dev->null_page); + } + + if (sx) { + dev->external_is_RAS = scatsx_external_is_RAS[mem_size >> 9]; + } else { + dev->external_is_RAS = (dev->regs[SCAT_VERSION] > 3) || (((mem_size & ~2047) >> 11) + ((mem_size & 1536) >> 9) + ((mem_size & 511) >> 7)) > 4; + } + + set_xms_bound(dev, 0); + memmap_state_update(dev); + shadow_state_update(dev); + + io_sethandler(0x0022, 2, + scat_in, NULL, NULL, scat_out, NULL, NULL, dev); + + device_add(&port_92_device); + + return(dev); +} + + +const device_t scat_device = { + "C&T SCAT (v1)", + 0, + 0, + scat_init, scat_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t scat_4_device = { + "C&T SCAT (v4)", + 0, + 4, + scat_init, scat_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t scat_sx_device = { + "C&T SCATsx", + 0, + 32, + scat_init, scat_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/scat_varcem.c b/src/chipset/scat_varcem.c new file mode 100644 index 000000000..fb0e6bf80 --- /dev/null +++ b/src/chipset/scat_varcem.c @@ -0,0 +1,1642 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the C&T 82C235 ("SCAT") chipset. + * + * Version: @(#)scat.c 1.0.18 2019/05/13 + * + * Authors: Fred N. van Kempen, + * Original by GreatPsycho for PCem. + * Miran Grca, + * + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include "../../emu.h" +#include "../../config.h" +#include "../../cpu/cpu.h" +#include "../../cpu/x86.h" +#include "../../io.h" +#include "../../mem.h" +#include "../../rom.h" +#include "../../device.h" +#include "../../plat.h" +#include "../system/nmi.h" +#include "scat.h" + + +#define SCAT_DMA_WAIT_STATE_CONTROL 0x01 +#define SCAT_VERSION 0x40 +#define SCAT_CLOCK_CONTROL 0x41 +#define SCAT_PERIPHERAL_CONTROL 0x44 +#define SCAT_MISCELLANEOUS_STATUS 0x45 +#define SCAT_POWER_MANAGEMENT 0x46 +#define SCAT_ROM_ENABLE 0x48 +#define SCAT_RAM_WRITE_PROTECT 0x49 +#define SCAT_SHADOW_RAM_ENABLE_1 0x4A +#define SCAT_SHADOW_RAM_ENABLE_2 0x4B +#define SCAT_SHADOW_RAM_ENABLE_3 0x4C +#define SCAT_DRAM_CONFIGURATION 0x4D +#define SCAT_EXTENDED_BOUNDARY 0x4E +#define SCAT_EMS_CONTROL 0x4F + +#define SCATSX_LAPTOP_FEATURES 0x60 +#define SCATSX_FAST_VIDEO_CONTROL 0x61 +#define SCATSX_FAST_VIDEORAM_ENABLE 0x62 +#define SCATSX_HIGH_PERFORMANCE_REFRESH 0x63 +#define SCATSX_CAS_TIMING_FOR_DMA 0x64 + + +typedef struct { + uint8_t regs_2x8; + uint8_t regs_2x9; +} ems_page_t; + +typedef struct { + int type; + + int indx; + uint8_t regs[256]; + uint8_t reg_2xA; + uint8_t port_92; + + uint32_t xms_bound; + + int external_is_RAS; + + ems_page_t page[32]; + + mem_mapping_t low_mapping[32]; + mem_mapping_t high_mapping[16]; + mem_mapping_t remap_mapping[6]; + mem_mapping_t efff_mapping[44]; + mem_mapping_t romcs_mapping[8]; + mem_mapping_t ems_mapping[32]; +} scat_t; + + +static const uint8_t max_map[32] = { + 0, 1, 1, 1, 2, 3, 4, 8, + 4, 8, 12, 16, 20, 24, 28, 32, + 0, 5, 9, 13, 6, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; +static const uint8_t max_map_sx[32] = { + 0, 1, 2, 1, 3, 4, 6, 10, + 5, 9, 13, 4, 8, 12, 16, 14, + 18, 22, 26, 20, 24, 28, 32, 18, + 20, 32, 0, 0, 0, 0, 0, 0 +}; +static const uint8_t scatsx_external_is_RAS[33] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0 +}; + + +static uint8_t scat_read(uint16_t port, priv_t priv); +static void scat_write(uint16_t port, uint8_t val, priv_t priv); + + +static void +romcs_state_update(scat_t *dev, uint8_t val) +{ + int i; + + for (i = 0; i < 4; i++) { + if (val & 1) { + mem_mapping_enable(&dev->romcs_mapping[i << 1]); + mem_mapping_enable(&dev->romcs_mapping[(i << 1) + 1]); + } else { + mem_mapping_disable(&dev->romcs_mapping[i << 1]); + mem_mapping_disable(&dev->romcs_mapping[(i << 1) + 1]); + } + val >>= 1; + } + + for (i = 0; i < 4; i++) { + if (val & 1) { + mem_mapping_enable(&bios_mapping[i << 1]); + mem_mapping_enable(&bios_mapping[(i << 1) + 1]); + } else { + mem_mapping_disable(&bios_mapping[i << 1]); + mem_mapping_disable(&bios_mapping[(i << 1) + 1]); + } + val >>= 1; + } +} + + +static void +shadow_state_update(scat_t *dev) +{ + int i, val; + + for (i = 0; i < 24; i++) { + val = ((dev->regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_READ_INTERNAL | MEM_WRITE_INTERNAL : MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL; + mem_set_mem_state((i + 40) << 14, 0x4000, val); + } + + flushmmucache(); +} + + +static void +set_xms_bound(scat_t *dev, uint8_t val) +{ + uint32_t xms_max = ((dev->regs[SCAT_VERSION] & 0xf0) != 0 && ((val & 0x10) != 0)) || (dev->regs[SCAT_VERSION] >= 4) ? 0xfe0000 : 0xfc0000; + int i; + + switch (val & 0x0f) { + case 1: + dev->xms_bound = 0x100000; + break; + + case 2: + dev->xms_bound = 0x140000; + break; + + case 3: + dev->xms_bound = 0x180000; + break; + + case 4: + dev->xms_bound = 0x200000; + break; + + case 5: + dev->xms_bound = 0x300000; + break; + + case 6: + dev->xms_bound = 0x400000; + break; + + case 7: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0x600000 : 0x500000; + break; + + case 8: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0x800000 : 0x700000; + break; + + case 9: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0xa00000 : 0x800000; + break; + + case 10: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0xc00000 : 0x900000; + break; + + case 11: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0xe00000 : 0xa00000; + break; + + case 12: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xb00000; + break; + + case 13: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xc00000; + break; + + case 14: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xd00000; + break; + + case 15: + dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xf00000; + break; + + default: + dev->xms_bound = xms_max; + break; + } + + if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && (val & 0x40) == 0 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) == 3) || + (((dev->regs[SCAT_VERSION] & 0xf0) != 0) && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 3)) { + if ((val & 0x0f) == 0 || dev->xms_bound > 0x160000) + dev->xms_bound = 0x160000; + + if (dev->xms_bound > 0x100000) + mem_set_mem_state(0x100000, dev->xms_bound - 0x100000, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + if (dev->xms_bound < 0x160000) + mem_set_mem_state(dev->xms_bound, 0x160000 - dev->xms_bound, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } else { + if (dev->xms_bound > xms_max) + dev->xms_bound = xms_max; + + if (dev->xms_bound > 0x100000) + mem_set_mem_state(0x100000, dev->xms_bound - 0x100000, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + if (dev->xms_bound < ((uint32_t)mem_size << 10)) + mem_set_mem_state(dev->xms_bound, (mem_size << 10) - dev->xms_bound, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + mem_mapping_set_addr(&dev->low_mapping[31], 0xf80000, + ((dev->regs[SCAT_VERSION] & 0xf0) != 0 && ((val & 0x10) != 0)) || + (dev->regs[SCAT_VERSION] >= 4) ? 0x60000 : 0x40000); + if (dev->regs[SCAT_VERSION] & 0xf0) { + for (i = 0; i < 8; i++) { + if (val & 0x10) + mem_mapping_disable(&dev->high_mapping[i]); + else + mem_mapping_enable(&dev->high_mapping[i]); + } + } +} + + +static uint32_t +get_addr(scat_t *dev, uint32_t addr, ems_page_t *p) +{ + int nbanks_2048k, nbanks_512k; + uint32_t addr2; + int nbank; + + if (p && (dev->regs[SCAT_EMS_CONTROL] & 0x80) && (p->regs_2x9 & 0x80)) + addr = (addr & 0x3fff) | (((p->regs_2x9 & 3) << 8) | p->regs_2x8) << 14; + + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + switch((dev->regs[SCAT_EXTENDED_BOUNDARY] & ((dev->regs[SCAT_VERSION] & 0x0f) > 3 ? 0x40 : 0)) | (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f)) { + case 0x41: + nbank = addr >> 19; + if (nbank < 4) + nbank = 1; + else if (nbank == 4) + nbank = 0; + else + nbank -= 3; + break; + + case 0x42: + nbank = addr >> 19; + if (nbank < 8) + nbank = 1 + (nbank >> 2); + else if (nbank == 8) + nbank = 0; + else + nbank -= 6; + break; + + case 0x43: + nbank = addr >> 19; + if (nbank < 12) + nbank = 1 + (nbank >> 2); + else if (nbank == 12) + nbank = 0; + else + nbank -= 9; + break; + + case 0x44: + nbank = addr >> 19; + if (nbank < 4) + nbank = 2; + else if (nbank < 6) + nbank -= 4; + else + nbank -= 3; + break; + + case 0x45: + nbank = addr >> 19; + if (nbank < 8) + nbank = 2 + (nbank >> 2); + else if (nbank < 10) + nbank -= 8; + else + nbank -= 6; + break; + + default: + nbank = addr >> (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) < 8 && (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) ? 19 : 21); + break; + } + + nbank &= (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3; + + if ((dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0 && + (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) == 3 && + nbank == 2 && (addr & 0x7ffff) < 0x60000 && mem_size > 640) { + nbank = 1; + addr ^= 0x70000; + } + + if (dev->external_is_RAS && (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) { + if (nbank == 3) + nbank = 7; + else + return 0xffffffff; + } else if (!dev->external_is_RAS && dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) { + switch(nbank) { + case 7: + nbank = 3; + break; + + /* Note - In the following cases, the chipset accesses multiple memory banks + at the same time, so it's impossible to predict which memory bank + is actually accessed. */ + case 5: + case 1: + nbank = 1; + break; + + case 3: + nbank = 2; + break; + + default: + nbank = 0; + break; + } + } + + if ((dev->regs[SCAT_VERSION] & 0x0f) > 3 && (mem_size > 2048) && (mem_size & 1536)) { + if ((mem_size & 1536) == 512) { + if (nbank == 0) + addr &= 0x7ffff; + else + addr = 0x80000 + ((addr & 0x1fffff) | ((nbank - 1) << 21)); + } else { + if (nbank < 2) + addr = (addr & 0x7ffff) | (nbank << 19); + else + addr = 0x100000 + ((addr & 0x1fffff) | ((nbank - 2) << 21)); + } + } else { + if (mem_size <= ((dev->regs[SCAT_VERSION] & 0x0f) > 3 ? 2048 : 4096) && (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) < 8) || dev->external_is_RAS)) { + nbanks_2048k = 0; + nbanks_512k = mem_size >> 9; + } else { + nbanks_2048k = mem_size >> 11; + nbanks_512k = (mem_size & 1536) >> 9; + } + + if (nbank < nbanks_2048k || (nbanks_2048k > 0 && nbank >= nbanks_2048k + nbanks_512k + ((mem_size & 511) >> 7))) { + addr &= 0x1fffff; + addr |= (nbank << 21); + } else if (nbank < nbanks_2048k + nbanks_512k || nbank >= nbanks_2048k + nbanks_512k + ((mem_size & 511) >> 7)) { + addr &= 0x7ffff; + addr |= (nbanks_2048k << 21) | ((nbank - nbanks_2048k) << 19); + } else { + addr &= 0x1ffff; + addr |= (nbanks_2048k << 21) | (nbanks_512k << 19) | ((nbank - nbanks_2048k - nbanks_512k) << 17); + } + } + } else { + switch(dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) { + case 0x02: + case 0x04: + nbank = addr >> 19; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else + addr2 = addr >> 10; + break; + + case 0x03: + nbank = addr >> 19; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) == 2 && (addr & 0x7ffff) < 0x60000) { + addr ^= 0x1f0000; + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else + addr2 = addr >> 10; + break; + + case 0x05: + nbank = addr >> 19; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) { + nbank = (addr >> 10) & 3; + addr2 = addr >> 12; + } else + addr2 = addr >> 10; + break; + + case 0x06: + nbank = addr >> 19; + if (nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else { + nbank = 2 + ((addr - 0x100000) >> 21); + addr2 = (addr - 0x100000) >> 11; + } + break; + + case 0x07: + case 0x0f: + nbank = addr >> 19; + if (nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if (nbank < 10) { + nbank = 2 + (((addr - 0x100000) >> 11) & 1); + addr2 = (addr - 0x100000) >> 12; + } else { + nbank = 4 + ((addr - 0x500000) >> 21); + addr2 = (addr - 0x500000) >> 11; + } + break; + + case 0x08: + nbank = addr >> 19; + if (nbank < 4) { + nbank = 1; + addr2 = addr >> 11; + } else if (nbank == 4) { + nbank = 0; + addr2 = addr >> 10; + } else { + nbank -= 3; + addr2 = addr >> 10; + } + break; + + case 0x09: + nbank = addr >> 19; + if (nbank < 8) { + nbank = 1 + ((addr >> 11) & 1); + addr2 = addr >> 12; + } else if (nbank == 8) { + nbank = 0; + addr2 = addr >> 10; + } else { + nbank -= 6; + addr2 = addr >> 10; + } + break; + + case 0x0a: + nbank = addr >> 19; + if (nbank < 8) { + nbank = 1 + ((addr >> 11) & 1); + addr2 = addr >> 12; + } else if (nbank < 12) { + nbank = 3; + addr2 = addr >> 11; + } else if (nbank == 12) { + nbank = 0; + addr2 = addr >> 10; + } else { + nbank -= 9; + addr2 = addr >> 10; + } + break; + + case 0x0b: + nbank = addr >> 21; + addr2 = addr >> 11; + break; + + case 0x0c: + case 0x0d: + nbank = addr >> 21; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { + nbank = (addr >> 11) & 1; + addr2 = addr >> 12; + } else + addr2 = addr >> 11; + break; + + case 0x0e: + case 0x13: + nbank = addr >> 21; + if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) { + nbank = (addr >> 11) & 3; + addr2 = addr >> 13; + } else + addr2 = addr >> 11; + break; + + case 0x10: + case 0x11: + nbank = addr >> 19; + if (nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if (nbank < 10) { + nbank = 2 + (((addr - 0x100000) >> 11) & 1); + addr2 = (addr - 0x100000) >> 12; + } else if (nbank < 18) { + nbank = 4 + (((addr - 0x500000) >> 11) & 1); + addr2 = (addr - 0x500000) >> 12; + } else { + nbank = 6 + ((addr - 0x900000) >> 21); + addr2 = (addr - 0x900000) >> 11; + } + break; + + case 0x12: + nbank = addr >> 19; + if (nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if (nbank < 10) { + nbank = 2 + (((addr - 0x100000) >> 11) & 1); + addr2 = (addr - 0x100000) >> 12; + } else { + nbank = 4 + (((addr - 0x500000) >> 11) & 3); + addr2 = (addr - 0x500000) >> 13; + } + break; + + case 0x14: + case 0x15: + nbank = addr >> 21; + if ((nbank & 7) < 4) { + nbank = (addr >> 11) & 3; + addr2 = addr >> 13; + } else if ((nbank & 7) < 6) { + nbank = 4 + (((addr - 0x800000) >> 11) & 1); + addr2 = (addr - 0x800000) >> 12; + } else { + nbank = 6 + (((addr - 0xc00000) >> 11) & 3); + addr2 = (addr - 0xc00000) >> 13; + } + break; + + case 0x16: + nbank = ((addr >> 21) & 4) | ((addr >> 11) & 3); + addr2 = addr >> 13; + break; + + case 0x17: + if (dev->external_is_RAS && (addr & 0x800) == 0) + return 0xffffffff; + nbank = addr >> 19; + if (nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else { + nbank = 2 + ((addr - 0x100000) >> 23); + addr2 = (addr - 0x100000) >> 12; + } + break; + + case 0x18: + if (dev->external_is_RAS && (addr & 0x800) == 0) + return 0xffffffff; + nbank = addr >> 21; + if (nbank < 4) { + nbank = 1; + addr2 = addr >> 12; + } else if (nbank == 4) { + nbank = 0; + addr2 = addr >> 11; + } else { + nbank -= 3; + addr2 = addr >> 11; + } + break; + + case 0x19: + if (dev->external_is_RAS && (addr & 0x800) == 0) + return 0xffffffff; + nbank = addr >> 23; + if ((nbank & 3) < 2) { + nbank = (addr >> 12) & 1; + addr2 = addr >> 13; + } else + addr2 = addr >> 12; + break; + + default: + if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 6) { + nbank = addr >> 19; + addr2 = (addr >> 10) & 0x1ff; + } else if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 0x17) { + nbank = addr >> 21; + addr2 = (addr >> 11) & 0x3ff; + } else { + nbank = addr >> 23; + addr2 = (addr >> 12) & 0x7ff; + } + break; + } + + nbank &= (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3; + + if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) > 0x16 && nbank == 3) + return 0xffffffff; + + if (dev->external_is_RAS && (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) { + if (nbank == 3) + nbank = 7; + else + return 0xffffffff; + } else if (!dev->external_is_RAS && dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) { + switch(nbank) { + case 7: + nbank = 3; + break; + + /* Note - In the following cases, the chipset accesses multiple memory banks + at the same time, so it's impossible to predict which memory bank + is actually accessed. */ + case 5: + case 1: + nbank = 1; + break; + + case 3: + nbank = 2; + break; + + default: + nbank = 0; + break; + } + } + + switch(mem_size & ~511) { + case 1024: + case 1536: + addr &= 0x3ff; + if (nbank < 2) + addr |= (nbank << 10) | ((addr2 & 0x1ff) << 11); + else + addr |= ((addr2 & 0x1ff) << 10) | (nbank << 19); + break; + + case 2048: + if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 5) { + addr &= 0x3ff; + if (nbank < 4) + addr |= (nbank << 10) | ((addr2 & 0x1ff) << 12); + else + addr |= ((addr2 & 0x1ff) << 10) | (nbank << 19); + } else { + addr &= 0x7ff; + addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21); + } + break; + + case 2560: + if (nbank == 0) + addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10); + else { + addr &= 0x7ff; + addr2 &= 0x3ff; + addr = addr + 0x80000 + ((addr2 << 11) | ((nbank - 1) << 21)); + } + break; + + case 3072: + if (nbank < 2) + addr = (addr & 0x3ff) | (nbank << 10) | ((addr2 & 0x1ff) << 11); + else + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11) | ((nbank - 2) << 21)); + break; + + case 4096: + case 6144: + addr &= 0x7ff; + if (nbank < 2) + addr |= (nbank << 11) | ((addr2 & 0x3ff) << 12); + else + addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21); + break; + + case 4608: + if (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) >= 8 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) <= 0x0a) || ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 0x18)) { + if (nbank == 0) + addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10); + else if (nbank < 3) + addr = 0x80000 + ((addr & 0x7ff) | ((nbank - 1) << 11) | ((addr2 & 0x3ff) << 12)); + else + addr = 0x480000 + ((addr & 0x3ff) | ((addr2 & 0x1ff) << 10) | ((nbank - 3) << 19)); + } else if (nbank == 0) + addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10); + else { + addr &= 0x7ff; + addr2 &= 0x3ff; + addr = addr + 0x80000 + ((addr2 << 11) | ((nbank - 1) << 21)); + } + break; + + case 5120: + case 7168: + if (nbank < 2) + addr = (addr & 0x3ff) | (nbank << 10) | ((addr2 & 0x1ff) << 11); + else if (nbank < 4) + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 12) | ((nbank & 1) << 11)); + else + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11) | ((nbank - 2) << 21)); + break; + + case 6656: + if (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) >= 8 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) <= 0x0a) || ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 0x18)) { + if (nbank == 0) + addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10); + else if (nbank < 3) + addr = 0x80000 + ((addr & 0x7ff) | ((nbank - 1) << 11) | ((addr2 & 0x3ff) << 12)); + else if (nbank == 3) + addr = 0x480000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11)); + else + addr = 0x680000 + ((addr & 0x3ff) | ((addr2 & 0x1ff) << 10) | ((nbank - 4) << 19)); + } else if (nbank == 0) + addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10); + else if (nbank == 1) { + addr &= 0x7ff; + addr2 &= 0x3ff; + addr = addr + 0x80000 + (addr2 << 11); + } else { + addr &= 0x7ff; + addr2 &= 0x3ff; + addr = addr + 0x280000 + ((addr2 << 12) | ((nbank & 1) << 11) | (((nbank - 2) & 6) << 21)); + } + break; + + case 8192: + addr &= 0x7ff; + if (nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3ff) << 13); + else + addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21); + break; + + case 9216: + if (nbank < 2) + addr = (addr & 0x3ff) | (nbank << 10) | ((addr2 & 0x1ff) << 11); + else if (dev->external_is_RAS) { + if (nbank < 6) + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 12) | ((nbank & 1) << 11)); + else + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11) | ((nbank - 2) << 21)); + } else + addr = 0x100000 + ((addr & 0xfff) | ((addr2 & 0x7ff) << 12) | ((nbank - 2) << 23)); + break; + + case 10240: + if (dev->external_is_RAS) { + addr &= 0x7ff; + if (nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3ff) << 13); + else + addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21); + } else if (nbank == 0) + addr = (addr & 0x7ff) | ((addr2 & 0x3ff) << 11); + else { + addr &= 0xfff; + addr2 &= 0x7ff; + addr = addr + 0x200000 + ((addr2 << 12) | ((nbank - 1) << 23)); + } + break; + + case 11264: + if (nbank < 2) + addr = (addr & 0x3ff) | (nbank << 10) | ((addr2 & 0x1ff) << 11); + else if (nbank < 6) + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 12) | ((nbank & 1) << 11)); + else + addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11) | ((nbank - 2) << 21)); + break; + + case 12288: + if (dev->external_is_RAS) { + addr &= 0x7ff; + if (nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3ff) << 13); + else if (nbank < 6) + addr |= ((nbank & 1) << 11) | ((addr2 & 0x3ff) << 12) | ((nbank & 4) << 21); + else + addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21); + } else { + if (nbank < 2) + addr = (addr & 0x7ff) | (nbank << 11) | ((addr2 & 0x3ff) << 12); + else + addr = 0x400000 + ((addr & 0xfff) | ((addr2 & 0x7ff) << 12) | ((nbank - 2) << 23)); + } + break; + + case 13312: + if (nbank < 2) + addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); + else if (nbank < 4) + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); + else + addr = 0x500000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 13) | ((nbank & 3) << 11)); + break; + + case 14336: + addr &= 0x7ff; + if (nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3ff) << 13); + else if (nbank < 6) + addr |= ((nbank & 1) << 11) | ((addr2 & 0x3ff) << 12) | ((nbank & 4) << 21); + else + addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21); + break; + + case 16384: + if (dev->external_is_RAS) { + addr &= 0x7ff; + addr2 &= 0x3ff; + addr |= ((nbank & 3) << 11) | (addr2 << 13) | ((nbank & 4) << 21); + } else { + addr &= 0xfff; + addr2 &= 0x7ff; + if (nbank < 2) + addr |= (addr2 << 13) | (nbank << 12); + else + addr |= (addr2 << 12) | (nbank << 23); + } + break; + + default: + if (mem_size < 2048 || ((mem_size & 1536) == 512) || (mem_size == 2048 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 6)) { + addr &= 0x3ff; + addr2 &= 0x1ff; + addr |= (addr2 << 10) | (nbank << 19); + } else if (mem_size < 8192 || (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 0x17) { + addr &= 0x7ff; + addr2 &= 0x3ff; + addr |= (addr2 << 11) | (nbank << 21); + } else { + addr &= 0xfff; + addr2 &= 0x7ff; + addr |= (addr2 << 12) | (nbank << 23); + } + break; + } + } + + return addr; +} + + +static void +set_global_EMS_state(scat_t *dev, int state) +{ + uint32_t base_addr, virt_addr; + int i, conf; + + for (i = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0 : 24; i < 32; i++) { + base_addr = (i + 16) << 14; + + if (i >= 24) + base_addr += 0x30000; + if (state && (dev->page[i].regs_2x9 & 0x80)) { + virt_addr = get_addr(dev, base_addr, &dev->page[i]); + if (i < 24) + mem_mapping_disable(&dev->efff_mapping[i]); + else + mem_mapping_disable(&dev->efff_mapping[i + 12]); + mem_mapping_enable(&dev->ems_mapping[i]); + + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[i], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[i], NULL); + } else { + mem_mapping_set_exec(&dev->ems_mapping[i], ram + base_addr); + mem_mapping_disable(&dev->ems_mapping[i]); + + conf = (dev->regs[SCAT_VERSION] & 0xf0) ? (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) + : (dev->regs[SCAT_DRAM_CONFIGURATION] & 0xf) | ((dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2); + if (i < 24) { + if (conf > 1 || (conf == 1 && i < 16)) + mem_mapping_enable(&dev->efff_mapping[i]); + else + mem_mapping_disable(&dev->efff_mapping[i]); + } else if (conf > 3 || ((dev->regs[SCAT_VERSION] & 0xf0) != 0 && conf == 2)) + mem_mapping_enable(&dev->efff_mapping[i + 12]); + else + mem_mapping_disable(&dev->efff_mapping[i + 12]); + } + } + + flushmmucache(); +} + + +static void +memmap_state_update(scat_t *dev) +{ + uint32_t addr; + int i; + + for (i = (((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0 : 16); i < 44; i++) { + addr = get_addr(dev, 0x40000 + (i << 14), NULL); + mem_mapping_set_exec(&dev->efff_mapping[i], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + } + + addr = get_addr(dev, 0, NULL); + mem_mapping_set_exec(&dev->low_mapping[0], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + + addr = get_addr(dev, 0xf0000, NULL); + mem_mapping_set_exec(&dev->low_mapping[1], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + + for (i = 2; i < 32; i++) { + addr = get_addr(dev, i << 19, NULL); + mem_mapping_set_exec(&dev->low_mapping[i], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + } + + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + for (i = 0; i < max_map[(dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) | ((dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2)]; i++) + mem_mapping_enable(&dev->low_mapping[i]); + + for (; i < 32; i++) + mem_mapping_disable(&dev->low_mapping[i]); + + for (i = 24; i < 36; i++) { + if (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) | (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40)) < 4) + mem_mapping_disable(&dev->efff_mapping[i]); + else + mem_mapping_enable(&dev->efff_mapping[i]); + } + } else { + for (i = 0; i < max_map_sx[dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f]; i++) + mem_mapping_enable(&dev->low_mapping[i]); + + for (; i < 32; i++) + mem_mapping_disable(&dev->low_mapping[i]); + + for(i = 24; i < 36; i++) { + if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 2 || (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 3) + mem_mapping_disable(&dev->efff_mapping[i]); + else + mem_mapping_enable(&dev->efff_mapping[i]); + } + } + + if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && + (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) || ((dev->regs[SCAT_VERSION] & 0xf0) != 0)) { + if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && + (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) == 3) || + (((dev->regs[SCAT_VERSION] & 0xf0) != 0) && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 3)) { + mem_mapping_disable(&dev->low_mapping[2]); + + for (i = 0; i < 6; i++) { + addr = get_addr(dev, 0x100000 + (i << 16), NULL); + mem_mapping_set_exec(&dev->remap_mapping[i], + addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL); + mem_mapping_enable(&dev->remap_mapping[i]); + } + } else { + for (i = 0; i < 6; i++) + mem_mapping_disable(&dev->remap_mapping[i]); + + if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && + (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) > 4) || (((dev->regs[SCAT_VERSION] & 0xf0) != 0) && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) > 3)) + mem_mapping_enable(&dev->low_mapping[2]); + } + } else { + for (i = 0; i < 6; i++) + mem_mapping_disable(&dev->remap_mapping[i]); + + mem_mapping_enable(&dev->low_mapping[2]); + } + + set_global_EMS_state(dev, dev->regs[SCAT_EMS_CONTROL] & 0x80); +} + + +static void +scat_write(uint16_t port, uint8_t val, priv_t priv) +{ + scat_t *dev = (scat_t *)priv; + uint8_t reg_valid = 0, + shadow_update = 0, + map_update = 0, + indx; + uint32_t base_addr, virt_addr; + + switch (port) { + case 0x22: + dev->indx = val; + break; + + case 0x23: + switch (dev->indx) { + case SCAT_DMA_WAIT_STATE_CONTROL: + case SCAT_CLOCK_CONTROL: + case SCAT_PERIPHERAL_CONTROL: + reg_valid = 1; + break; + + case SCAT_EMS_CONTROL: + if (val & 0x40) { + if (val & 1) { + io_sethandler(0x0218, 3, scat_read,NULL,NULL, scat_write,NULL,NULL, dev); + io_removehandler(0x0208, 3, scat_read,NULL,NULL, scat_write,NULL,NULL, dev); + } else { + io_sethandler(0x0208, 3, scat_read,NULL,NULL, scat_write,NULL,NULL, dev); + io_removehandler(0x0218, 3, scat_read,NULL,NULL, scat_write,NULL,NULL, dev); + } + } else { + io_removehandler(0x0208, 0x0003, scat_read,NULL,NULL, scat_write,NULL,NULL, dev); + io_removehandler(0x0218, 0x0003, scat_read,NULL,NULL, scat_write,NULL,NULL, dev); + } + set_global_EMS_state(dev, val & 0x80); + reg_valid = 1; + break; + + case SCAT_POWER_MANAGEMENT: + /* TODO - Only use AUX parity disable bit for this version. + Other bits should be implemented later. */ + val &= (dev->regs[SCAT_VERSION] & 0xf0) == 0 ? 0x40 : 0x60; + reg_valid = 1; + break; + + case SCAT_DRAM_CONFIGURATION: + map_update = 1; + + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + config.cpu_waitstates = (val & 0x70) == 0 ? 1 : 2; + cpu_update_waitstates(); + } + + reg_valid = 1; + break; + + case SCAT_EXTENDED_BOUNDARY: + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + if (dev->regs[SCAT_VERSION] < 4) { + val &= 0xbf; + set_xms_bound(dev, val & 0x0f); + } else { + val = (val & 0x7f) | 0x80; + set_xms_bound(dev, val & 0x4f); + } + } else + set_xms_bound(dev, val & 0x1f); + + mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if ((val ^ dev->regs[SCAT_EXTENDED_BOUNDARY]) & 0xc0) + map_update = 1; + reg_valid = 1; + break; + + case SCAT_ROM_ENABLE: + romcs_state_update(dev, val); + reg_valid = 1; + break; + + case SCAT_RAM_WRITE_PROTECT: + reg_valid = 1; + flushmmucache_cr3(); + break; + + case SCAT_SHADOW_RAM_ENABLE_1: + case SCAT_SHADOW_RAM_ENABLE_2: + case SCAT_SHADOW_RAM_ENABLE_3: + reg_valid = 1; + shadow_update = 1; + break; + + case SCATSX_LAPTOP_FEATURES: + if ((dev->regs[SCAT_VERSION] & 0xf0) != 0) { + val = (val & ~8) | (dev->regs[SCATSX_LAPTOP_FEATURES] & 8); + reg_valid = 1; + } + break; + + case SCATSX_FAST_VIDEO_CONTROL: + case SCATSX_FAST_VIDEORAM_ENABLE: + case SCATSX_HIGH_PERFORMANCE_REFRESH: + case SCATSX_CAS_TIMING_FOR_DMA: + if ((dev->regs[SCAT_VERSION] & 0xf0) != 0) + reg_valid = 1; + break; + + default: + break; + } + + if (reg_valid) + dev->regs[dev->indx] = val; + + if (shadow_update) + shadow_state_update(dev); + + if (map_update) + memmap_state_update(dev); + break; + + case 0x92: + if ((mem_a20_alt ^ val) & 2) { + mem_a20_alt = val & 2; + mem_a20_recalc(); + } + if ((~dev->port_92 & val) & 1) { + cpu_reset(0); + cpu_set_edx(); + } + dev->port_92 = val; + break; + + case 0x208: + case 0x218: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + indx = dev->reg_2xA & 0x1f; + else + indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24; + dev->page[indx].regs_2x8 = val; + base_addr = (indx + 16) << 14; + if (indx >= 24) + base_addr += 0x30000; + + if ((dev->regs[SCAT_EMS_CONTROL] & 0x80) && (dev->page[indx].regs_2x9 & 0x80)) { + virt_addr = get_addr(dev, base_addr, &dev->page[indx]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[indx], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[indx], NULL); + flushmmucache(); + } + } + break; + + case 0x209: + case 0x219: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + indx = dev->reg_2xA & 0x1f; + else + indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24; + dev->page[indx].regs_2x9 = val; + base_addr = (indx + 16) << 14; + if (indx >= 24) + base_addr += 0x30000; + + if (dev->regs[SCAT_EMS_CONTROL] & 0x80) { + if (val & 0x80) { + virt_addr = get_addr(dev, base_addr, &dev->page[indx]); + if (indx < 24) + mem_mapping_disable(&dev->efff_mapping[indx]); + else + mem_mapping_disable(&dev->efff_mapping[indx + 12]); + if (virt_addr < ((uint32_t)mem_size << 10)) + mem_mapping_set_exec(&dev->ems_mapping[indx], ram + virt_addr); + else + mem_mapping_set_exec(&dev->ems_mapping[indx], NULL); + mem_mapping_enable(&dev->ems_mapping[indx]); + } else { + mem_mapping_set_exec(&dev->ems_mapping[indx], ram + base_addr); + mem_mapping_disable(&dev->ems_mapping[indx]); + if (indx < 24) + mem_mapping_enable(&dev->efff_mapping[indx]); + else + mem_mapping_enable(&dev->efff_mapping[indx + 12]); + } + + flushmmucache(); + } + + if (dev->reg_2xA & 0x80) + dev->reg_2xA = (dev->reg_2xA & 0xe0) | ((dev->reg_2xA + 1) & (((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0x1f : 3)); + } + break; + + case 0x20a: + case 0x21a: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) + dev->reg_2xA = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? val : val & 0xc3; + break; + } +} + + +static uint8_t +scat_read(uint16_t port, priv_t priv) +{ + scat_t *dev = (scat_t *)priv; + uint8_t ret = 0xff, indx; + + switch (port) { + case 0x23: + switch (dev->indx) { + case SCAT_MISCELLANEOUS_STATUS: + ret = (dev->regs[dev->indx] & 0x3f) | (~nmi_mask & 0x80) | ((mem_a20_key & 2) << 5); + break; + + case SCAT_DRAM_CONFIGURATION: + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + ret = (dev->regs[dev->indx] & 0x8f) | (config.cpu_waitstates == 1 ? 0 : 0x10); + else + ret = dev->regs[dev->indx]; + break; + + case SCAT_EXTENDED_BOUNDARY: + ret = dev->regs[dev->indx]; + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) { + if ((dev->regs[SCAT_VERSION] & 0x0f) >= 4) + ret |= 0x80; + else + ret &= 0xaf; + } + break; + + default: + ret = dev->regs[dev->indx]; + break; + } + break; + + case 0x92: + ret = dev->port_92; + break; + + case 0x208: + case 0x218: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + indx = dev->reg_2xA & 0x1f; + else + indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24; + ret = dev->page[indx].regs_2x8; + } + break; + + case 0x209: + case 0x219: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) + indx = dev->reg_2xA & 0x1f; + else + indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24; + ret = dev->page[indx].regs_2x9; + } + break; + + case 0x20a: + case 0x21a: + if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) + ret = dev->reg_2xA; + break; + } + + return ret; +} + + +static uint8_t +mem_read_scatb(uint32_t addr, priv_t priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + scat_t *dev = (scat_t *)map->dev; + ems_page_t *page = (ems_page_t *)map->p2; + uint8_t val = 0xff; + + addr = get_addr(dev, addr, page); + if (addr < ((uint32_t)mem_size << 10)) + val = ram[addr]; + + return val; +} + + +static uint16_t +mem_read_scatw(uint32_t addr, priv_t priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + scat_t *dev = (scat_t *)map->dev; + ems_page_t *page = (ems_page_t *)map->p2; + uint16_t val = 0xffff; + + addr = get_addr(dev, addr, page); + if (addr < ((uint32_t)mem_size << 10)) + val = *(uint16_t *)&ram[addr]; + + return val; +} + + +static uint32_t +mem_read_scatl(uint32_t addr, priv_t priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + scat_t *dev = (scat_t *)map->dev; + ems_page_t *page = (ems_page_t *)map->p2; + uint32_t val = 0xffffffff; + + addr = get_addr(dev, addr, page); + if (addr < ((uint32_t)mem_size << 10)) + val = *(uint32_t *)&ram[addr]; + + return val; +} + + +static void +mem_write_scatb(uint32_t addr, uint8_t val, priv_t priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + scat_t *dev = (scat_t *)map->dev; + ems_page_t *page = (ems_page_t *)map->p2; + uint32_t oldaddr = addr, chkaddr; + + addr = get_addr(dev, addr, page); + chkaddr = page ? addr : oldaddr; + if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { + if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; + } + + if (addr < ((uint32_t)mem_size << 10)) + ram[addr] = val; +} + + +static void +mem_write_scatw(uint32_t addr, uint16_t val, priv_t priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + scat_t *dev = (scat_t *)map->dev; + ems_page_t *page = (ems_page_t *)map->p2; + uint32_t oldaddr = addr, chkaddr; + + addr = get_addr(dev, addr, page); + chkaddr = page ? addr : oldaddr; + if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { + if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; + } + + if (addr < ((uint32_t)mem_size << 10)) + *(uint16_t *)&ram[addr] = val; +} + + +static void +mem_write_scatl(uint32_t addr, uint32_t val, priv_t priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + scat_t *dev = (scat_t *)map->dev; + ems_page_t *page = (ems_page_t *)map->p2; + uint32_t oldaddr = addr, chkaddr; + + addr = get_addr(dev, addr, page); + chkaddr = page ? addr : oldaddr; + if (chkaddr >= 0xc0000 && chkaddr < 0x100000) { + if (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))) return; + } + if (addr < ((uint32_t)mem_size << 10)) + *(uint32_t *)&ram[addr] = val; +} + + +static void +scat_close(priv_t priv) +{ + scat_t *dev = (scat_t *)priv; + + free(dev); +} + + +static priv_t +scat_init(const device_t *info, UNUSED(void *parent)) +{ + scat_t *dev; + uint32_t k; + int i, sx; + + dev = (scat_t *)mem_alloc(sizeof(scat_t)); + memset(dev, 0x00, sizeof(scat_t)); + dev->type = info->local; + + sx = (dev->type == 32) ? 1 : 0; + + for (i = 0; i < sizeof(dev->regs); i++) + dev->regs[i] = 0xff; + + if (sx) { + dev->regs[SCAT_VERSION] = 0x13; + dev->regs[SCAT_CLOCK_CONTROL] = 6; + dev->regs[SCAT_PERIPHERAL_CONTROL] = 0; + dev->regs[SCAT_DRAM_CONFIGURATION] = 1; + dev->regs[SCATSX_LAPTOP_FEATURES] = 0; + dev->regs[SCATSX_FAST_VIDEO_CONTROL] = 0; + dev->regs[SCATSX_FAST_VIDEORAM_ENABLE] = 0; + dev->regs[SCATSX_HIGH_PERFORMANCE_REFRESH] = 8; + dev->regs[SCATSX_CAS_TIMING_FOR_DMA] = 3; + } else { + switch(dev->type) { + case 4: + dev->regs[SCAT_VERSION] = 4; + break; + + default: + dev->regs[SCAT_VERSION] = 1; + break; + } + dev->regs[SCAT_CLOCK_CONTROL] = 2; + dev->regs[SCAT_PERIPHERAL_CONTROL] = 0x80; + dev->regs[SCAT_DRAM_CONFIGURATION] = config.cpu_waitstates == 1 ? 2 : 0x12; + } + dev->regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; + dev->regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; + dev->regs[SCAT_ROM_ENABLE] = 0xc0; + dev->regs[SCAT_RAM_WRITE_PROTECT] = 0; + dev->regs[SCAT_POWER_MANAGEMENT] = 0; + dev->regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; + dev->regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; + dev->regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; + dev->regs[SCAT_EXTENDED_BOUNDARY] = 0; + dev->regs[SCAT_EMS_CONTROL] = 0; + dev->port_92 = 0; + + /* Disable all system mappings, we will override them. */ + mem_mapping_disable(&ram_low_mapping); + if (! sx) + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); + for (i = 0; i < 4; i++) + mem_mapping_disable(&bios_mapping[i]); + + k = (sx) ? 0x80000 : 0x40000; + mem_mapping_add(&dev->low_mapping[0], 0, k, + mem_read_scatb, mem_read_scatw, mem_read_scatl, + mem_write_scatb, mem_write_scatw, mem_write_scatl, + ram, MEM_MAPPING_INTERNAL, &dev->low_mapping[0]); + mem_mapping_set_dev(&dev->low_mapping[0], dev); + + mem_mapping_add(&dev->low_mapping[1], 0xf0000, 0x10000, + mem_read_scatb,mem_read_scatw,mem_read_scatl, + mem_write_scatb,mem_write_scatw,mem_write_scatl, + ram + 0xf0000, MEM_MAPPING_INTERNAL, &dev->low_mapping[1]); + mem_mapping_set_dev(&dev->low_mapping[1], dev); + + for (i = 2; i < 32; i++) { + mem_mapping_add(&dev->low_mapping[i], (i << 19), 0x80000, + mem_read_scatb,mem_read_scatw,mem_read_scatl, + mem_write_scatb,mem_write_scatw,mem_write_scatl, + ram + (i<<19), MEM_MAPPING_INTERNAL, &dev->low_mapping[i]); + mem_mapping_set_dev(&dev->low_mapping[i], dev); + } + + if (sx) { + i = 16; + k = 0x40000; + } else { + i = 0; + k = (dev->regs[SCAT_VERSION] < 4) ? 0x40000 : 0x60000; + } + mem_mapping_set_addr(&dev->low_mapping[31], 0xf80000, k); + + for (; i < 44; i++) { + mem_mapping_add(&dev->efff_mapping[i], 0x40000 + (i << 14), 0x4000, + mem_read_scatb,mem_read_scatw,mem_read_scatl, + mem_write_scatb,mem_write_scatw,mem_write_scatl, + mem_size > (256 + (i << 4)) ? ram + 0x40000 + (i << 14) : NULL, + MEM_MAPPING_INTERNAL, &dev->efff_mapping[i]); + mem_mapping_set_dev(&dev->efff_mapping[i], dev); + + if (sx) + mem_mapping_enable(&dev->efff_mapping[i]); + } + + for (i = 0; i < 8; i++) { + mem_mapping_add(&dev->romcs_mapping[i], 0xc0000 + (i << 14), 0x4000, + rom_bios_read,rom_bios_readw,rom_bios_readl, + mem_write_null,mem_write_nullw,mem_write_nulll, + bios + ((i << 14) & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, NULL); + mem_mapping_disable(&dev->romcs_mapping[i]); + } + + if (sx) { + for (i = 24; i < 32; i++) { + dev->page[i].regs_2x8 = 0xff; + dev->page[i].regs_2x9 = 0x03; + mem_mapping_add(&dev->ems_mapping[i], (i + 28) << 14, 0x04000, + mem_read_scatb,mem_read_scatw,mem_read_scatl, + mem_write_scatb,mem_write_scatw,mem_write_scatl, + ram + ((i + 28) << 14), 0, &dev->ems_mapping[i]); + mem_mapping_set_dev(&dev->ems_mapping[i], dev); + mem_mapping_set_p2(&dev->ems_mapping[i], &dev->page[i]); + mem_mapping_disable(&dev->ems_mapping[i]); + } + + for (i = 0; i < 16; i++) { + mem_mapping_add(&dev->high_mapping[i], (i << 14) + 0xfc0000, 0x04000, + rom_bios_read,rom_bios_readw,rom_bios_readl, + mem_write_null,mem_write_nullw,mem_write_nulll, + bios + ((i << 14) & biosmask), 0, NULL); + mem_mapping_enable(&dev->high_mapping[i]); + } + } else { + for (i = 0; i < 32; i++) { + dev->page[i].regs_2x8 = 0xff; + dev->page[i].regs_2x9 = 0x03; + mem_mapping_add(&dev->ems_mapping[i], (i + (i >= 24 ? 28 : 16)) << 14, 0x04000, + mem_read_scatb,mem_read_scatw,mem_read_scatl, + mem_write_scatb,mem_write_scatw,mem_write_scatl, + ram + ((i + (i >= 24 ? 28 : 16)) << 14), + 0, &dev->ems_mapping[i]); + mem_mapping_set_dev(&dev->ems_mapping[i], dev); + mem_mapping_set_p2(&dev->ems_mapping[i], &dev->page[i]); + } + + for (i = (dev->regs[SCAT_VERSION] < 4 ? 0 : 8); i < 16; i++) { + mem_mapping_add(&dev->high_mapping[i], (i << 14) + 0xfc0000, 0x04000, + rom_bios_read,rom_bios_readw,rom_bios_readl, + mem_write_null,mem_write_nullw,mem_write_nulll, + bios + ((i << 14) & biosmask), 0, NULL); + mem_mapping_enable(&dev->high_mapping[i]); + } + } + + for (i = 0; i < 6; i++) { + mem_mapping_add(&dev->remap_mapping[i], 0x100000 + (i << 16), 0x10000, + mem_read_scatb,mem_read_scatw,mem_read_scatl, + mem_write_scatb,mem_write_scatw,mem_write_scatl, + mem_size >= 1024 ? ram + get_addr(dev, 0x100000 + (i << 16), NULL) : NULL, + MEM_MAPPING_INTERNAL, &dev->remap_mapping[i]); + mem_mapping_set_dev(&dev->remap_mapping[i], dev); + } + + if (sx) { + dev->external_is_RAS = scatsx_external_is_RAS[mem_size >> 9]; + } else { + dev->external_is_RAS = (dev->regs[SCAT_VERSION] > 3) || (((mem_size & ~2047) >> 11) + ((mem_size & 1536) >> 9) + ((mem_size & 511) >> 7)) > 4; + } + + set_xms_bound(dev, 0); + memmap_state_update(dev); + shadow_state_update(dev); + + io_sethandler(0x0022, 2, + scat_read,NULL,NULL, scat_write,NULL,NULL, dev); + io_sethandler(0x0092, 1, + scat_read,NULL,NULL, scat_write,NULL,NULL, dev); + + return((priv_t)dev); +} + + +const device_t scat_device = { + "C&T SCAT (v1)", + 0, + 0, + NULL, + scat_init, scat_close, NULL, + NULL, NULL, NULL, NULL, + NULL +}; + +const device_t scat_4_device = { + "C&T SCAT (v4)", + 0, + 4, + NULL, + scat_init, scat_close, NULL, + NULL, NULL, NULL, NULL, + NULL +}; + +const device_t scat_sx_device = { + "C&T SCATsx", + 0, + 32, + NULL, + scat_init, scat_close, NULL, + NULL, NULL, NULL, NULL, + NULL +}; diff --git a/src/machine/m_at_sis_85c471.c b/src/chipset/sis_85c471.c similarity index 53% rename from src/machine/m_at_sis_85c471.c rename to src/chipset/sis_85c471.c index 6f408b5ea..422aa9442 100644 --- a/src/machine/m_at_sis_85c471.c +++ b/src/chipset/sis_85c471.c @@ -4,16 +4,20 @@ * PC systems and compatibles from 1981 through fairly recent * system designs based on the PCI bus. * + * This file is part of the 86Box distribution. + * * Emulation of the SiS 85c471 chip. * * SiS sis85c471 Super I/O Chip * Used by DTK PKM-0038S E-2 * - * Version: @(#)m_at_sis85c471.c 1.0.13 2018/11/12 + * Version: @(#)sis_85c471.c 1.0.0 2019/05/13 * - * Author: Miran Grca, + * Authors: Miran Grca, + * Sarah Walker, * - * Copyright 2015-2018 Miran Grca. + * Copyright 2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. */ #include #include @@ -21,64 +25,115 @@ #include #include #include "../86box.h" +#include "../mem.h" #include "../io.h" -#include "../memregs.h" -#include "../device.h" #include "../lpt.h" -#include "../serial.h" -#include "../disk/hdc.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" #include "../disk/hdc_ide.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "machine.h" +#include "../keyboard.h" +#include "../timer.h" +#include "../port_92.h" +#include "../serial.h" +#include "../machine/machine.h" +#include "chipset.h" typedef struct { - uint8_t cur_reg, - regs[39]; - serial_t *uart[2]; + uint8_t cur_reg, + regs[39], + scratch[2]; + port_92_t * port_92; } sis_85c471_t; +static void +sis_85c471_recalcmapping(sis_85c471_t *dev) +{ + uint32_t base; + uint32_t i, shflags = 0; + + shadowbios = 0; + shadowbios_write = 0; + + for (i = 0; i < 8; i++) { + base = 0xc0000 + (i << 15); + + if ((i > 5) || (dev->regs[0x02] & (1 << i))) { + shadowbios |= (base >= 0xe0000) && (dev->regs[0x02] & 0x80); + shadowbios_write |= (base >= 0xe0000) && !(dev->regs[0x02] & 0x40); + shflags = (dev->regs[0x02] & 0x80) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL; + shflags |= (dev->regs[0x02] & 0x40) ? MEM_WRITE_EXTERNAL : MEM_WRITE_INTERNAL; + mem_set_mem_state(base, 0x8000, shflags); + } else + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + flushmmucache(); +} + + static void sis_85c471_write(uint16_t port, uint8_t val, void *priv) { sis_85c471_t *dev = (sis_85c471_t *) priv; - uint8_t index = (port & 1) ? 0 : 1; - uint8_t valxor; + uint8_t valxor = 0x00; - if (index) { + if (port == 0x22) { if ((val >= 0x50) && (val <= 0x76)) dev->cur_reg = val; return; - } else { + } else if (port == 0x23) { if ((dev->cur_reg < 0x50) || (dev->cur_reg > 0x76)) return; valxor = val ^ dev->regs[dev->cur_reg - 0x50]; - /* Writes to 0x52 are blocked as otherwise, large hard disks don't read correctly. */ - if (dev->cur_reg != 0x52) - dev->regs[dev->cur_reg - 0x50] = val; + dev->regs[dev->cur_reg - 0x50] = val; + } else if ((port == 0xe1) || (port == 0xe2)) { + dev->scratch[port - 0xe1] = val; + return; } switch(dev->cur_reg) { - case 0x73: - if (valxor & 0x40) { - ide_pri_disable(); - if (val & 0x40) - ide_pri_enable(); + case 0x52: + sis_85c471_recalcmapping(dev); + break; + + case 0x57: + if (valxor & 0x12) + port_92_set_features(dev->port_92, !!(val & 0x10), !!(val & 0x02)); + + if (valxor & 0x08) { + if (val & 0x08) + port_92_set_period(dev->port_92, 6ULL * TIMER_USEC); + else + port_92_set_period(dev->port_92, 2ULL * TIMER_USEC); } - if (valxor & 0x20) { - serial_remove(dev->uart[0]); - serial_remove(dev->uart[1]); - if (val & 0x20) { - serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); - serial_setup(dev->uart[0], SERIAL2_ADDR, SERIAL2_IRQ); - } + break; + + case 0x5b: + if (valxor & 0x02) { + if (val & 0x02) + mem_remap_top(0); + else + mem_remap_top(256); } + break; + + case 0x63: if (valxor & 0x10) { - lpt1_remove(); - if (val & 0x10) - lpt1_init(0x378); + if (dev->regs[0x13] & 0x10) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + break; + + case 0x72: + if (valxor & 0x01) { + port_92_remove(dev->port_92); + if (val & 0x01) + port_92_add(dev->port_92); } break; } @@ -91,17 +146,19 @@ static uint8_t sis_85c471_read(uint16_t port, void *priv) { sis_85c471_t *dev = (sis_85c471_t *) priv; - uint8_t index = (port & 1) ? 0 : 1; - uint8_t ret = 0xff;; + uint8_t ret = 0xff; - if (index) + if (port == 0x22) ret = dev->cur_reg; - else { + else if (port == 0x23) { if ((dev->cur_reg >= 0x50) && (dev->cur_reg <= 0x76)) { ret = dev->regs[dev->cur_reg - 0x50]; + if (dev->cur_reg == 0x58) + ret &= 0xf7; dev->cur_reg = 0; } - } + } else if ((port == 0xe1) || (port == 0xe2)) + ret = dev->scratch[port - 0xe1]; return ret; } @@ -124,8 +181,6 @@ sis_85c471_init(const device_t *info) sis_85c471_t *dev = (sis_85c471_t *) malloc(sizeof(sis_85c471_t)); memset(dev, 0, sizeof(sis_85c471_t)); - lpt2_remove(); - dev->cur_reg = 0; for (i = 0; i < 0x27; i++) dev->regs[i] = 0x00; @@ -199,15 +254,27 @@ sis_85c471_init(const device_t *info) dev->regs[0x11] = 9; dev->regs[0x12] = 0xFF; + dev->regs[0x1f] = 0x20; /* Video access enabled. */ dev->regs[0x23] = 0xF0; dev->regs[0x26] = 1; - dev->uart[0] = device_add_inst(&i8250_device, 1); - dev->uart[1] = device_add_inst(&i8250_device, 2); + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed < 25000000) + dev->regs[0x08] |= 0x80; io_sethandler(0x0022, 0x0002, sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, dev); + dev->scratch[0] = dev->scratch[1] = 0xff; + + io_sethandler(0x00e1, 0x0002, + sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, dev); + + dev->port_92 = device_add(&port_92_device); + port_92_set_period(dev->port_92, 2ULL * TIMER_USEC); + port_92_set_features(dev->port_92, 0, 0); + + sis_85c471_recalcmapping(dev); + return dev; } @@ -220,14 +287,3 @@ const device_t sis_85c471_device = { NULL, NULL, NULL, NULL }; - - -void -machine_at_dtk486_init(const machine_t *model) -{ - machine_at_ide_init(model); - device_add(&fdc_at_device); - - memregs_init(); - device_add(&sis_85c471_device); -} diff --git a/src/machine/m_at_sis_85c496.c b/src/chipset/sis_85c496.c similarity index 50% rename from src/machine/m_at_sis_85c496.c rename to src/chipset/sis_85c496.c index b224b1228..c4262532b 100644 --- a/src/machine/m_at_sis_85c496.c +++ b/src/chipset/sis_85c496.c @@ -8,13 +8,12 @@ * * Implementation of the SiS 85c496/85c497 chip. * - * Version: @(#)m_at_sis_85c496.c 1.0.3 2018/11/05 + * Version: @(#)sis_85c496.c 1.0.0 2019/05/13 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2019 Miran Grca. */ #include #include @@ -22,22 +21,25 @@ #include #include #include "../86box.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" #include "../device.h" #include "../keyboard.h" -#include "../io.h" -#include "../pci.h" -#include "../mem.h" -#include "../memregs.h" -#include "../sio.h" -#include "../disk/hdc.h" -#include "machine.h" +#include "../timer.h" +#include "../port_92.h" +#include "../disk/hdc_ide.h" +#include "../machine/machine.h" +#include "chipset.h" typedef struct sis_85c496_t { - uint8_t cur_reg, - regs[39], - pci_conf[256]; + uint8_t cur_reg, + regs[127], + pci_conf[256]; + port_92_t * port_92; } sis_85c496_t; @@ -48,18 +50,14 @@ sis_85c497_write(uint16_t port, uint8_t val, void *priv) uint8_t index = (port & 1) ? 0 : 1; if (index) { - if ((val >= 0x50) && (val <= 0x76)) + if ((val != 0x01) || ((val >= 0x70) && (val <= 0x76))) dev->cur_reg = val; - return; } else { - if ((dev->cur_reg < 0x50) || (dev->cur_reg > 0x76)) + if (((dev->cur_reg < 0x70) && (dev->cur_reg != 0x01)) || (dev->cur_reg > 0x76)) return; - /* Writes to 0x52 are blocked as otherwise, large hard disks don't read correctly. */ - if (dev->cur_reg != 0x52) - dev->regs[dev->cur_reg - 0x50] = val; + dev->regs[dev->cur_reg] = val; + dev->cur_reg = 0; } - - dev->cur_reg = 0; } @@ -73,8 +71,8 @@ sis_85c497_read(uint16_t port, void *priv) if (index) ret = dev->cur_reg; else { - if ((dev->cur_reg >= 0x50) && (dev->cur_reg <= 0x76)) { - ret = dev->regs[dev->cur_reg - 0x50]; + if ((dev->cur_reg != 0x01) || ((dev->cur_reg >= 0x70) && (dev->cur_reg <= 0x76))) { + ret = dev->regs[dev->cur_reg]; dev->cur_reg = 0; } } @@ -86,51 +84,115 @@ sis_85c497_read(uint16_t port, void *priv) static void sis_85c496_recalcmapping(sis_85c496_t *dev) { - int c; uint32_t base; + uint32_t i, shflags = 0; - for (c = 0; c < 8; c++) { - base = 0xc0000 + (c << 15); - if (dev->pci_conf[0x44] & (1 << c)) { - switch (dev->pci_conf[0x45] & 3) { - case 0: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 1: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - } + shadowbios = 0; + shadowbios_write = 0; + + for (i = 0; i < 8; i++) { + base = 0xc0000 + (i << 15); + + if (dev->pci_conf[0x44] & (1 << i)) { + shadowbios |= (base >= 0xe0000) && (dev->pci_conf[0x45] & 0x02); + shadowbios_write |= (base >= 0xe0000) && !(dev->pci_conf[0x45] & 0x01); + shflags = (dev->pci_conf[0x45] & 0x02) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL; + shflags |= (dev->pci_conf[0x45] & 0x01) ? MEM_WRITE_EXTERNAL : MEM_WRITE_INTERNAL; + mem_set_mem_state(base, 0x8000, shflags); } else mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); } flushmmucache(); - shadowbios = (dev->pci_conf[0x44] & 0xf0); } +/* 00 - 3F = PCI Configuration, 40 - 7F = 85C496, 80 - FF = 85C497 */ static void sis_85c496_write(int func, int addr, uint8_t val, void *priv) { sis_85c496_t *dev = (sis_85c496_t *) priv; + uint8_t old = dev->pci_conf[addr]; + uint8_t valxor; + + if ((addr >= 4 && addr < 8) || addr >= 0x40) + dev->pci_conf[addr] = val; + + valxor = old ^ val; switch (addr) { case 0x44: /*Shadow configure*/ - if ((dev->pci_conf[0x44] & val) ^ 0xf0) { - dev->pci_conf[0x44] = val; + if (valxor & 0xff) sis_85c496_recalcmapping(dev); - } break; case 0x45: /*Shadow configure*/ - if ((dev->pci_conf[0x45] & val) ^ 0x01) { - dev->pci_conf[0x45] = val; + if (valxor & 0x03) sis_85c496_recalcmapping(dev); + break; + + case 0x56: + if (valxor & 0x02) { + port_92_remove(dev->port_92); + if (val & 0x02) + port_92_add(dev->port_92); + pclog("Port 92: %sabled\n", (val & 0x02) ? "En" : "Dis"); + } + break; + + case 0x59: + if (valxor & 0x02) { + if (val & 0x02) { + ide_set_base(0, 0x0170); + ide_set_side(0, 0x0376); + ide_set_base(1, 0x01f0); + ide_set_side(1, 0x03f6); + } else { + ide_set_base(0, 0x01f0); + ide_set_side(0, 0x03f6); + ide_set_base(1, 0x0170); + ide_set_side(1, 0x0376); + } + } + break; + + case 0x58: + if (valxor & 0x80) { + if (dev->pci_conf[0x59] & 0x02) { + ide_sec_disable(); + if (val & 0x80) + ide_sec_enable(); + } else { + ide_pri_disable(); + if (val & 0x80) + ide_pri_enable(); + } + } + if (valxor & 0x40) { + if (dev->pci_conf[0x59] & 0x02) { + ide_pri_disable(); + if (val & 0x40) + ide_pri_enable(); + } else { + ide_sec_disable(); + if (val & 0x40) + ide_sec_enable(); + } + } + break; + + case 0x5a: + if (valxor & 0x04) { + if (val & 0x04) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + break; + + case 0x67: + if (valxor & 0x60) { + port_92_set_features(dev->port_92, !!(val & 0x20), !!(val & 0x40)); + pclog("[Port 92] Set features: %sreset, %sA20\n", !!(val & 0x20) ? "" : "no ", !!(val & 0x40) ? "" : "no "); } break; @@ -163,9 +225,6 @@ sis_85c496_write(int func, int addr, uint8_t val, void *priv) pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); break; } - - if ((addr >= 4 && addr < 8) || addr >= 0x40) - dev->pci_conf[addr] = val; } @@ -174,6 +233,13 @@ sis_85c496_read(int func, int addr, void *priv) { sis_85c496_t *dev = (sis_85c496_t *) priv; + switch (addr) { + case 0x82: /*Port 22h Mirror*/ + return inb(0x22); + case 0x70: /*Port 70h Mirror*/ + return inb(0x70); + } + return dev->pci_conf[addr]; } @@ -181,85 +247,11 @@ sis_85c496_read(int func, int addr, void *priv) static void sis_85c497_reset(sis_85c496_t *dev) { - int mem_size_mb, i = 0; - memset(dev->regs, 0, sizeof(dev->regs)); - dev->cur_reg = 0; - for (i = 0; i < 0x27; i++) - dev->regs[i] = 0x00; - - dev->regs[9] = 0x40; - - mem_size_mb = mem_size >> 10; - switch (mem_size_mb) { - case 0: case 1: - dev->regs[9] |= 0; - break; - case 2: case 3: - dev->regs[9] |= 1; - break; - case 4: - dev->regs[9] |= 2; - break; - case 5: - dev->regs[9] |= 0x20; - break; - case 6: case 7: - dev->regs[9] |= 9; - break; - case 8: case 9: - dev->regs[9] |= 4; - break; - case 10: case 11: - dev->regs[9] |= 5; - break; - case 12: case 13: case 14: case 15: - dev->regs[9] |= 0xB; - break; - case 16: - dev->regs[9] |= 0x13; - break; - case 17: - dev->regs[9] |= 0x21; - break; - case 18: case 19: - dev->regs[9] |= 6; - break; - case 20: case 21: case 22: case 23: - dev->regs[9] |= 0xD; - break; - case 24: case 25: case 26: case 27: - case 28: case 29: case 30: case 31: - dev->regs[9] |= 0xE; - break; - case 32: case 33: case 34: case 35: - dev->regs[9] |= 0x1B; - break; - case 36: case 37: case 38: case 39: - dev->regs[9] |= 0xF; - break; - case 40: case 41: case 42: case 43: - case 44: case 45: case 46: case 47: - dev->regs[9] |= 0x17; - break; - case 48: - dev->regs[9] |= 0x1E; - break; - default: - if (mem_size_mb < 64) - dev->regs[9] |= 0x1E; - else if ((mem_size_mb >= 65) && (mem_size_mb < 68)) - dev->regs[9] |= 0x22; - else - dev->regs[9] |= 0x24; - break; - } - - dev->regs[0x11] = 9; - dev->regs[0x12] = 0xFF; - dev->regs[0x23] = 0xF0; - dev->regs[0x26] = 1; + dev->regs[0x01] = 0xc0; + dev->regs[0x71] = 0x01; + dev->regs[0x72] = 0xff; io_removehandler(0x0022, 0x0002, sis_85c497_read, NULL, NULL, sis_85c497_write, NULL, NULL, dev); @@ -271,12 +263,9 @@ sis_85c497_reset(sis_85c496_t *dev) static void sis_85c496_reset(void *priv) { - uint8_t val = 0; + sis_85c496_t *dev = (sis_85c496_t *) priv; - val = sis_85c496_read(0, 0x44, priv); /* Read current value of 0x44. */ - sis_85c496_write(0, 0x44, val & 0xf, priv); /* Turn off shadow BIOS but keep the lower 4 bits. */ - - sis_85c497_reset((sis_85c496_t *) priv); + sis_85c497_reset(dev); } @@ -314,10 +303,19 @@ static void dev->pci_conf[0x0e] = 0x00; /*Single function device*/ + dev->pci_conf[0xd0] = 0x78; /* ROM at E0000-FFFFF, Flash enable. */ + dev->pci_conf[0xd1] = 0xff; + pci_add_card(5, sis_85c496_read, sis_85c496_write, dev); sis_85c497_reset(dev); + dev->port_92 = device_add(&port_92_device); + port_92_set_period(dev->port_92, 2ULL * TIMER_USEC); + port_92_set_features(dev->port_92, 0, 0); + + sis_85c496_recalcmapping(dev); + return dev; } @@ -335,37 +333,3 @@ const device_t sis_85c496_device = NULL, NULL }; - - -static void -machine_at_sis_85c496_common_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - device_add(&ide_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x05, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); - - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - - device_add(&sis_85c496_device); -} - - -void -machine_at_r418_init(const machine_t *model) -{ - machine_at_sis_85c496_common_init(model); - - device_add(&fdc37c665_device); -} diff --git a/src/chipset/sis_85c50x.c b/src/chipset/sis_85c50x.c new file mode 100644 index 000000000..a5018ddac --- /dev/null +++ b/src/chipset/sis_85c50x.c @@ -0,0 +1,441 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the SiS 85c501/85c503 chip. + * + * Version: @(#)sis_85c50x.c 1.0.0 2019/05/13 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../keyboard.h" +#include "../port_92.h" +#include "chipset.h" + + +typedef struct sis_85c501_t +{ + /* 85c501 */ + uint8_t turbo_reg; + + /* 85c503 */ + + /* Registers */ + uint8_t pci_conf[2][256]; + + /* 85c50x ISA */ + uint8_t cur_reg, + regs[39]; +} sis_85c50x_t; + + +static void +sis_85c501_recalcmapping(sis_85c50x_t *dev) +{ + int c, d; + uint32_t base; + + for (c = 0; c < 1; c++) { + for (d = 0; d < 4; d++) { + base = 0xe0000 + (d << 14); + if (dev->pci_conf[0][0x54 + c] & (1 << (d + 4))) { + switch (dev->pci_conf[0][0x53] & 0x60) { + case 0x00: + mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x20: + mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 0x40: + mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x60: + mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } else + mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + + flushmmucache(); + shadowbios = 1; +} + + +static void +sis_85c501_write(int func, int addr, uint8_t val, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + if (func) + return; + + if ((addr >= 0x10) && (addr < 0x4f)) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x42; + val |= 0x04; + break; + case 0x05: + val &= 0x01; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + + case 0x54: /*Shadow configure*/ + if ((dev->pci_conf[0][0x54] & val) ^ 0xf0) { + dev->pci_conf[0][0x54] = val; + sis_85c501_recalcmapping(dev); + } + break; + } + + dev->pci_conf[0][addr] = val; +} + + +static void +sis_85c503_write(int func, int addr, uint8_t val, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + if (func > 0) + return; + + if (addr >= 0x0f && addr < 0x41) + return; + + switch(addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x08; + val |= 0x07; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + + case 0x41: + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x42: + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x43: + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x44: + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; + } + + dev->pci_conf[1][addr] = val; +} + + +static void +sis_85c50x_isa_write(uint16_t port, uint8_t val, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + if (port & 1) { + if (dev->cur_reg <= 0x1a) + dev->regs[dev->cur_reg] = val; + } else + dev->cur_reg = val; +} + + +static uint8_t +sis_85c501_read(int func, int addr, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + if (func) + return 0xff; + + return dev->pci_conf[0][addr]; +} + + +static uint8_t +sis_85c503_read(int func, int addr, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + if (func > 0) + return 0xff; + + return dev->pci_conf[1][addr]; +} + + +static uint8_t +sis_85c50x_isa_read(uint16_t port, void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + if (port & 1) { + if (dev->cur_reg <= 0x1a) + return dev->regs[dev->cur_reg]; + else + return 0xff; + } else + return dev->cur_reg; +} + + +static void +sis_85c50x_isa_reset(sis_85c50x_t *dev) +{ + int mem_size_mb, i = 0; + + memset(dev->regs, 0, sizeof(dev->regs)); + + dev->cur_reg = 0; + for (i = 0; i < 0x27; i++) + dev->regs[i] = 0x00; + + dev->regs[9] = 0x40; + + mem_size_mb = mem_size >> 10; + switch (mem_size_mb) { + case 0: case 1: + dev->regs[9] |= 0; + break; + case 2: case 3: + dev->regs[9] |= 1; + break; + case 4: + dev->regs[9] |= 2; + break; + case 5: + dev->regs[9] |= 0x20; + break; + case 6: case 7: + dev->regs[9] |= 9; + break; + case 8: case 9: + dev->regs[9] |= 4; + break; + case 10: case 11: + dev->regs[9] |= 5; + break; + case 12: case 13: case 14: case 15: + dev->regs[9] |= 0xB; + break; + case 16: + dev->regs[9] |= 0x13; + break; + case 17: + dev->regs[9] |= 0x21; + break; + case 18: case 19: + dev->regs[9] |= 6; + break; + case 20: case 21: case 22: case 23: + dev->regs[9] |= 0xD; + break; + case 24: case 25: case 26: case 27: + case 28: case 29: case 30: case 31: + dev->regs[9] |= 0xE; + break; + case 32: case 33: case 34: case 35: + dev->regs[9] |= 0x1B; + break; + case 36: case 37: case 38: case 39: + dev->regs[9] |= 0xF; + break; + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + dev->regs[9] |= 0x17; + break; + case 48: + dev->regs[9] |= 0x1E; + break; + default: + if (mem_size_mb < 64) + dev->regs[9] |= 0x1E; + else if ((mem_size_mb >= 65) && (mem_size_mb < 68)) + dev->regs[9] |= 0x22; + else + dev->regs[9] |= 0x24; + break; + } + + dev->regs[0x11] = 9; + dev->regs[0x12] = 0xFF; + dev->regs[0x23] = 0xF0; + dev->regs[0x26] = 1; + + io_removehandler(0x22, 0x0002, + sis_85c50x_isa_read, NULL, NULL, sis_85c50x_isa_write, NULL, NULL, dev); + io_sethandler(0x22, 0x0002, + sis_85c50x_isa_read, NULL, NULL, sis_85c50x_isa_write, NULL, NULL, dev); +} + + +static void +sis_85c50x_reset(void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + uint8_t val = 0; + + val = sis_85c501_read(0, 0x54, priv); /* Read current value of 0x44. */ + sis_85c501_write(0, 0x54, val & 0xf, priv); /* Turn off shadow BIOS but keep the lower 4 bits. */ + + sis_85c50x_isa_reset(dev); +} + + +static void +sis_85c50x_setup(sis_85c50x_t *dev) +{ + memset(dev, 0, sizeof(sis_85c50x_t)); + + /* 85c501 */ + dev->pci_conf[0][0x00] = 0x39; /*SiS*/ + dev->pci_conf[0][0x01] = 0x10; + dev->pci_conf[0][0x02] = 0x06; /*501/502*/ + dev->pci_conf[0][0x03] = 0x04; + + dev->pci_conf[0][0x04] = 7; + dev->pci_conf[0][0x05] = 0; + + dev->pci_conf[0][0x06] = 0x80; + dev->pci_conf[0][0x07] = 0x02; + + dev->pci_conf[0][0x08] = 0; /*Device revision*/ + + dev->pci_conf[0][0x09] = 0x00; /*Device class (PCI bridge)*/ + dev->pci_conf[0][0x0a] = 0x00; + dev->pci_conf[0][0x0b] = 0x06; + + dev->pci_conf[0][0x0e] = 0x00; /*Single function device*/ + + dev->pci_conf[0][0x50] = 0xbc; + dev->pci_conf[0][0x51] = 0xfb; + dev->pci_conf[0][0x52] = 0xad; + dev->pci_conf[0][0x53] = 0xfe; + + shadowbios = 1; + + /* 85c503 */ + dev->pci_conf[1][0x00] = 0x39; /*SiS*/ + dev->pci_conf[1][0x01] = 0x10; + dev->pci_conf[1][0x02] = 0x08; /*503*/ + dev->pci_conf[1][0x03] = 0x00; + + dev->pci_conf[1][0x04] = 7; + dev->pci_conf[1][0x05] = 0; + + dev->pci_conf[1][0x06] = 0x80; + dev->pci_conf[1][0x07] = 0x02; + + dev->pci_conf[1][0x08] = 0; /*Device revision*/ + + dev->pci_conf[1][0x09] = 0x00; /*Device class (PCI bridge)*/ + dev->pci_conf[1][0x0a] = 0x01; + dev->pci_conf[1][0x0b] = 0x06; + + dev->pci_conf[1][0x0e] = 0x00; /*Single function device*/ + + dev->pci_conf[1][0x41] = dev->pci_conf[1][0x42] = + dev->pci_conf[1][0x43] = dev->pci_conf[1][0x44] = 0x80; +} + + +static void +sis_85c50x_close(void *priv) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) priv; + + free(dev); +} + + +static void * +sis_85c50x_init(const device_t *info) +{ + sis_85c50x_t *dev = (sis_85c50x_t *) malloc(sizeof(sis_85c50x_t)); + + pci_add_card(0, sis_85c501_read, sis_85c501_write, dev); + pci_add_card(5, sis_85c503_read, sis_85c503_write, dev); + + sis_85c50x_setup(dev); + sis_85c50x_isa_reset(dev); + + device_add(&port_92_pci_device); + + return dev; +} + + +const device_t sis_85c50x_device = +{ + "SiS 85c501/85c503", + DEVICE_PCI, + 0, + sis_85c50x_init, + sis_85c50x_close, + sis_85c50x_reset, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/chipset/wd76c10 - Cópia.c b/src/chipset/wd76c10 - Cópia.c new file mode 100644 index 000000000..7a834e910 --- /dev/null +++ b/src/chipset/wd76c10 - Cópia.c @@ -0,0 +1,196 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the WD76C10 System Controller chip. + * + * Version: @(#)wd76c10.c 1.0.0 2019/05/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. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../timer.h" +#include "../io.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../port_92.h" +#include "../serial.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../video/vid_paradise.h" +#include "chipset.h" + + +typedef struct { + int type; + + uint16_t reg_0092; + uint16_t reg_2072; + uint16_t reg_2872; + uint16_t reg_5872; + + serial_t *uart[2]; + + fdc_t *fdc; +} wd76c10_t; + + +static uint16_t +wd76c10_read(uint16_t port, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + int16_t ret = 0xffff; + + switch (port) { + case 0x2072: + ret = dev->reg_2072; + break; + + case 0x2872: + ret = dev->reg_2872; + break; + + case 0x5872: + ret = dev->reg_5872; + break; + } + + return(ret); +} + + +static void +wd76c10_write(uint16_t port, uint16_t val, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + switch (port) { + case 0x2072: + dev->reg_2072 = val; + + serial_remove(dev->uart[0]); + if (!(val & 0x10)) + { + switch ((val >> 5) & 7) + { + case 1: serial_setup(dev->uart[0], 0x3f8, 4); break; + case 2: serial_setup(dev->uart[0], 0x2f8, 4); break; + case 3: serial_setup(dev->uart[0], 0x3e8, 4); break; + case 4: serial_setup(dev->uart[0], 0x2e8, 4); break; + default: break; + } + } + serial_remove(dev->uart[1]); + if (!(val & 0x01)) + { + switch ((val >> 1) & 7) + { + case 1: serial_setup(dev->uart[1], 0x3f8, 3); break; + case 2: serial_setup(dev->uart[1], 0x2f8, 3); break; + case 3: serial_setup(dev->uart[1], 0x3e8, 3); break; + case 4: serial_setup(dev->uart[1], 0x2e8, 3); break; + default: break; + } + } + break; + + case 0x2872: + dev->reg_2872 = val; + + fdc_remove(dev->fdc); + if (! (val & 1)) + fdc_set_base(dev->fdc, 0x03f0); + break; + + case 0x5872: + dev->reg_5872 = val; + break; + } +} + + +static uint8_t +wd76c10_readb(uint16_t port, void *priv) +{ + if (port & 1) + return(wd76c10_read(port & ~1, priv) >> 8); + + return(wd76c10_read(port, priv) & 0xff); +} + + +static void +wd76c10_writeb(uint16_t port, uint8_t val, void *priv) +{ + uint16_t temp = wd76c10_read(port, priv); + + if (port & 1) + wd76c10_write(port & ~1, (temp & 0x00ff) | (val << 8), priv); + else + wd76c10_write(port , (temp & 0xff00) | val, priv); +} + + +static void +wd76c10_close(void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + free(dev); +} + + +static void * +wd76c10_init(const device_t *info) +{ + wd76c10_t *dev; + + dev = (wd76c10_t *) malloc(sizeof(wd76c10_t)); + memset(dev, 0x00, sizeof(wd76c10_t)); + dev->type = info->local; + + dev->fdc = (fdc_t *)device_add(&fdc_at_device); + + dev->uart[0] = device_add_inst(&i8250_device, 1); + dev->uart[1] = device_add_inst(&i8250_device, 2); + + device_add(&port_92_word_device); + + io_sethandler(0x2072, 2, + wd76c10_readb,wd76c10_read,NULL, + wd76c10_writeb,wd76c10_write,NULL, dev); + io_sethandler(0x2872, 2, + wd76c10_readb,wd76c10_read,NULL, + wd76c10_writeb,wd76c10_write,NULL, dev); + io_sethandler(0x5872, 2, + wd76c10_readb,wd76c10_read,NULL, + wd76c10_writeb,wd76c10_write,NULL, dev); + + return(dev); +} + + +const device_t wd76c10_device = { + "WD 76C10", + 0, + 0, + wd76c10_init, wd76c10_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/chipset/wd76c10.c b/src/chipset/wd76c10.c new file mode 100644 index 000000000..abd61c09b --- /dev/null +++ b/src/chipset/wd76c10.c @@ -0,0 +1,292 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the WD76C10 System Controller chip. + * + * Version: @(#)wd76c10.c 1.0.0 2019/05/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. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../timer.h" +#include "../io.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../port_92.h" +#include "../serial.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../video/vid_paradise.h" +#include "chipset.h" + + +typedef struct { + int type; + + uint16_t reg_0092; + uint16_t reg_2072; + uint16_t reg_2872; + uint16_t reg_5872; + + uint16_t reg_f872; + + serial_t *uart[2]; + + fdc_t *fdc; + + mem_mapping_t extram_mapping; + uint8_t extram[65536]; +} wd76c10_t; + + +static uint16_t +wd76c10_read(uint16_t port, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + int16_t ret = 0xffff; + + switch (port) { + case 0x2072: + ret = dev->reg_2072; + break; + + case 0x2872: + ret = dev->reg_2872; + break; + + case 0x5872: + ret = dev->reg_5872; + break; + + case 0xf872: + ret = dev->reg_f872; + break; + } + + return(ret); +} + + +static void +wd76c10_write(uint16_t port, uint16_t val, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + switch (port) { + case 0x2072: + dev->reg_2072 = val; + + serial_remove(dev->uart[0]); + if (!(val & 0x10)) + { + switch ((val >> 5) & 7) + { + case 1: serial_setup(dev->uart[0], 0x3f8, 4); break; + case 2: serial_setup(dev->uart[0], 0x2f8, 4); break; + case 3: serial_setup(dev->uart[0], 0x3e8, 4); break; + case 4: serial_setup(dev->uart[0], 0x2e8, 4); break; + default: break; + } + } + serial_remove(dev->uart[1]); + if (!(val & 0x01)) + { + switch ((val >> 1) & 7) + { + case 1: serial_setup(dev->uart[1], 0x3f8, 3); break; + case 2: serial_setup(dev->uart[1], 0x2f8, 3); break; + case 3: serial_setup(dev->uart[1], 0x3e8, 3); break; + case 4: serial_setup(dev->uart[1], 0x2e8, 3); break; + default: break; + } + } + break; + + case 0x2872: + dev->reg_2872 = val; + + fdc_remove(dev->fdc); + if (! (val & 1)) + fdc_set_base(dev->fdc, 0x03f0); + break; + + case 0x5872: + dev->reg_5872 = val; + break; + + case 0xf872: + dev->reg_f872 = val; + switch (val & 3) { + case 0: + mem_set_mem_state(0xd0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(0xd0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(0xd0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(0xd0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); + if (val & 4) + mem_mapping_enable(&dev->extram_mapping); + else + mem_mapping_disable(&dev->extram_mapping); + flushmmucache_nopc(); + break; + } +} + + +static uint8_t +wd76c10_readb(uint16_t port, void *priv) +{ + if (port & 1) + return(wd76c10_read(port & ~1, priv) >> 8); + + return(wd76c10_read(port, priv) & 0xff); +} + + +static void +wd76c10_writeb(uint16_t port, uint8_t val, void *priv) +{ + uint16_t temp = wd76c10_read(port, priv); + + if (port & 1) + wd76c10_write(port & ~1, (temp & 0x00ff) | (val << 8), priv); + else + wd76c10_write(port , (temp & 0xff00) | val, priv); +} + + +uint8_t +wd76c10_read_extram(uint32_t addr, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + return dev->extram[addr & 0xffff]; +} + + +uint16_t +wd76c10_read_extramw(uint32_t addr, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + return *(uint16_t *)&dev->extram[addr & 0xffff]; +} + + +uint32_t +wd76c10_read_extraml(uint32_t addr, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + return *(uint32_t *)&dev->extram[addr & 0xffff]; +} + + +void +wd76c10_write_extram(uint32_t addr, uint8_t val, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + dev->extram[addr & 0xffff] = val; +} + + +void +wd76c10_write_extramw(uint32_t addr, uint16_t val, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + *(uint16_t *)&dev->extram[addr & 0xffff] = val; +} + + +void +wd76c10_write_extraml(uint32_t addr, uint32_t val, void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + *(uint32_t *)&dev->extram[addr & 0xffff] = val; +} + + +static void +wd76c10_close(void *priv) +{ + wd76c10_t *dev = (wd76c10_t *)priv; + + free(dev); +} + + +static void * +wd76c10_init(const device_t *info) +{ + wd76c10_t *dev; + + dev = (wd76c10_t *) malloc(sizeof(wd76c10_t)); + memset(dev, 0x00, sizeof(wd76c10_t)); + dev->type = info->local; + + dev->fdc = (fdc_t *)device_add(&fdc_at_device); + + dev->uart[0] = device_add_inst(&i8250_device, 1); + dev->uart[1] = device_add_inst(&i8250_device, 2); + + device_add(&port_92_word_device); + + io_sethandler(0x2072, 2, + wd76c10_readb,wd76c10_read,NULL, + wd76c10_writeb,wd76c10_write,NULL, dev); + io_sethandler(0x2872, 2, + wd76c10_readb,wd76c10_read,NULL, + wd76c10_writeb,wd76c10_write,NULL, dev); + io_sethandler(0x5872, 2, + wd76c10_readb,wd76c10_read,NULL, + wd76c10_writeb,wd76c10_write,NULL, dev); + io_sethandler(0xf872, 2, + wd76c10_readb,wd76c10_read,NULL, + wd76c10_writeb,wd76c10_write,NULL, dev); + + mem_mapping_add(&dev->extram_mapping, 0xd0000, 0x10000, + wd76c10_read_extram,wd76c10_read_extramw,wd76c10_read_extraml, + wd76c10_write_extram,wd76c10_write_extramw,wd76c10_write_extraml, + dev->extram, MEM_MAPPING_EXTERNAL, dev); + mem_mapping_disable(&dev->extram_mapping); + + return(dev); +} + + +const device_t wd76c10_device = { + "WD 76C10", + 0, + 0, + wd76c10_init, wd76c10_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/config.c b/src/config.c index 5653ebcb8..9cb5e5c0b 100644 --- a/src/config.c +++ b/src/config.c @@ -8,7 +8,7 @@ * * Configuration file handler. * - * Version: @(#)config.c 1.0.60 2019/01/13 + * Version: @(#)config.c 1.0.61 2019/03/03 * * Authors: Sarah Walker, * Miran Grca, @@ -16,10 +16,10 @@ * Overdoze, * David Hrdlička, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2018 David Hrdlička. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2018,2019 David Hrdlička. * * NOTE: Forcing config files to be in Unicode encoding breaks * it on Windows XP, and possibly also Vista. Use the @@ -36,6 +36,7 @@ #include "86box.h" #include "cpu/cpu.h" #include "device.h" +#include "timer.h" #include "nvr.h" #include "config.h" #include "isamem.h" @@ -517,7 +518,6 @@ load_machine(void) if (machine >= machine_count()) machine = machine_count() - 1; - romset = machine_getromset(); cpu_manufacturer = config_get_int(cat, "cpu_manufacturer", 0); cpu = config_get_int(cat, "cpu", 0); cpu_waitstates = config_get_int(cat, "cpu_waitstates", 0); @@ -565,7 +565,7 @@ load_video(void) char *cat = "Video"; char *p; - if (machines[machine].fixed_gfxcard) { + if (machines[machine].flags & MACHINE_VIDEO_FIXED) { config_delete_var(cat, "gfxcard"); gfxcard = VID_INTERNAL; } else { @@ -726,28 +726,30 @@ load_ports(void) { char *cat = "Ports (COM & LPT)"; char *p; + char temp[512]; + int c, d; - serial_enabled[0] = !!config_get_int(cat, "serial1_enabled", 1); - serial_enabled[1] = !!config_get_int(cat, "serial2_enabled", 1); - lpt_enabled = !!config_get_int(cat, "lpt_enabled", 1); + for (c = 0; c < 2; c++) { + sprintf(temp, "serial%d_enabled", c + 1); + serial_enabled[c] = !!config_get_int(cat, temp, 1); + } - p = (char *)config_get_string(cat, "lpt1_device", NULL); - if (p != NULL) - strcpy(lpt_device_names[0], p); - else - strcpy(lpt_device_names[0], "none"); + for (c = 0; c < 3; c++) { + sprintf(temp, "lpt%d_enabled", c + 1); + lpt_ports[c].enabled = !!config_get_int(cat, temp, (c == 0) ? 1 : 0); - p = (char *)config_get_string(cat, "lpt2_device", NULL); - if (p != NULL) - strcpy(lpt_device_names[1], p); - else - strcpy(lpt_device_names[1], "none"); + sprintf(temp, "lpt%d_device", c + 1); + p = (char *) config_get_string(cat, temp, "none"); + lpt_ports[c].device = lpt_device_get_from_internal_name(p); + } - p = (char *)config_get_string(cat, "lpt3_device", NULL); - if (p != NULL) - strcpy(lpt_device_names[2], p); - else - strcpy(lpt_device_names[2], "none"); + /* Legacy config compatibility. */ + d = config_get_int(cat, "lpt_enabled", 2); + if (d < 2) { + for (c = 0; c < 3; c++) + lpt_ports[c].enabled = d; + } + config_delete_var(cat, "lpt_enabled"); } @@ -757,8 +759,8 @@ load_other_peripherals(void) { char *cat = "Other peripherals"; char *p; - char temp[512]; - int c; + char temp[512]; + int c; p = config_get_string(cat, "scsicard", NULL); if (p != NULL) @@ -776,7 +778,14 @@ load_other_peripherals(void) strcpy(p, "none"); } } - hdc_current = hdc_get_from_internal_name(p); + if (!strcmp(p, "mfm_xt")) + hdc_current = hdc_get_from_internal_name("st506_xt"); + else if (!strcmp(p, "mfm_xt_dtc5150x")) + hdc_current = hdc_get_from_internal_name("st506_xt_dtc5150x"); + else if (!strcmp(p, "mfm_at")) + hdc_current = hdc_get_from_internal_name("st506_at"); + else + hdc_current = hdc_get_from_internal_name(p); ide_ter_enabled = !!config_get_int(cat, "ide_ter", 0); ide_qua_enabled = !!config_get_int(cat, "ide_qua", 0); @@ -789,7 +798,7 @@ load_other_peripherals(void) p = config_get_string(cat, temp, "none"); isamem_type[c] = isamem_get_from_internal_name(p); } - + p = config_get_string(cat, "isartc_type", "none"); isartc_type = isartc_get_from_internal_name(p); } @@ -823,7 +832,7 @@ load_hard_disks(void) break; case HDD_BUS_MFM: - max_spt = 17; /* 26 for RLL */ + max_spt = 26; /* 26 for RLL */ max_hpc = 15; max_tracks = 1023; break; @@ -1069,8 +1078,11 @@ load_other_removable_devices(void) if (cdrom[c].ide_channel > 7) cdrom[c].ide_channel = 7; } else { - sprintf(temp, "cdrom_%02i_scsi_id", c+1); - if (cdrom[c].bus_type == CDROM_BUS_SCSI) { + if (cdrom[c].bus_type == CDROM_BUS_SCSI_CHINON) + sprintf(temp, "cdrom_%02i_scsi_id_chinon", c+1); + else + sprintf(temp, "cdrom_%02i_scsi_id", c+1); + if (cdrom[c].bus_type == CDROM_BUS_SCSI || cdrom[c].bus_type == CDROM_BUS_SCSI_CHINON) { cdrom[c].scsi_device_id = config_get_int(cat, temp, c+2); if (cdrom[c].scsi_device_id > 15) @@ -1121,6 +1133,9 @@ load_other_removable_devices(void) sprintf(temp, "cdrom_%02i_scsi_id", c+1); config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_scsi_id_chinon", c+1); + config_delete_var(cat, temp); sprintf(temp, "cdrom_%02i_image_path", c+1); config_delete_var(cat, temp); @@ -1240,7 +1255,9 @@ config_load(void) hdc_current = hdc_get_from_internal_name("none"); serial_enabled[0] = 1; serial_enabled[1] = 1; - lpt_enabled = 1; + lpt_ports[0].enabled = 1; + lpt_ports[1].enabled = 0; + lpt_ports[2].enabled = 0; for (i = 0; i < FDD_NUM; i++) { if (i < 2) fdd_set_type(i, 2); @@ -1586,36 +1603,32 @@ static void save_ports(void) { char *cat = "Ports (COM & LPT)"; + char temp[512]; + int c, d; - if (serial_enabled[0]) - config_delete_var(cat, "serial1_enabled"); - else - config_set_int(cat, "serial1_enabled", serial_enabled[0]); + for (c = 0; c < 2; c++) { + sprintf(temp, "serial%d_enabled", c + 1); + if (serial_enabled[c]) + config_delete_var(cat, temp); + else + config_set_int(cat, temp, serial_enabled[c]); + } - if (serial_enabled[1]) - config_delete_var(cat, "serial2_enabled"); - else - config_set_int(cat, "serial2_enabled", serial_enabled[1]); + for (c = 0; c < 3; c++) { + sprintf(temp, "lpt%d_enabled", c + 1); + d = (c == 0) ? 1 : 0; + if (lpt_ports[c].enabled == d) + config_delete_var(cat, temp); + else + config_set_int(cat, temp, lpt_ports[c].enabled); - if (lpt_enabled) - config_delete_var(cat, "lpt_enabled"); - else - config_set_int(cat, "lpt_enabled", lpt_enabled); - - if (!strcmp(lpt_device_names[0], "none")) - config_delete_var(cat, "lpt1_device"); - else - config_set_string(cat, "lpt1_device", lpt_device_names[0]); - - if (!strcmp(lpt_device_names[1], "none")) - config_delete_var(cat, "lpt2_device"); - else - config_set_string(cat, "lpt2_device", lpt_device_names[1]); - - if (!strcmp(lpt_device_names[2], "none")) - config_delete_var(cat, "lpt3_device"); - else - config_set_string(cat, "lpt3_device", lpt_device_names[2]); + sprintf(temp, "lpt%d_device", c + 1); + if (lpt_ports[c].device == 0) + config_delete_var(cat, temp); + else + config_set_string(cat, temp, + (char *) lpt_device_get_internal_name(lpt_ports[c].device)); + } delete_section_if_empty(cat); } @@ -1626,8 +1639,8 @@ static void save_other_peripherals(void) { char *cat = "Other peripherals"; - char temp[512]; - int c; + char temp[512]; + int c; if (scsi_card_current == 0) config_delete_var(cat, "scsicard"); @@ -1827,9 +1840,13 @@ save_other_removable_devices(void) cdrom[c].ide_channel & 1); config_set_string(cat, temp, tmp2); } - - sprintf(temp, "cdrom_%02i_scsi_id", c + 1); - if (cdrom[c].bus_type != CDROM_BUS_SCSI) { + + if (cdrom[c].bus_type == CDROM_BUS_SCSI_CHINON) + sprintf(temp, "cdrom_%02i_scsi_id_chinon", c + 1); + else + sprintf(temp, "cdrom_%02i_scsi_id", c + 1); + + if (cdrom[c].bus_type != CDROM_BUS_SCSI && cdrom[c].bus_type != CDROM_BUS_SCSI_CHINON) { config_delete_var(cat, temp); } else { config_set_int(cat, temp, cdrom[c].scsi_device_id); diff --git a/src/cpu/386.c b/src/cpu/386.c index 988b5e987..7694a0be4 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -11,13 +11,13 @@ #define HAVE_STDARG_H #include "../86box.h" #include "cpu.h" +#include "../timer.h" #include "x86.h" #include "x87.h" #include "../nmi.h" #include "../mem.h" #include "../pic.h" #include "../pit.h" -#include "../timer.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "386_common.h" @@ -29,12 +29,11 @@ extern int codegen_flags_changed; int cpl_override = 0, fpucount = 0; int tempc, oldcpl, optype, inttype, oddeven = 0; -int use32, stack32; +int stack32, timetolive; -uint16_t flags, eflags; -uint16_t rds, ea_rseg; uint16_t oldcs; +uint32_t use32; uint32_t oldds, oldss, olddslimit, oldsslimit, olddslimitw, oldsslimitw; uint32_t *eal_r, *eal_w; @@ -44,11 +43,9 @@ uint32_t rmdat32; uint32_t backupregs[16]; x86seg gdt,ldt,idt,tr; -x86seg _cs,_ds,_es,_ss,_fs,_gs; x86seg _oldds; -#define rmdat rmdat32 -#define fetchdat rmdat32 +uint32_t rmdat; #define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 0; } #define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 0 @@ -68,7 +65,7 @@ uint32_t testr[9]; extern int dontprint; #undef NOTRM -#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ +#define NOTRM if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\ { \ x86_int(6); \ return 0; \ @@ -82,7 +79,7 @@ extern int dontprint; #include "x86_ops.h" #undef NOTRM -#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ +#define NOTRM if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\ { \ x86_int(6); \ break; \ @@ -111,49 +108,46 @@ x386_log(const char *fmt, ...) void exec386(int cycs) { - uint8_t temp; + int vector, tempi, cycdiff, oldcyc; + int ins_cycles; uint32_t addr; - int tempi; - int cycdiff; - int oldcyc; cycles+=cycs; - /* output=3; */ while (cycles>0) { - int cycle_period = (timer_count >> TIMER_SHIFT) + 1; + int cycle_period = (timer_target - (uint32_t)tsc) + 1; x86_was_reset = 0; cycdiff=0; oldcyc=cycles; - timer_start_period(cycles << TIMER_SHIFT); while (cycdiff < cycle_period) { + ins_cycles = cycles; + oldcs=CS; cpu_state.oldpc = cpu_state.pc; - oldcpl=CPL; + oldcpl=CPL; cpu_state.op32 = use32; x86_was_reset = 0; dontprint=0; - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; cpu_state.ssegs = 0; fetchdat = fastreadl(cs + cpu_state.pc); if (!cpu_state.abrt) - { - trap = flags & T_FLAG; + { opcode = fetchdat & 0xFF; - fetchdat >>= 8; + fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; cpu_state.pc++; x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); - if (x86_was_reset) - break; - if(x86_was_reset) break; + if(x86_was_reset) + break; } if (!use32) cpu_state.pc &= 0xffff; @@ -180,6 +174,10 @@ dontprint=0; } } } + + ins_cycles -= cycles; + tsc += ins_cycles; + cycdiff=oldcyc-cycles; if (trap) @@ -193,13 +191,13 @@ dontprint=0; } else { - writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-2)&0xFFFF,cpu_state.flags); writememw(ss,(SP-4)&0xFFFF,CS); writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); SP-=6; addr = (1 << 2) + idt.base; - flags&=~I_FLAG; - flags&=~T_FLAG; + cpu_state.flags&=~I_FLAG; + cpu_state.flags&=~T_FLAG; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); } @@ -216,26 +214,26 @@ dontprint=0; nmi = 0; } } - else if ((flags&I_FLAG) && pic_intpending) + else if ((cpu_state.flags & I_FLAG) && pic_intpending) { - temp=picinterrupt(); - if (temp!=0xFF) + vector = picinterrupt(); + if (vector != -1) { flags_rebuild(); if (msw&1) { - pmodeint(temp,0); + pmodeint(vector,0); } else { - writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-2)&0xFFFF,cpu_state.flags); writememw(ss,(SP-4)&0xFFFF,CS); writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); SP-=6; - addr = (temp << 2) + idt.base; - flags&=~I_FLAG; - flags&=~T_FLAG; - oxpc=cpu_state.pc; + addr = (vector << 2) + idt.base; + cpu_state.flags&=~I_FLAG; + cpu_state.flags&=~T_FLAG; + oxpc = cpu_state.pc; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); } @@ -252,8 +250,7 @@ dontprint=0; } } - tsc += cycdiff; - - timer_end_period(cycles << TIMER_SHIFT); + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); } } diff --git a/src/cpu/386.h b/src/cpu/386.h deleted file mode 100644 index e207d48ca..000000000 --- a/src/cpu/386.h +++ /dev/null @@ -1,5 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -extern void cpu_386_flags_extract(); -extern void cpu_386_flags_rebuild(); diff --git a/src/cpu/386_common.h b/src/cpu/386_common.h index c7abc9793..d85c3e247 100644 --- a/src/cpu/386_common.h +++ b/src/cpu/386_common.h @@ -8,16 +8,14 @@ * * Common 386 CPU code. * - * Version: @(#)386_common.h 1.0.0 2017/05/30 + * Version: @(#)386_common.h 1.0.1 2019/02/19 * * Author: Sarah Walker, * Miran Grca, - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016-2017 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ -extern uint16_t ea_rseg; - #undef readmemb #undef writememb @@ -32,7 +30,7 @@ extern uint16_t ea_rseg; #define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v -#define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \ +#define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (cpu_state.eflags&VM_FLAG))) \ { \ int tempi = checkio(port); \ if (cpu_state.abrt) return 1; \ @@ -43,46 +41,88 @@ extern uint16_t ea_rseg; } \ } -#define checkio_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \ - { \ - tempi = checkio(port); \ - if (cpu_state.abrt) break; \ - if (tempi) \ - { \ - x86gpf("checkio_perm(): no permission",0); \ - break; \ - } \ - } +#define SEG_CHECK_READ(seg) \ + do \ + { \ + if ((seg)->base == 0xffffffff) \ + { \ + x86gpf("Segment can't read", 0);\ + return 1; \ + } \ + } while (0) + +#define SEG_CHECK_WRITE(seg) \ + do \ + { \ + if ((seg)->base == 0xffffffff) \ + { \ + x86gpf("Segment can't write", 0);\ + return 1; \ + } \ + } while (0) #define CHECK_READ(chseg, low, high) \ - if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || ((msw & 1) && !(eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) \ { \ x86gpf("Limit check (READ)", 0); \ return 1; \ } \ - if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ { \ - if ((chseg) == &_ss) \ + if ((chseg) == &cpu_state.seg_ss) \ x86ss(NULL,(chseg)->seg & 0xfffc); \ else \ x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ return 1; \ - } + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 0); \ + (void) mmutranslatereal((chseg)->base + high, 0); \ + if (cpu_state.abrt) \ + return 1; \ + } + +#define CHECK_READ_REP(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ + { \ + x86gpf("Limit check (READ)", 0); \ + break; \ + } \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &cpu_state.seg_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ + break; \ + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 0); \ + (void) mmutranslatereal((chseg)->base + high, 0); \ + if (cpu_state.abrt) \ + break; \ + } #define CHECK_WRITE(chseg, low, high) \ - if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2) || ((msw & 1) && !(eflags & VM_FLAG) && ((chseg)->access & 8))) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && ((chseg)->access & 8))) \ { \ x86gpf("Limit check (WRITE)", 0); \ return 1; \ } \ - if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ { \ - if ((chseg) == &_ss) \ + if ((chseg) == &cpu_state.seg_ss) \ x86ss(NULL,(chseg)->seg & 0xfffc); \ else \ x86np("Write to seg not present", (chseg)->seg & 0xfffc); \ return 1; \ - } + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 1); \ + (void) mmutranslatereal((chseg)->base + high, 1); \ + if (cpu_state.abrt) \ + return 1; \ + } #define CHECK_WRITE_REP(chseg, low, high) \ if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ @@ -90,17 +130,23 @@ extern uint16_t ea_rseg; x86gpf("Limit check (WRITE REP)", 0); \ break; \ } \ - if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ { \ - if ((chseg) == &_ss) \ + if ((chseg) == &cpu_state.seg_ss) \ x86ss(NULL,(chseg)->seg & 0xfffc); \ else \ x86np("Write (REP) to seg not present", (chseg)->seg & 0xfffc); \ break; \ - } + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 1); \ + (void) mmutranslatereal((chseg)->base + high, 1); \ + if (cpu_state.abrt) \ + break; \ + } -#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ +#define NOTRM if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\ { \ x86_int(6); \ return 1; \ @@ -165,6 +211,17 @@ static __inline uint32_t fastreadl(uint32_t a) return val; } +static __inline void *get_ram_ptr(uint32_t a) +{ + if ((a >> 12) == pccache) + return &pccache2[a]; + else + { + uint8_t *t = getpccache(a); + return &t[a]; + } +} + static __inline uint8_t getbyte() { cpu_state.pc++; @@ -204,7 +261,6 @@ static __inline uint16_t geteaw() { if (cpu_mod == 3) return cpu_state.regs[cpu_rm].w; - /* cycles-=3; */ if (eal_r) return *(uint16_t *)eal_r; return readmemw(easeg, cpu_state.eaaddr); @@ -214,7 +270,6 @@ static __inline uint32_t geteal() { if (cpu_mod == 3) return cpu_state.regs[cpu_rm].l; - /* cycles-=3; */ if (eal_r) return *eal_r; return readmeml(easeg, cpu_state.eaaddr); @@ -246,10 +301,11 @@ static __inline void seteaq(uint64_t v) writememql(easeg, cpu_state.eaaddr, v); } -#define seteab(v) if (cpu_mod!=3) { if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,cpu_state.eaaddr,v); } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v -#define seteaw(v) if (cpu_mod!=3) { if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v -#define seteal(v) if (cpu_mod!=3) { if (eal_w) *eal_w=v; else writememll(easeg,cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v - +#define seteab(v) if (cpu_mod!=3) { CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); if (eal_w) *(uint8_t *)eal_w=v; else { writememb386l(easeg,cpu_state.eaaddr,v); } } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v +#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else { writememwl(easeg,cpu_state.eaaddr,v); } } else cpu_state.regs[cpu_rm].w=v +#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else { writememll(easeg,cpu_state.eaaddr,v); } } else cpu_state.regs[cpu_rm].l=v + + #define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,cpu_state.eaaddr,v); #define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v); #define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg,cpu_state.eaaddr,v); @@ -258,9 +314,3 @@ static __inline void seteaq(uint64_t v) #define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 #define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++ #define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2 - - -#define rmdat rmdat32 -#define fetchdat rmdat32 - -void x86_int(int num); diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index b14e192f5..fab7e429c 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -40,7 +40,7 @@ int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latch #ifdef ENABLE_386_DYNAREC_LOG -int x386_dynarec_do_log = ENABLE_386_DYNAREC_LOG;#endif +int x386_dynarec_do_log = ENABLE_386_DYNAREC_LOG; void @@ -63,7 +63,6 @@ static __inline void fetch_ea_32_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; - ea_rseg = cpu_state.ea_seg->seg; if (cpu_rm == 4) { uint8_t sib = rmdat >> 8; @@ -89,8 +88,7 @@ static __inline void fetch_ea_32_long(uint32_t rmdat) else if ((sib & 6) == 4 && !cpu_state.ssegs) { easeg = ss; - ea_rseg = SS; - cpu_state.ea_seg = &_ss; + cpu_state.ea_seg = &cpu_state.seg_ss; } if (((sib >> 3) & 7) != 4) cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); @@ -103,8 +101,7 @@ static __inline void fetch_ea_32_long(uint32_t rmdat) if (cpu_rm == 5 && !cpu_state.ssegs) { easeg = ss; - ea_rseg = SS; - cpu_state.ea_seg = &_ss; + cpu_state.ea_seg = &cpu_state.seg_ss; } if (cpu_mod == 1) { @@ -136,7 +133,6 @@ static __inline void fetch_ea_16_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; - ea_rseg = cpu_state.ea_seg->seg; if (!cpu_mod && cpu_rm == 6) { cpu_state.eaaddr = getword(); @@ -159,8 +155,7 @@ static __inline void fetch_ea_16_long(uint32_t rmdat) if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs) { easeg = ss; - ea_rseg = SS; - cpu_state.ea_seg = &_ss; + cpu_state.ea_seg = &cpu_state.seg_ss; } cpu_state.eaaddr &= 0xFFFF; } @@ -211,22 +206,22 @@ void x86_int(int num) { if (stack32) { - writememw(ss,ESP-2,flags); + writememw(ss,ESP-2,cpu_state.flags); writememw(ss,ESP-4,CS); writememw(ss,ESP-6,cpu_state.pc); ESP-=6; } else { - writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); writememw(ss,((SP-4)&0xFFFF),CS); writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); SP-=6; } - flags&=~I_FLAG; - flags&=~T_FLAG; - oxpc=cpu_state.pc; + cpu_state.flags&=~I_FLAG; + cpu_state.flags&=~T_FLAG; + oxpc=cpu_state.pc; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); } @@ -256,22 +251,22 @@ void x86_int_sw(int num) { if (stack32) { - writememw(ss,ESP-2,flags); + writememw(ss,ESP-2,cpu_state.flags); writememw(ss,ESP-4,CS); writememw(ss,ESP-6,cpu_state.pc); ESP-=6; } else { - writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); writememw(ss,((SP-4)&0xFFFF),CS); writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); SP-=6; } - flags&=~I_FLAG; - flags&=~T_FLAG; - oxpc=cpu_state.pc; + cpu_state.flags&=~I_FLAG; + cpu_state.flags&=~T_FLAG; + oxpc=cpu_state.pc; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); cycles -= timing_int_rm; @@ -295,7 +290,7 @@ int x86_int_sw_rm(int num) if (cpu_state.abrt) return 1; - writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); if (cpu_state.abrt) { #ifdef ENABLE_386_DYNAREC_LOG x386_dynarec_log("abrt5\n"); @@ -312,11 +307,11 @@ int x86_int_sw_rm(int num) } SP-=6; - eflags &= ~VIF_FLAG; - flags &= ~T_FLAG; + cpu_state.eflags &= ~VIF_FLAG; + cpu_state.flags &= ~T_FLAG; cpu_state.pc = new_pc; loadcs(new_cs); - oxpc=cpu_state.pc; + oxpc=cpu_state.pc; cycles -= timing_int_rm; trap = 0; @@ -400,6 +395,8 @@ static void prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int } prefetch_prefixes = 0; + if (prefetch_bytes > 16) + prefetch_bytes = 16; } static void prefetch_flush() @@ -509,14 +506,14 @@ int dontprint=0; #include "386_ops.h" -#define CACHE_ON() (!(cr0 & (1 << 30)) /*&& (cr0 & 1)*/ && !(flags & T_FLAG)) +#define CACHE_ON() (!(cr0 & (1 << 30)) /*&& (cr0 & 1)*/ && !(cpu_state.flags & T_FLAG)) #ifdef USE_DYNAREC static int cycles_main = 0; void exec386_dynarec(int cycs) { - uint8_t temp; + int vector; uint32_t addr; int tempi; int cycdiff; @@ -533,7 +530,6 @@ void exec386_dynarec(int cycs) cycles += cyc_period; cycles_start = cycles; - timer_start_period(cycles << TIMER_SHIFT); while (cycles>0) { oldcs = CS; @@ -552,18 +548,18 @@ void exec386_dynarec(int cycs) { oldcs=CS; cpu_state.oldpc = cpu_state.pc; - oldcpl=CPL; + oldcpl = CPL; cpu_state.op32 = use32; - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; cpu_state.ssegs = 0; fetchdat = fastreadl(cs + cpu_state.pc); if (!cpu_state.abrt) { - trap = flags & T_FLAG; - opcode = fetchdat & 0xFF; - fetchdat >>= 8; + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; cpu_state.pc++; x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); @@ -602,7 +598,7 @@ void exec386_dynarec(int cycs) int hash = HASH(phys_addr); codeblock_t *block = codeblock_hash[hash]; int valid_block = 0; - trap = 0; + trap = 0; if (block && !cpu_state.abrt) { @@ -699,18 +695,18 @@ inrecomp=0; { oldcs=CS; cpu_state.oldpc = cpu_state.pc; - oldcpl=CPL; + oldcpl = CPL; cpu_state.op32 = use32; - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; cpu_state.ssegs = 0; fetchdat = fastreadl(cs + cpu_state.pc); if (!cpu_state.abrt) - { - trap = flags & T_FLAG; - opcode = fetchdat & 0xFF; - fetchdat >>= 8; + { + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; cpu_state.pc++; @@ -769,20 +765,20 @@ inrecomp=0; { oldcs=CS; cpu_state.oldpc = cpu_state.pc; - oldcpl=CPL; + oldcpl = CPL; cpu_state.op32 = use32; - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; cpu_state.ssegs = 0; codegen_endpc = (cs + cpu_state.pc) + 8; fetchdat = fastreadl(cs + cpu_state.pc); if (!cpu_state.abrt) - { - trap = flags & T_FLAG; - opcode = fetchdat & 0xFF; - fetchdat >>= 8; + { + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; cpu_state.pc++; @@ -857,7 +853,6 @@ inrecomp=0; if (trap) { - flags_rebuild(); if (msw&1) { @@ -865,13 +860,13 @@ inrecomp=0; } else { - writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-2)&0xFFFF,cpu_state.flags); writememw(ss,(SP-4)&0xFFFF,CS); writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); SP-=6; addr = (1 << 2) + idt.base; - flags&=~I_FLAG; - flags&=~T_FLAG; + cpu_state.flags&=~I_FLAG; + cpu_state.flags&=~T_FLAG; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); } @@ -888,35 +883,37 @@ inrecomp=0; nmi = 0; } } - else if ((flags&I_FLAG) && pic_intpending) + else if ((cpu_state.flags&I_FLAG) && pic_intpending) { - temp=picinterrupt(); - if (temp!=0xFF) + vector=picinterrupt(); + if (vector!=-1) { CPU_BLOCK_END(); flags_rebuild(); if (msw&1) { - pmodeint(temp,0); + pmodeint(vector,0); } else { - writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-2)&0xFFFF,cpu_state.flags); writememw(ss,(SP-4)&0xFFFF,CS); writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); SP-=6; - addr=temp<<2; - flags&=~I_FLAG; - flags&=~T_FLAG; - oxpc=cpu_state.pc; + addr=vector<<2; + cpu_state.flags&=~I_FLAG; + cpu_state.flags&=~T_FLAG; + oxpc=cpu_state.pc; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); } } } } - timer_end_period(cycles << TIMER_SHIFT); - cycles_main -= (cycles_start - cycles); + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); + + cycles_main -= (cycles_start - cycles); } } #endif diff --git a/src/cpu/386_dynarec_ops.c b/src/cpu/386_dynarec_ops.c index a47095e88..aa4784ba8 100644 --- a/src/cpu/386_dynarec_ops.c +++ b/src/cpu/386_dynarec_ops.c @@ -24,14 +24,10 @@ #include "386_common.h" -extern uint16_t *mod1add[2][8]; -extern uint32_t *mod1seg[8]; - static __inline void fetch_ea_32_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; - ea_rseg = cpu_state.ea_seg->seg; if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { uint32_t addr = easeg + cpu_state.eaaddr; @@ -47,7 +43,6 @@ static __inline void fetch_ea_16_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; - ea_rseg = cpu_state.ea_seg->seg; if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { uint32_t addr = easeg + cpu_state.eaaddr; diff --git a/src/cpu/386_ops.h b/src/cpu/386_ops.h index 45f2ddf67..55d7d72f3 100644 --- a/src/cpu/386_ops.h +++ b/src/cpu/386_ops.h @@ -910,6 +910,7 @@ const OpFn OP_TABLE(k6_0f)[1024] = }; #endif +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) const OpFn OP_TABLE(c6x86mx_0f)[1024] = { /*16-bit data, 16-bit addr*/ @@ -1000,6 +1001,7 @@ const OpFn OP_TABLE(c6x86mx_0f)[1024] = /*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, /*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, }; +#endif #ifdef DEV_BRANCH #ifdef USE_I686 diff --git a/src/cpu/808x.c b/src/cpu/808x.c index dd5b08a6b..814775b0c 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -9,15 +9,13 @@ * 808x CPU emulation, mostly ported from reenigne's XTCE, which * is cycle-accurate. * - * Version: @(#)808x.c 1.0.8 2018/11/14 + * Version: @(#)808x.c 1.0.9 2019/02/13 * * Authors: Andrew Jenner, * Miran Grca, - * Authors: Sarah Walker, * - * Copyright 2015-2018 Andrew Jenner. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. + * Copyright 2015-2019 Andrew Jenner. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -37,11 +35,10 @@ #include "../pic.h" #include "../timer.h" - /* The opcode of the instruction currently being executed. */ uint8_t opcode; -/* The tables to speed up the setting of the Z, N, and P flags. */ +/* The tables to speed up the setting of the Z, N, and P cpu_state.flags. */ uint8_t znptable8[256]; uint16_t znptable16[65536]; @@ -51,10 +48,10 @@ uint16_t zero = 0; /* MOD and R/M stuff. */ uint16_t *mod1add[2][8]; uint32_t *mod1seg[8]; -int rmdat; +uint32_t rmdat; /* XT CPU multiplier. */ -int xt_cpu_multi; +uint64_t xt_cpu_multi; /* Is the CPU 8088 or 8086. */ int is8086 = 0; @@ -80,7 +77,7 @@ uint32_t easeg; static uint8_t pfq[6]; /* Variables to aid with the prefetch queue operation. */ -static int fetchcycles = 0, pfq_pos = 0; +static int biu_cycles = 0, pfq_pos = 0; /* The IP equivalent of the current prefetch queue position. */ static uint16_t pfq_ip; @@ -89,14 +86,48 @@ static uint16_t pfq_ip; static uint32_t *opseg[4]; static x86seg *_opseg[4]; -static int takeint = 0, noint = 0; -static int in_lock = 0, halt = 0; +static int noint = 0; +static int in_lock = 0; static int cpu_alu_op, pfq_size; static uint16_t cpu_src = 0, cpu_dest = 0; -static uint16_t cpu_data = 0; +static uint16_t cpu_data = 0, last_addr = 0x0000; static uint32_t *ovr_seg = NULL; +static int prefetching = 1, completed = 1; +static int in_rep = 0, repeating = 0; +static int oldc, clear_lock = 0; +static int refresh = 0, takeint = 0; +static int cycdiff; + + +/* Various things needed for 8087. */ +#define OP_TABLE(name) ops_ ## name + +#define CPU_BLOCK_END() +#define SEG_CHECK_READ(seg) +#define SEG_CHECK_WRITE(seg) +#define CHECK_READ(a, b, c) +#define CHECK_WRITE(a, b, c) +#define UN_USED(x) (void)(x) +#define fetch_ea_16(val) +#define fetch_ea_32(val) +#define PREFETCH_RUN(a, b, c, d, e, f, g, h) + +#define CYCLES(val) \ + { \ + wait(val, 0); \ + } + +#define CLOCK_CYCLES(val) \ + { \ + wait(val, 0); \ + } + +typedef int (*OpFn)(uint32_t fetchdat); + + +static int tempc_fpu = 0; #ifdef ENABLE_808X_LOG @@ -130,7 +161,7 @@ dumpregs(int force) return; x808x_log("EIP=%08X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n", - cpu_state.pc, CS, DS, ES, SS, flags); + cpu_state.pc, CS, DS, ES, SS, cpu_state.flags); x808x_log("Old CS:EIP: %04X:%08X; %i ins\n", oldcs, cpu_state.oldpc, ins); for (c = 0; c < 4; c++) { x808x_log("%s : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", @@ -139,15 +170,15 @@ dumpregs(int force) } if (is386) { x808x_log("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", - seg_fs, _fs.limit, _fs.access, _fs.limit_low, _fs.limit_high); + seg_fs, cpu_state.seg_fs.limit, cpu_state.seg_fs.access, cpu_state.seg_fs.limit_low, cpu_state.seg_fs.limit_high); x808x_log("GS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", - gs, _gs.limit, _gs.access, _gs.limit_low, _gs.limit_high); + gs, cpu_state.seg_gs.limit, cpu_state.seg_gs.access, cpu_state.seg_gs.limit_low, cpu_state.seg_gs.limit_high); x808x_log("GDT : base=%06X limit=%04X\n", gdt.base, gdt.limit); x808x_log("LDT : base=%06X limit=%04X\n", ldt.base, ldt.limit); x808x_log("IDT : base=%06X limit=%04X\n", idt.base, idt.limit); x808x_log("TR : base=%06X limit=%04X\n", tr.base, tr.limit); x808x_log("386 in %s mode: %i-bit data, %-i-bit stack\n", - (msw & 1) ? ((eflags & VM_FLAG) ? "V86" : "protected") : "real", + (msw & 1) ? ((cpu_state.eflags & VM_FLAG) ? "V86" : "protected") : "real", (use32) ? 32 : 16, (stack32) ? 32 : 16); x808x_log("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n", cr0, cr2, cr3, cr4); x808x_log("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n", @@ -166,17 +197,69 @@ dumpregs(int force) #endif -static void pfq_add(int c); +static void pfq_add(int c, int add); static void set_pzs(int bits); +uint16_t +get_last_addr(void) +{ + return last_addr; +} + + static int irq_pending(void) { - if ((nmi && nmi_enable && nmi_mask) || ((flags & I_FLAG) && (pic.pend & ~pic.mask) && !noint)) - return 1; + uint8_t temp; - return 0; + if (takeint && !noint) + temp = 1; + else + temp = (nmi && nmi_enable && nmi_mask) || ((cpu_state.flags & T_FLAG) && !noint); + + takeint = (cpu_state.flags & I_FLAG) && (pic.pend &~ pic.mask); + + return temp; +} + + +static void +clock_start(void) +{ + cycdiff = cycles; +} + + +static void +clock_end(void) +{ + int diff = cycdiff - cycles; + + /* On 808x systems, clock speed is usually crystal frequency divided by an integer. */ + tsc += (uint64_t)diff * ((uint64_t)xt_cpu_multi >> 32ULL); /* Shift xt_cpu_multi by 32 bits to the right and then multiply. */ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); +} + + +static void +fetch_and_bus(int c, int bus) +{ + if (refresh > 0) { + /* Finish the current fetch, if any. */ + cycles -= ((4 - (biu_cycles & 3)) & 3); + pfq_add((4 - (biu_cycles & 3)) & 3, 1); + /* Add 4 memory access cycles. */ + cycles -= 4; + pfq_add(4, 0); + + refresh--; + } + + pfq_add(c, !bus); + clock_end(); + clock_start(); } @@ -184,13 +267,26 @@ static void wait(int c, int bus) { cycles -= c; - if (!bus) - pfq_add(c); + + fetch_and_bus(c, bus); +} + + +/* This is for external subtraction of cycles. */ +void +sub_cycles(int c) +{ + cycles -= c; + + if (!is286) + fetch_and_bus(c, 1); } #undef readmemb #undef readmemw +#undef readmeml +#undef readmemq /* Common read function. */ static uint8_t @@ -210,8 +306,7 @@ readmemb_common(uint32_t a) return ret; } -/* Reads a byte from the memory and accounts for memory transfer cycles to - subtract from the cycles to use for adding to the prefetch queue. */ +/* Reads a byte from the memory and advances the BIU. */ static uint8_t readmemb(uint32_t a) { @@ -224,9 +319,7 @@ readmemb(uint32_t a) } -/* Reads a byte from the memory but does not accounts for memory transfer - cycles to subtract from the cycles to use for adding to the prefetch - queue. */ +/* Reads a byte from the memory but does not advance the BIU. */ static uint8_t readmembf(uint32_t a) { @@ -239,8 +332,7 @@ readmembf(uint32_t a) } -/* Reads a word from the memory and accounts for memory transfer cycles to - subtract from the cycles to use for adding to the prefetch queue. */ +/* Reads a word from the memory and advances the BIU. */ static uint16_t readmemw_common(uint32_t s, uint16_t a) { @@ -279,9 +371,40 @@ readmemwf(uint16_t a) } +static uint16_t +readmem(uint32_t s) +{ + if (opcode & 1) + return readmemw(s, cpu_state.eaaddr); + else + return (uint16_t) readmemb(s + cpu_state.eaaddr); +} + + +static uint32_t +readmeml(uint32_t s, uint16_t a) +{ + uint32_t temp; + + temp = (uint32_t) (readmemw(s, a + 2)) << 16; + temp |= readmemw(s, a); + + return temp; +} + + +static uint64_t +readmemq(uint32_t s, uint16_t a) +{ + uint64_t temp; + + temp = (uint64_t) (readmeml(s, a + 4)) << 32; + temp |= readmeml(s, a); + + return temp; +} + -/* Writes a byte from the memory and accounts for memory transfer cycles to - subtract from the cycles to use for adding to the prefetch queue. */ static void writememb_common(uint32_t a, uint8_t v) { @@ -293,19 +416,22 @@ writememb_common(uint32_t a, uint8_t v) else *(uint8_t *)(writelookup2[a >> 12] + a) = v; } + + if ((a >= 0xf0000) && (a <= 0xfffff)) + last_addr = a & 0xffff; } +/* Writes a byte to the memory and advances the BIU. */ static void -writememb(uint32_t a, uint8_t v) +writememb(uint32_t s, uint32_t a, uint8_t v) { wait(4, 1); - writememb_common(a, v); + writememb_common(s + a, v); } -/* Writes a word from the memory and accounts for memory transfer cycles to - subtract from the cycles to use for adding to the prefetch queue. */ +/* Writes a word to the memory and advances the BIU. */ static void writememw(uint32_t s, uint32_t a, uint16_t v) { @@ -318,25 +444,50 @@ writememw(uint32_t s, uint32_t a, uint16_t v) } +static void +writemem(uint32_t s, uint16_t v) +{ + if (opcode & 1) + return writememw(s, cpu_state.eaaddr, v); + else + return writememb(s, cpu_state.eaaddr, (uint8_t) (v & 0xff)); +} + + +static void +writememl(uint32_t s, uint32_t a, uint32_t v) +{ + writememw(s, a, v & 0xffff); + writememw(s, a + 2, v >> 16); +} + + +static void +writememq(uint32_t s, uint32_t a, uint64_t v) +{ + writememl(s, a, v & 0xffffffff); + writememl(s, a + 4, v >> 32); +} + + static void pfq_write(void) { uint16_t tempw; - /* On 8086 and even IP, fetch *TWO* bytes at once. */ - if (pfq_pos < pfq_size) { - /* If we're filling the last byte of the prefetch queue, do *NOT* - read more than one byte even on the 8086. */ - if (is8086 && !(pfq_ip & 1) && !(pfq_pos & 1)) { - tempw = readmemwf(pfq_ip); - *(uint16_t *) &(pfq[pfq_pos]) = tempw; - pfq_ip += 2; - pfq_pos += 2; - } else { - pfq[pfq_pos] = readmembf(pfq_ip); - pfq_ip++; - pfq_pos++; - } + if (is8086 && (pfq_pos < (pfq_size - 1))) { + /* The 8086 fetches 2 bytes at a time, and only if there's at least 2 bytes + free in the queue. */ + tempw = readmemwf(pfq_ip); + *(uint16_t *) &(pfq[pfq_pos]) = tempw; + pfq_ip += 2; + pfq_pos += 2; + } else if (!is8086 && (pfq_pos < pfq_size)) { + /* The 8088 fetches 1 byte at a time, and only if there's at least 1 byte + free in the queue. */ + pfq[pfq_pos] = readmembf(pfq_ip); + pfq_ip++; + pfq_pos++; } } @@ -350,7 +501,7 @@ pfq_read(void) for (i = 0; i < (pfq_size - 1); i++) pfq[i] = pfq[i + 1]; pfq_pos--; - cpu_state.pc++; + cpu_state.pc = (cpu_state.pc + 1) & 0xffff; return temp; } @@ -358,55 +509,73 @@ pfq_read(void) /* Fetches a byte from the prefetch queue, or from memory if the queue has been drained. */ static uint8_t -pfq_fetchb(void) +pfq_fetchb_common(void) { uint8_t temp; if (pfq_pos == 0) { - /* Extra cycles due to having to fetch on read. */ - wait(4 - (fetchcycles & 3), 1); - fetchcycles = 4; /* Reset prefetch queue internal position. */ pfq_ip = cpu_state.pc; /* Fill the queue. */ - pfq_write(); - } else - fetchcycles -= 4; + wait(4 - (biu_cycles & 3), 0); + } /* Fetch. */ temp = pfq_read(); - wait(1, 0); return temp; } +static uint8_t +pfq_fetchb(void) +{ + uint8_t ret; + + ret = pfq_fetchb_common(); + wait(1, 0); + return ret; +} + + /* Fetches a word from the prefetch queue, or from memory if the queue has been drained. */ static uint16_t pfq_fetchw(void) { - uint8_t temp = pfq_fetchb(); - return temp | (pfq_fetchb() << 8); + uint16_t temp; + + temp = pfq_fetchb_common(); + wait(1, 0); + temp |= (pfq_fetchb_common() << 8); + + return temp; +} + + +static uint16_t +pfq_fetch() +{ + if (opcode & 1) + return pfq_fetchw(); + else + return (uint16_t) pfq_fetchb(); } /* Adds bytes to the prefetch queue based on the instruction's cycle count. */ static void -pfq_add(int c) +pfq_add(int c, int add) { int d; - if (c < 0) + + if ((c <= 0) || (pfq_pos >= pfq_size)) return; - if (pfq_pos >= pfq_size) - return; - d = c + (fetchcycles & 3); - while ((d > 3) && (pfq_pos < pfq_size)) { - d -= 4; - pfq_write(); + + for (d = 0; d < c; d++) { + biu_cycles = (biu_cycles + 1) & 0x03; + if (prefetching && add && (biu_cycles == 0x00)) + pfq_write(); } - fetchcycles += c; - if (fetchcycles > 16) - fetchcycles = 16; } @@ -414,30 +583,22 @@ pfq_add(int c) static void pfq_clear() { - pfq_ip = cpu_state.pc; pfq_pos = 0; + prefetching = 0; +} + + +static void +set_ip(uint16_t new_ip) { + pfq_ip = cpu_state.pc = new_ip; + prefetching = 1; } /* Memory refresh read - called by reads and writes on DMA channel 0. */ void refreshread(void) { - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed > 4772728) - wait(8, 1); /* Insert extra wait states. */ - - /* Do the actual refresh stuff. */ - /* If there's no extra cycles left to consume, return. */ - if (!(fetchcycles & 3)) - return; - /* If the prefetch queue is full, return. */ - if (pfq_pos >= pfq_size) - return; - /* Subtract from 1 to 8 cycles. */ - wait(8 - (fetchcycles % 7), 1); - /* Write to the prefetch queue. */ - pfq_write(); - /* Add those cycles to fetchcycles. */ - fetchcycles += (4 - (fetchcycles & 3)); + refresh++; } @@ -473,10 +634,17 @@ makemod1table(void) opseg[1] = &cs; opseg[2] = &ss; opseg[3] = &ds; - _opseg[0] = &_es; - _opseg[1] = &_cs; - _opseg[2] = &_ss; - _opseg[3] = &_ds; + _opseg[0] = &cpu_state.seg_es; + _opseg[1] = &cpu_state.seg_cs; + _opseg[2] = &cpu_state.seg_ss; + _opseg[3] = &cpu_state.seg_ds; +} + + +static uint16_t +sign_extend(uint8_t data) +{ + return data + (data < 0x80 ? 0 : 0xff00); } @@ -492,46 +660,37 @@ do_mod_rm(void) if (cpu_mod == 3) return; - wait(3, 0); - - if (!cpu_mod && (cpu_rm == 6)) { - wait(2, 0); - cpu_state.eaaddr = pfq_fetchw(); - easeg = ds; + wait(1, 0); + if ((rmdat & 0xc7) == 0x06) { wait(1, 0); - } else { - switch (cpu_rm) { - case 0: - case 3: - wait(2, 0); - break; - case 1: - case 2: - wait(3, 0); - break; - } - - cpu_state.eaaddr = (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); - easeg = *mod1seg[cpu_rm]; - - switch (cpu_mod) { - case 1: - wait(4, 0); - cpu_state.eaaddr += (uint16_t) (int8_t) pfq_fetchb(); - break; - case 2: - wait(4, 0); - cpu_state.eaaddr += pfq_fetchw(); - break; - } - wait(2, 0); + cpu_state.eaaddr = pfq_fetchw(); + easeg = ovr_seg ? *ovr_seg : ds; + wait(1, 0); + return; + } else switch (cpu_rm) { + case 0: + case 3: + wait(2, 0); + break; + case 1: + case 2: + wait(3, 0); + break; + } + cpu_state.eaaddr = (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + easeg = ovr_seg ? *ovr_seg : *mod1seg[cpu_rm]; + switch (rmdat & 0xc0) { + case 0x40: + wait(3, 0); + cpu_state.eaaddr += sign_extend(pfq_fetchb()); + break; + case 0x80: + wait(3, 0); + cpu_state.eaaddr += pfq_fetchw(); + break; } - cpu_state.eaaddr &= 0xffff; - cpu_state.last_ea = cpu_state.eaaddr; - - if (ovr_seg) - easeg = *ovr_seg; + wait(2, 0); } @@ -547,9 +706,8 @@ do_mod_rm(void) static uint8_t geteab(void) { - if (cpu_mod == 3) { + if (cpu_mod == 3) return (getr8(cpu_rm)); - } return readmemb(easeg + cpu_state.eaaddr); } @@ -561,10 +719,37 @@ geteaw(void) { if (cpu_mod == 3) return cpu_state.regs[cpu_rm].w; + return readmemw(easeg, cpu_state.eaaddr); } +/* Neede for 8087 - memory only. */ +static uint32_t +geteal(void) +{ + if (cpu_mod == 3) { + fatal("808x register geteal()\n"); + return 0xffffffff; + } + + return readmeml(easeg, cpu_state.eaaddr); +} + + +/* Neede for 8087 - memory only. */ +static uint64_t +geteaq(void) +{ + if (cpu_mod == 3) { + fatal("808x register geteaq()\n"); + return 0xffffffff; + } + + return readmemq(easeg, cpu_state.eaaddr); +} + + static void read_ea(int memory_only, int bits) { @@ -587,10 +772,11 @@ read_ea(int memory_only, int bits) static void read_ea2(int bits) { + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; if (bits == 16) - cpu_data = readmemw(easeg, (cpu_state.eaaddr + 2) & 0xffff); + cpu_data = readmemw(easeg, cpu_state.eaaddr); else - cpu_data = readmemb(easeg + ((cpu_state.eaaddr + 2) & 0xffff)); + cpu_data = readmemb(easeg + cpu_state.eaaddr); } @@ -601,7 +787,7 @@ seteab(uint8_t val) if (cpu_mod == 3) { setr8(cpu_rm, val); } else - writememb(easeg + cpu_state.eaaddr, val); + writememb(easeg, cpu_state.eaaddr, val); } @@ -615,29 +801,50 @@ seteaw(uint16_t val) writememw(easeg, cpu_state.eaaddr, val); } -/* Prepare the ZNP table needed to speed up the setting of the Z, N, and P flags. */ + +static void +seteal(uint32_t val) +{ + if (cpu_mod == 3) { + fatal("808x register seteal()\n"); + return; + } else + writememl(easeg, cpu_state.eaaddr, val); +} + + +static void +seteaq(uint64_t val) +{ + if (cpu_mod == 3) { + fatal("808x register seteaq()\n"); + return; + } else + writememq(easeg, cpu_state.eaaddr, val); +} + + +/* Leave out the 686 stuff as it's not needed and + complicates compiling. */ +#define FPU_8087 +#define tempc tempc_fpu +#include "x87.h" +#include "x87_ops.h" +#undef tempc +#undef FPU_8087 + + +/* Prepare the ZNP table needed to speed up the setting of the Z, N, and P cpu_state.flags. */ static void makeznptable(void) { - int c, d; + int c, d, e; for (c = 0; c < 256; c++) { d = 0; - if (c & 1) - d++; - if (c & 2) - d++; - if (c & 4) - d++; - if (c & 8) - d++; - if (c & 16) - d++; - if (c & 32) - d++; - if (c & 64) - d++; - if (c & 128) - d++; + for (e = 0; e < 8; e++) { + if (c & (1 << e)) + d++; + } if (d & 1) znptable8[c] = 0; else @@ -654,22 +861,10 @@ makeznptable(void) for (c = 0; c < 65536; c++) { d = 0; - if (c & 1) - d++; - if (c & 2) - d++; - if (c & 4) - d++; - if (c & 8) - d++; - if (c & 16) - d++; - if (c & 32) - d++; - if (c & 64) - d++; - if (c & 128) - d++; + for (e = 0; e < 8; e++) { + if (c & (1 << e)) + d++; + } if (d & 1) znptable16[c] = 0; else @@ -692,6 +887,14 @@ makeznptable(void) static void reset_common(int hard) { + biu_cycles = 0; + in_rep = 0; + in_lock = 0; + completed = 1; + repeating = 0; + clear_lock = 0; + refresh = 0; + if (hard) { #ifdef ENABLE_808X_LOG x808x_log("x86 reset\n"); @@ -710,7 +913,7 @@ reset_common(int hard) cpu_cache_int_enabled = 0; cpu_update_waitstates(); cr4 = 0; - eflags = 0; + cpu_state.eflags = 0; cgate32 = 0; if (AT) { loadcs(0xF000); @@ -718,15 +921,17 @@ reset_common(int hard) rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; } else { loadcs(0xFFFF); - cpu_state.pc=0; + cpu_state.pc = 0; rammask = 0xfffff; } idt.base = 0; idt.limit = is386 ? 0x03FF : 0xFFFF; - flags = 2; + cpu_state.flags = 2; trap = 0; ovr_seg = NULL; - in_lock = halt = 0; + in_lock = 0; + + EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0; if (hard) { makeznptable(); @@ -735,19 +940,21 @@ reset_common(int hard) resetmcr(); pfq_clear(); cpu_set_edx(); - EAX = 0; - ESP = 0; mmu_perm = 4; pfq_size = (is8086) ? 6 : 4; } - x86seg_reset(); #ifdef USE_DYNAREC if (hard) codegen_reset(); #endif + if (!hard) + flushmmucache(); x86_was_reset = 1; - port_92_clear_reset(); + cpu_alt_reset = 0; + + prefetching = 1; + takeint = 0; } @@ -769,18 +976,11 @@ softresetx86(void) /* Pushes a word to the stack. */ static void -push_ex(uint16_t val) -{ - writememw(ss, (SP & 0xFFFF), val); - cpu_state.last_ea = SP; -} - - -static void -push(uint16_t val) +push(uint16_t *val) { SP -= 2; - push_ex(val); + cpu_state.eaaddr = (SP & 0xffff); + writememw(ss, cpu_state.eaaddr, *val); } @@ -788,12 +988,9 @@ push(uint16_t val) static uint16_t pop(void) { - uint16_t tempw; - - tempw = readmemw(ss, SP); + cpu_state.eaaddr = (SP & 0xffff); SP += 2; - cpu_state.last_ea = SP; - return tempw; + return readmemw(ss, cpu_state.eaaddr); } @@ -805,133 +1002,146 @@ access(int num, int bits) case 67: case 69: case 71: case 72: default: break; - case 1: case 6: case 8: case 9: - case 17: case 20: case 21: case 24: - case 28: case 55: case 56: - wait(1 + (cycles % 3), 0); + case 1: case 6: case 7: case 8: + case 9: case 17: case 20: case 21: + case 24: case 28: case 47: case 48: + case 49: case 50: case 51: case 55: + case 56: case 62: case 66: case 68: + wait(1, 0); break; - case 2: case 15: case 22: case 23: - case 25: case 26: case 46: case 53: - wait(2 + (cycles % 3), 0); + case 3: case 11: case 15: case 22: + case 23: case 25: case 26: case 35: + case 44: case 45: case 46: case 52: + case 53: case 54: + wait(2, 0); break; - case 3: case 44: case 45: case 52: - case 54: - wait(2 + (cycles & 1), 0); + case 16: case 18: case 19: case 27: + case 32: case 37: case 42: + wait(3, 0); break; - case 4: - wait(5 + (cycles & 1), 0); + case 10: case 12: case 13: case 14: + case 29: case 30: case 33: case 34: + case 39: case 41: case 60: + wait(4, 0); + break; + case 4: case 70: + wait(5, 0); + break; + case 31: case 38: case 40: + wait(6, 0); break; case 5: if (opcode == 0xcc) - wait(7 + (cycles % 3), 0); + wait(7, 0); else - wait(4 + (cycles & 1), 0); - break; - case 7: case 47: case 48: case 49: - case 50: case 51: - wait(1 + (cycles % 4), 0); - break; - case 10: case 11: case 18: case 19: - case 43: - wait(3 + (cycles % 3), 0); - break; - case 12: case 13: case 14: case 29: - case 30: case 33: - wait(4 + (cycles % 3), 0); - break; - case 16: - if (!(opcode & 1) && (cycles & 1)) - wait(1, 0); - /* Fall through. */ - case 42: - wait(3 + (cycles & 1), 0); - break; - case 27: case 32: case 37: - wait(3, 0); - break; - case 31: - wait(6 + (cycles % 3), 0); - break; - case 34: case 39: case 41: case 60: - wait(4, 0); - break; - case 35: - wait(2, 0); + wait(4, 0); break; case 36: - wait(5 + (cycles & 1), 0); + wait(1, 0); + pfq_clear(); + wait (1, 0); if (cpu_mod != 3) wait(1, 0); + wait(3, 0); break; - case 38: - wait(5 + (cycles % 3), 0); - break; - case 40: - wait(6, 0); + case 43: + wait(2, 0); + pfq_clear(); + wait(1, 0); break; case 57: if (cpu_mod != 3) wait(2, 0); - wait(4 + (cycles & 1), 0); + wait(4, 0); break; case 58: if (cpu_mod != 3) wait(1, 0); - wait(4 + (cycles & 1), 0); + wait(4, 0); break; case 59: + wait(2, 0); + pfq_clear(); if (cpu_mod != 3) wait(1, 0); - wait(5 + (cycles & 1), 0); - break; - case 62: - wait(1, 0); + wait(3, 0); break; case 65: - wait(3 + (cycles & 1), 0); + wait(1, 0); + pfq_clear(); + wait(2, 0); if (cpu_mod != 3) wait(1, 0); break; - case 70: - wait(5, 0); - break; } } /* Calls an interrupt. */ static void -interrupt(uint16_t addr, int cli) +interrupt(uint16_t addr) { uint16_t old_cs, old_ip; uint16_t new_cs, new_ip; + uint16_t tempf; addr <<= 2; + cpu_state.eaaddr = addr; old_cs = CS; access(5, 16); - new_ip = readmemw(0, addr); + new_ip = readmemw(0, cpu_state.eaaddr); wait(1, 0); + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; access(6, 16); - new_cs = readmemw(0, (addr + 2) & 0xffff); + new_cs = readmemw(0, cpu_state.eaaddr); + pfq_clear(); access(39, 16); - push(flags & 0x0fd7); - if (cli) - flags &= ~I_FLAG; - flags &= ~T_FLAG; + tempf = cpu_state.flags & 0x0fd7; + push(&tempf); + cpu_state.flags &= ~(I_FLAG | T_FLAG); access(40, 16); - push(old_cs); + push(&old_cs); old_ip = cpu_state.pc; loadcs(new_cs); access(68, 16); - cpu_state.pc = new_ip; + set_ip(new_ip); access(41, 16); - push(old_ip); - pfq_clear(); + push(&old_ip); +} + + +static void +check_interrupts(void) +{ + int temp; + + if (irq_pending()) { + if ((cpu_state.flags & T_FLAG) && !noint) { + interrupt(1); + return; + } + if (nmi && nmi_enable && nmi_mask) { + nmi_enable = 0; + interrupt(2); + return; + } + temp = picinterrupt(); + if (temp != -1) { + repeating = 0; + completed = 1; + ovr_seg = NULL; + in_lock = 0; + clear_lock = 0; + ovr_seg = NULL; + wait(9, 0); + interrupt((uint16_t) (temp & 0xffff)); + } + } } static int -rep_action(int *completed, int *repeating, int in_rep, int bits) +rep_action(int bits) { uint16_t t; @@ -939,22 +1149,22 @@ rep_action(int *completed, int *repeating, int in_rep, int bits) return 0; wait(2, 0); t = CX; - if (irq_pending()) { + if (irq_pending() && (repeating != 0)) { access(71, bits); pfq_clear(); - cpu_state.pc = cpu_state.pc - 2; + set_ip(cpu_state.pc - 2); t = 0; } if (t == 0) { wait(1, 0); - *completed = 1; - *repeating = 0; + completed = 1; + repeating = 0; return 1; } --CX; - *completed = 0; + completed = 0; wait(2, 0); - if (!*repeating) + if (!repeating) wait(2, 0); return 0; } @@ -965,21 +1175,14 @@ jump(uint16_t delta) { uint16_t old_ip; access(67, 8); + pfq_clear(); wait(5, 0); old_ip = cpu_state.pc; - cpu_state.pc = (cpu_state.pc + delta) & 0xffff; - pfq_clear(); + set_ip((cpu_state.pc + delta) & 0xffff); return old_ip; } -static uint16_t -sign_extend(uint8_t data) -{ - return data + (data < 0x80 ? 0 : 0xff00); -} - - static void jump_short(void) { @@ -1011,21 +1214,21 @@ jcc(uint8_t opcode, int cond) static void set_cf(int cond) { - flags = (flags & ~C_FLAG) | (cond ? C_FLAG : 0); + cpu_state.flags = (cpu_state.flags & ~C_FLAG) | (cond ? C_FLAG : 0); } static void set_if(int cond) { - flags = (flags & ~I_FLAG) | (cond ? I_FLAG : 0); + cpu_state.flags = (cpu_state.flags & ~I_FLAG) | (cond ? I_FLAG : 0); } static void set_df(int cond) { - flags = (flags & ~D_FLAG) | (cond ? D_FLAG : 0); + cpu_state.flags = (cpu_state.flags & ~D_FLAG) | (cond ? D_FLAG : 0); } @@ -1033,7 +1236,7 @@ static void bitwise(int bits, uint16_t data) { cpu_data = data; - flags &= ~(C_FLAG | A_FLAG | V_FLAG); + cpu_state.flags &= ~(C_FLAG | A_FLAG | V_FLAG); set_pzs(bits); } @@ -1050,7 +1253,7 @@ test(int bits, uint16_t dest, uint16_t src) static void set_of(int of) { - flags = (flags & ~0x800) | (of ? 0x800 : 0); + cpu_state.flags = (cpu_state.flags & ~0x800) | (of ? 0x800 : 0); } @@ -1081,7 +1284,7 @@ set_of_sub(int bits) static void set_af(int af) { - flags = (flags & ~0x10) | (af ? 0x10 : 0); + cpu_state.flags = (cpu_state.flags & ~0x10) | (af ? 0x10 : 0); } @@ -1111,8 +1314,8 @@ add(int bits) /* Anything - FF with carry on is basically anything + 0x100: value stays unchanged but carry goes on. */ - if ((cpu_alu_op == 2) && !(cpu_src & size_mask) && (flags & C_FLAG)) - flags |= C_FLAG; + if ((cpu_alu_op == 2) && !(cpu_src & size_mask) && (cpu_state.flags & C_FLAG)) + cpu_state.flags |= C_FLAG; else set_cf((cpu_src & size_mask) > (cpu_data & size_mask)); } @@ -1129,8 +1332,8 @@ sub(int bits) /* Anything - FF with carry on is basically anything - 0x100: value stays unchanged but carry goes on. */ - if ((cpu_alu_op == 3) && !(cpu_src & size_mask) && (flags & C_FLAG)) - flags |= C_FLAG; + if ((cpu_alu_op == 3) && !(cpu_src & size_mask) && (cpu_state.flags & C_FLAG)) + cpu_state.flags |= C_FLAG; else set_cf((cpu_src & size_mask) > (cpu_dest & size_mask)); } @@ -1144,14 +1347,14 @@ alu_op(int bits) bitwise(bits, (cpu_dest | cpu_src)); break; case 2: - if (flags & C_FLAG) + if (cpu_state.flags & C_FLAG) cpu_src++; /* Fall through. */ case 0: add(bits); break; case 3: - if (flags & C_FLAG) + if (cpu_state.flags & C_FLAG) cpu_src++; /* Fall through. */ case 5: case 7: @@ -1170,7 +1373,7 @@ alu_op(int bits) static void set_sf(int bits) { - flags = (flags & ~0x80) | (top_bit(cpu_data, bits) ? 0x80 : 0); + cpu_state.flags = (cpu_state.flags & ~0x80) | (top_bit(cpu_data, bits) ? 0x80 : 0); } @@ -1195,7 +1398,7 @@ set_pf(void) 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4}; - flags = (flags & ~4) | table[cpu_data & 0xff]; + cpu_state.flags = (cpu_state.flags & ~4) | table[cpu_data & 0xff]; } @@ -1256,7 +1459,7 @@ mul(uint16_t a, uint16_t b) add(bit_count); c = cpu_data & size_mask; wait(1, 0); - carry = !!(flags & C_FLAG); + carry = !!(cpu_state.flags & C_FLAG); } r = (c >> 1) + (carry ? high_bit : 0); carry = (c & 1) != 0; @@ -1292,7 +1495,7 @@ set_zf(int bits) { int size_mask = (1 << bits) - 1; - flags = (flags & ~0x40) | (((cpu_data & size_mask) == 0) ? 0x40 : 0); + cpu_state.flags = (cpu_state.flags & ~0x40) | (((cpu_data & size_mask) == 0) ? 0x40 : 0); } @@ -1315,8 +1518,9 @@ set_co_mul(int carry) } +/* Was div(), renamed to avoid conflicts with stdlib div(). */ static int -div(uint16_t l, uint16_t h) +x86_div(uint16_t l, uint16_t h) { int b, bit_count = 8; int negative = 0; @@ -1358,7 +1562,7 @@ div(uint16_t l, uint16_t h) if (h >= cpu_src) { if (opcode != 0xd4) wait(1, 0); - interrupt(0, 1); + interrupt(0); return 0; } if (opcode != 0xd4) @@ -1394,7 +1598,7 @@ div(uint16_t l, uint16_t h) if (top_bit(l, bit_count)) { if (cpu_mod == 3) wait(1, 0); - interrupt(0, 1); + interrupt(0); return 0; } wait(7, 0); @@ -1418,31 +1622,40 @@ div(uint16_t l, uint16_t h) } +static uint16_t +string_increment(int bits) +{ + int d = bits >> 3; + if (cpu_state.flags & D_FLAG) + cpu_state.eaaddr -= d; + else + cpu_state.eaaddr += d; + cpu_state.eaaddr &= 0xffff; + return cpu_state.eaaddr; +} + + static void lods(int bits) { + cpu_state.eaaddr = SI; if (bits == 16) - cpu_data = readmemw((ovr_seg ? *ovr_seg : ds), SI); + cpu_data = readmemw((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); else - cpu_data = readmemb((ovr_seg ? *ovr_seg : ds) + SI); - if (flags & D_FLAG) - SI -= (bits >> 3); - else - SI += (bits >> 3); + cpu_data = readmemb((ovr_seg ? *ovr_seg : ds) + cpu_state.eaaddr); + SI = string_increment(bits); } static void stos(int bits) { + cpu_state.eaaddr = DI; if (bits == 16) - writememw(es, DI, cpu_data); + writememw(es, cpu_state.eaaddr, cpu_data); else - writememb(es + DI, (uint8_t) (cpu_data & 0xff)); - if (flags & D_FLAG) - DI -= (bits >> 3); - else - DI += (bits >> 3); + writememb(es, cpu_state.eaaddr, (uint8_t) (cpu_data & 0xff)); + DI = string_increment(bits); } @@ -1479,6 +1692,57 @@ clear_ca(void) } +static uint16_t +get_ea(void) +{ + if (opcode & 1) + return geteaw(); + else + return (uint16_t) geteab(); +} + + +static uint16_t +get_reg(uint8_t reg) +{ + if (opcode & 1) + return cpu_state.regs[reg].w; + else + return (uint16_t) getr8(reg); +} + + +static void +set_ea(uint16_t val) +{ + if (opcode & 1) + seteaw(val); + else + seteab((uint8_t) (val & 0xff)); +} + + +static void +set_reg(uint8_t reg, uint16_t val) +{ + if (opcode & 1) + cpu_state.regs[reg].w = val; + else + setr8(reg, (uint8_t) (val & 0xff)); +} + + +static void +cpu_data_opff_rm(void) { + if (!(opcode & 1)) { + if (cpu_mod != 3) + cpu_data |= 0xff00; + else + cpu_data = cpu_state.regs[cpu_rm].w; + } +} + + /* Executes instructions up to the specified number of cycles. */ void execx86(int cycs) @@ -1486,47 +1750,39 @@ execx86(int cycs) uint8_t temp = 0, temp2; uint16_t addr, tempw; uint16_t new_cs, new_ip; - int bits, completed; - int in_rep, repeating; - int oldc; + int bits; cycles += cycs; while (cycles > 0) { - timer_start_period(cycles * xt_cpu_multi); - cpu_state.oldpc = cpu_state.pc; - in_rep = repeating = 0; - completed = 0; - -opcodestart: - if (halt) { - wait(2, 0); - goto on_halt; - } + clock_start(); if (!repeating) { + cpu_state.oldpc = cpu_state.pc; opcode = pfq_fetchb(); - oldc = flags & C_FLAG; - trap = flags & T_FLAG; + oldc = cpu_state.flags & C_FLAG; + if (clear_lock) { + in_lock = 0; + clear_lock = 0; + } wait(1, 0); - - /* if (!in_rep && !ovr_seg && (CS < 0xf000)) - pclog("%04X:%04X %02X\n", CS, (cpu_state.pc - 1) & 0xFFFF, opcode); */ } + completed = 1; switch (opcode) { case 0x06: case 0x0E: case 0x16: case 0x1E: /* PUSH seg */ access(29, 16); - push(_opseg[(opcode >> 3) & 0x03]->seg); + push(&(_opseg[(opcode >> 3) & 0x03]->seg)); break; case 0x07: case 0x0F: case 0x17: case 0x1F: /* POP seg */ access(22, 16); if (opcode == 0x0F) { loadcs(pop()); - pfq_clear(); + pfq_pos = 0; } else loadseg(pop(), _opseg[(opcode >> 3) & 0x03]); wait(1, 0); + /* All POP segment instructions suppress interrupts for one instruction. */ noint = 1; break; @@ -1536,7 +1792,8 @@ opcodestart: case 0x3E: /*DS:*/ wait(1, 0); ovr_seg = opseg[(opcode >> 3) & 0x03]; - goto opcodestart; + completed = 0; + break; case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: @@ -1550,16 +1807,13 @@ opcodestart: bits = 8 << (opcode & 1); do_mod_rm(); access(46, bits); - if (opcode & 1) - tempw = geteaw(); - else - tempw = geteab(); + tempw = get_ea(); cpu_alu_op = (opcode >> 3) & 7; if ((opcode & 2) == 0) { cpu_dest = tempw; - cpu_src = (opcode & 1) ? cpu_state.regs[cpu_reg].w : getr8(cpu_reg); + cpu_src = get_reg(cpu_reg); } else { - cpu_dest = (opcode & 1) ? cpu_state.regs[cpu_reg].w : getr8(cpu_reg); + cpu_dest = get_reg(cpu_reg); cpu_src = tempw; } if (cpu_mod != 3) @@ -1569,17 +1823,11 @@ opcodestart: if (cpu_alu_op != 7) { if ((opcode & 2) == 0) { access(10, bits); - if (opcode & 1) - seteaw(cpu_data); - else - seteab((uint8_t) (cpu_data & 0xff)); + set_ea(cpu_data); if (cpu_mod == 3) wait(1, 0); } else { - if (opcode & 1) - cpu_state.regs[cpu_reg].w = cpu_data; - else - setr8(cpu_reg, (uint8_t) (cpu_data & 0xff)); + set_reg(cpu_reg, cpu_data); wait(1, 0); } } else @@ -1593,35 +1841,26 @@ opcodestart: /* alu A, imm */ bits = 8 << (opcode & 1); wait(1, 0); - if (opcode & 1) { - cpu_data = pfq_fetchw(); - cpu_dest = AX; - } else { - cpu_data = pfq_fetchb(); - cpu_dest = AL; - } + cpu_data = pfq_fetch(); + cpu_dest = get_reg(0); /* AX/AL */ cpu_src = cpu_data; cpu_alu_op = (opcode >> 3) & 7; alu_op(bits); - if (cpu_alu_op != 7) { - if (opcode & 1) - AX = cpu_data; - else - AL = (uint8_t) (cpu_data & 0xff); - } + if (cpu_alu_op != 7) + set_reg(0, cpu_data); wait(1, 0); break; case 0x27: /*DAA*/ wait(1, 0); - if ((flags & A_FLAG) || (AL & 0x0f) > 9) { + if ((cpu_state.flags & A_FLAG) || (AL & 0x0f) > 9) { cpu_data = AL + 6; AL = (uint8_t) cpu_data; set_af(1); if ((cpu_data & 0x100) != 0) set_cf(1); } - if ((flags & C_FLAG) || AL > 0x9f) { + if ((cpu_state.flags & C_FLAG) || AL > 0x9f) { AL += 0x60; set_cf(1); } @@ -1630,14 +1869,14 @@ opcodestart: case 0x2F: /*DAS*/ wait(1, 0); temp = AL; - if ((flags & A_FLAG) || ((AL & 0xf) > 9)) { + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { cpu_data = AL - 6; AL = (uint8_t) cpu_data; set_af(1); if ((cpu_data & 0x100) != 0) set_cf(1); } - if ((flags & C_FLAG) || temp > 0x9f) { + if ((cpu_state.flags & C_FLAG) || temp > 0x9f) { AL -= 0x60; set_cf(1); } @@ -1645,7 +1884,7 @@ opcodestart: break; case 0x37: /*AAA*/ wait(1, 0); - if ((flags & A_FLAG) || ((AL & 0xf) > 9)) { + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { AL += 6; ++AH; set_ca(); @@ -1657,7 +1896,7 @@ opcodestart: break; case 0x3F: /*AAS*/ wait(1, 0); - if ((flags & A_FLAG) || ((AL & 0xf) > 9)) { + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { AL -= 6; --AH; set_ca(); @@ -1692,11 +1931,7 @@ opcodestart: case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ case 0x54: case 0x55: case 0x56: case 0x57: access(30, 16); - if (opcode == 0x54) { - SP -= 2; - push_ex(cpu_state.regs[opcode & 0x07].w); - } else - push(cpu_state.regs[opcode & 0x07].w); + push(&(cpu_state.regs[opcode & 0x07].w)); break; case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ case 0x5C: case 0x5D: case 0x5E: case 0x5F: @@ -1709,53 +1944,53 @@ opcodestart: case 0x70: /*JO*/ case 0x61: /*JNO alias*/ case 0x71: /*JNO*/ - jcc(opcode, flags & V_FLAG); + jcc(opcode, cpu_state.flags & V_FLAG); break; case 0x62: /*JB alias*/ case 0x72: /*JB*/ case 0x63: /*JNB alias*/ case 0x73: /*JNB*/ - jcc(opcode, flags & C_FLAG); + jcc(opcode, cpu_state.flags & C_FLAG); break; case 0x64: /*JE alias*/ case 0x74: /*JE*/ case 0x65: /*JNE alias*/ case 0x75: /*JNE*/ - jcc(opcode, flags & Z_FLAG); + jcc(opcode, cpu_state.flags & Z_FLAG); break; case 0x66: /*JBE alias*/ case 0x76: /*JBE*/ case 0x67: /*JNBE alias*/ case 0x77: /*JNBE*/ - jcc(opcode, flags & (C_FLAG | Z_FLAG)); + jcc(opcode, cpu_state.flags & (C_FLAG | Z_FLAG)); break; case 0x68: /*JS alias*/ case 0x78: /*JS*/ case 0x69: /*JNS alias*/ case 0x79: /*JNS*/ - jcc(opcode, flags & N_FLAG); + jcc(opcode, cpu_state.flags & N_FLAG); break; case 0x6A: /*JP alias*/ case 0x7A: /*JP*/ case 0x6B: /*JNP alias*/ case 0x7B: /*JNP*/ - jcc(opcode, flags & P_FLAG); + jcc(opcode, cpu_state.flags & P_FLAG); break; case 0x6C: /*JL alias*/ case 0x7C: /*JL*/ case 0x6D: /*JNL alias*/ case 0x7D: /*JNL*/ - temp = (flags & N_FLAG) ? 1 : 0; - temp2 = (flags & V_FLAG) ? 1 : 0; + temp = (cpu_state.flags & N_FLAG) ? 1 : 0; + temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; jcc(opcode, temp ^ temp2); break; case 0x6E: /*JLE alias*/ case 0x7E: /*JLE*/ case 0x6F: /*JNLE alias*/ case 0x7F: /*JNLE*/ - temp = (flags & N_FLAG) ? 1 : 0; - temp2 = (flags & V_FLAG) ? 1 : 0; - jcc(opcode, (flags & Z_FLAG) || (temp != temp2)); + temp = (cpu_state.flags & N_FLAG) ? 1 : 0; + temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; + jcc(opcode, (cpu_state.flags & Z_FLAG) || (temp != temp2)); break; case 0x80: case 0x81: case 0x82: case 0x83: @@ -1763,10 +1998,7 @@ opcodestart: bits = 8 << (opcode & 1); do_mod_rm(); access(47, bits); - if (opcode & 1) - cpu_data = geteaw(); - else - cpu_data = geteab(); + cpu_data = get_ea(); cpu_dest = cpu_data; if (cpu_mod != 3) wait(3, 0); @@ -1787,10 +2019,7 @@ opcodestart: alu_op(bits); if (cpu_alu_op != 7) { access(11, bits); - if (opcode & 1) - seteaw(cpu_data); - else - seteab((uint8_t) (cpu_data & 0xff)); + set_ea(cpu_data); } else { if (cpu_mod != 3) wait(1, 0); @@ -1802,13 +2031,8 @@ opcodestart: bits = 8 << (opcode & 1); do_mod_rm(); access(48, bits); - if (opcode & 1) { - cpu_data = geteaw(); - test(bits, cpu_data, cpu_state.regs[cpu_reg].w); - } else { - cpu_data = geteab(); - test(bits, cpu_data, getr8(cpu_reg)); - } + cpu_data = get_ea(); + test(bits, cpu_data, get_reg(cpu_reg)); if (cpu_mod == 3) wait(2, 0); wait(2, 0); @@ -1818,21 +2042,12 @@ opcodestart: bits = 8 << (opcode & 1); do_mod_rm(); access(49, bits); - if (opcode & 1) { - cpu_data = geteaw(); - cpu_src = cpu_state.regs[cpu_reg].w; - cpu_state.regs[cpu_reg].w = cpu_data; - } else { - cpu_data = geteab(); - cpu_src = getr8(cpu_reg); - setr8(cpu_reg, cpu_data); - } + cpu_data = get_ea(); + cpu_src = get_reg(cpu_reg); + set_reg(cpu_reg, cpu_data); wait(3, 0); access(12, bits); - if (opcode & 1) - seteaw(cpu_src); - else - seteab((uint8_t) (cpu_src & 0xff)); + set_ea(cpu_src); break; case 0x88: case 0x89: @@ -1841,20 +2056,14 @@ opcodestart: do_mod_rm(); wait(1, 0); access(13, bits); - if (opcode & 1) - seteaw(cpu_state.regs[cpu_reg].w); - else - seteab(getr8((uint8_t) (cpu_reg & 0xff))); + set_ea(get_reg(cpu_reg)); break; case 0x8A: case 0x8B: /* MOV reg, rm */ bits = 8 << (opcode & 1); do_mod_rm(); access(50, bits); - if (opcode & 1) - cpu_state.regs[cpu_reg].w = geteaw(); - else - setr8(cpu_reg, geteab()); + set_reg(cpu_reg, get_ea()); wait(1, 0); if (cpu_mod != 3) wait(2, 0); @@ -1865,25 +2074,12 @@ opcodestart: if (cpu_mod == 3) wait(1, 0); access(14, 16); - switch (rmdat & 0x38) { - case 0x00: /*ES*/ - seteaw(ES); - break; - case 0x08: /*CS*/ - seteaw(CS); - break; - case 0x18: /*DS*/ - seteaw(DS); - break; - case 0x10: /*SS*/ - seteaw(SS); - break; - } + seteaw(_opseg[(rmdat & 0x18) >> 3]->seg); break; case 0x8D: /*LEA*/ do_mod_rm(); - cpu_state.regs[cpu_reg].w = (cpu_mod == 3) ? cpu_state.last_ea : cpu_state.eaaddr; + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; wait(1, 0); if (cpu_mod != 3) wait(2, 0); @@ -1893,25 +2089,16 @@ opcodestart: do_mod_rm(); access(51, 16); tempw = geteaw(); - switch (rmdat & 0x38) { - case 0x00: /*ES*/ - loadseg(tempw, &_es); - break; - case 0x08: /*CS - 8088/8086 only*/ - loadcs(tempw); - pfq_clear(); - break; - case 0x18: /*DS*/ - loadseg(tempw, &_ds); - break; - case 0x10: /*SS*/ - loadseg(tempw, &_ss); - break; - } + if ((rmdat & 0x18) == 0x08) { + loadcs(tempw); + pfq_pos = 0; + } else + loadseg(tempw, _opseg[(rmdat & 0x18) >> 3]); wait(1, 0); if (cpu_mod != 3) wait(2, 0); - noint = 1; + if (((rmdat & 0x18) >> 3) == 2) + noint = 1; break; case 0x8F: /*POPW*/ @@ -1956,71 +2143,81 @@ opcodestart: new_ip = pfq_fetchw(); wait(1, 0); new_cs = pfq_fetchw(); + pfq_clear(); access(31, 16); - push(CS); + push(&(CS)); access(60, 16); cpu_state.oldpc = cpu_state.pc; loadcs(new_cs); - cpu_state.pc = new_ip; + set_ip(new_ip); access(32, 16); - push(cpu_state.oldpc); - pfq_clear(); + push((uint16_t *) &(cpu_state.oldpc)); break; case 0x9B: /*WAIT*/ - wait(4, 0); + if (!repeating) + wait(2, 0); + wait(5, 0); +#ifdef NO_HACK + if (irq_pending()) { + wait(7, 0); + check_interrupts(); + } else { + repeating = 1; + completed = 0; + clock_end(); + } +#else + wait(7, 0); + check_interrupts(); +#endif break; case 0x9C: /*PUSHF*/ access(33, 16); - push((flags & 0x0fd7) | 0xf000); + tempw = (cpu_state.flags & 0x0fd7) | 0xf000; + push(&tempw); break; case 0x9D: /*POPF*/ access(25, 16); - flags = pop() | 2; + cpu_state.flags = pop() | 2; wait(1, 0); break; case 0x9E: /*SAHF*/ wait(1, 0); - flags = (flags & 0xff02) | AH; + cpu_state.flags = (cpu_state.flags & 0xff02) | AH; wait(2, 0); break; case 0x9F: /*LAHF*/ wait(1, 0); - AH = flags & 0xd7; + AH = cpu_state.flags & 0xd7; break; case 0xA0: case 0xA1: /* MOV A, [iw] */ bits = 8 << (opcode & 1); wait(1, 0); - addr = pfq_fetchw(); + cpu_state.eaaddr = pfq_fetchw(); access(1, bits); - if (opcode & 1) - AX = readmemw((ovr_seg ? *ovr_seg : ds), addr); - else - AL = readmemb((ovr_seg ? *ovr_seg : ds) + addr); + set_reg(0, readmem((ovr_seg ? *ovr_seg : ds))); wait(1, 0); break; case 0xA2: case 0xA3: /* MOV [iw], A */ bits = 8 << (opcode & 1); wait(1, 0); - addr = pfq_fetchw(); + cpu_state.eaaddr = pfq_fetchw(); access(7, bits); - if (opcode & 1) - writememw((ovr_seg ? *ovr_seg : ds), addr, AX); - else - writememb((ovr_seg ? *ovr_seg : ds) + addr, AL); + writemem((ovr_seg ? *ovr_seg : ds), get_reg(0)); break; case 0xA4: case 0xA5: /* MOVS */ case 0xAC: case 0xAD: /* LODS */ bits = 8 << (opcode & 1); if (!repeating) { - wait(1 /*2*/, 0); + wait(1, 0); if ((opcode & 8) == 0 && in_rep != 0) wait(1, 0); } - if (rep_action(&completed, &repeating, in_rep, bits)) { + if (rep_action(bits)) { wait(1, 0); if ((opcode & 8) != 0) wait(1, 0); @@ -2034,10 +2231,7 @@ opcodestart: access(27, bits); stos(bits); } else { - if (opcode & 1) - AX = cpu_data; - else - AL = (uint8_t) (cpu_data & 0xff); + set_reg(0, cpu_data); if (in_rep != 0) wait(2, 0); } @@ -2048,24 +2242,22 @@ opcodestart: break; } repeating = 1; - timer_end_period(cycles * xt_cpu_multi); - goto opcodestart; + clock_end(); + break; case 0xA6: case 0xA7: /* CMPS */ case 0xAE: case 0xAF: /* SCAS */ bits = 8 << (opcode & 1); if (!repeating) wait(1, 0); - if (rep_action(&completed, &repeating, in_rep, bits)) { + if (rep_action(bits)) { wait(2, 0); break; } if (in_rep != 0) wait(1, 0); - if (opcode & 1) - cpu_dest = AX; - else - cpu_dest = AL; + wait(1, 0); + cpu_dest = get_reg(0); if ((opcode & 8) == 0) { access(21, bits); lods(bits); @@ -2073,14 +2265,9 @@ opcodestart: cpu_dest = cpu_data; } access(2, bits); - if (opcode & 1) - cpu_data = readmemw(es, DI); - else - cpu_data = readmemb(es + DI); - if (flags & D_FLAG) - DI -= (bits >> 3); - else - DI += (bits >> 3); + cpu_state.eaaddr = DI; + cpu_data = readmem(es); + DI = string_increment(bits); cpu_src = cpu_data; sub(bits); wait(2, 0); @@ -2088,37 +2275,32 @@ opcodestart: wait(3, 0); break; } - if ((!!(flags & Z_FLAG)) == (in_rep == 1)) { + if ((!!(cpu_state.flags & Z_FLAG)) == (in_rep == 1)) { + completed = 1; wait(4, 0); break; } repeating = 1; - timer_end_period(cycles * xt_cpu_multi); - goto opcodestart; + clock_end(); + break; case 0xA8: case 0xA9: /* TEST A, imm */ bits = 8 << (opcode & 1); wait(1, 0); - if (opcode & 1) { - cpu_data = pfq_fetchw(); - test(bits, AX, cpu_data); - } else { - cpu_data = pfq_fetchb(); - test(bits, AL, cpu_data); - } + cpu_data = pfq_fetch(); + test(bits, get_reg(0), cpu_data); wait(1, 0); break; case 0xAA: case 0xAB: /* STOS */ bits = 8 << (opcode & 1); if (!repeating) { - if (opcode & 1) - wait(1, 0); + wait(1, 0); if (in_rep != 0) wait(1, 0); } - if (rep_action(&completed, &repeating, in_rep, bits)) { + if (rep_action(bits)) { wait(1, 0); break; } @@ -2130,8 +2312,8 @@ opcodestart: break; } repeating = 1; - timer_end_period(cycles * xt_cpu_multi); - goto opcodestart; + clock_end(); + break; case 0xB0: case 0xB1: case 0xB2: case 0xB3: /*MOV cpu_reg,#8*/ case 0xB4: case 0xB5: case 0xB6: case 0xB7: @@ -2162,6 +2344,7 @@ opcodestart: } if ((opcode & 9) == 9) wait(1, 0); + pfq_clear(); access(26, bits); new_ip = pop(); wait(2, 0); @@ -2179,8 +2362,7 @@ opcodestart: } loadcs(new_cs); access(72, bits); - cpu_state.pc = new_ip; - pfq_clear(); + set_ip(new_ip); break; case 0xC4: case 0xC5: @@ -2188,11 +2370,12 @@ opcodestart: do_mod_rm(); bits = 16; access(52, bits); - cpu_state.regs[cpu_reg].w = readmemw(easeg, cpu_state.eaaddr); - tempw = readmemw(easeg, (cpu_state.eaaddr + 2) & 0xFFFF); - loadseg(tempw, (opcode & 0x01) ? &_ds : &_es); + read_ea(1, bits); + cpu_state.regs[cpu_reg].w = cpu_data; + access(57, bits); + read_ea2(bits); + loadseg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es); wait(1, 0); - noint = 1; break; case 0xC6: case 0xC7: @@ -2202,31 +2385,25 @@ opcodestart: wait(1, 0); if (cpu_mod != 3) wait(2, 0); - if (opcode & 1) - cpu_data = pfq_fetchw(); - else - cpu_data = pfq_fetchb(); + cpu_data = pfq_fetch(); if (cpu_mod == 3) wait(1, 0); access(16, bits); - if (opcode & 1) - seteaw(cpu_data); - else - seteab((uint8_t) (cpu_data & 0xff)); + set_ea(cpu_data); break; case 0xCC: /*INT 3*/ - interrupt(3, 1); + interrupt(3); break; case 0xCD: /*INT*/ wait(1, 0); - interrupt(pfq_fetchb(), 1); + interrupt(pfq_fetchb()); break; case 0xCE: /*INTO*/ wait(3, 0); - if (flags & V_FLAG) { + if (cpu_state.flags & V_FLAG) { wait(2, 0); - interrupt(4, 1); + interrupt(4); } break; @@ -2238,13 +2415,12 @@ opcodestart: new_cs = pop(); loadcs(new_cs); access(62, 8); - cpu_state.pc = new_ip; + set_ip(new_ip); access(45, 8); - flags = pop() | 2; + cpu_state.flags = pop() | 2; wait(5, 0); noint = 1; nmi_enable = 1; - pfq_clear(); break; case 0xD0: case 0xD1: case 0xD2: case 0xD3: @@ -2254,10 +2430,7 @@ opcodestart: if (cpu_mod == 3) wait(1, 0); access(53, bits); - if (opcode & 1) - cpu_data = geteaw(); - else - cpu_data = geteab(); + cpu_data = get_ea(); if ((opcode & 2) == 0) { cpu_src = 1; wait((cpu_mod != 3) ? 4 : 0, 0); @@ -2267,18 +2440,18 @@ opcodestart: } while (cpu_src != 0) { cpu_dest = cpu_data; - oldc = flags & C_FLAG; + oldc = cpu_state.flags & C_FLAG; switch (rmdat & 0x38) { case 0x00: /* ROL */ set_cf(top_bit(cpu_data, bits)); cpu_data <<= 1; - cpu_data |= ((flags & C_FLAG) ? 1 : 0); + cpu_data |= ((cpu_state.flags & C_FLAG) ? 1 : 0); set_of_rotate(bits); break; case 0x08: /* ROR */ set_cf((cpu_data & 1) != 0); cpu_data >>= 1; - if (flags & C_FLAG) + if (cpu_state.flags & C_FLAG) cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000); set_of_rotate(bits); break; @@ -2332,16 +2505,13 @@ opcodestart: --cpu_src; } access(17, bits); - if (opcode & 1) - seteaw(cpu_data); - else - seteab((uint8_t) (cpu_data & 0xff)); + set_ea(cpu_data); break; case 0xD4: /*AAM*/ wait(1, 0); cpu_src = pfq_fetchb(); - if (div(AL, 0)) + if (x86_div(AL, 0)) set_pzs(16); break; case 0xD5: /*AAD*/ @@ -2353,14 +2523,13 @@ opcodestart: break; case 0xD6: /*SALC*/ wait(1, 0); - AL = (flags & C_FLAG) ? 0xff : 0x00; + AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; wait(1, 0); break; case 0xD7: /*XLATB*/ - addr = BX + AL; - cpu_state.last_ea = addr; + cpu_state.eaaddr = (BX + AL) & 0xffff; access(4, 8); - AL = readmemb((ovr_seg ? *ovr_seg : ds) + addr); + AL = readmemb((ovr_seg ? *ovr_seg : ds) + cpu_state.eaaddr); wait(1, 0); break; @@ -2369,7 +2538,37 @@ opcodestart: /* esc i, r, rm */ do_mod_rm(); access(54, 16); - geteaw(); + tempw = cpu_state.pc; + if (!hasfpu) + geteaw(); + else switch(opcode) { + case 0xD8: + ops_fpu_8087_d8[(rmdat >> 3) & 0x1f]((uint32_t) rmdat); + break; + case 0xD9: + ops_fpu_8087_d9[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDA: + ops_fpu_8087_da[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDB: + ops_fpu_8087_db[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDC: + ops_fpu_8087_dc[(rmdat >> 3) & 0x1f]((uint32_t) rmdat); + break; + case 0xDD: + ops_fpu_8087_dd[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDE: + ops_fpu_8087_de[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDF: + ops_fpu_8087_df[rmdat & 0xff]((uint32_t) rmdat); + break; + } + cpu_state.pc = tempw; /* Do this as the x87 code advances it, which is needed on + the 286+ core, but not here. */ wait(1, 0); if (cpu_mod != 3) wait(2, 0); @@ -2386,11 +2585,11 @@ opcodestart: oldc = (CX != 0); switch (opcode) { case 0xE0: - if (flags & Z_FLAG) + if (cpu_state.flags & Z_FLAG) oldc = 0; break; case 0xE1: - if (!(flags & Z_FLAG)) + if (!(cpu_state.flags & Z_FLAG)) oldc = 0; break; } @@ -2409,6 +2608,7 @@ opcodestart: cpu_data = pfq_fetchb(); else cpu_data = DX; + cpu_state.eaaddr = cpu_data; if ((opcode & 2) == 0) { access(3, bits); if ((opcode & 1) && is8086 && !(cpu_data & 1)) { @@ -2417,7 +2617,7 @@ opcodestart: } else { AL = inb(cpu_data); if (opcode & 1) - AH = inb(temp + 1); + AH = inb(cpu_data + 1); wait(bits >> 1, 1); /* I/O access. */ } wait(1, 0); @@ -2442,8 +2642,7 @@ opcodestart: wait(1, 0); cpu_state.oldpc = jump_near(); access(34, 8); - push(cpu_state.oldpc); - pfq_clear(); + push((uint16_t *) &(cpu_state.oldpc)); break; case 0xE9: /*JMP rel 16*/ wait(1, 0); @@ -2456,58 +2655,61 @@ opcodestart: tempw = pfq_fetchw(); loadcs(tempw); access(70, 8); - cpu_state.pc = addr; pfq_clear(); + set_ip(addr); break; case 0xEB: /*JMP rel*/ wait(1, 0); cpu_data = (int8_t) pfq_fetchb(); jump_short(); wait(1, 0); - pfq_clear(); break; case 0xF0: case 0xF1: /*LOCK - F1 is alias*/ in_lock = 1; wait(1, 0); - goto opcodestart; + completed = 0; + break; case 0xF2: /*REPNE*/ case 0xF3: /*REPE*/ wait(1, 0); in_rep = (opcode == 0xf2 ? 1 : 2); - repeating = 0; completed = 0; - goto opcodestart; + break; case 0xF4: /*HLT*/ - halt = 1; - pfq_clear(); - wait(2, 0); + if (!repeating) { + wait(1, 0); + pfq_clear(); + } + wait(1, 0); + if (irq_pending()) { + wait(cycles & 1, 0); + check_interrupts(); + } else { + repeating = 1; + completed = 0; + clock_end(); + } break; case 0xF5: /*CMC*/ wait(1, 0); - flags ^= C_FLAG; + cpu_state.flags ^= C_FLAG; break; case 0xF6: case 0xF7: bits = 8 << (opcode & 1); do_mod_rm(); access(55, bits); - if (opcode & 1) - cpu_data = geteaw(); - else - cpu_data = geteab(); + cpu_data = get_ea(); switch (rmdat & 0x38) { case 0x00: case 0x08: /* TEST */ wait(2, 0); if (cpu_mod != 3) wait(1, 0); - if (opcode & 1) - cpu_src = pfq_fetchw(); - else - cpu_src = pfq_fetchb(); + cpu_src = pfq_fetch(); wait(1, 0); test(bits, cpu_data, cpu_src); if (cpu_mod != 3) @@ -2524,10 +2726,7 @@ opcodestart: sub(bits); } access(18, bits); - if (opcode & 1) - seteaw(cpu_data); - else - seteab((uint8_t) (cpu_data & 0xff)); + set_ea(cpu_data); break; case 0x20: /* MUL */ case 0x28: /* IMUL */ @@ -2537,13 +2736,16 @@ opcodestart: AX = cpu_data; DX = cpu_dest; cpu_data |= DX; - set_co_mul((DX != ((AX & 0x8000) == 0) || ((rmdat & 0x38) == 0x20) ? 0 : 0xffff)); + set_co_mul(DX != ((AX & 0x8000) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xffff)); } else { mul(AL, cpu_data); AL = (uint8_t) cpu_data; AH = (uint8_t) cpu_dest; - set_co_mul(AH != (((AL & 0x80) == 0) || ((rmdat & 0x38) == 0x20) ? 0 : 0xff)); + cpu_data |= AH; + set_co_mul(AH != ((AL & 0x80) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xff)); } + /* NOTE: When implementing the V20, care should be taken to not change + the zero flag. */ set_zf(bits); if (cpu_mod != 3) wait(1, 0); @@ -2553,7 +2755,7 @@ opcodestart: if (cpu_mod != 3) wait(1, 0); cpu_src = cpu_data; - if (div(AL, AH)) + if (x86_div(AL, AH)) wait(1, 0); break; } @@ -2597,29 +2799,22 @@ opcodestart: set_pzs(bits); wait(2, 0); access(19, bits); - if (opcode & 1) - seteaw(cpu_data); - else - seteab((uint8_t) (cpu_data & 0xff)); + set_ea(cpu_data); break; case 0x10: /* CALL rm */ - if (!(opcode & 1)) { - if (cpu_mod != 3) - cpu_data |= 0xff00; - else - cpu_data = cpu_state.regs[cpu_rm].w; - } + cpu_data_opff_rm(); access(63, bits); - wait(5, 0); + wait(1, 0); + pfq_clear(); + wait(4, 0); if (cpu_mod != 3) wait(1, 0); wait(1, 0); /* Wait. */ cpu_state.oldpc = cpu_state.pc; - cpu_state.pc = cpu_data; + set_ip(cpu_data); wait(2, 0); access(35, bits); - push(cpu_state.oldpc); - pfq_clear(); + push((uint16_t *) &(cpu_state.oldpc)); break; case 0x18: /* CALL rmd */ new_ip = cpu_data; @@ -2629,26 +2824,19 @@ opcodestart: cpu_data |= 0xff00; new_cs = cpu_data; access(36, bits); - push(CS); + push(&(CS)); access(64, bits); wait(4, 0); cpu_state.oldpc = cpu_state.pc; loadcs(new_cs); - cpu_state.pc = new_ip; + set_ip(new_ip); access(37, bits); - push(cpu_state.oldpc); - pfq_clear(); + push((uint16_t *) &(cpu_state.oldpc)); break; case 0x20: /* JMP rm */ - if (!(opcode & 1)) { - if (cpu_mod != 3) - cpu_data |= 0xff00; - else - cpu_data = cpu_state.regs[cpu_rm].w; - } + cpu_data_opff_rm(); access(65, bits); - cpu_state.pc = cpu_data; - pfq_clear(); + set_ip(cpu_data); break; case 0x28: /* JMP rmd */ new_ip = cpu_data; @@ -2659,18 +2847,14 @@ opcodestart: new_cs = cpu_data; loadcs(new_cs); access(66, bits); - cpu_state.pc = new_ip; - pfq_clear(); + set_ip(new_ip); break; case 0x30: /* PUSH rm */ case 0x38: if (cpu_mod != 3) wait(1, 0); access(38, bits); - if ((cpu_mod == 3) && (cpu_rm == 4)) - push(cpu_data - 2); - else - push(cpu_data); + push(&(cpu_data)); break; } break; @@ -2682,44 +2866,19 @@ opcodestart: break; } - cpu_state.pc &= 0xFFFF; - -on_halt: - if (ovr_seg) + if (completed) { + repeating = 0; ovr_seg = NULL; + in_rep = 0; + if (in_lock) + clear_lock = 1; + clock_end(); + check_interrupts(); - if (in_lock) - in_lock = 0; - - /* FIXME: Find out why this is needed. */ - if (((romset == ROM_IBMPC) && ((cs + cpu_state.pc) == 0xFE545)) || - ((romset == ROM_IBMPC82) && ((cs + cpu_state.pc) == 0xFE4A7))) { - /* You didn't seriously think I was going to emulate the cassette, did you? */ - CX = 1; - BX = 0x500; + if (noint) + noint = 0; } - timer_end_period(cycles * xt_cpu_multi); - - if (trap && (flags & T_FLAG) && !noint) { - halt = 0; - interrupt(1, 1); - } else if (nmi && nmi_enable && nmi_mask) { - halt = 0; - interrupt(2, 1); - nmi_enable = 0; - } else if (takeint && !noint) { - temp = picinterrupt(); - if (temp != 0xFF) { - halt = 0; - interrupt(temp, 1); - } - } - takeint = (flags & I_FLAG) && (pic.pend &~ pic.mask); - - if (noint) - noint = 0; - ins++; } } diff --git a/src/cpu/codegen_ops_misc.h b/src/cpu/codegen_ops_misc.h index d3039c81a..1752c4180 100644 --- a/src/cpu/codegen_ops_misc.h +++ b/src/cpu/codegen_ops_misc.h @@ -5,12 +5,12 @@ static uint32_t ropNOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32 static uint32_t ropCLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - CLEAR_BITS((uintptr_t)&flags, D_FLAG); + CLEAR_BITS((uintptr_t)&cpu_state.flags, D_FLAG); return op_pc; } static uint32_t ropSTD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { - SET_BITS((uintptr_t)&flags, D_FLAG); + SET_BITS((uintptr_t)&cpu_state.flags, D_FLAG); return op_pc; } @@ -18,14 +18,14 @@ static uint32_t ropCLI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32 { if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) return 0; - CLEAR_BITS((uintptr_t)&flags, I_FLAG); + CLEAR_BITS((uintptr_t)&cpu_state.flags, I_FLAG); return op_pc; } static uint32_t ropSTI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) return 0; - SET_BITS((uintptr_t)&flags, I_FLAG); + SET_BITS((uintptr_t)&cpu_state.flags, I_FLAG); return op_pc; } @@ -152,7 +152,7 @@ static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(-2); host_reg = LOAD_REG_IMM(op_pc + 1); - MEM_STORE_ADDR_EA_W(&_ss, host_reg); + MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); SP_MODIFY(-2); host_reg = LOAD_VAR_W((uintptr_t)&codegen_temp); @@ -168,7 +168,7 @@ static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint host_reg = LOAD_HOST_REG(host_reg); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(-2); - MEM_STORE_ADDR_EA_W(&_ss, host_reg); + MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); SP_MODIFY(-2); return op_pc + 1; } @@ -245,7 +245,7 @@ static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(-4); host_reg = LOAD_REG_IMM(op_pc + 1); - MEM_STORE_ADDR_EA_L(&_ss, host_reg); + MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg); SP_MODIFY(-4); host_reg = LOAD_VAR_L((uintptr_t)&codegen_temp); @@ -261,7 +261,7 @@ static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint host_reg = LOAD_HOST_REG(host_reg); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(-4); - MEM_STORE_ADDR_EA_L(&_ss, host_reg); + MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg); SP_MODIFY(-4); return op_pc + 1; } diff --git a/src/cpu/codegen_ops_mov.h b/src/cpu/codegen_ops_mov.h index cb4498343..fc4ec1637 100644 --- a/src/cpu/codegen_ops_mov.h +++ b/src/cpu/codegen_ops_mov.h @@ -588,16 +588,16 @@ static uint32_t ropMOV_seg_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, switch (fetchdat & 0x38) { case 0x00: /*ES*/ - LOAD_SEG(host_reg, &_es); + LOAD_SEG(host_reg, &cpu_state.seg_es); break; case 0x18: /*DS*/ - LOAD_SEG(host_reg, &_ds); + LOAD_SEG(host_reg, &cpu_state.seg_ds); break; case 0x20: /*FS*/ - LOAD_SEG(host_reg, &_fs); + LOAD_SEG(host_reg, &cpu_state.seg_fs); break; case 0x28: /*GS*/ - LOAD_SEG(host_reg, &_gs); + LOAD_SEG(host_reg, &cpu_state.seg_gs); break; } @@ -644,13 +644,13 @@ static uint32_t ropL ## seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u STORE_REG_TARGET_W_RELEASE(host_reg, dest_reg); \ } \ \ - if (&rseg == &_ss) \ + if (&rseg == &cpu_state.seg_ss) \ CPU_BLOCK_END(); /*Instruction might change stack size, so end block here*/ \ return op_pc + 1; \ } -ropLseg(DS, _ds) -ropLseg(ES, _es) -ropLseg(FS, _fs) -ropLseg(GS, _gs) -ropLseg(SS, _ss) +ropLseg(DS, cpu_state.seg_ds) +ropLseg(ES, cpu_state.seg_es) +ropLseg(FS, cpu_state.seg_fs) +ropLseg(GS, cpu_state.seg_gs) +ropLseg(SS, cpu_state.seg_ss) diff --git a/src/cpu/codegen_ops_stack.h b/src/cpu/codegen_ops_stack.h index 96b900273..288be2c6c 100644 --- a/src/cpu/codegen_ops_stack.h +++ b/src/cpu/codegen_ops_stack.h @@ -5,7 +5,7 @@ static uint32_t ropPUSH_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ui STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(-2); host_reg = LOAD_REG_W(opcode & 7); - MEM_STORE_ADDR_EA_W(&_ss, host_reg); + MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); SP_MODIFY(-2); return op_pc; @@ -17,7 +17,7 @@ static uint32_t ropPUSH_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, ui STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(-4); host_reg = LOAD_REG_L(opcode & 7); - MEM_STORE_ADDR_EA_L(&_ss, host_reg); + MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg); SP_MODIFY(-4); return op_pc; @@ -31,7 +31,7 @@ static uint32_t ropPUSH_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(-2); host_reg = LOAD_REG_IMM(imm); - MEM_STORE_ADDR_EA_W(&_ss, host_reg); + MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); SP_MODIFY(-2); return op_pc+2; @@ -44,7 +44,7 @@ static uint32_t ropPUSH_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32 STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(-4); host_reg = LOAD_REG_IMM(imm); - MEM_STORE_ADDR_EA_L(&_ss, host_reg); + MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg); SP_MODIFY(-4); return op_pc+4; @@ -61,7 +61,7 @@ static uint32_t ropPUSH_imm_b16(uint8_t opcode, uint32_t fetchdat, uint32_t op_3 STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(-2); host_reg = LOAD_REG_IMM(imm); - MEM_STORE_ADDR_EA_W(&_ss, host_reg); + MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); SP_MODIFY(-2); return op_pc+1; @@ -77,7 +77,7 @@ static uint32_t ropPUSH_imm_b32(uint8_t opcode, uint32_t fetchdat, uint32_t op_3 STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(-4); host_reg = LOAD_REG_IMM(imm); - MEM_STORE_ADDR_EA_L(&_ss, host_reg); + MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg); SP_MODIFY(-4); return op_pc+1; @@ -87,7 +87,7 @@ static uint32_t ropPOP_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin { STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); - MEM_LOAD_ADDR_EA_W(&_ss); + MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); SP_MODIFY(2); STORE_REG_TARGET_W_RELEASE(0, opcode & 7); @@ -97,7 +97,7 @@ static uint32_t ropPOP_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin { STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); - MEM_LOAD_ADDR_EA_L(&_ss); + MEM_LOAD_ADDR_EA_L(&cpu_state.seg_ss); SP_MODIFY(4); STORE_REG_TARGET_L_RELEASE(0, opcode & 7); @@ -108,7 +108,7 @@ static uint32_t ropRET_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin { STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); - MEM_LOAD_ADDR_EA_W(&_ss); + MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); SP_MODIFY(2); @@ -118,7 +118,7 @@ static uint32_t ropRET_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uin { STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); - MEM_LOAD_ADDR_EA_L(&_ss); + MEM_LOAD_ADDR_EA_L(&cpu_state.seg_ss); STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); SP_MODIFY(4); @@ -131,7 +131,7 @@ static uint32_t ropRET_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); - MEM_LOAD_ADDR_EA_W(&_ss); + MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); SP_MODIFY(2+offset); @@ -143,7 +143,7 @@ static uint32_t ropRET_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(0); - MEM_LOAD_ADDR_EA_L(&_ss); + MEM_LOAD_ADDR_EA_L(&cpu_state.seg_ss); STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); SP_MODIFY(4+offset); @@ -158,7 +158,7 @@ static uint32_t ropCALL_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(-2); host_reg = LOAD_REG_IMM(op_pc+2); - MEM_STORE_ADDR_EA_W(&_ss, host_reg); + MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); SP_MODIFY(-2); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, (op_pc+2+offset) & 0xffff); @@ -172,7 +172,7 @@ static uint32_t ropCALL_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_STACK_TO_EA(-4); host_reg = LOAD_REG_IMM(op_pc+4); - MEM_STORE_ADDR_EA_L(&_ss, host_reg); + MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg); SP_MODIFY(-4); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+4+offset); @@ -185,7 +185,7 @@ static uint32_t ropLEAVE_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_EBP_TO_EA(0); - MEM_LOAD_ADDR_EA_W(&_ss); + MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); host_reg = LOAD_REG_W(REG_BP); /*SP = BP + 2*/ ADD_HOST_REG_IMM_W(host_reg, 2); STORE_REG_TARGET_W_RELEASE(host_reg, REG_SP); @@ -199,7 +199,7 @@ static uint32_t ropLEAVE_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, u STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); LOAD_EBP_TO_EA(0); - MEM_LOAD_ADDR_EA_L(&_ss); + MEM_LOAD_ADDR_EA_L(&cpu_state.seg_ss); host_reg = LOAD_REG_L(REG_EBP); /*ESP = EBP + 4*/ ADD_HOST_REG_IMM(host_reg, 4); STORE_REG_TARGET_L_RELEASE(host_reg, REG_ESP); @@ -216,7 +216,7 @@ static uint32_t ropPUSH_ ## seg ## _16(uint8_t opcode, uint32_t fetchdat, uint32 STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ LOAD_STACK_TO_EA(-2); \ host_reg = LOAD_VAR_W((uintptr_t)&seg); \ - MEM_STORE_ADDR_EA_W(&_ss, host_reg); \ + MEM_STORE_ADDR_EA_W(&cpu_state.seg_ss, host_reg); \ SP_MODIFY(-2); \ \ return op_pc; \ @@ -228,7 +228,7 @@ static uint32_t ropPUSH_ ## seg ## _32(uint8_t opcode, uint32_t fetchdat, uint32 STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ LOAD_STACK_TO_EA(-4); \ host_reg = LOAD_VAR_W((uintptr_t)&seg); \ - MEM_STORE_ADDR_EA_L(&_ss, host_reg); \ + MEM_STORE_ADDR_EA_L(&cpu_state.seg_ss, host_reg); \ SP_MODIFY(-4); \ \ return op_pc; \ @@ -246,7 +246,7 @@ static uint32_t ropPOP_ ## seg ## _16(uint8_t opcode, uint32_t fetchdat, uint32_ { \ STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ LOAD_STACK_TO_EA(0); \ - MEM_LOAD_ADDR_EA_W(&_ss); \ + MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); \ LOAD_SEG(0, &rseg); \ SP_MODIFY(2); \ \ @@ -256,14 +256,14 @@ static uint32_t ropPOP_ ## seg ## _32(uint8_t opcode, uint32_t fetchdat, uint32_ { \ STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ LOAD_STACK_TO_EA(0); \ - MEM_LOAD_ADDR_EA_W(&_ss); \ + MEM_LOAD_ADDR_EA_W(&cpu_state.seg_ss); \ LOAD_SEG(0, &rseg); \ SP_MODIFY(4); \ \ return op_pc; \ } -ROP_POP_SEG(DS, _ds) -ROP_POP_SEG(ES, _es) -ROP_POP_SEG(FS, _fs) -ROP_POP_SEG(GS, _gs) +ROP_POP_SEG(DS, cpu_state.seg_ds) +ROP_POP_SEG(ES, cpu_state.seg_es) +ROP_POP_SEG(FS, cpu_state.seg_fs) +ROP_POP_SEG(GS, cpu_state.seg_gs) diff --git a/src/cpu/codegen_ops_x86-64.h b/src/cpu/codegen_ops_x86-64.h index de12f93d5..de6763561 100644 --- a/src/cpu/codegen_ops_x86-64.h +++ b/src/cpu/codegen_ops_x86-64.h @@ -647,7 +647,7 @@ static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u } if (mod1seg[rm] == &ss && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; } return op_ea_seg; } @@ -796,7 +796,7 @@ static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u addlong(stack_offset); } if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; } else { @@ -814,7 +814,7 @@ static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, u if (mod) { if (rm == 5 && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; if (mod == 1) { addbyte(0x67); /*LEA EAX, base_reg+imm8*/ @@ -857,14 +857,14 @@ static inline x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_sseg static inline void CHECK_SEG_READ(x86seg *seg) { /*Segments always valid in real/V86 mode*/ - if (!(cr0 & 1) || (eflags & VM_FLAG)) + if (!(cr0 & 1) || (cpu_state.eflags & VM_FLAG)) return; /*CS and SS must always be valid*/ - if (seg == &_cs || seg == &_ss) + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) return; if (seg->checked) return; - if (seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) return; if (IS_32_ADDR(&seg->base)) @@ -893,14 +893,14 @@ static inline void CHECK_SEG_READ(x86seg *seg) static inline void CHECK_SEG_WRITE(x86seg *seg) { /*Segments always valid in real/V86 mode*/ - if (!(cr0 & 1) || (eflags & VM_FLAG)) + if (!(cr0 & 1) || (cpu_state.eflags & VM_FLAG)) return; /*CS and SS must always be valid*/ - if (seg == &_cs || seg == &_ss) + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) return; if (seg->checked) return; - if (seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) return; if (IS_32_ADDR(&seg->base)) @@ -928,7 +928,7 @@ static inline void CHECK_SEG_WRITE(x86seg *seg) } static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) return; if (IS_32_ADDR(&seg->base)) @@ -967,7 +967,7 @@ static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1040,7 +1040,7 @@ static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) } static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1126,7 +1126,7 @@ static inline void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) } static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1204,7 +1204,7 @@ static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) } static inline void MEM_LOAD_ADDR_EA_Q(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1325,7 +1325,7 @@ static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) addbyte(8); host_reg = 8; } - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1409,7 +1409,7 @@ static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1500,7 +1500,7 @@ static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -1589,7 +1589,7 @@ static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -5270,7 +5270,7 @@ static inline void MEM_CHECK_WRITE(x86seg *seg) CHECK_SEG_WRITE(seg); - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -5321,7 +5321,7 @@ static inline void MEM_CHECK_WRITE(x86seg *seg) addbyte(0xc1); /*SHR EDI, 12*/ addbyte(0xef); addbyte(12); - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if (!(seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xfe); @@ -5352,7 +5352,7 @@ static inline void MEM_CHECK_WRITE(x86seg *seg) jump2 = &codeblock[block_current].data[block_pos]; addbyte(0); - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if (!(seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) *jump3 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump3 - 1; /*slowpath:*/ addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ @@ -5385,7 +5385,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) CHECK_SEG_WRITE(seg); - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -5433,7 +5433,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) addbyte(0x79); /*JNS +*/ jump1 = &codeblock[block_current].data[block_pos]; addbyte(0); - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if (!(seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xfe); @@ -5442,7 +5442,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) addbyte(0x8d); /*LEA ESI, 1[EDI]*/ addbyte(0x77); addbyte(0x01); - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if (!(seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x74); /*JE slowpath*/ jump4 = &codeblock[block_current].data[block_pos]; @@ -5498,7 +5498,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) /*slowpath:*/ *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if (!(seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) *jump4 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump4 - 1; jump_pos = block_pos; load_param_1_reg_32(REG_EBX); @@ -5534,7 +5534,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) CHECK_SEG_WRITE(seg); - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -5582,7 +5582,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) addbyte(0x79); /*JNS +*/ jump1 = &codeblock[block_current].data[block_pos]; addbyte(0); - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if (!(seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x83); /*CMP ESI, -1*/ addbyte(0xfe); @@ -5591,7 +5591,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) addbyte(0x8d); /*LEA ESI, 3[EDI]*/ addbyte(0x77); addbyte(0x03); - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if (!(seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x74); /*JE slowpath*/ jump4 = &codeblock[block_current].data[block_pos]; @@ -5647,7 +5647,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) /*slowpath:*/ *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; - if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if (!(seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) *jump4 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump4 - 1; jump_pos = block_pos; load_param_1_reg_32(REG_EBX); @@ -5678,7 +5678,7 @@ static inline void MEM_CHECK_WRITE_L(x86seg *seg) static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -5750,7 +5750,7 @@ static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) } static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -5828,7 +5828,7 @@ static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) } static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ECX, ECX*/ addbyte(0xc9); @@ -5928,7 +5928,7 @@ static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) addbyte(8); host_reg = 8; } - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR EBX, EBX*/ addbyte(0xdb); @@ -6005,7 +6005,7 @@ static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR EBX, EBX*/ addbyte(0xdb); @@ -6089,7 +6089,7 @@ static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR EBX, EBX*/ addbyte(0xdb); diff --git a/src/cpu/codegen_ops_x86.h b/src/cpu/codegen_ops_x86.h index 8f38b3cdf..225490cd3 100644 --- a/src/cpu/codegen_ops_x86.h +++ b/src/cpu/codegen_ops_x86.h @@ -611,14 +611,14 @@ static inline void SAR_L_IMM(int reg, int count) static inline void CHECK_SEG_READ(x86seg *seg) { /*Segments always valid in real/V86 mode*/ - if (!(cr0 & 1) || (eflags & VM_FLAG)) + if (!(cr0 & 1) || (cpu_state.eflags & VM_FLAG)) return; /*CS and SS must always be valid*/ - if (seg == &_cs || seg == &_ss) + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) return; if (seg->checked) return; - if (seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) return; addbyte(0x83); /*CMP seg->base, -1*/ @@ -634,14 +634,14 @@ static inline void CHECK_SEG_READ(x86seg *seg) static inline void CHECK_SEG_WRITE(x86seg *seg) { /*Segments always valid in real/V86 mode*/ - if (!(cr0 & 1) || (eflags & VM_FLAG)) + if (!(cr0 & 1) || (cpu_state.eflags & VM_FLAG)) return; /*CS and SS must always be valid*/ - if (seg == &_cs || seg == &_ss) + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) return; if (seg->checked) return; - if (seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) return; addbyte(0x83); /*CMP seg->base, -1*/ @@ -656,7 +656,7 @@ static inline void CHECK_SEG_WRITE(x86seg *seg) } static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) return; addbyte(0x3b); /*CMP EAX, seg->limit_low*/ @@ -684,7 +684,7 @@ static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -702,7 +702,7 @@ static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) } static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -722,7 +722,7 @@ static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) } static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -740,7 +740,7 @@ static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) } static inline void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -761,7 +761,7 @@ static inline void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) } static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -781,7 +781,7 @@ static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) } static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -800,7 +800,7 @@ static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) } static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -821,7 +821,7 @@ static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) static inline void MEM_LOAD_ADDR_EA_Q(x86seg *seg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR EDX, EDX*/ addbyte(0xd2); @@ -859,7 +859,7 @@ static inline void MEM_LOAD_ADDR_IMM_L(x86seg *seg, uint32_t addr) static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -880,7 +880,7 @@ static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -901,7 +901,7 @@ static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -922,7 +922,7 @@ static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -943,7 +943,7 @@ static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -964,7 +964,7 @@ static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) } static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) { - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -995,7 +995,7 @@ static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) addbyte(0x89); /*MOV ECX, host_reg2*/ addbyte(0xc0 | REG_ECX | (host_reg2 << 3)); } - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -1087,7 +1087,7 @@ static inline x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_s addlong(0xffff); if (mod1seg[rm] == &ss && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; } return op_ea_seg; } @@ -1154,7 +1154,7 @@ static inline x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_s } } if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; if (((sib >> 3) & 7) != 4) { switch (sib >> 6) @@ -1199,7 +1199,7 @@ static inline x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_s if (mod) { if (rm == 5 && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; if (mod == 1) { addbyte(0x83); /*ADD EAX, imm8*/ @@ -3919,7 +3919,7 @@ static inline void LOAD_EA() static inline void MEM_CHECK_WRITE(x86seg *seg) { CHECK_SEG_WRITE(seg); - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -3937,7 +3937,7 @@ static inline void MEM_CHECK_WRITE(x86seg *seg) static inline void MEM_CHECK_WRITE_W(x86seg *seg) { CHECK_SEG_WRITE(seg); - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); @@ -3955,7 +3955,7 @@ static inline void MEM_CHECK_WRITE_W(x86seg *seg) static inline void MEM_CHECK_WRITE_L(x86seg *seg) { CHECK_SEG_WRITE(seg); - if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) { addbyte(0x31); /*XOR ESI, ESI*/ addbyte(0xf6); diff --git a/src/cpu/codegen_timing_pentium.c b/src/cpu/codegen_timing_pentium.c index 60a6fbea0..88c4e9544 100644 --- a/src/cpu/codegen_timing_pentium.c +++ b/src/cpu/codegen_timing_pentium.c @@ -817,7 +817,7 @@ static inline int COUNT(uint64_t timings, uint64_t deps, int op_32) case CYCLES_RMW: return 3; case CYCLES_BRANCH: - return cpu_hasMMX ? 1 : 2; + return cpu_has_feature(CPU_FEATURE_MMX) ? 1 : 2; } fatal("Illegal COUNT %016llx\n", timings); @@ -950,13 +950,13 @@ void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat) last_prefix = prefix; return; } - if (cpu_hasMMX && prefix == 0x0f) + if (cpu_has_feature(CPU_FEATURE_MMX) && prefix == 0x0f) { /*On Pentium MMX 0fh prefix is 'free'*/ last_prefix = prefix; return; } - if (cpu_hasMMX && (prefix == 0x66 || prefix == 0x67)) + if (cpu_has_feature(CPU_FEATURE_MMX) && (prefix == 0x66 || prefix == 0x67)) { /*On Pentium MMX 66h and 67h prefixes take 2 clocks*/ decode_delay_offset += 2; @@ -1223,7 +1223,7 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) else has_displacement = 0; - if (!has_displacement && (!cpu_hasMMX || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) + if (!has_displacement && (!cpu_has_feature(CPU_FEATURE_MMX) || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) { int t1 = u_pipe_timings[u_pipe_opcode] & CYCLES_MASK; int t2 = timings[opcode] & CYCLES_MASK; @@ -1276,7 +1276,7 @@ nopair: else has_displacement = 0; - if ((!has_displacement || cpu_hasMMX) && (!cpu_hasMMX || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) + if ((!has_displacement || cpu_has_feature(CPU_FEATURE_MMX)) && (!cpu_has_feature(CPU_FEATURE_MMX) || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) { /*Instruction might pair with next*/ u_pipe_full = 1; diff --git a/src/cpu/codegen_x86-64.c b/src/cpu/codegen_x86-64.c index a1de499b8..42136207c 100644 --- a/src/cpu/codegen_x86-64.c +++ b/src/cpu/codegen_x86-64.c @@ -376,7 +376,7 @@ void codegen_block_start_recompile(codeblock_t *block) codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] = codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0; - _ds.checked = _es.checked = _fs.checked = _gs.checked = (cr0 & 1) ? 0 : 1; + cpu_state.seg_ds.checked = cpu_state.seg_es.checked = cpu_state.seg_fs.checked = cpu_state.seg_gs.checked = (cr0 & 1) ? 0 : 1; codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; @@ -692,7 +692,7 @@ static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, addbyte((uint8_t)cpu_state_offset(eaaddr)); if (mod1seg[cpu_rm] == &ss && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; } return op_ea_seg; } @@ -840,7 +840,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, addlong(stack_offset); } if (((sib & 7) == 4 || (cpu_mod && (sib & 7) == 5)) && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; addbyte(0x89); /*MOV eaaddr, EAX*/ addbyte(0x45); @@ -864,7 +864,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, if (cpu_mod) { if (cpu_rm == 5 && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; if (cpu_mod == 1) { addbyte(0x67); /*LEA EAX, base_reg+imm8*/ @@ -913,7 +913,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t int test_modrm = 1; int c; - op_ea_seg = &_ds; + op_ea_seg = &cpu_state.seg_ds; op_ssegs = 0; op_old_pc = old_pc; @@ -935,27 +935,27 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t break; case 0x26: /*ES:*/ - op_ea_seg = &_es; + op_ea_seg = &cpu_state.seg_es; op_ssegs = 1; break; case 0x2e: /*CS:*/ - op_ea_seg = &_cs; + op_ea_seg = &cpu_state.seg_cs; op_ssegs = 1; break; case 0x36: /*SS:*/ - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; op_ssegs = 1; break; case 0x3e: /*DS:*/ - op_ea_seg = &_ds; + op_ea_seg = &cpu_state.seg_ds; op_ssegs = 1; break; case 0x64: /*FS:*/ - op_ea_seg = &_fs; + op_ea_seg = &cpu_state.seg_fs; op_ssegs = 1; break; case 0x65: /*GS:*/ - op_ea_seg = &_gs; + op_ea_seg = &cpu_state.seg_gs; op_ssegs = 1; break; diff --git a/src/cpu/codegen_x86.c b/src/cpu/codegen_x86.c index 4e1a8845d..a3352943f 100644 --- a/src/cpu/codegen_x86.c +++ b/src/cpu/codegen_x86.c @@ -1495,7 +1495,7 @@ void codegen_block_start_recompile(codeblock_t *block) codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] = codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0; - _ds.checked = _es.checked = _fs.checked = _gs.checked = (cr0 & 1) ? 0 : 1; + cpu_state.seg_ds.checked = cpu_state.seg_es.checked = cpu_state.seg_fs.checked = cpu_state.seg_gs.checked = (cr0 & 1) ? 0 : 1; block->TOP = cpu_state.TOP; block->was_recompiled = 1; @@ -1735,7 +1735,7 @@ static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, addlong((uint32_t)&cpu_state.eaaddr); if (mod1seg[cpu_rm] == &ss && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; } return op_ea_seg; } @@ -1791,7 +1791,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, addlong(stack_offset); } if (((sib & 7) == 4 || (cpu_mod && (sib & 7) == 5)) && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; if (((sib >> 3) & 7) != 4) { switch (sib >> 6) @@ -1840,7 +1840,7 @@ static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, if (cpu_mod) { if (cpu_rm == 5 && !op_ssegs) - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; if (cpu_mod == 1) { addbyte(0x05); @@ -1875,7 +1875,7 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t int test_modrm = 1; int c; - op_ea_seg = &_ds; + op_ea_seg = &cpu_state.seg_ds; op_ssegs = 0; op_old_pc = old_pc; @@ -1898,27 +1898,27 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t break; case 0x26: /*ES:*/ - op_ea_seg = &_es; + op_ea_seg = &cpu_state.seg_es; op_ssegs = 1; break; case 0x2e: /*CS:*/ - op_ea_seg = &_cs; + op_ea_seg = &cpu_state.seg_cs; op_ssegs = 1; break; case 0x36: /*SS:*/ - op_ea_seg = &_ss; + op_ea_seg = &cpu_state.seg_ss; op_ssegs = 1; break; case 0x3e: /*DS:*/ - op_ea_seg = &_ds; + op_ea_seg = &cpu_state.seg_ds; op_ssegs = 1; break; case 0x64: /*FS:*/ - op_ea_seg = &_fs; + op_ea_seg = &cpu_state.seg_fs; op_ssegs = 1; break; case 0x65: /*GS:*/ - op_ea_seg = &_gs; + op_ea_seg = &cpu_state.seg_gs; op_ssegs = 1; break; @@ -2131,7 +2131,7 @@ generate_call: if (op_ea_seg != last_ea_seg) { last_ea_seg = op_ea_seg; - addbyte(0xC7); /*MOVL $&_ds,(ea_seg)*/ + addbyte(0xC7); /*MOVL $&cpu_state.seg_ds,(ea_seg)*/ addbyte(0x45); addbyte((uint8_t)cpu_state_offset(ea_seg)); addlong((uint32_t)op_ea_seg); diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index cd5804b71..dc068d62f 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -49,12 +49,20 @@ #include "../io.h" #include "x86_ops.h" #include "../mem.h" +#include "../nmi.h" +#include "../pic.h" #include "../pci.h" #ifdef USE_DYNAREC # include "codegen.h" #endif +#if 1 +static void cpu_write(uint16_t addr, uint8_t val, void *priv); +static uint8_t cpu_read(uint16_t addr, void *priv); +#endif + + enum { CPUID_FPU = (1 << 0), CPUID_VME = (1 << 1), @@ -120,7 +128,6 @@ int cpu_multi; int cpu_16bitbus; int cpu_busspeed; int cpu_cyrix_alignment; -int cpuspeed; int CPUID; uint64_t cpu_CR4_mask; int isa_cycles; @@ -130,7 +137,9 @@ int cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles; int cpu_waitstates; int cpu_cache_int_enabled, cpu_cache_ext_enabled; -int cpu_pci_speed; +int cpu_pci_speed, cpu_alt_reset; + +uint32_t cpu_features; int is286, is386, @@ -139,12 +148,7 @@ int is286, israpidcad, is_pentium; -int hasfpu, - cpu_hasrdtsc, - cpu_hasMMX, - cpu_hasMSR, - cpu_hasCR4, - cpu_hasVME; +int hasfpu; uint64_t tsc = 0; @@ -205,6 +209,11 @@ int timing_misaligned; static uint8_t ccr0, ccr1, ccr2, ccr3, ccr4, ccr5, ccr6; +int cpu_has_feature(int feature) +{ + return cpu_features & feature; +} + void cpu_dynamic_switch(int new_cpu) @@ -236,36 +245,40 @@ cpu_set(void) cpu_manufacturer = 0; cpu = 0; } - + cpu_effective = cpu; cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective]; + cpu_alt_reset = 0; + CPUID = cpu_s->cpuid_model; - cpuspeed = cpu_s->speed; is8086 = (cpu_s->cpu_type > CPU_8088); is286 = (cpu_s->cpu_type >= CPU_286); is386 = (cpu_s->cpu_type >= CPU_386SX); israpidcad = (cpu_s->cpu_type == CPU_RAPIDCAD); is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_RAPIDCAD); - is_pentium= (cpu_s->cpu_type >= CPU_WINCHIP); + is_pentium = (cpu_s->cpu_type >= CPU_WINCHIP); hasfpu = (cpu_s->cpu_type >= CPU_i486DX) || (cpu_s->cpu_type == CPU_RAPIDCAD); +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86 || cpu_s->cpu_type == CPU_Cx6x86 || cpu_s->cpu_type == CPU_Cx6x86MX || cpu_s->cpu_type == CPU_Cx6x86L || cpu_s->cpu_type == CPU_CxGX1); +#else + cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86); +#endif + cpu_16bitbus = (cpu_s->cpu_type == CPU_286 || cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC); - if (cpu_s->multi) - cpu_busspeed = cpu_s->rspeed / cpu_s->multi; + 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; - cpu_hasrdtsc = 0; - cpu_hasMMX = 0; - cpu_hasMSR = 0; - cpu_hasCR4 = 0; ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = 0; - if ((cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) || (cpu_s->cpu_type == CPU_386DX) || (cpu_s->cpu_type == CPU_i486SX)) - { - if (enable_external_fpu) - { - hasfpu = 1; - } + if ((cpu_s->cpu_type == CPU_8088) || (cpu_s->cpu_type == CPU_8086) || + (cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) || + (cpu_s->cpu_type == CPU_386DX) || (cpu_s->cpu_type == CPU_i486SX)) { + hasfpu = !!enable_external_fpu; } cpu_update_waitstates(); @@ -289,10 +302,15 @@ cpu_set(void) } if (cpu_iscyrix) - io_sethandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL); + io_sethandler(0x0022, 0x0002, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); else - io_removehandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL); - + io_removehandler(0x0022, 0x0002, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + + if (hasfpu) + io_sethandler(0x00f0, 0x000f, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + else + io_removehandler(0x00f0, 0x000f, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + #ifdef USE_DYNAREC x86_setopcodes(ops_386, ops_386_0f, dynarec_ops_386, dynarec_ops_386_0f); #else @@ -636,8 +654,7 @@ cpu_set(void) break; case CPU_iDX4: - cpu_hasCR4 = 1; - cpu_hasVME = 1; + cpu_features = CPU_FEATURE_CR4 | CPU_FEATURE_VME; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_VME; case CPU_i486SX: case CPU_i486DX: @@ -807,10 +824,8 @@ cpu_set(void) timing_mml = 3; timing_bt = 3-1; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = cpu_hasMSR = 1; - cpu_hasCR4 = 1; cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; /*unknown*/ timing_int_rm = 26; @@ -873,12 +888,8 @@ cpu_set(void) timing_jmp_pm = 3; timing_jmp_pm_gate = 18; timing_misaligned = 3; - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = 0; - cpu_hasMSR = 1; - cpu_hasCR4 = 1; - cpu_hasVME = 1; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_pentium); @@ -920,18 +931,15 @@ cpu_set(void) timing_jmp_pm = 3; timing_jmp_pm_gate = 18; timing_misaligned = 3; - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = 1; - cpu_hasMSR = 1; - cpu_hasCR4 = 1; - cpu_hasVME = 1; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_pentium); #endif break; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) case CPU_Cx6x86: #ifdef USE_DYNAREC x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); @@ -967,11 +975,8 @@ cpu_set(void) timing_jmp_pm_gate = 14; timing_misaligned = 2; cpu_cyrix_alignment = 1; - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = 0; - cpu_hasMSR = 0; - cpu_hasCR4 = 0; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); #endif @@ -1013,11 +1018,8 @@ cpu_set(void) timing_jmp_pm_gate = 14; timing_misaligned = 2; cpu_cyrix_alignment = 1; - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = 0; - cpu_hasMSR = 0; - cpu_hasCR4 = 0; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); #endif @@ -1042,11 +1044,8 @@ cpu_set(void) timing_bnt = 1; /*branch not taken*/ timing_misaligned = 2; cpu_cyrix_alignment = 1; - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = 0; - cpu_hasMSR = 1; - cpu_hasCR4 = 1; cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); @@ -1101,17 +1100,15 @@ cpu_set(void) timing_jmp_pm_gate = 14; timing_misaligned = 2; cpu_cyrix_alignment = 1; - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_MMX; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = 1; - cpu_hasMSR = 1; - cpu_hasCR4 = 1; cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); #endif ccr4 = 0x80; break; +#endif #if defined(DEV_BRANCH) && defined(USE_AMD_K) case CPU_K5: @@ -1131,11 +1128,8 @@ cpu_set(void) timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ timing_misaligned = 3; - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = 1; - cpu_hasMSR = 1; - cpu_hasCR4 = 1; cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; break; @@ -1155,12 +1149,8 @@ cpu_set(void) timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ timing_misaligned = 3; - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = 1; - cpu_hasMSR = 1; - cpu_hasCR4 = 1; - cpu_hasVME = 1; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_pentium); @@ -1197,12 +1187,8 @@ cpu_set(void) timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ timing_misaligned = 3; - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = 0; - cpu_hasMSR = 1; - cpu_hasCR4 = 1; - cpu_hasVME = 1; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); @@ -1238,12 +1224,8 @@ cpu_set(void) timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ timing_misaligned = 3; - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = 1; - cpu_hasMSR = 1; - cpu_hasCR4 = 1; - cpu_hasVME = 1; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); @@ -1279,12 +1261,8 @@ cpu_set(void) timing_bt = 0; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ timing_misaligned = 3; - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); - cpu_hasMMX = 1; - cpu_hasMSR = 1; - cpu_hasCR4 = 1; - cpu_hasVME = 1; cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE | CR4_OSFXSR; #ifdef USE_DYNAREC codegen_timing_set(&codegen_timing_686); @@ -1410,7 +1388,7 @@ cpu_CPUID(void) EAX = 0x540; EBX = ECX = 0; EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; - if (msr.fcr & (1 << 1)) + if (cpu_has_feature(CPU_FEATURE_CX8)) EDX |= CPUID_CMPXCHG8B; if (msr.fcr & (1 << 9)) EDX |= CPUID_MMX; @@ -1590,6 +1568,7 @@ cpu_CPUID(void) break; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) case CPU_Cx6x86: if (!EAX) { @@ -1665,6 +1644,7 @@ cpu_CPUID(void) else EAX = EBX = ECX = EDX = 0; break; +#endif #ifdef DEV_BRANCH #ifdef USE_I686 @@ -1820,6 +1800,7 @@ void cpu_RDMSR() break; } break; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) case CPU_Cx6x86: case CPU_Cx6x86L: case CPU_CxGX1: @@ -1832,6 +1813,7 @@ void cpu_RDMSR() break; } break; +#endif #ifdef DEV_BRANCH #ifdef USE_I686 @@ -1953,6 +1935,7 @@ void cpu_RDMSR() break; default: i686_invalid_rdmsr: + pclog("Invalid MSR read %08X\n", ECX); x86gpf(NULL, 0); break; } @@ -1983,11 +1966,18 @@ void cpu_WRMSR() break; case 0x107: msr.fcr = EAX; - cpu_hasMMX = EAX & (1 << 9); - if (EAX & (1 << 29)) - CPUID = 0; + if (EAX & (1 << 9)) + cpu_features |= CPU_FEATURE_MMX; else - CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpuid_model; + cpu_features &= ~CPU_FEATURE_MMX; + if (EAX & (1 << 1)) + cpu_features |= CPU_FEATURE_CX8; + else + cpu_features &= ~CPU_FEATURE_CX8; + if (EAX & (1 << 29)) + CPUID = 0; + else + CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpuid_model; break; case 0x108: msr.fcr2 = EAX | ((uint64_t)EDX << 32); @@ -2032,6 +2022,7 @@ void cpu_WRMSR() break; } break; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) case CPU_Cx6x86: case CPU_Cx6x86L: case CPU_CxGX1: @@ -2043,6 +2034,7 @@ void cpu_WRMSR() break; } break; +#endif #ifdef DEV_BRANCH #ifdef USE_I686 @@ -2132,6 +2124,7 @@ void cpu_WRMSR() break; default: i686_invalid_wrmsr: + pclog("Invalid MSR write %08X: %08X%08X\n", ECX, EDX, EAX); x86gpf(NULL, 0); break; } @@ -2143,8 +2136,18 @@ i686_invalid_wrmsr: static int cyrix_addr; -void cyrix_write(uint16_t addr, uint8_t val, void *priv) +static void cpu_write(uint16_t addr, uint8_t val, void *priv) { + if (addr == 0xf0) { + /* Writes to F0 clear FPU error and deassert the interrupt. */ + if (is286) + picintc(1 << 13); + else + nmi = 0; + return; + } else if (addr >= 0xf1) + return; /* FPU stuff */ + if (!(addr & 1)) cyrix_addr = val; else switch (cyrix_addr) @@ -2165,6 +2168,7 @@ void cyrix_write(uint16_t addr, uint8_t val, void *priv) if ((ccr3 & 0xf0) == 0x10) { ccr4 = val; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_Cx6x86) { if (val & 0x80) @@ -2172,6 +2176,7 @@ void cyrix_write(uint16_t addr, uint8_t val, void *priv) else CPUID = 0; } +#endif } break; case 0xe9: /*CCR5*/ @@ -2185,8 +2190,11 @@ void cyrix_write(uint16_t addr, uint8_t val, void *priv) } } -uint8_t cyrix_read(uint16_t addr, void *priv) +static uint8_t cpu_read(uint16_t addr, void *priv) { + if (addr >= 0xf0) + return 0xff; /* FPU stuff */ + if (addr & 1) { switch (cyrix_addr) diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 56e0ddf9c..17ffebae8 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -18,6 +18,10 @@ * Copyright 2016-2018 leilei. * Copyright 2016,2018 Miran Grca. */ +#ifdef USE_NEW_DYNAREC +#include "../cpu_new/cpu.h" +#else + #ifndef EMU_CPU_H # define EMU_CPU_H @@ -77,17 +81,16 @@ typedef struct { const char *name; int cpu_type; - int speed; int rspeed; int multi; int pci_speed; uint32_t edx_reset; uint32_t cpuid_model; uint16_t cyrix_id; - int cpu_flags; - int mem_read_cycles, mem_write_cycles; - int cache_read_cycles, cache_write_cycles; - int atclk_div; + 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[]; @@ -143,9 +146,9 @@ extern CPU cpus_Pentium2D[]; #define CR4_PVI (1 << 1) #define CR4_PSE (1 << 4) -#define CPL ((_cs.access>>5)&3) +#define CPL ((cpu_state.seg_cs.access>>5)&3) -#define IOPL ((flags>>12)&3) +#define IOPL ((cpu_state.flags>>12)&3) #define IOPLp ((!(msw&1)) || (CPL<=IOPL)) @@ -240,9 +243,18 @@ struct _cpustate_ { uint16_t old_npxc, new_npxc; uint32_t last_ea; + + x86seg seg_cs, + seg_ds, + seg_es, + seg_ss, + seg_fs, + seg_gs; + + uint16_t flags, eflags; } cpu_state; -/*The flags below must match in both cpu_cur_status and block->status for a block +/*The cpu_state.flags below must match in both cpu_cur_status and block->status for a block to be valid*/ #define CPU_STATUS_USE32 (1 << 0) #define CPU_STATUS_STACK32 (1 << 1) @@ -250,7 +262,7 @@ struct _cpustate_ { #define CPU_STATUS_V86 (1 << 3) #define CPU_STATUS_FLAGS 0xffff -/*If the flags below are set in cpu_cur_status, they must be set in block->status. +/*If the cpu_state.flags below are set in cpu_cur_status, they must be set in block->status. Otherwise they are ignored*/ #define CPU_STATUS_NOTFLATDS (1 << 16) #define CPU_STATUS_NOTFLATSS (1 << 17) @@ -319,18 +331,20 @@ extern int cpu_cyrix_alignment; /*Cyrix 5x86/6x86 only has data misalignment extern int is8086, is286, is386, is486; extern int is_rapidcad; extern int hasfpu; -extern int cpu_hasrdtsc; -extern int cpu_hasMSR; -extern int cpu_hasMMX; -extern int cpu_hasCR4; -extern int cpu_hasVME; +#define CPU_FEATURE_RDTSC (1 << 0) +#define CPU_FEATURE_MSR (1 << 1) +#define CPU_FEATURE_MMX (1 << 2) +#define CPU_FEATURE_CR4 (1 << 3) +#define CPU_FEATURE_VME (1 << 4) +#define CPU_FEATURE_CX8 (1 << 5) +#define CPU_FEATURE_3DNOW (1 << 6) + +extern uint32_t cpu_features; extern uint32_t cpu_cur_status; extern uint64_t cpu_CR4_mask; extern uint64_t tsc; extern msr_t msr; -extern int cpuspeed; -extern int cycles_lost; extern uint8_t opcode; extern int insc; extern int fpucount; @@ -339,16 +353,14 @@ extern int clockrate; extern int cgate16; extern int cpl_override; extern int CPUID; -extern int xt_cpu_multi; +extern uint64_t xt_cpu_multi; extern int isa_cycles; -extern uint16_t flags,eflags; extern uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; extern int ins,output; -extern int cycdiff; extern uint32_t pccache; extern uint8_t *pccache2; -extern float isa_timing, bus_timing; +extern double bus_timing; extern uint64_t pmc[2]; extern uint16_t temp_seg_data[4]; extern uint16_t cs_msr; @@ -372,24 +384,22 @@ extern uint32_t dr[8]; CS,DS,ES,SS is the 16-bit data cs,ds,es,ss are defines to the bases*/ extern x86seg gdt,ldt,idt,tr; -extern x86seg _cs,_ds,_es,_ss,_fs,_gs; extern x86seg _oldds; -#define CS _cs.seg -#define DS _ds.seg -#define ES _es.seg -#define SS _ss.seg -#define FS _fs.seg -#define GS _gs.seg -#define cs _cs.base -#define ds _ds.base -#define es _es.base -#define ss _ss.base -#define seg_fs _fs.base -#define gs _gs.base +#define CS cpu_state.seg_cs.seg +#define DS cpu_state.seg_ds.seg +#define ES cpu_state.seg_es.seg +#define SS cpu_state.seg_ss.seg +#define FS cpu_state.seg_fs.seg +#define GS cpu_state.seg_gs.seg +#define cs cpu_state.seg_cs.base +#define ds cpu_state.seg_ds.base +#define es cpu_state.seg_es.base +#define ss cpu_state.seg_ss.base +#define fs_seg cpu_state.seg_fs.base +#define gs cpu_state.seg_gs.base -#define ISA_CYCLES_SHIFT 6 -#define ISA_CYCLES(x) ((x * isa_cycles) >> ISA_CYCLES_SHIFT) +#define ISA_CYCLES(x) (x * isa_cycles) extern int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l; extern int cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles; @@ -424,8 +434,8 @@ extern CPU cpus_acer[]; // FIXME: should be in machine file! /* Functions. */ -extern void cyrix_write(uint16_t addr, uint8_t val, void *priv); -extern uint8_t cyrix_read(uint16_t addr, void *priv); +extern int cpu_has_feature(int feature); + extern void loadseg(uint16_t seg, x86seg *s); extern void loadcs(uint16_t seg); @@ -448,7 +458,7 @@ extern void exec386(int cycs); extern void exec386_dynarec(int cycs); extern int idivl(int32_t val); extern void loadcscall(uint16_t seg); -extern void loadcsjmp(uint16_t seg, uint32_t oxpc); +extern void loadcsjmp(uint16_t seg, uint32_t old_pc); extern void pmodeint(int num, int soft); extern void pmoderetf(int is32, uint16_t off); extern void pmodeiret(int is32); @@ -457,6 +467,7 @@ extern void resetx86(void); extern void refreshread(void); extern void resetreadlookup(void); extern void softresetx86(void); +extern void x86_int(int num); extern void x86_int_sw(int num); extern int x86_int_sw_rm(int num); extern void x86gpf(char *s, uint16_t error); @@ -470,8 +481,9 @@ extern void x87_dumpregs(void); extern void x87_reset(void); #endif -extern int cpu_effective; +extern int cpu_effective, cpu_alt_reset; extern void cpu_dynamic_switch(int new_cpu); #endif /*EMU_CPU_H*/ +#endif \ No newline at end of file diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index a61e05349..7806d7eba 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -52,371 +52,370 @@ CPU cpus_8088[] = { /*8088 standard*/ - {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/7.16", CPU_8088, 1, 7159092, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/10", CPU_8088, 1, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/12", CPU_8088, 1, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8088/16", CPU_8088, 1, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"8088/4.77", CPU_8088, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/7.16", CPU_8088, 7159092, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/8", CPU_8088, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/10", CPU_8088, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/12", CPU_8088, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/16", CPU_8088, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_pcjr[] = { /*8088 PCjr*/ - {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"8088/4.77", CPU_8088, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_europc[] = { /*8088 EuroPC*/ - {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, - {"8088/7.16", CPU_8088, 1, 7159092, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, - {"8088/9.54", CPU_8088, 1, 9545456, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"8088/4.77", CPU_8088, 4772728, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8088/7.16", CPU_8088, 7159092, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8088/9.54", CPU_8088, 9545456, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_8086[] = { /*8086 standard*/ - {"8086/7.16", CPU_8086, 1, 7159092, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, - {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"8086/9.54", CPU_8086, 1, 9545456, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, - {"8086/10", CPU_8086, 2, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"8086/7.16", CPU_8086, 7159092, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8086/8", CPU_8086, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/9.54", CPU_8086, 9545456, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8086/10", CPU_8086, 10000000, 2, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/12", CPU_8086, 12000000, 3, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/16", CPU_8086, 16000000, 4, 0, 0, 0, 0, 0, 0,0,0,0, 2}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_pc1512[] = { /*8086 Amstrad*/ - {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"8086/8", CPU_8086, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_286[] = { /*286*/ - {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, - {"286/8", CPU_286, 1, 8000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, - {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, - {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, - {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, - {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, - {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/8", CPU_286, 8000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/10", CPU_286, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/12", CPU_286, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/16", CPU_286, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/20", CPU_286, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"286/25", CPU_286, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_ibmat[] = { /*286*/ - {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, - {"286/8", CPU_286, 0, 8000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"286/8", CPU_286, 8000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_ibmxt286[] = { /*286*/ - {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_ps1_m2011[] = { /*286*/ - {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"286/10", CPU_286, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 9} }; CPU cpus_ps2_m30_286[] = { /*286*/ - {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, - {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, - {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, - {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, - {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"286/10", CPU_286, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/12", CPU_286, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/16", CPU_286, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/20", CPU_286, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"286/25", CPU_286, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_i386SX[] = { /*i386SX*/ - {"i386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, - {"i386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, - {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, - {"i386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, - {"i386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"i386SX/16", CPU_386SX, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"i386SX/20", CPU_386SX, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"i386SX/25", CPU_386SX, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"i386SX/33", CPU_386SX, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"i386SX/40", CPU_386SX, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_i386DX[] = { /*i386DX*/ - {"i386DX/16", CPU_386DX, 0, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3, 2}, - {"i386DX/20", CPU_386DX, 1, 20000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, - {"i386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, - {"i386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, - {"i386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, - {"RapidCAD/25", CPU_RAPIDCAD, 2, 25000000, 1, 0, 0x430, 0, 0, 0, 4,4,3,3, 3}, - {"RapidCAD/33", CPU_RAPIDCAD, 3, 33333333, 1, 0, 0x430, 0, 0, 0, 6,6,3,3, 4}, - {"RapidCAD/40", CPU_RAPIDCAD, 4, 40000000, 1, 0, 0x430, 0, 0, 0, 7,7,3,3, 5}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"i386DX/16", CPU_386DX, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3, 2}, + {"i386DX/20", CPU_386DX, 20000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"i386DX/25", CPU_386DX, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"i386DX/33", CPU_386DX, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"i386DX/40", CPU_386DX, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"RapidCAD/25", CPU_RAPIDCAD, 25000000, 1, 0, 0x0430, 0, 0, 0, 4,4,3,3, 3}, + {"RapidCAD/33", CPU_RAPIDCAD, 33333333, 1, 0, 0x0430, 0, 0, 0, 6,6,3,3, 4}, + {"RapidCAD/40", CPU_RAPIDCAD, 40000000, 1, 0, 0x0430, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; -#if 0 -CPU cpus_acer[] = { - /*i386SX*/ - {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,4,4, 3}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} -}; -#endif - CPU cpus_Am386SX[] = { /*Am386*/ - {"Am386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, - {"Am386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, - {"Am386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, - {"Am386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, - {"Am386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Am386SX/16", CPU_386SX, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"Am386SX/20", CPU_386SX, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386SX/25", CPU_386SX, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386SX/33", CPU_386SX, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"Am386SX/40", CPU_386SX, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_Am386DX[] = { /*Am386*/ - {"Am386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, - {"Am386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, - {"Am386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Am386DX/25", CPU_386DX, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386DX/33", CPU_386DX, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"Am386DX/40", CPU_386DX, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_486SLC[] = { /*Cx486SLC*/ - {"Cx486SLC/20", CPU_486SLC, 1, 20000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, - {"Cx486SLC/25", CPU_486SLC, 2, 25000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, - {"Cx486SLC/33", CPU_486SLC, 3, 33333333, 1, 0, 0x400, 0, 0x0000, 0, 6,6,3,3, 4}, - {"Cx486SRx2/32", CPU_486SLC, 3, 32000000, 2, 0, 0x406, 0, 0x0006, 0, 6,6,6,6, 4}, - {"Cx486SRx2/40", CPU_486SLC, 4, 40000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, - {"Cx486SRx2/50", CPU_486SLC, 5, 50000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Cx486SLC/20", CPU_486SLC, 20000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"Cx486SLC/25", CPU_486SLC, 25000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"Cx486SLC/33", CPU_486SLC, 33333333, 1, 0, 0x400, 0, 0x0000, 0, 6,6,3,3, 4}, + {"Cx486SRx2/32", CPU_486SLC, 32000000, 2, 0, 0x406, 0, 0x0006, 0, 6,6,6,6, 4}, + {"Cx486SRx2/40", CPU_486SLC, 40000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, + {"Cx486SRx2/50", CPU_486SLC, 50000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} }; CPU cpus_486DLC[] = { /*Cx486DLC*/ - {"Cx486DLC/25", CPU_486DLC, 2, 25000000, 1, 0, 0x401, 0, 0x0001, 0, 4,4,3,3, 3}, - {"Cx486DLC/33", CPU_486DLC, 3, 33333333, 1, 0, 0x401, 0, 0x0001, 0, 6,6,3,3, 4}, - {"Cx486DLC/40", CPU_486DLC, 4, 40000000, 1, 0, 0x401, 0, 0x0001, 0, 7,7,3,3, 5}, - {"Cx486DRx2/32", CPU_486DLC, 3, 32000000, 2, 0, 0x407, 0, 0x0007, 0, 6,6,6,6, 4}, - {"Cx486DRx2/40", CPU_486DLC, 4, 40000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6, 6}, - {"Cx486DRx2/50", CPU_486DLC, 5, 50000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6, 6}, - {"Cx486DRx2/66", CPU_486DLC, 6, 66666666, 2, 0, 0x407, 0, 0x0007, 0, 12,12,6,6, 8}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Cx486DLC/25", CPU_486DLC, 25000000, 1, 0, 0x401, 0, 0x0001, 0, 4, 4,3,3, 3}, + {"Cx486DLC/33", CPU_486DLC, 33333333, 1, 0, 0x401, 0, 0x0001, 0, 6, 6,3,3, 4}, + {"Cx486DLC/40", CPU_486DLC, 40000000, 1, 0, 0x401, 0, 0x0001, 0, 7, 7,3,3, 5}, + {"Cx486DRx2/32", CPU_486DLC, 32000000, 2, 0, 0x407, 0, 0x0007, 0, 6, 6,6,6, 4}, + {"Cx486DRx2/40", CPU_486DLC, 40000000, 2, 0, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6}, + {"Cx486DRx2/50", CPU_486DLC, 50000000, 2, 0, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6}, + {"Cx486DRx2/66", CPU_486DLC, 66666666, 2, 0, 0x407, 0, 0x0007, 0, 12,12,6,6, 8}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} }; CPU cpus_i486[] = { /*i486*/ - {"i486SX/16", CPU_i486SX, 0, 16000000, 1, 16000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 3,3,3,3, 2}, - {"i486SX/20", CPU_i486SX, 1, 20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, - {"i486SX/25", CPU_i486SX, 2, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, - {"i486SX/33", CPU_i486SX, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, - {"i486SX2/50", CPU_i486SX, 5, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, - {"i486SX2/66 (Q0569)", CPU_i486SX, 6, 66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 8}, - {"i486DX/25", CPU_i486DX, 2, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, - {"i486DX/33", CPU_i486DX, 3, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, - {"i486DX/50", CPU_i486DX, 5, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4, 6}, - {"i486DX2/40", CPU_i486DX, 4, 40000000, 2, 20000000, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, - {"i486DX2/50", CPU_i486DX, 5, 50000000, 2, 25000000, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, - {"i486DX2/66", CPU_i486DX, 6, 66666666, 2, 33333333, 0x430, 0x430, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, - {"iDX4/75", CPU_iDX4, 7, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, /*CPUID available on DX4, >= 75 MHz*/ - {"iDX4/100", CPU_iDX4, 10, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 12}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/ - {"Pentium OverDrive/63", CPU_PENTIUM, 6, 62500000, 3, 25000000, 0x1531, 0x1531, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,7,7, 15/2}, - {"Pentium OverDrive/83", CPU_PENTIUM, 8, 83333333, 3, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8, 10}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"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, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"i486SX2/66 (Q0569)", CPU_i486SX, 66666666, 2, 33333333, 0x45b, 0x45b, 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}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} }; CPU cpus_Am486[] = { /*Am486/5x86*/ - {"Am486SX/33", CPU_Am486SX, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, - {"Am486SX/40", CPU_Am486SX, 4, 40000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, - {"Am486SX2/50", CPU_Am486SX, 5, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ - {"Am486SX2/66", CPU_Am486SX, 6, 66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, /*Isn't on all real AMD SX2s and DX2s, availability here is pretty arbitary (and distinguishes them from the Intel chips)*/ - {"Am486DX/33", CPU_Am486DX, 3, 33333333, 1, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, - {"Am486DX/40", CPU_Am486DX, 4, 40000000, 1, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, - {"Am486DX2/50", CPU_Am486DX, 5, 50000000, 2, 25000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, - {"Am486DX2/66", CPU_Am486DX, 6, 66666666, 2, 33333333, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, - {"Am486DX2/80", CPU_Am486DX, 8, 80000000, 2, 20000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14,6,6, 10}, - {"Am486DX4/75", CPU_Am486DX, 7, 75000000, 3, 25000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, - {"Am486DX4/90", CPU_Am486DX, 9, 90000000, 3, 30000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 12}, - {"Am486DX4/100", CPU_Am486DX, 10, 100000000, 3, 33333333, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 12}, - {"Am486DX4/120", CPU_Am486DX, 11, 120000000, 3, 20000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 21,21,9,9, 15}, - {"Am5x86/P75", CPU_Am486DX, 12, 133333333, 4, 33333333, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, - {"Am5x86/P75+", CPU_Am486DX, 13, 160000000, 4, 20000000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Am486SX/33", CPU_Am486SX, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6, 3, 3, 4}, + {"Am486SX/40", CPU_Am486SX, 40000000, 1, 20000000, 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}, + {"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}, + {"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}, + {"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}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; CPU cpus_Cx486[] = { /*Cx486/5x86*/ - {"Cx486S/25", CPU_Cx486S, 2, 25000000, 1, 25000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, - {"Cx486S/33", CPU_Cx486S, 3, 33333333, 1, 33333333, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, - {"Cx486S/40", CPU_Cx486S, 4, 40000000, 1, 20000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, - {"Cx486DX/33", CPU_Cx486DX, 3, 33333333, 1, 33333333, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, - {"Cx486DX/40", CPU_Cx486DX, 4, 40000000, 1, 20000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, - {"Cx486DX2/50", CPU_Cx486DX, 5, 50000000, 2, 25000000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, - {"Cx486DX2/66", CPU_Cx486DX, 6, 66666666, 2, 33333333, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, - {"Cx486DX2/80", CPU_Cx486DX, 8, 80000000, 2, 20000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14,16,16, 10}, - {"Cx486DX4/75", CPU_Cx486DX, 7, 75000000, 3, 25000000, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, - {"Cx486DX4/100", CPU_Cx486DX, 10, 100000000, 3, 33333333, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 12}, - {"Cx5x86/100", CPU_Cx5x86, 10, 100000000, 3, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 12}, - {"Cx5x86/120", CPU_Cx5x86, 11, 120000000, 3, 20000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 21,21,9,9, 15}, - {"Cx5x86/133", CPU_Cx5x86, 12, 133333333, 4, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"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}, + {"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}, + {"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}, + {"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}, + {"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/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_6x86[] = { /*Cyrix 6x86*/ - {"6x86-P90", CPU_Cx6x86, 17, 80000000, 3, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8,8,6,6, 10}, - {"6x86-PR120+", CPU_Cx6x86, 17, 100000000, 3, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, - {"6x86-PR133+", CPU_Cx6x86, 17, 110000000, 3, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 14}, - {"6x86-PR150+", CPU_Cx6x86, 17, 120000000, 3, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"6x86-PR166+", CPU_Cx6x86, 17, 133333333, 3, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"6x86-PR200+", CPU_Cx6x86, 17, 150000000, 3, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 18}, + {"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}, /*Cyrix 6x86L*/ - {"6x86L-PR133+", CPU_Cx6x86L, 19, 110000000, 3, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 14}, - {"6x86L-PR150+", CPU_Cx6x86L, 19, 120000000, 3, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"6x86L-PR166+", CPU_Cx6x86L, 19, 133333333, 3, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"6x86L-PR200+", CPU_Cx6x86L, 19, 150000000, 3, 37500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 18}, + {"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}, /*Cyrix 6x86MX*/ - {"6x86MX-PR166", CPU_Cx6x86MX, 18, 133333333, 3, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"6x86MX-PR200", CPU_Cx6x86MX, 18, 166666666, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"6x86MX-PR233", CPU_Cx6x86MX, 18, 188888888, 3, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 45/2}, - {"6x86MX-PR266", CPU_Cx6x86MX, 18, 207500000, 3, 41666667, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17,7,7, 25}, - {"6x86MX-PR300", CPU_Cx6x86MX, 18, 233333333, 3, 33333333, 0x600, 0x600, 0x0454, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,7,7, 28}, - {"6x86MX-PR333", CPU_Cx6x86MX, 18, 250000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 20,20,9,9, 30}, - {"6x86MX-PR366", CPU_Cx6x86MX, 18, 250000000, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 30}, - {"6x86MX-PR400", CPU_Cx6x86MX, 18, 285000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 33}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"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}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; +#endif +#endif CPU cpus_WinChip[] = { /*IDT WinChip*/ - {"WinChip 75", CPU_WINCHIP, 7, 75000000, 2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4, 9}, - {"WinChip 90", CPU_WINCHIP, 9, 90000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9,9,4,4, 21/2}, - {"WinChip 100", CPU_WINCHIP, 10, 100000000, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9,9,4,4, 12}, - {"WinChip 120", CPU_WINCHIP, 11, 120000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 14}, - {"WinChip 133", CPU_WINCHIP, 12, 133333333, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 16}, - {"WinChip 150", CPU_WINCHIP, 13, 150000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15,7,7, 35/2}, - {"WinChip 166", CPU_WINCHIP, 15, 166666666, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15,7,7, 40}, - {"WinChip 180", CPU_WINCHIP, 16, 180000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 21}, - {"WinChip 200", CPU_WINCHIP, 17, 200000000, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 24}, - {"WinChip 225", CPU_WINCHIP, 17, 225000000, 3, 37500000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 27}, - {"WinChip 240", CPU_WINCHIP, 17, 240000000, 6, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 28}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"WinChip 75", CPU_WINCHIP, 75000000, 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}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; CPU cpus_Pentium5V[] = { /*Intel Pentium (5V, socket 4)*/ - {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7}, - {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, - {"Pentium OverDrive 120",CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"Pentium OverDrive 133",CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Pentium 60", CPU_PENTIUM, 60000000, 1, 30000000, 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 OverDrive 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Pentium OverDrive 133", CPU_PENTIUM, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} }; CPU cpus_Pentium5V50[] = { /*Intel Pentium (5V, socket 4, including 50 MHz FSB)*/ - {"Pentium 50 (Q0399)",CPU_PENTIUM, 5, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4,4,3,3, 6}, - {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7}, - {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, - {"Pentium OverDrive 100",CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8,8,6,6, 12}, - {"Pentium OverDrive 120",CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"Pentium OverDrive 133",CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Pentium 50 (Q0399)", CPU_PENTIUM, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4,3,3, 6}, + {"Pentium 60", CPU_PENTIUM, 60000000, 1, 30000000, 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 OverDrive 100", CPU_PENTIUM, 100000000, 2, 25000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8,6,6, 12}, + {"Pentium OverDrive 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Pentium OverDrive 133", CPU_PENTIUM, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} }; CPU cpus_PentiumS5[] = { /*Intel Pentium (Socket 5)*/ - {"Pentium 75", CPU_PENTIUM, 9, 75000000, 2, 25000000, 0x522, 0x522, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"Pentium OverDrive MMX 75",CPU_PENTIUMMMX,9,75000000,2,25000000,0x1542,0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"Pentium 90", CPU_PENTIUM, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, - {"Pentium 100/50", CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, - {"Pentium 100/66", CPU_PENTIUM, 13, 100000000, 2, 33333333, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, - {"Pentium 120", CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 16}, - {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 40}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 21}, - {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Pentium 75", CPU_PENTIUM, 75000000, 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}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} }; CPU cpus_Pentium[] = { /*Intel Pentium*/ - {"Pentium 75", CPU_PENTIUM, 9, 75000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"Pentium OverDrive MMX 75",CPU_PENTIUMMMX,9,75000000,2,25000000,0x1542,0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"Pentium 90", CPU_PENTIUM, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, - {"Pentium 100/50", CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, - {"Pentium 100/66", CPU_PENTIUM, 13, 100000000, 2, 33333333, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, - {"Pentium 120", CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"Pentium 133", CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"Pentium 150", CPU_PENTIUM, 17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium 166", CPU_PENTIUM, 19, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium 200", CPU_PENTIUM, 21, 200000000, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"Pentium MMX 166", CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium MMX 200", CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"Pentium MMX 233", CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"Mobile Pentium MMX 120", CPU_PENTIUMMMX, 14, 120000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"Mobile Pentium MMX 133", CPU_PENTIUMMMX, 16, 133333333, 2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"Mobile Pentium MMX 150", CPU_PENTIUMMMX, 17, 150000000, 3, 30000000, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Mobile Pentium MMX 166", CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Mobile Pentium MMX 200", CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"Mobile Pentium MMX 233", CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"Mobile Pentium MMX 266", CPU_PENTIUMMMX, 26, 266666666, 4, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"Mobile Pentium MMX 300", CPU_PENTIUMMMX, 28, 300000000, 5, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, - {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 21}, - {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"Pentium 75", CPU_PENTIUM, 75000000, 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}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; #ifdef DEV_BRANCH #ifdef USE_AMD_K CPU cpus_K5[] = { /*AMD K5 (Socket 5)*/ - {"K5 (5k86) 75 (P75)", CPU_K5, 9, 75000000, 2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"K5 (SSA/5) 75 (PR75)", CPU_K5, 9, 75000000, 2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"K5 (5k86) 90 (P90)", CPU_K5, 12, 90000000, 2, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, - {"K5 (SSA/5) 90 (PR90)", CPU_K5, 12, 90000000, 2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, - {"K5 (5k86) 100 (P100)", CPU_K5, 13, 100000000, 2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, - {"K5 (SSA/5) 100 (PR100)",CPU_K5, 13, 100000000, 2, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, - {"K5 (5k86) 90 (PR120)", CPU_5K86, 14, 120000000, 2, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"K5 (5k86) 100 (PR133)", CPU_5K86, 16, 133333333, 2, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"K5 (5k86) 105 (PR150)", CPU_5K86, 17, 150000000, 3, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"K5 (5k86) 116.5 (PR166)",CPU_5K86, 19, 166666666, 3, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"K5 (5k86) 133 (PR200)", CPU_5K86, 21, 200000000, 3, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"K5 (5k86) 75 (P75)", CPU_K5, 75000000, 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}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} }; CPU cpus_K56[] = { /*AMD K5 and K6 (Socket 7)*/ - {"K5 (5k86) 75 (P75)", CPU_K5, 9, 75000000, 2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"K5 (SSA/5) 75 (PR75)", CPU_K5, 9, 75000000, 2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"K5 (5k86) 90 (P90)", CPU_K5, 12, 90000000, 2, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, - {"K5 (SSA/5) 90 (PR90)", CPU_K5, 12, 90000000, 2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, - {"K5 (5k86) 100 (P100)", CPU_K5, 13, 100000000, 2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, - {"K5 (SSA/5) 100 (PR100)",CPU_K5, 13, 100000000, 2, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, - {"K5 (5k86) 90 (PR120)", CPU_5K86, 14, 120000000, 2, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, - {"K5 (5k86) 100 (PR133)", CPU_5K86, 16, 133333333, 2, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, - {"K5 (5k86) 105 (PR150)", CPU_5K86, 17, 150000000, 3, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"K5 (5k86) 116.5 (PR166)",CPU_5K86, 19, 166666666, 3, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"K5 (5k86) 133 (PR200)", CPU_5K86, 21, 200000000, 3, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"K6 (Model 6) 166", CPU_K6, 19, 166666666, 3, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"K6 (Model 6) 200", CPU_K6, 21, 200000000, 3, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"K6 (Model 6) 233", CPU_K6, 24, 233333333, 4, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"K6 (Model 7) 200", CPU_K6, 21, 200000000, 3, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"K6 (Model 7) 233", CPU_K6, 24, 233333333, 4, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, - {"K6 (Model 7) 266", CPU_K6, 26, 266666666, 4, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"K6 (Model 7) 300", CPU_K6, 28, 300000000, 5, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"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} }; #endif #endif @@ -425,27 +424,28 @@ CPU cpus_K56[] = { #ifdef USE_I686 CPU cpus_PentiumPro[] = { /*Intel Pentium Pro and II Overdrive*/ - {"Pentium Pro 50", CPU_PENTIUMPRO, 5, 50000000, 1, 25000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4,4,3,3, 6}, - {"Pentium Pro 60" , CPU_PENTIUMPRO, 6, 60000000, 1, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7}, - {"Pentium Pro 66" , CPU_PENTIUMPRO, 6, 66666666, 1, 33333333, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, - {"Pentium Pro 75", CPU_PENTIUMPRO, 9, 75000000, 2, 25000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"Pentium Pro 150", CPU_PENTIUMPRO, 17, 150000000, 3, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, - {"Pentium Pro 166", CPU_PENTIUMPRO, 19, 166666666, 3, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, - {"Pentium Pro 180", CPU_PENTIUMPRO, 20, 180000000, 3, 30000000, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 21}, - {"Pentium Pro 200", CPU_PENTIUMPRO, 21, 200000000, 3, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, - {"Pentium II Overdrive 50", CPU_PENTIUM2D, 5, 50000000, 1, 25000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4,4,3,3, 6}, - {"Pentium II Overdrive 60", CPU_PENTIUM2D, 6, 60000000, 1, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7}, - {"Pentium II Overdrive 66", CPU_PENTIUM2D, 6, 66666666, 1, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, - {"Pentium II Overdrive 75", CPU_PENTIUM2D, 9, 75000000, 2, 25000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, - {"Pentium II Overdrive 210", CPU_PENTIUM2D, 22, 210000000, 4, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17,7,7, 25}, - {"Pentium II Overdrive 233", CPU_PENTIUM2D, 24, 233333333, 4, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,1, 28}, - {"Pentium II Overdrive 240", CPU_PENTIUM2D, 25, 240000000, 4, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 29}, - {"Pentium II Overdrive 266", CPU_PENTIUM2D, 26, 266666666, 4, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, - {"Pentium II Overdrive 270", CPU_PENTIUM2D, 27, 270000000, 5, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 33}, - {"Pentium II Overdrive 300/66",CPU_PENTIUM2D, 28, 300000000, 5, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, - {"Pentium II Overdrive 300/60",CPU_PENTIUM2D, 28, 300000000, 5, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, - {"Pentium II Overdrive 333", CPU_PENTIUM2D, 29, 333333333, 5, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 40}, - {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + {"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}, + {"Pentium II 75", CPU_PENTIUM2D, 75000000, 2, 25000000, 0x654, 0x654, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; #endif #endif diff --git a/src/cpu/x86.h b/src/cpu/x86.h index 86a6aa14d..cf664a8b1 100644 --- a/src/cpu/x86.h +++ b/src/cpu/x86.h @@ -1,28 +1,33 @@ +#ifdef USE_NEW_DYNAREC +#include "../cpu_new/x86.h" +#else + extern uint8_t opcode, opcode2; extern uint8_t flags_p; extern uint8_t znptable8[256]; extern uint16_t zero, oldcs; extern uint16_t lastcs, lastpc; -extern uint16_t rds, ea_rseg; -extern uint16_t znptable16[65536]; extern uint16_t *mod1add[2][8]; +extern uint16_t znptable16[65536]; -extern int x86_was_reset, codegen_flat_ds; -extern int codegen_flat_ss, nmi_enable; +extern int x86_was_reset, trap; +extern int codegen_flat_ss, codegen_flat_ds; extern int timetolive, keyboardtimer, trap; -extern int tempc, optype, use32, stack32; +extern int optype, stack32; extern int oldcpl, cgate32, cpl_override, fpucount; -extern int gpf, nmi_enable; +extern int nmi_enable; extern int oddeven, inttype; -extern uint32_t rmdat32, easeg; +extern uint32_t use32; +extern uint32_t rmdat, easeg; extern uint32_t oxpc, flags_zn; extern uint32_t abrt_error; extern uint32_t backupregs[16]; extern uint32_t *mod1seg[8]; extern uint32_t *eal_r, *eal_w; +#define fetchdat rmdat #define setznp168 setznp16 @@ -50,10 +55,6 @@ extern uint32_t *eal_r, *eal_w; #define IRET 3 #define OPTYPE_INT 4 -#define FLAG_N (flags_zn>>31) -#define FLAG_Z (flags_zn) -#define FLAG_P (znptable8[flags_p]&P_FLAG) - enum { @@ -71,3 +72,4 @@ extern void x86_doabrt(int x86_abrt); extern void x86illegal(); extern void x86seg_reset(); extern void x86gpf(char *s, uint16_t error); +#endif diff --git a/src/cpu/x86_flags.h b/src/cpu/x86_flags.h index dab54dbf6..7068a243d 100644 --- a/src/cpu/x86_flags.h +++ b/src/cpu/x86_flags.h @@ -1,6 +1,8 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ +extern int tempc; + enum { FLAGS_UNKNOWN, @@ -69,7 +71,7 @@ static __inline int ZF_SET() return !cpu_state.flags_res; case FLAGS_UNKNOWN: - return flags & Z_FLAG; + return cpu_state.flags & Z_FLAG; default: return 0; @@ -111,7 +113,7 @@ static __inline int NF_SET() return cpu_state.flags_res & 0x80000000; case FLAGS_UNKNOWN: - return flags & N_FLAG; + return cpu_state.flags & N_FLAG; default: return 0; @@ -149,7 +151,7 @@ static __inline int PF_SET() return znptable8[cpu_state.flags_res & 0xff] & P_FLAG; case FLAGS_UNKNOWN: - return flags & P_FLAG; + return cpu_state.flags & P_FLAG; default: return 0; @@ -171,20 +173,20 @@ static __inline int VF_SET() case FLAGS_ADD8: case FLAGS_INC8: return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); - case FLAGS_ADD16: + case FLAGS_ADD16: case FLAGS_INC16: return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x8000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); - case FLAGS_ADD32: + case FLAGS_ADD32: case FLAGS_INC32: return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80000000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); - + case FLAGS_SUB8: case FLAGS_DEC8: return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); - case FLAGS_SUB16: + case FLAGS_SUB16: case FLAGS_DEC16: return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); - case FLAGS_SUB32: + case FLAGS_SUB32: case FLAGS_DEC32: return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); @@ -203,7 +205,7 @@ static __inline int VF_SET() return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80000000)); case FLAGS_UNKNOWN: - return flags & V_FLAG; + return cpu_state.flags & V_FLAG; default: return 0; @@ -243,9 +245,9 @@ static __inline int AF_SET() case FLAGS_DEC16: case FLAGS_DEC32: return ((cpu_state.flags_op1 & 0xF) - (cpu_state.flags_op2 & 0xF)) & 0x10; - + case FLAGS_UNKNOWN: - return flags & A_FLAG; + return cpu_state.flags & A_FLAG; default: return 0; @@ -267,7 +269,7 @@ static __inline int CF_SET() case FLAGS_SUB16: case FLAGS_SUB32: return (cpu_state.flags_op1 < cpu_state.flags_op2); - + case FLAGS_SHL8: return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80; case FLAGS_SHL16: @@ -299,7 +301,7 @@ static __inline int CF_SET() case FLAGS_INC16: case FLAGS_INC32: case FLAGS_UNKNOWN: - return flags & C_FLAG; + return cpu_state.flags & C_FLAG; default: return 0; @@ -317,7 +319,7 @@ static __inline void flags_rebuild() if (ZF_SET()) tempf |= Z_FLAG; if (NF_SET()) tempf |= N_FLAG; if (VF_SET()) tempf |= V_FLAG; - flags = (flags & ~0x8d5) | tempf; + cpu_state.flags = (cpu_state.flags & ~0x8d5) | tempf; cpu_state.flags_op = FLAGS_UNKNOWN; } } @@ -332,9 +334,9 @@ static __inline void flags_rebuild_c() if (cpu_state.flags_op != FLAGS_UNKNOWN) { if (CF_SET()) - flags |= C_FLAG; + cpu_state.flags |= C_FLAG; else - flags &= ~C_FLAG; + cpu_state.flags &= ~C_FLAG; } } @@ -457,65 +459,68 @@ static __inline void setadc8(uint8_t a, uint8_t b) { uint16_t c=(uint16_t)a+(uint16_t)b+tempc; cpu_state.flags_op = FLAGS_UNKNOWN; - flags&=~0x8D5; - flags|=znptable8[c&0xFF]; - if (c&0x100) flags|=C_FLAG; - if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; + cpu_state.flags&=~0x8D5; + cpu_state.flags|=znptable8[c&0xFF]; + if (c&0x100) cpu_state.flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) cpu_state.flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) cpu_state.flags|=A_FLAG; } static __inline void setadc16(uint16_t a, uint16_t b) { uint32_t c=(uint32_t)a+(uint32_t)b+tempc; cpu_state.flags_op = FLAGS_UNKNOWN; - flags&=~0x8D5; - flags|=znptable16[c&0xFFFF]; - if (c&0x10000) flags|=C_FLAG; - if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; - if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; + cpu_state.flags&=~0x8D5; + cpu_state.flags|=znptable16[c&0xFFFF]; + if (c&0x10000) cpu_state.flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) cpu_state.flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) cpu_state.flags|=A_FLAG; } +static __inline void setadc32(uint32_t a, uint32_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + cpu_state.flags&=~0x8D5; + cpu_state.flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + cpu_state.flags|=(znptable8[c&0xFF]&P_FLAG); + if ((ca) || (c==a && tempc)) flags|=C_FLAG; - if ((a^b)&(a^c)&0x80000000) flags|=V_FLAG; - if (((a&0xF)-((b&0xF)+tempc))&0x10) flags|=A_FLAG; + cpu_state.flags&=~0x8D5; + cpu_state.flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + cpu_state.flags|=(znptable8[c&0xFF]&P_FLAG); + if ((c>a) || (c==a && tempc)) cpu_state.flags|=C_FLAG; + if ((a^b)&(a^c)&0x80000000) cpu_state.flags|=V_FLAG; + if (((a&0xF)-((b&0xF)+tempc))&0x10) cpu_state.flags|=A_FLAG; } +extern void cpu_386_flags_extract(); +extern void cpu_386_flags_rebuild(); \ No newline at end of file diff --git a/src/cpu/x86_ops.h b/src/cpu/x86_ops.h index 5b30c0747..12a7e96bc 100644 --- a/src/cpu/x86_ops.h +++ b/src/cpu/x86_ops.h @@ -83,7 +83,9 @@ extern const OpFn dynarec_ops_winchip_0f[1024]; extern const OpFn dynarec_ops_pentium_0f[1024]; extern const OpFn dynarec_ops_pentiummmx_0f[1024]; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) extern const OpFn dynarec_ops_c6x86mx_0f[1024]; +#endif #if defined(DEV_BRANCH) && defined(USE_AMD_K) extern const OpFn dynarec_ops_k6_0f[1024]; @@ -175,7 +177,9 @@ extern const OpFn ops_winchip_0f[1024]; extern const OpFn ops_pentium_0f[1024]; extern const OpFn ops_pentiummmx_0f[1024]; +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) extern const OpFn ops_c6x86mx_0f[1024]; +#endif #if defined(DEV_BRANCH) && defined(USE_AMD_K) extern const OpFn ops_k6_0f[1024]; diff --git a/src/cpu/x86_ops_amd.h b/src/cpu/x86_ops_amd.h index 54e567721..8f003e1fb 100644 --- a/src/cpu/x86_ops_amd.h +++ b/src/cpu/x86_ops_amd.h @@ -40,36 +40,36 @@ static int opSYSCALL(uint32_t fetchdat) if (!AMD_SYSCALL_SB) return internal_illegal("SYSCALL: AMD SYSCALL SB MSR is zero"); /* Set VM, IF, RF to 0. */ - /* eflags &= ~0x00030200; - flags &= ~0x0200; */ + /* cpu_state.eflags &= ~0x00030200; + cpu_state.flags &= ~0x0200; */ /* Let's do this by the AMD spec. */ ECX = cpu_state.pc; - eflags &= ~0x0002; - flags &= ~0x0200; + cpu_state.eflags &= ~0x0002; + cpu_state.flags &= ~0x0200; /* CS */ - _cs.seg = AMD_SYSCALL_SB & ~7; + cpu_state.seg_cs.seg = AMD_SYSCALL_SB & ~7; if (AMD_SYSCALL_SB & 4) { - if (_cs.seg >= ldt.limit) + if (cpu_state.seg_cs.seg >= ldt.limit) { x386_dynarec_log("Bigger than LDT limit %04X %04X CS\n",AMD_SYSCALL_SB,ldt.limit); x86gpf(NULL, AMD_SYSCALL_SB & ~3); return 1; } - _cs.seg +=ldt.base; + cpu_state.seg_cs.seg +=ldt.base; } else { - if (_cs.seg >= gdt.limit) + if (cpu_state.seg_cs.seg >= gdt.limit) { x386_dynarec_log("Bigger than GDT limit %04X %04X CS\n",AMD_SYSCALL_SB,gdt.limit); x86gpf(NULL, AMD_SYSCALL_SB & ~3); return 1; } - _cs.seg += gdt.base; + cpu_state.seg_cs.seg += gdt.base; } cpl_override = 1; @@ -83,27 +83,27 @@ static int opSYSCALL(uint32_t fetchdat) use32 = 0x300; CS = (AMD_SYSCALL_SB & ~3) | 0; - do_seg_load(&_cs, syscall_cs_seg_data); + do_seg_load(&cpu_state.seg_cs, syscall_cs_seg_data); use32 = 0x300; CS = (CS & 0xFFFC) | 0; - _cs.limit = 0xFFFFFFFF; - _cs.limit_high = 0xFFFFFFFF; + cpu_state.seg_cs.limit = 0xFFFFFFFF; + cpu_state.seg_cs.limit_high = 0xFFFFFFFF; /* SS */ syscall_ss_seg_data[0] = 0xFFFF; syscall_ss_seg_data[1] = 0; syscall_ss_seg_data[2] = 0x9300; syscall_ss_seg_data[3] = 0xC0; - do_seg_load(&_ss, syscall_ss_seg_data); - _ss.seg = (AMD_SYSCALL_SB + 8) & 0xFFFC; + do_seg_load(&cpu_state.seg_ss, syscall_ss_seg_data); + cpu_state.seg_ss.seg = (AMD_SYSCALL_SB + 8) & 0xFFFC; stack32 = 1; - _ss.limit = 0xFFFFFFFF; - _ss.limit_high = 0xFFFFFFFF; + cpu_state.seg_ss.limit = 0xFFFFFFFF; + cpu_state.seg_ss.limit_high = 0xFFFFFFFF; - _ss.checked = 0; + cpu_state.seg_ss.checked = 0; cpu_state.pc = AMD_SYSCALL_EIP; @@ -125,29 +125,29 @@ static int opSYSRET(uint32_t fetchdat) cpu_state.pc = ECX; - eflags |= (1 << 1); + cpu_state.eflags |= (1 << 1); /* CS */ - _cs.seg = AMD_SYSRET_SB & ~7; + cpu_state.seg_cs.seg = AMD_SYSRET_SB & ~7; if (AMD_SYSRET_SB & 4) { - if (_cs.seg >= ldt.limit) + if (cpu_state.seg_cs.seg >= ldt.limit) { x386_dynarec_log("Bigger than LDT limit %04X %04X CS\n",AMD_SYSRET_SB,ldt.limit); x86gpf(NULL, AMD_SYSRET_SB & ~3); return 1; } - _cs.seg +=ldt.base; + cpu_state.seg_cs.seg +=ldt.base; } else { - if (_cs.seg >= gdt.limit) + if (cpu_state.seg_cs.seg >= gdt.limit) { x386_dynarec_log("Bigger than GDT limit %04X %04X CS\n",AMD_SYSRET_SB,gdt.limit); x86gpf(NULL, AMD_SYSRET_SB & ~3); return 1; } - _cs.seg += gdt.base; + cpu_state.seg_cs.seg += gdt.base; } cpl_override = 1; @@ -161,28 +161,28 @@ static int opSYSRET(uint32_t fetchdat) use32 = 0x300; CS = (AMD_SYSRET_SB & ~3) | 3; - do_seg_load(&_cs, sysret_cs_seg_data); + do_seg_load(&cpu_state.seg_cs, sysret_cs_seg_data); flushmmucache_cr3(); use32 = 0x300; CS = (CS & 0xFFFC) | 3; - _cs.limit = 0xFFFFFFFF; - _cs.limit_high = 0xFFFFFFFF; + cpu_state.seg_cs.limit = 0xFFFFFFFF; + cpu_state.seg_cs.limit_high = 0xFFFFFFFF; /* SS */ sysret_ss_seg_data[0] = 0xFFFF; sysret_ss_seg_data[1] = 0; sysret_ss_seg_data[2] = 0xF300; sysret_ss_seg_data[3] = 0xC0; - do_seg_load(&_ss, sysret_ss_seg_data); - _ss.seg = ((AMD_SYSRET_SB + 8) & 0xFFFC) | 3; + do_seg_load(&cpu_state.seg_ss, sysret_ss_seg_data); + cpu_state.seg_ss.seg = ((AMD_SYSRET_SB + 8) & 0xFFFC) | 3; stack32 = 1; - _ss.limit = 0xFFFFFFFF; - _ss.limit_high = 0xFFFFFFFF; + cpu_state.seg_ss.limit = 0xFFFFFFFF; + cpu_state.seg_ss.limit_high = 0xFFFFFFFF; - _ss.checked = 0; + cpu_state.seg_ss.checked = 0; CLOCK_CYCLES(20); diff --git a/src/cpu/x86_ops_arith.h b/src/cpu/x86_ops_arith.h index 3c6b67fa6..80a0da788 100644 --- a/src/cpu/x86_ops_arith.h +++ b/src/cpu/x86_ops_arith.h @@ -16,6 +16,7 @@ } \ else \ { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ dst = geteab(); if (cpu_state.abrt) return 1; \ src = getr8(cpu_reg); \ seteab(operation); if (cpu_state.abrt) return 1; \ @@ -42,6 +43,7 @@ } \ else \ { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ dst = geteab(); if (cpu_state.abrt) return 1; \ src = getr8(cpu_reg); \ seteab(operation); if (cpu_state.abrt) return 1; \ @@ -69,6 +71,7 @@ } \ else \ { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ dst = geteaw(); if (cpu_state.abrt) return 1; \ src = cpu_state.regs[cpu_reg].w; \ seteaw(operation); if (cpu_state.abrt) return 1; \ @@ -95,6 +98,7 @@ } \ else \ { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ dst = geteaw(); if (cpu_state.abrt) return 1; \ src = cpu_state.regs[cpu_reg].w; \ seteaw(operation); if (cpu_state.abrt) return 1; \ @@ -122,6 +126,7 @@ } \ else \ { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ dst = geteal(); if (cpu_state.abrt) return 1; \ src = cpu_state.regs[cpu_reg].l; \ seteal(operation); if (cpu_state.abrt) return 1; \ @@ -148,6 +153,7 @@ } \ else \ { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ dst = geteal(); if (cpu_state.abrt) return 1; \ src = cpu_state.regs[cpu_reg].l; \ seteal(operation); if (cpu_state.abrt) return 1; \ @@ -163,6 +169,8 @@ uint8_t dst, src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ dst = getr8(cpu_reg); \ src = geteab(); if (cpu_state.abrt) return 1; \ setflags ## 8 flagops; \ @@ -176,6 +184,8 @@ uint8_t dst, src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ dst = getr8(cpu_reg); \ src = geteab(); if (cpu_state.abrt) return 1; \ setflags ## 8 flagops; \ @@ -190,6 +200,8 @@ uint16_t dst, src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ dst = cpu_state.regs[cpu_reg].w; \ src = geteaw(); if (cpu_state.abrt) return 1; \ setflags ## 16 flagops; \ @@ -203,6 +215,8 @@ uint16_t dst, src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ dst = cpu_state.regs[cpu_reg].w; \ src = geteaw(); if (cpu_state.abrt) return 1; \ setflags ## 16 flagops; \ @@ -217,6 +231,8 @@ uint32_t dst, src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ dst = cpu_state.regs[cpu_reg].l; \ src = geteal(); if (cpu_state.abrt) return 1; \ setflags ## 32 flagops; \ @@ -230,6 +246,8 @@ uint32_t dst, src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ dst = cpu_state.regs[cpu_reg].l; \ src = geteal(); if (cpu_state.abrt) return 1; \ setflags ## 32 flagops; \ @@ -287,6 +305,8 @@ static int opCMP_b_rmw_a16(uint32_t fetchdat) { uint8_t dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteab(); if (cpu_state.abrt) return 1; setsub8(dst, getr8(cpu_reg)); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -298,6 +318,8 @@ static int opCMP_b_rmw_a32(uint32_t fetchdat) { uint8_t dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteab(); if (cpu_state.abrt) return 1; setsub8(dst, getr8(cpu_reg)); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -310,6 +332,8 @@ static int opCMP_w_rmw_a16(uint32_t fetchdat) { uint16_t dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteaw(); if (cpu_state.abrt) return 1; setsub16(dst, cpu_state.regs[cpu_reg].w); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -321,6 +345,8 @@ static int opCMP_w_rmw_a32(uint32_t fetchdat) { uint16_t dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteaw(); if (cpu_state.abrt) return 1; setsub16(dst, cpu_state.regs[cpu_reg].w); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -333,6 +359,8 @@ static int opCMP_l_rmw_a16(uint32_t fetchdat) { uint32_t dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteal(); if (cpu_state.abrt) return 1; setsub32(dst, cpu_state.regs[cpu_reg].l); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -344,6 +372,8 @@ static int opCMP_l_rmw_a32(uint32_t fetchdat) { uint32_t dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteal(); if (cpu_state.abrt) return 1; setsub32(dst, cpu_state.regs[cpu_reg].l); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -355,7 +385,9 @@ static int opCMP_l_rmw_a32(uint32_t fetchdat) static int opCMP_b_rm_a16(uint32_t fetchdat) { uint8_t src; - fetch_ea_16(fetchdat); + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); src = geteab(); if (cpu_state.abrt) return 1; setsub8(getr8(cpu_reg), src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); @@ -365,7 +397,9 @@ static int opCMP_b_rm_a16(uint32_t fetchdat) static int opCMP_b_rm_a32(uint32_t fetchdat) { uint8_t src; - fetch_ea_32(fetchdat); + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); src = geteab(); if (cpu_state.abrt) return 1; setsub8(getr8(cpu_reg), src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); @@ -376,7 +410,9 @@ static int opCMP_b_rm_a32(uint32_t fetchdat) static int opCMP_w_rm_a16(uint32_t fetchdat) { uint16_t src; - fetch_ea_16(fetchdat); + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); src = geteaw(); if (cpu_state.abrt) return 1; setsub16(cpu_state.regs[cpu_reg].w, src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); @@ -386,7 +422,9 @@ static int opCMP_w_rm_a16(uint32_t fetchdat) static int opCMP_w_rm_a32(uint32_t fetchdat) { uint16_t src; - fetch_ea_32(fetchdat); + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); src = geteaw(); if (cpu_state.abrt) return 1; setsub16(cpu_state.regs[cpu_reg].w, src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); @@ -395,9 +433,11 @@ static int opCMP_w_rm_a32(uint32_t fetchdat) } static int opCMP_l_rm_a16(uint32_t fetchdat) -{ - uint32_t src; - fetch_ea_16(fetchdat); +{ + uint32_t src; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); src = geteal(); if (cpu_state.abrt) return 1; setsub32(cpu_state.regs[cpu_reg].l, src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); @@ -407,7 +447,9 @@ static int opCMP_l_rm_a16(uint32_t fetchdat) static int opCMP_l_rm_a32(uint32_t fetchdat) { uint32_t src; - fetch_ea_32(fetchdat); + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); src = geteal(); if (cpu_state.abrt) return 1; setsub32(cpu_state.regs[cpu_reg].l, src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); @@ -446,6 +488,8 @@ static int opTEST_b_a16(uint32_t fetchdat) { uint8_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; temp2 = getr8(cpu_reg); setznp8(temp & temp2); @@ -458,6 +502,8 @@ static int opTEST_b_a32(uint32_t fetchdat) { uint8_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; temp2 = getr8(cpu_reg); setznp8(temp & temp2); @@ -471,6 +517,8 @@ static int opTEST_w_a16(uint32_t fetchdat) { uint16_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; temp2 = cpu_state.regs[cpu_reg].w; setznp16(temp & temp2); @@ -483,6 +531,8 @@ static int opTEST_w_a32(uint32_t fetchdat) { uint16_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; temp2 = cpu_state.regs[cpu_reg].w; setznp16(temp & temp2); @@ -496,6 +546,8 @@ static int opTEST_l_a16(uint32_t fetchdat) { uint32_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; temp2 = cpu_state.regs[cpu_reg].l; setznp32(temp & temp2); @@ -508,6 +560,8 @@ static int opTEST_l_a32(uint32_t fetchdat) { uint32_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; temp2 = cpu_state.regs[cpu_reg].l; setznp32(temp & temp2); @@ -600,6 +654,8 @@ static int op80_a16(uint32_t fetchdat) uint8_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; ARITH_MULTI(b, 8); if ((rmdat & 0x38) == 0x38) @@ -614,6 +670,8 @@ static int op80_a32(uint32_t fetchdat) uint8_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; ARITH_MULTI(b, 8); if ((rmdat & 0x38) == 0x38) @@ -628,6 +686,8 @@ static int op81_w_a16(uint32_t fetchdat) uint16_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getword(); if (cpu_state.abrt) return 1; ARITH_MULTI(w, 16); if ((rmdat & 0x38) == 0x38) @@ -642,6 +702,8 @@ static int op81_w_a32(uint32_t fetchdat) uint16_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getword(); if (cpu_state.abrt) return 1; ARITH_MULTI(w, 16); if ((rmdat & 0x38) == 0x38) @@ -670,6 +732,8 @@ static int op81_l_a32(uint32_t fetchdat) uint32_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getlong(); if (cpu_state.abrt) return 1; ARITH_MULTI(l, 32); if ((rmdat & 0x38) == 0x38) @@ -685,6 +749,8 @@ static int op83_w_a16(uint32_t fetchdat) uint16_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; if (src & 0x80) src |= 0xff00; ARITH_MULTI(w, 16); @@ -700,6 +766,8 @@ static int op83_w_a32(uint32_t fetchdat) uint16_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; if (src & 0x80) src |= 0xff00; ARITH_MULTI(w, 16); @@ -716,6 +784,8 @@ static int op83_l_a16(uint32_t fetchdat) uint32_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; if (src & 0x80) src |= 0xffffff00; ARITH_MULTI(l, 32); @@ -731,6 +801,8 @@ static int op83_l_a32(uint32_t fetchdat) uint32_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; if (src & 0x80) src |= 0xffffff00; ARITH_MULTI(l, 32); diff --git a/src/cpu/x86_ops_arith_ex.h b/src/cpu/x86_ops_arith_ex.h new file mode 100644 index 000000000..cc4fcd7c3 --- /dev/null +++ b/src/cpu/x86_ops_arith_ex.h @@ -0,0 +1,752 @@ +#define OP_ARITH(name, operation, setflags, flagops, gettempc) \ + static int op ## name ## _b_rmw_a16(uint32_t fetchdat) \ + { \ + uint8_t dst; \ + uint8_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = getr8(cpu_rm); \ + src = getr8(cpu_reg); \ + setflags ## 8 flagops; \ + setr8(cpu_rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + dst = geteab(); if (cpu_state.abrt) return 1; \ + src = getr8(cpu_reg); \ + seteab(operation); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_mr, 2, rmdat, 1,0,1,0, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _b_rmw_a32(uint32_t fetchdat) \ + { \ + uint8_t dst; \ + uint8_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = getr8(cpu_rm); \ + src = getr8(cpu_reg); \ + setflags ## 8 flagops; \ + setr8(cpu_rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + dst = geteab(); if (cpu_state.abrt) return 1; \ + src = getr8(cpu_reg); \ + seteab(operation); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_mr, 2, rmdat, 1,0,1,0, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _w_rmw_a16(uint32_t fetchdat) \ + { \ + uint16_t dst; \ + uint16_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].w; \ + src = cpu_state.regs[cpu_reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].w; \ + seteaw(operation); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 1,0,1,0, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _w_rmw_a32(uint32_t fetchdat) \ + { \ + uint16_t dst; \ + uint16_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].w; \ + src = cpu_state.regs[cpu_reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].w; \ + seteaw(operation); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 1,0,1,0, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _l_rmw_a16(uint32_t fetchdat) \ + { \ + uint32_t dst; \ + uint32_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].l; \ + src = cpu_state.regs[cpu_reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + dst = geteal(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].l; \ + seteal(operation); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,1,0,1, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _l_rmw_a32(uint32_t fetchdat) \ + { \ + uint32_t dst; \ + uint32_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].l; \ + src = cpu_state.regs[cpu_reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + dst = geteal(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].l; \ + seteal(operation); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,1,0,1, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _b_rm_a16(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = getr8(cpu_reg); \ + src = geteab(); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + setr8(cpu_reg, operation); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); \ + return 0; \ + } \ + static int op ## name ## _b_rm_a32(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = getr8(cpu_reg); \ + src = geteab(); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + setr8(cpu_reg, operation); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); \ + return 0; \ + } \ + \ + static int op ## name ## _w_rm_a16(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = cpu_state.regs[cpu_reg].w; \ + src = geteaw(); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_reg].w = operation; \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); \ + return 0; \ + } \ + static int op ## name ## _w_rm_a32(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = cpu_state.regs[cpu_reg].w; \ + src = geteaw(); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_reg].w = operation; \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); \ + return 0; \ + } \ + \ + static int op ## name ## _l_rm_a16(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = cpu_state.regs[cpu_reg].l; \ + src = geteal(); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_reg].l = operation; \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); \ + return 0; \ + } \ + static int op ## name ## _l_rm_a32(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = cpu_state.regs[cpu_reg].l; \ + src = geteal(); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_reg].l = operation; \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); \ + return 0; \ + } \ + \ + static int op ## name ## _AL_imm(uint32_t fetchdat) \ + { \ + uint8_t dst = AL; \ + uint8_t src = getbytef(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 8 flagops; \ + AL = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int op ## name ## _AX_imm(uint32_t fetchdat) \ + { \ + uint16_t dst = AX; \ + uint16_t src = getwordf(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 16 flagops; \ + AX = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int op ## name ## _EAX_imm(uint32_t fetchdat) \ + { \ + uint32_t dst = EAX; \ + uint32_t src = getlong(); if (cpu_state.abrt) return 1; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 32 flagops; \ + EAX = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); \ + return 0; \ + } + +OP_ARITH(ADD, dst + src, setadd, (dst, src), 0) +OP_ARITH(ADC, dst + src + tempc, setadc, (dst, src), 1) +OP_ARITH(SUB, dst - src, setsub, (dst, src), 0) +OP_ARITH(SBB, dst - (src + tempc), setsbc, (dst, src), 1) +OP_ARITH(OR, dst | src, setznp, (dst | src), 0) +OP_ARITH(AND, dst & src, setznp, (dst & src), 0) +OP_ARITH(XOR, dst ^ src, setznp, (dst ^ src), 0) + +static int opCMP_b_rmw_a16(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_16(fetchdat); + dst = geteab(); if (cpu_state.abrt) return 1; + setsub8(dst, getr8(cpu_reg)); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_b_rmw_a32(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_32(fetchdat); + dst = geteab(); if (cpu_state.abrt) return 1; + setsub8(dst, getr8(cpu_reg)); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_w_rmw_a16(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_16(fetchdat); + dst = geteaw(); if (cpu_state.abrt) return 1; + setsub16(dst, cpu_state.regs[cpu_reg].w); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_w_rmw_a32(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_32(fetchdat); + dst = geteaw(); if (cpu_state.abrt) return 1; + setsub16(dst, cpu_state.regs[cpu_reg].w); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_l_rmw_a16(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_16(fetchdat); + dst = geteal(); if (cpu_state.abrt) return 1; + setsub32(dst, cpu_state.regs[cpu_reg].l); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +static int opCMP_l_rmw_a32(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_32(fetchdat); + dst = geteal(); if (cpu_state.abrt) return 1; + setsub32(dst, cpu_state.regs[cpu_reg].l); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opCMP_b_rm_a16(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_16(fetchdat); + src = geteab(); if (cpu_state.abrt) return 1; + setsub8(getr8(cpu_reg), src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_b_rm_a32(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_32(fetchdat); + src = geteab(); if (cpu_state.abrt) return 1; + setsub8(getr8(cpu_reg), src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_w_rm_a16(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_16(fetchdat); + src = geteaw(); if (cpu_state.abrt) return 1; + setsub16(cpu_state.regs[cpu_reg].w, src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_w_rm_a32(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_32(fetchdat); + src = geteaw(); if (cpu_state.abrt) return 1; + setsub16(cpu_state.regs[cpu_reg].w, src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_l_rm_a16(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_16(fetchdat); + src = geteal(); if (cpu_state.abrt) return 1; + setsub32(cpu_state.regs[cpu_reg].l, src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +static int opCMP_l_rm_a32(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_32(fetchdat); + src = geteal(); if (cpu_state.abrt) return 1; + setsub32(cpu_state.regs[cpu_reg].l, src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opCMP_AL_imm(uint32_t fetchdat) +{ + uint8_t src = getbytef(); + setsub8(AL, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opCMP_AX_imm(uint32_t fetchdat) +{ + uint16_t src = getwordf(); + setsub16(AX, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} + +static int opCMP_EAX_imm(uint32_t fetchdat) +{ + uint32_t src = getlong(); if (cpu_state.abrt) return 1; + setsub32(EAX, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + +static int opTEST_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + temp2 = getr8(cpu_reg); + setznp8(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opTEST_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + temp2 = getr8(cpu_reg); + setznp8(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opTEST_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].w; + setznp16(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opTEST_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].w; + setznp16(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opTEST_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].l; + setznp32(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0,(cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +static int opTEST_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].l; + setznp32(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0,(cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opTEST_AL(uint32_t fetchdat) +{ + uint8_t temp = getbytef(); + setznp8(AL & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opTEST_AX(uint32_t fetchdat) +{ + uint16_t temp = getwordf(); + setznp16(AX & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opTEST_EAX(uint32_t fetchdat) +{ + uint32_t temp = getlong(); if (cpu_state.abrt) return 1; + setznp32(EAX & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + + +#define ARITH_MULTI(ea_width, flag_width, is32) \ + dst = read ## ea_width(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; \ + switch ((rmdat >> 3) & 7) \ + { \ + case 0x00: /*ADD ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + write ## ea_width(easeg, cpu_state.eaaddr, dst + src); if (cpu_state.abrt) return 1; \ + setadd ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x01: /*OR ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + dst |= src; \ + write ## ea_width(easeg, cpu_state.eaaddr, dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x02: /*ADC ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + tempc = CF_SET() ? 1 : 0; \ + write ## ea_width(easeg, cpu_state.eaaddr, dst + src + tempc); if (cpu_state.abrt) return 1; \ + setadc ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x03: /*SBB ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + tempc = CF_SET() ? 1 : 0; \ + write ## ea_width(easeg, cpu_state.eaaddr, dst - (src + tempc)); if (cpu_state.abrt) return 1; \ + setsbc ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x04: /*AND ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + dst &= src; \ + write ## ea_width(easeg, cpu_state.eaaddr, dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x05: /*SUB ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + write ## ea_width(easeg, cpu_state.eaaddr, dst - src); if (cpu_state.abrt) return 1; \ + setsub ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x06: /*XOR ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 1, is32) \ + dst ^= src; \ + write ## ea_width(easeg, cpu_state.eaaddr, dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x07: /*CMP ea, #*/ \ + if (cpu_mod != 3) x86_translate_break(cpu_state.ea_seg, cpu_state.eaaddr, 0, is32) \ + setsub ## flag_width(dst, src); \ + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); \ + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 7); \ + break; \ + } + + +static int op80_a16(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + ARITH_MULTI(8, 8, 0); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +static int op80_a32(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + ARITH_MULTI(8, 8, 1); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} +static int op81_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + src = getword(); if (cpu_state.abrt) return 1; + ARITH_MULTI(16, 16, 0); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 4, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +static int op81_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + src = getword(); if (cpu_state.abrt) return 1; + ARITH_MULTI(16, 16, 1); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 4, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} +static int op81_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + src = getlong(); if (cpu_state.abrt) return 1; + ARITH_MULTI(32, 32, 0); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + + return 0; +} +static int op81_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + src = getlong(); if (cpu_state.abrt) return 1; + ARITH_MULTI(32, 32, 1); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + + return 0; +} + +static int op83_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(16, 16, 0); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +static int op83_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(16, 16, 1); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} + +static int op83_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(32, 32, 0); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + + return 0; +} +static int op83_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(32, 32, 1); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + + return 0; +} + diff --git a/src/cpu/x86_ops_atomic.h b/src/cpu/x86_ops_atomic.h index 7d90e22d1..c490d747a 100644 --- a/src/cpu/x86_ops_atomic.h +++ b/src/cpu/x86_ops_atomic.h @@ -8,6 +8,7 @@ static int opCMPXCHG_b_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; if (AL == temp) seteab(getr8(cpu_reg)); else AL = temp; @@ -26,6 +27,7 @@ static int opCMPXCHG_b_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; if (AL == temp) seteab(getr8(cpu_reg)); else AL = temp; @@ -45,6 +47,7 @@ static int opCMPXCHG_w_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; if (AX == temp) seteaw(cpu_state.regs[cpu_reg].w); else AX = temp; @@ -63,6 +66,7 @@ static int opCMPXCHG_w_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; if (AX == temp) seteaw(cpu_state.regs[cpu_reg].w); else AX = temp; @@ -82,6 +86,7 @@ static int opCMPXCHG_l_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; if (EAX == temp) seteal(cpu_state.regs[cpu_reg].l); else EAX = temp; @@ -100,6 +105,7 @@ static int opCMPXCHG_l_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; if (EAX == temp) seteal(cpu_state.regs[cpu_reg].l); else EAX = temp; @@ -119,6 +125,7 @@ static int opCMPXCHG8B_a16(uint32_t fetchdat) return 0; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); temp_hi = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; if (EAX == temp && EDX == temp_hi) @@ -134,9 +141,9 @@ static int opCMPXCHG8B_a16(uint32_t fetchdat) if (cpu_state.abrt) return 0; flags_rebuild(); if (temp == temp2 && temp_hi == temp2_hi) - flags |= Z_FLAG; + cpu_state.flags |= Z_FLAG; else - flags &= ~Z_FLAG; + cpu_state.flags &= ~Z_FLAG; cycles -= (cpu_mod == 3) ? 6 : 10; return 0; } @@ -150,6 +157,7 @@ static int opCMPXCHG8B_a32(uint32_t fetchdat) return 0; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); temp_hi = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; if (EAX == temp && EDX == temp_hi) @@ -165,9 +173,9 @@ static int opCMPXCHG8B_a32(uint32_t fetchdat) if (cpu_state.abrt) return 0; flags_rebuild(); if (temp == temp2 && temp_hi == temp2_hi) - flags |= Z_FLAG; + cpu_state.flags |= Z_FLAG; else - flags &= ~Z_FLAG; + cpu_state.flags &= ~Z_FLAG; cycles -= (cpu_mod == 3) ? 6 : 10; return 0; } @@ -182,6 +190,7 @@ static int opXADD_b_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; seteab(temp + getr8(cpu_reg)); if (cpu_state.abrt) return 1; setadd8(temp, getr8(cpu_reg)); @@ -199,6 +208,7 @@ static int opXADD_b_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; seteab(temp + getr8(cpu_reg)); if (cpu_state.abrt) return 1; setadd8(temp, getr8(cpu_reg)); @@ -217,6 +227,7 @@ static int opXADD_w_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(temp + cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; setadd16(temp, cpu_state.regs[cpu_reg].w); @@ -234,6 +245,7 @@ static int opXADD_w_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(temp + cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; setadd16(temp, cpu_state.regs[cpu_reg].w); @@ -252,6 +264,7 @@ static int opXADD_l_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(temp + cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; setadd32(temp, cpu_state.regs[cpu_reg].l); @@ -269,6 +282,7 @@ static int opXADD_l_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(temp + cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; setadd32(temp, cpu_state.regs[cpu_reg].l); diff --git a/src/cpu/x86_ops_bcd.h b/src/cpu/x86_ops_bcd.h index 241216b14..cd29b1405 100644 --- a/src/cpu/x86_ops_bcd.h +++ b/src/cpu/x86_ops_bcd.h @@ -1,14 +1,14 @@ static int opAAA(uint32_t fetchdat) { flags_rebuild(); - if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) { AL += 6; AH++; - flags |= (A_FLAG | C_FLAG); + cpu_state.flags |= (A_FLAG | C_FLAG); } else - flags &= ~(A_FLAG | C_FLAG); + cpu_state.flags &= ~(A_FLAG | C_FLAG); AL &= 0xF; CLOCK_CYCLES(is486 ? 3 : 4); PREFETCH_RUN(is486 ? 3 : 4, 1, -1, 0,0,0,0, 0); @@ -42,14 +42,14 @@ static int opAAM(uint32_t fetchdat) static int opAAS(uint32_t fetchdat) { flags_rebuild(); - if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) { AL -= 6; AH--; - flags |= (A_FLAG | C_FLAG); + cpu_state.flags |= (A_FLAG | C_FLAG); } else - flags &= ~(A_FLAG | C_FLAG); + cpu_state.flags &= ~(A_FLAG | C_FLAG); AL &= 0xF; CLOCK_CYCLES(is486 ? 3 : 4); PREFETCH_RUN(is486 ? 3 : 4, 1, -1, 0,0,0,0, 0); @@ -61,23 +61,23 @@ static int opDAA(uint32_t fetchdat) uint16_t tempw; flags_rebuild(); - if ((flags & A_FLAG) || ((AL & 0xf) > 9)) + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { int tempi = ((uint16_t)AL) + 6; AL += 6; - flags |= A_FLAG; - if (tempi & 0x100) flags |= C_FLAG; + cpu_state.flags |= A_FLAG; + if (tempi & 0x100) cpu_state.flags |= C_FLAG; } - if ((flags & C_FLAG) || (AL > 0x9f)) + if ((cpu_state.flags & C_FLAG) || (AL > 0x9f)) { AL += 0x60; - flags |= C_FLAG; + cpu_state.flags |= C_FLAG; } - tempw = flags & (C_FLAG | A_FLAG); + tempw = cpu_state.flags & (C_FLAG | A_FLAG); setznp8(AL); flags_rebuild(); - flags |= tempw; + cpu_state.flags |= tempw; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0); @@ -89,23 +89,23 @@ static int opDAS(uint32_t fetchdat) uint16_t tempw; flags_rebuild(); - if ((flags & A_FLAG) || ((AL & 0xf) > 9)) + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { int tempi = ((uint16_t)AL) - 6; AL -= 6; - flags |= A_FLAG; - if (tempi & 0x100) flags |= C_FLAG; + cpu_state.flags |= A_FLAG; + if (tempi & 0x100) cpu_state.flags |= C_FLAG; } - if ((flags & C_FLAG) || (AL > 0x9f)) + if ((cpu_state.flags & C_FLAG) || (AL > 0x9f)) { AL -= 0x60; - flags |= C_FLAG; + cpu_state.flags |= C_FLAG; } - tempw = flags & (C_FLAG | A_FLAG); + tempw = cpu_state.flags & (C_FLAG | A_FLAG); setznp8(AL); flags_rebuild(); - flags |= tempw; + cpu_state.flags |= tempw; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0); diff --git a/src/cpu/x86_ops_bit.h b/src/cpu/x86_ops_bit.h index 7390265a8..42d9aa4aa 100644 --- a/src/cpu/x86_ops_bit.h +++ b/src/cpu/x86_ops_bit.h @@ -3,11 +3,12 @@ static int opBT_w_r_a16(uint32_t fetchdat) uint16_t temp; fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = 0; temp = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); - if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 0); @@ -18,11 +19,12 @@ static int opBT_w_r_a32(uint32_t fetchdat) uint16_t temp; fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = 0; temp = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); - if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 1); @@ -33,11 +35,12 @@ static int opBT_l_r_a16(uint32_t fetchdat) uint32_t temp; fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = 0; temp = geteal(); if (cpu_state.abrt) return 1; flags_rebuild(); - if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 0); @@ -48,11 +51,12 @@ static int opBT_l_r_a32(uint32_t fetchdat) uint32_t temp; fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = 0; temp = geteal(); if (cpu_state.abrt) return 1; flags_rebuild(); - if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 1); @@ -66,14 +70,16 @@ static int opBT_l_r_a32(uint32_t fetchdat) uint16_t temp; \ \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = eal_w = 0; \ temp = geteaw(); if (cpu_state.abrt) return 1; \ tempc = (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) ? 1 : 0; \ temp operation (1 << (cpu_state.regs[cpu_reg].w & 15)); \ seteaw(temp); if (cpu_state.abrt) return 1; \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ - else flags &= ~C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ \ CLOCK_CYCLES(6); \ PREFETCH_RUN(6, 2, rmdat, 1,0,1,0, 0); \ @@ -85,14 +91,16 @@ static int opBT_l_r_a32(uint32_t fetchdat) uint16_t temp; \ \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = eal_w = 0; \ temp = geteaw(); if (cpu_state.abrt) return 1; \ tempc = (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) ? 1 : 0; \ temp operation (1 << (cpu_state.regs[cpu_reg].w & 15)); \ seteaw(temp); if (cpu_state.abrt) return 1; \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ - else flags &= ~C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ \ CLOCK_CYCLES(6); \ PREFETCH_RUN(6, 2, rmdat, 1,0,1,0, 1); \ @@ -104,14 +112,16 @@ static int opBT_l_r_a32(uint32_t fetchdat) uint32_t temp; \ \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = eal_w = 0; \ temp = geteal(); if (cpu_state.abrt) return 1; \ tempc = (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) ? 1 : 0; \ temp operation (1 << (cpu_state.regs[cpu_reg].l & 31)); \ seteal(temp); if (cpu_state.abrt) return 1; \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ - else flags &= ~C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ \ CLOCK_CYCLES(6); \ PREFETCH_RUN(6, 2, rmdat, 0,1,0,1, 0); \ @@ -123,14 +133,16 @@ static int opBT_l_r_a32(uint32_t fetchdat) uint32_t temp; \ \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = eal_w = 0; \ temp = geteal(); if (cpu_state.abrt) return 1; \ tempc = (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) ? 1 : 0; \ temp operation (1 << (cpu_state.regs[cpu_reg].l & 31)); \ seteal(temp); if (cpu_state.abrt) return 1; \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ - else flags &= ~C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ \ CLOCK_CYCLES(6); \ PREFETCH_RUN(6, 2, rmdat, 0,1,0,1, 1); \ @@ -147,6 +159,8 @@ static int opBA_w_a16(uint32_t fetchdat) uint16_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); count = getbyte(); if (cpu_state.abrt) return 1; @@ -155,8 +169,8 @@ static int opBA_w_a16(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x20: /*BT w,imm*/ - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); return 0; @@ -177,8 +191,8 @@ static int opBA_w_a16(uint32_t fetchdat) break; } seteaw(temp); if (cpu_state.abrt) return 1; - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(6); PREFETCH_RUN(6, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); return 0; @@ -189,6 +203,8 @@ static int opBA_w_a32(uint32_t fetchdat) uint16_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); count = getbyte(); if (cpu_state.abrt) return 1; @@ -197,8 +213,8 @@ static int opBA_w_a32(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x20: /*BT w,imm*/ - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); return 0; @@ -219,8 +235,8 @@ static int opBA_w_a32(uint32_t fetchdat) break; } seteaw(temp); if (cpu_state.abrt) return 1; - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(6); PREFETCH_RUN(6, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); return 0; @@ -232,6 +248,8 @@ static int opBA_l_a16(uint32_t fetchdat) uint32_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); count = getbyte(); if (cpu_state.abrt) return 1; @@ -240,8 +258,8 @@ static int opBA_l_a16(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x20: /*BT w,imm*/ - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); return 0; @@ -262,8 +280,8 @@ static int opBA_l_a16(uint32_t fetchdat) break; } seteal(temp); if (cpu_state.abrt) return 1; - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(6); PREFETCH_RUN(6, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); return 0; @@ -274,6 +292,8 @@ static int opBA_l_a32(uint32_t fetchdat) uint32_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); count = getbyte(); if (cpu_state.abrt) return 1; @@ -282,8 +302,8 @@ static int opBA_l_a32(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x20: /*BT w,imm*/ - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); return 0; @@ -304,8 +324,8 @@ static int opBA_l_a32(uint32_t fetchdat) break; } seteal(temp); if (cpu_state.abrt) return 1; - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(6); PREFETCH_RUN(6, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); return 0; diff --git a/src/cpu/x86_ops_bitscan.h b/src/cpu/x86_ops_bitscan.h index 9252b4b87..46f0fc605 100644 --- a/src/cpu/x86_ops_bitscan.h +++ b/src/cpu/x86_ops_bitscan.h @@ -4,7 +4,7 @@ if (temp) \ { \ int c; \ - flags &= ~Z_FLAG; \ + cpu_state.flags &= ~Z_FLAG; \ for (c = start; c != end; c += dir) \ { \ CLOCK_CYCLES(time); \ @@ -17,7 +17,7 @@ } \ } \ else \ - flags |= Z_FLAG; + cpu_state.flags |= Z_FLAG; static int opBSF_w_a16(uint32_t fetchdat) { @@ -25,6 +25,8 @@ static int opBSF_w_a16(uint32_t fetchdat) int instr_cycles = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; BS_common(0, 16, 1, cpu_state.regs[cpu_reg].w, (is486) ? 1 : 3); @@ -40,6 +42,8 @@ static int opBSF_w_a32(uint32_t fetchdat) int instr_cycles = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; BS_common(0, 16, 1, cpu_state.regs[cpu_reg].w, (is486) ? 1 : 3); @@ -55,6 +59,8 @@ static int opBSF_l_a16(uint32_t fetchdat) int instr_cycles = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; BS_common(0, 32, 1, cpu_state.regs[cpu_reg].l, (is486) ? 1 : 3); @@ -70,6 +76,8 @@ static int opBSF_l_a32(uint32_t fetchdat) int instr_cycles = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; BS_common(0, 32, 1, cpu_state.regs[cpu_reg].l, (is486) ? 1 : 3); @@ -86,6 +94,8 @@ static int opBSR_w_a16(uint32_t fetchdat) int instr_cycles = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; BS_common(15, -1, -1, cpu_state.regs[cpu_reg].w, 3); @@ -101,6 +111,8 @@ static int opBSR_w_a32(uint32_t fetchdat) int instr_cycles = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; BS_common(15, -1, -1, cpu_state.regs[cpu_reg].w, 3); @@ -116,6 +128,8 @@ static int opBSR_l_a16(uint32_t fetchdat) int instr_cycles = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; BS_common(31, -1, -1, cpu_state.regs[cpu_reg].l, 3); @@ -131,6 +145,8 @@ static int opBSR_l_a32(uint32_t fetchdat) int instr_cycles = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; BS_common(31, -1, -1, cpu_state.regs[cpu_reg].l, 3); diff --git a/src/cpu/x86_ops_call.h b/src/cpu/x86_ops_call.h index 30e60410c..8c52e632e 100644 --- a/src/cpu/x86_ops_call.h +++ b/src/cpu/x86_ops_call.h @@ -1,11 +1,11 @@ #define CALL_FAR_w(new_seg, new_pc) \ old_cs = CS; \ old_pc = cpu_state.pc; \ - oxpc = cpu_state.pc; \ + oxpc = cpu_state.pc; \ cpu_state.pc = new_pc; \ optype = CALL; \ cgate16 = cgate32 = 0; \ - if (msw & 1) loadcscall(new_seg); \ + if (msw & 1) loadcscall(new_seg); \ else \ { \ loadcs(new_seg); \ @@ -30,11 +30,11 @@ #define CALL_FAR_l(new_seg, new_pc) \ old_cs = CS; \ old_pc = cpu_state.pc; \ - oxpc = cpu_state.pc; \ + oxpc = cpu_state.pc; \ cpu_state.pc = new_pc; \ optype = CALL; \ cgate16 = cgate32 = 0; \ - if (msw & 1) loadcscall(new_seg); \ + if (msw & 1) loadcscall(new_seg); \ else \ { \ loadcs(new_seg); \ @@ -104,6 +104,8 @@ static int opFF_w_a16(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*INC w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(temp + 1); if (cpu_state.abrt) return 1; setadd16nc(temp, 1); @@ -111,6 +113,8 @@ static int opFF_w_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); break; case 0x08: /*DEC w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(temp - 1); if (cpu_state.abrt) return 1; setsub16nc(temp, 1); @@ -118,6 +122,8 @@ static int opFF_w_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); break; case 0x10: /*CALL*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteaw(); if (cpu_state.abrt) return 1; PUSH_W(cpu_state.pc); cpu_state.pc = new_pc; @@ -128,6 +134,8 @@ static int opFF_w_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x18: /*CALL far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1; @@ -137,6 +145,8 @@ static int opFF_w_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x20: /*JMP*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteaw(); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); @@ -146,6 +156,8 @@ static int opFF_w_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); oxpc = cpu_state.pc; new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; @@ -156,6 +168,8 @@ static int opFF_w_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x30: /*PUSH w*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; PUSH_W(temp); CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); @@ -181,6 +195,8 @@ static int opFF_w_a32(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*INC w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(temp + 1); if (cpu_state.abrt) return 1; setadd16nc(temp, 1); @@ -188,6 +204,8 @@ static int opFF_w_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); break; case 0x08: /*DEC w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(temp - 1); if (cpu_state.abrt) return 1; setsub16nc(temp, 1); @@ -195,6 +213,8 @@ static int opFF_w_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); break; case 0x10: /*CALL*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteaw(); if (cpu_state.abrt) return 1; PUSH_W(cpu_state.pc); cpu_state.pc = new_pc; @@ -205,6 +225,8 @@ static int opFF_w_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x18: /*CALL far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1; @@ -214,6 +236,8 @@ static int opFF_w_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x20: /*JMP*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteaw(); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); @@ -223,6 +247,8 @@ static int opFF_w_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); oxpc = cpu_state.pc; new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; @@ -233,6 +259,8 @@ static int opFF_w_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x30: /*PUSH w*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; PUSH_W(temp); CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); @@ -259,6 +287,8 @@ static int opFF_l_a16(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*INC l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(temp + 1); if (cpu_state.abrt) return 1; setadd32nc(temp, 1); @@ -266,6 +296,8 @@ static int opFF_l_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); break; case 0x08: /*DEC l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(temp - 1); if (cpu_state.abrt) return 1; setsub32nc(temp, 1); @@ -273,6 +305,8 @@ static int opFF_l_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); break; case 0x10: /*CALL*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteal(); if (cpu_state.abrt) return 1; PUSH_L(cpu_state.pc); cpu_state.pc = new_pc; @@ -283,6 +317,8 @@ static int opFF_l_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x18: /*CALL far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1; @@ -292,6 +328,8 @@ static int opFF_l_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x20: /*JMP*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteal(); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); @@ -301,6 +339,8 @@ static int opFF_l_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); oxpc = cpu_state.pc; new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; @@ -311,6 +351,8 @@ static int opFF_l_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x30: /*PUSH l*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; PUSH_L(temp); CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); @@ -336,6 +378,8 @@ static int opFF_l_a32(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*INC l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(temp + 1); if (cpu_state.abrt) return 1; setadd32nc(temp, 1); @@ -343,6 +387,8 @@ static int opFF_l_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); break; case 0x08: /*DEC l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(temp - 1); if (cpu_state.abrt) return 1; setsub32nc(temp, 1); @@ -350,6 +396,8 @@ static int opFF_l_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); break; case 0x10: /*CALL*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteal(); if (cpu_state.abrt) return 1; PUSH_L(cpu_state.pc); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; @@ -360,6 +408,8 @@ static int opFF_l_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x18: /*CALL far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1; @@ -369,6 +419,8 @@ static int opFF_l_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x20: /*JMP*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteal(); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); @@ -378,6 +430,8 @@ static int opFF_l_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); oxpc = cpu_state.pc; new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; @@ -388,6 +442,8 @@ static int opFF_l_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x30: /*PUSH l*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; PUSH_L(temp); PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 1); diff --git a/src/cpu/x86_ops_flag.h b/src/cpu/x86_ops_flag.h index 59c692c65..8441b4987 100644 --- a/src/cpu/x86_ops_flag.h +++ b/src/cpu/x86_ops_flag.h @@ -1,7 +1,7 @@ static int opCMC(uint32_t fetchdat) { flags_rebuild(); - flags ^= C_FLAG; + cpu_state.flags ^= C_FLAG; CLOCK_CYCLES(2); PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); return 0; @@ -11,14 +11,14 @@ static int opCMC(uint32_t fetchdat) static int opCLC(uint32_t fetchdat) { flags_rebuild(); - flags &= ~C_FLAG; + cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(2); PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); return 0; } static int opCLD(uint32_t fetchdat) { - flags &= ~D_FLAG; + cpu_state.flags &= ~D_FLAG; CLOCK_CYCLES(2); PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); return 0; @@ -27,10 +27,10 @@ static int opCLI(uint32_t fetchdat) { if (!IOPLp) { - if ((!(eflags & VM_FLAG) && (cr4 & CR4_PVI)) || - ((eflags & VM_FLAG) && (cr4 & CR4_VME))) + if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) { - eflags &= ~VIF_FLAG; + cpu_state.eflags &= ~VIF_FLAG; } else { @@ -39,7 +39,7 @@ static int opCLI(uint32_t fetchdat) } } else - flags &= ~I_FLAG; + cpu_state.flags &= ~I_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); @@ -49,14 +49,14 @@ static int opCLI(uint32_t fetchdat) static int opSTC(uint32_t fetchdat) { flags_rebuild(); - flags |= C_FLAG; + cpu_state.flags |= C_FLAG; CLOCK_CYCLES(2); PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); return 0; } static int opSTD(uint32_t fetchdat) { - flags |= D_FLAG; + cpu_state.flags |= D_FLAG; CLOCK_CYCLES(2); PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); return 0; @@ -65,16 +65,16 @@ static int opSTI(uint32_t fetchdat) { if (!IOPLp) { - if ((!(eflags & VM_FLAG) && (cr4 & CR4_PVI)) || - ((eflags & VM_FLAG) && (cr4 & CR4_VME))) + if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) { - if (eflags & VIP_FLAG) + if (cpu_state.eflags & VIP_FLAG) { x86gpf(NULL,0); return 1; } else - eflags |= VIF_FLAG; + cpu_state.eflags |= VIF_FLAG; } else { @@ -83,7 +83,7 @@ static int opSTI(uint32_t fetchdat) } } else - flags |= I_FLAG; + cpu_state.flags |= I_FLAG; CPU_BLOCK_END(); @@ -95,7 +95,7 @@ static int opSTI(uint32_t fetchdat) static int opSAHF(uint32_t fetchdat) { flags_rebuild(); - flags = (flags & 0xff00) | (AH & 0xd5) | 2; + cpu_state.flags = (cpu_state.flags & 0xff00) | (AH & 0xd5) | 2; CLOCK_CYCLES(3); PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); @@ -108,7 +108,7 @@ static int opSAHF(uint32_t fetchdat) static int opLAHF(uint32_t fetchdat) { flags_rebuild(); - AH = flags & 0xff; + AH = cpu_state.flags & 0xff; CLOCK_CYCLES(3); PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); return 0; @@ -116,15 +116,15 @@ static int opLAHF(uint32_t fetchdat) static int opPUSHF(uint32_t fetchdat) { - if ((eflags & VM_FLAG) && (IOPL < 3)) + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { if (cr4 & CR4_VME) { uint16_t temp; flags_rebuild(); - temp = (flags & ~I_FLAG) | 0x3000; - if (eflags & VIF_FLAG) + temp = (cpu_state.flags & ~I_FLAG) | 0x3000; + if (cpu_state.eflags & VIF_FLAG) temp |= I_FLAG; PUSH_W(temp); } @@ -137,7 +137,7 @@ static int opPUSHF(uint32_t fetchdat) else { flags_rebuild(); - PUSH_W(flags); + PUSH_W(cpu_state.flags); } CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); @@ -146,16 +146,16 @@ static int opPUSHF(uint32_t fetchdat) static int opPUSHFD(uint32_t fetchdat) { uint16_t tempw; - if ((eflags & VM_FLAG) && (IOPL < 3)) + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { x86gpf(NULL, 0); return 1; } - if (cpu_CR4_mask & CR4_VME) tempw = eflags & 0x3c; - else if (CPUID) tempw = eflags & 0x24; - else tempw = eflags & 4; + if (cpu_CR4_mask & CR4_VME) tempw = cpu_state.eflags & 0x3c; + else if (CPUID) tempw = cpu_state.eflags & 0x24; + else tempw = cpu_state.eflags & 4; flags_rebuild(); - PUSH_L(flags | (tempw << 16)); + PUSH_L(cpu_state.flags | (tempw << 16)); CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,1, 0); return cpu_state.abrt; @@ -165,7 +165,7 @@ static int opPOPF_286(uint32_t fetchdat) { uint16_t tempw; - if ((eflags & VM_FLAG) && (IOPL < 3)) + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { x86gpf(NULL, 0); return 1; @@ -173,10 +173,10 @@ static int opPOPF_286(uint32_t fetchdat) tempw = POP_W(); if (cpu_state.abrt) return 1; - if (!(msw & 1)) flags = (flags & 0x7000) | (tempw & 0x0fd5) | 2; - else if (!(CPL)) flags = (tempw & 0x7fd5) | 2; - else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; - else flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + if (!(msw & 1)) cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2; + else if (!(CPL)) cpu_state.flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2; + else cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; flags_extract(); CLOCK_CYCLES(5); @@ -192,7 +192,7 @@ static int opPOPF(uint32_t fetchdat) { uint16_t tempw; - if ((eflags & VM_FLAG) && (IOPL < 3)) + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { if (cr4 & CR4_VME) { @@ -206,17 +206,17 @@ static int opPOPF(uint32_t fetchdat) return 1; } - if ((tempw & T_FLAG) || ((tempw & I_FLAG) && (eflags & VIP_FLAG))) + if ((tempw & T_FLAG) || ((tempw & I_FLAG) && (cpu_state.eflags & VIP_FLAG))) { ESP = old_esp; x86gpf(NULL, 0); return 1; } if (tempw & I_FLAG) - eflags |= VIF_FLAG; + cpu_state.eflags |= VIF_FLAG; else - eflags &= ~VIF_FLAG; - flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + cpu_state.eflags &= ~VIF_FLAG; + cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; } else { @@ -231,11 +231,11 @@ static int opPOPF(uint32_t fetchdat) return 1; if (!(CPL) || !(msw & 1)) - flags = (tempw & 0x7fd5) | 2; + cpu_state.flags = (tempw & 0x7fd5) | 2; else if (IOPLp) - flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; + cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2; else - flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; } flags_extract(); @@ -252,7 +252,7 @@ static int opPOPFD(uint32_t fetchdat) { uint32_t templ; - if ((eflags & VM_FLAG) && (IOPL < 3)) + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { x86gpf(NULL, 0); return 1; @@ -260,16 +260,16 @@ static int opPOPFD(uint32_t fetchdat) templ = POP_L(); if (cpu_state.abrt) return 1; - if (!(CPL) || !(msw & 1)) flags = (templ & 0x7fd5) | 2; - else if (IOPLp) flags = (flags & 0x3000) | (templ & 0x4fd5) | 2; - else flags = (flags & 0x3200) | (templ & 0x4dd5) | 2; + if (!(CPL) || !(msw & 1)) cpu_state.flags = (templ & 0x7fd5) | 2; + else if (IOPLp) cpu_state.flags = (cpu_state.flags & 0x3000) | (templ & 0x4fd5) | 2; + else cpu_state.flags = (cpu_state.flags & 0x3200) | (templ & 0x4dd5) | 2; templ &= is486 ? 0x3c0000 : 0; - templ |= ((eflags&3) << 16); - if (cpu_CR4_mask & CR4_VME) eflags = (templ >> 16) & 0x3f; - else if (CPUID) eflags = (templ >> 16) & 0x27; - else if (is486) eflags = (templ >> 16) & 7; - else eflags = (templ >> 16) & 3; + templ |= ((cpu_state.eflags&3) << 16); + if (cpu_CR4_mask & CR4_VME) cpu_state.eflags = (templ >> 16) & 0x3f; + else if (CPUID) cpu_state.eflags = (templ >> 16) & 0x27; + else if (is486) cpu_state.eflags = (templ >> 16) & 7; + else cpu_state.eflags = (templ >> 16) & 3; flags_extract(); diff --git a/src/cpu/x86_ops_i686.h b/src/cpu/x86_ops_i686.h index 7d0eeb16e..6d4cf7484 100644 --- a/src/cpu/x86_ops_i686.h +++ b/src/cpu/x86_ops_i686.h @@ -43,15 +43,15 @@ static int opSYSENTER(uint32_t fetchdat) x386_dynarec_log("SYSENTER called\n"); #endif - if (!(cr0 & 1)) return internal_illegal("SYSENTER: CPU not in protected mode"); + if (!(msw & 1)) return internal_illegal("SYSENTER: CPU not in protected mode"); if (!(cs_msr & 0xFFFC)) return internal_illegal("SYSENTER: CS MSR is zero"); #ifdef SYSENTER_LOG x386_dynarec_log("SYSENTER started:\n"); - x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); - x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); - x386_dynarec_log("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, eflags, flags, use32, stack32); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32); #endif if (cpu_state.abrt) return 1; @@ -63,17 +63,17 @@ static int opSYSENTER(uint32_t fetchdat) cgate16 = cgate32 = 0; \ /* Set VM, RF, and IF to 0. */ - eflags &= ~0x0003; - flags &= ~0x0200; + cpu_state.eflags &= ~(VM_FLAG | 0x0001); + cpu_state.flags &= ~I_FLAG; CS = (cs_msr & 0xFFFC); make_seg_data(sysenter_cs_seg_data, 0, 0xFFFFF, 11, 1, 0, 1, 1, 1, 0); - do_seg_load(&_cs, sysenter_cs_seg_data); + do_seg_load(&cpu_state.seg_cs, sysenter_cs_seg_data); use32 = 0x300; SS = ((cs_msr + 8) & 0xFFFC); make_seg_data(sysenter_ss_seg_data, 0, 0xFFFFF, 3, 1, 0, 1, 1, 1, 0); - do_seg_load(&_ss, sysenter_ss_seg_data); + do_seg_load(&cpu_state.seg_ss, sysenter_ss_seg_data); stack32 = 1; cycles -= timing_call_pm; @@ -84,10 +84,10 @@ static int opSYSENTER(uint32_t fetchdat) #ifdef SYSENTER_LOG x386_dynarec_log("SYSENTER completed:\n"); - x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); - x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); - x386_dynarec_log("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, eflags, flags, use32, stack32); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32); #endif return 0; @@ -103,15 +103,15 @@ static int opSYSEXIT(uint32_t fetchdat) #endif if (!(cs_msr & 0xFFFC)) return internal_illegal("SYSEXIT: CS MSR is zero"); - if (!(cr0 & 1)) return internal_illegal("SYSEXIT: CPU not in protected mode"); - if (CS & 3) return internal_illegal("SYSEXIT: CPL not 0"); + if (!(msw & 1)) return internal_illegal("SYSEXIT: CPU not in protected mode"); + if (CPL) return internal_illegal("SYSEXIT: CPL not 0"); #ifdef SYSEXIT_LOG x386_dynarec_log("SYSEXIT start:\n"); - x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); - x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); - x386_dynarec_log("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, eflags, flags, use32, stack32, ECX, EDX); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32, ECX, EDX); #endif if (cpu_state.abrt) return 1; @@ -124,12 +124,12 @@ static int opSYSEXIT(uint32_t fetchdat) CS = ((cs_msr + 16) & 0xFFFC) | 3; make_seg_data(sysexit_cs_seg_data, 0, 0xFFFFF, 11, 1, 3, 1, 1, 1, 0); - do_seg_load(&_cs, sysexit_cs_seg_data); + do_seg_load(&cpu_state.seg_cs, sysexit_cs_seg_data); use32 = 0x300; SS = CS + 8; make_seg_data(sysexit_ss_seg_data, 0, 0xFFFFF, 3, 1, 3, 1, 1, 1, 0); - do_seg_load(&_ss, sysexit_ss_seg_data); + do_seg_load(&cpu_state.seg_ss, sysexit_ss_seg_data); stack32 = 1; flushmmucache_cr3(); @@ -142,10 +142,10 @@ static int opSYSEXIT(uint32_t fetchdat) #ifdef SYSEXIT_LOG x386_dynarec_log("SYSEXIT completed:\n"); - x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); - x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); - x386_dynarec_log("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, eflags, flags, use32, stack32, ECX, EDX); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32, ECX, EDX); #endif return 0; @@ -202,7 +202,7 @@ static int opFXSAVESTOR_a16(uint32_t fetchdat) /* if (cr0 & 1) { x87_pc_seg &= 0xFFFC; - x87_pc_seg |= ((_cs.access >> 5) & 3); + x87_pc_seg |= ((cpu_state.seg_cs.access >> 5) & 3); } */ ftwb = readmemb(easeg, cpu_state.eaaddr + 4); @@ -380,7 +380,7 @@ static int opFXSAVESTOR_a32(uint32_t fetchdat) /* if (cr0 & 1) { x87_pc_seg &= 0xFFFC; - x87_pc_seg |= ((_cs.access >> 5) & 3); + x87_pc_seg |= ((cpu_state.seg_cs.access >> 5) & 3); } */ ftwb = readmemb(easeg, cpu_state.eaaddr + 4); diff --git a/src/cpu/x86_ops_inc_dec.h b/src/cpu/x86_ops_inc_dec.h index 56293c7bf..ff4a4ab73 100644 --- a/src/cpu/x86_ops_inc_dec.h +++ b/src/cpu/x86_ops_inc_dec.h @@ -49,7 +49,9 @@ static int opINCDEC_b_a16(uint32_t fetchdat) { uint8_t temp; - fetch_ea_16(fetchdat); + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp=geteab(); if (cpu_state.abrt) return 1; if (rmdat&0x38) @@ -70,7 +72,9 @@ static int opINCDEC_b_a32(uint32_t fetchdat) { uint8_t temp; - fetch_ea_32(fetchdat); + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp=geteab(); if (cpu_state.abrt) return 1; if (rmdat&0x38) diff --git a/src/cpu/x86_ops_int.h b/src/cpu/x86_ops_int.h index 5aa05fc11..260fcdad5 100644 --- a/src/cpu/x86_ops_int.h +++ b/src/cpu/x86_ops_int.h @@ -1,7 +1,7 @@ static int opINT3(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); return 1; @@ -15,7 +15,7 @@ static int opINT3(uint32_t fetchdat) static int opINT1(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); return 1; @@ -31,7 +31,7 @@ static int opINT(uint32_t fetchdat) int cycles_old = cycles; UN_USED(cycles_old); uint8_t temp = getbytef(); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { if (cr4 & CR4_VME) { @@ -72,7 +72,7 @@ static int opINTO(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); return 1; diff --git a/src/cpu/x86_ops_jump.h b/src/cpu/x86_ops_jump.h index 63ca65ea0..6eb9862af 100644 --- a/src/cpu/x86_ops_jump.h +++ b/src/cpu/x86_ops_jump.h @@ -247,12 +247,12 @@ static int opJMP_r32(uint32_t fetchdat) static int opJMP_far_a16(uint32_t fetchdat) { uint16_t addr, seg; - uint32_t oxpc; + uint32_t old_pc; addr = getwordf(); seg = getword(); if (cpu_state.abrt) return 1; - oxpc = cpu_state.pc; + old_pc = cpu_state.pc; cpu_state.pc = addr; - loadcsjmp(seg, oxpc); + loadcsjmp(seg, old_pc); CPU_BLOCK_END(); PREFETCH_RUN(11, 5, -1, 0,0,0,0, 0); PREFETCH_FLUSH(); @@ -261,12 +261,12 @@ static int opJMP_far_a16(uint32_t fetchdat) static int opJMP_far_a32(uint32_t fetchdat) { uint16_t seg; - uint32_t addr, oxpc; + uint32_t addr, old_pc; addr = getlong(); seg = getword(); if (cpu_state.abrt) return 1; - oxpc = cpu_state.pc; + old_pc = cpu_state.pc; cpu_state.pc = addr; - loadcsjmp(seg, oxpc); + loadcsjmp(seg, old_pc); CPU_BLOCK_END(); PREFETCH_RUN(11, 7, -1, 0,0,0,0, 0); PREFETCH_FLUSH(); diff --git a/src/cpu/x86_ops_misc.h b/src/cpu/x86_ops_misc.h index f7bf454b6..b9d35a73c 100644 --- a/src/cpu/x86_ops_misc.h +++ b/src/cpu/x86_ops_misc.h @@ -70,15 +70,15 @@ static int opF6_a16(uint32_t fetchdat) int8_t temps; fetch_ea_16(fetchdat); - if (cpu_mod != 3) - { + if (cpu_mod != 3) { + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); } dst = geteab(); if (cpu_state.abrt) return 1; 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); @@ -86,11 +86,15 @@ static int opF6_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; case 0x10: /*NOT b*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteab(~dst); if (cpu_state.abrt) return 1; CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); break; case 0x18: /*NEG b*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteab(0 - dst); if (cpu_state.abrt) return 1; setsub8(0, dst); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); @@ -99,8 +103,8 @@ static int opF6_a16(uint32_t fetchdat) case 0x20: /*MUL AL,b*/ AX = AL * dst; flags_rebuild(); - if (AH) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (AH) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(13); PREFETCH_RUN(13, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; @@ -108,8 +112,8 @@ static int opF6_a16(uint32_t fetchdat) tempws = (int)((int8_t)AL) * (int)((int8_t)dst); AX = tempws & 0xffff; flags_rebuild(); - if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(14); PREFETCH_RUN(14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; @@ -123,8 +127,8 @@ static int opF6_a16(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - flags |= 0x8D5; /*Not a Cyrix*/ - flags &= ~1; + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -146,8 +150,8 @@ static int opF6_a16(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - flags|=0x8D5; /*Not a Cyrix*/ - flags &= ~1; + cpu_state.flags|=0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -173,11 +177,13 @@ static int opF6_a32(uint32_t fetchdat) int8_t temps; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteab(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) { case 0x00: /*TEST b,#8*/ - case 0x08: + case 0x08: src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; setznp8(src & dst); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -185,11 +191,15 @@ static int opF6_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; case 0x10: /*NOT b*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteab(~dst); if (cpu_state.abrt) return 1; CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); break; case 0x18: /*NEG b*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteab(0 - dst); if (cpu_state.abrt) return 1; setsub8(0, dst); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); @@ -198,8 +208,8 @@ static int opF6_a32(uint32_t fetchdat) case 0x20: /*MUL AL,b*/ AX = AL * dst; flags_rebuild(); - if (AH) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (AH) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(13); PREFETCH_RUN(13, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; @@ -207,8 +217,8 @@ static int opF6_a32(uint32_t fetchdat) tempws = (int)((int8_t)AL) * (int)((int8_t)dst); AX = tempws & 0xffff; flags_rebuild(); - if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(14); PREFETCH_RUN(14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; @@ -222,8 +232,8 @@ static int opF6_a32(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - flags |= 0x8D5; /*Not a Cyrix*/ - flags &= ~1; + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -245,8 +255,8 @@ static int opF6_a32(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - flags|=0x8D5; /*Not a Cyrix*/ - flags &= ~1; + cpu_state.flags|=0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -275,6 +285,8 @@ static int opF7_w_a16(uint32_t fetchdat) uint16_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteaw(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) { @@ -287,11 +299,15 @@ static int opF7_w_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; case 0x10: /*NOT w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(~dst); if (cpu_state.abrt) return 1; CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); break; case 0x18: /*NEG w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(0 - dst); if (cpu_state.abrt) return 1; setsub16(0, dst); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); @@ -302,8 +318,8 @@ static int opF7_w_a16(uint32_t fetchdat) AX = templ & 0xFFFF; DX = templ >> 16; flags_rebuild(); - if (DX) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (DX) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(21); PREFETCH_RUN(21, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; @@ -312,8 +328,8 @@ static int opF7_w_a16(uint32_t fetchdat) AX = templ & 0xFFFF; DX = templ >> 16; flags_rebuild(); - if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(22); PREFETCH_RUN(22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; @@ -362,11 +378,13 @@ static int opF7_w_a16(uint32_t fetchdat) static int opF7_w_a32(uint32_t fetchdat) { uint32_t templ, templ2; - int tempws, tempws2 = 0; + int tempws, tempws2 = 1; int16_t temps16; uint16_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteaw(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) { @@ -379,11 +397,15 @@ static int opF7_w_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; case 0x10: /*NOT w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(~dst); if (cpu_state.abrt) return 1; CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); break; case 0x18: /*NEG w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(0 - dst); if (cpu_state.abrt) return 1; setsub16(0, dst); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); @@ -394,8 +416,8 @@ static int opF7_w_a32(uint32_t fetchdat) AX = templ & 0xFFFF; DX = templ >> 16; flags_rebuild(); - if (DX) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (DX) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(21); PREFETCH_RUN(21, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; @@ -404,8 +426,8 @@ static int opF7_w_a32(uint32_t fetchdat) AX = templ & 0xFFFF; DX = templ >> 16; flags_rebuild(); - if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(22); PREFETCH_RUN(22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; @@ -458,6 +480,8 @@ static int opF7_l_a16(uint32_t fetchdat) uint32_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteal(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) @@ -471,11 +495,15 @@ static int opF7_l_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 5, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); break; case 0x10: /*NOT l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(~dst); if (cpu_state.abrt) return 1; CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); break; case 0x18: /*NEG l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(0 - dst); if (cpu_state.abrt) return 1; setsub32(0, dst); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); @@ -486,8 +514,8 @@ static int opF7_l_a16(uint32_t fetchdat) EAX = temp64 & 0xffffffff; EDX = temp64 >> 32; flags_rebuild(); - if (EDX) flags |= (C_FLAG|V_FLAG); - else flags &= ~(C_FLAG|V_FLAG); + if (EDX) cpu_state.flags |= (C_FLAG|V_FLAG); + else cpu_state.flags &= ~(C_FLAG|V_FLAG); CLOCK_CYCLES(21); PREFETCH_RUN(21, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); break; @@ -496,8 +524,8 @@ static int opF7_l_a16(uint32_t fetchdat) EAX = temp64 & 0xffffffff; EDX = temp64 >> 32; flags_rebuild(); - if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(38); PREFETCH_RUN(38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); break; @@ -528,6 +556,8 @@ static int opF7_l_a32(uint32_t fetchdat) uint32_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteal(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) @@ -541,11 +571,15 @@ static int opF7_l_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 5, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); break; case 0x10: /*NOT l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(~dst); if (cpu_state.abrt) return 1; CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); break; case 0x18: /*NEG l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(0 - dst); if (cpu_state.abrt) return 1; setsub32(0, dst); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); @@ -556,8 +590,8 @@ static int opF7_l_a32(uint32_t fetchdat) EAX = temp64 & 0xffffffff; EDX = temp64 >> 32; flags_rebuild(); - if (EDX) flags |= (C_FLAG|V_FLAG); - else flags &= ~(C_FLAG|V_FLAG); + if (EDX) cpu_state.flags |= (C_FLAG|V_FLAG); + else cpu_state.flags &= ~(C_FLAG|V_FLAG); CLOCK_CYCLES(21); PREFETCH_RUN(21, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); break; @@ -566,8 +600,8 @@ static int opF7_l_a32(uint32_t fetchdat) EAX = temp64 & 0xffffffff; EDX = temp64 >> 32; flags_rebuild(); - if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(38); PREFETCH_RUN(38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); break; @@ -596,12 +630,12 @@ static int opF7_l_a32(uint32_t fetchdat) static int opHLT(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x86gpf(NULL,0); return 1; } - if (!((flags&I_FLAG) && pic_intpending)) + if (!((cpu_state.flags&I_FLAG) && pic_intpending)) { CLOCK_CYCLES_ALWAYS(100); cpu_state.pc--; @@ -637,6 +671,7 @@ static int opBOUND_w_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); low = geteaw(); high = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; @@ -656,6 +691,7 @@ static int opBOUND_w_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); low = geteaw(); high = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; @@ -676,6 +712,7 @@ static int opBOUND_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); low = geteal(); high = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; @@ -695,6 +732,7 @@ static int opBOUND_l_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); low = geteal(); high = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; @@ -712,7 +750,7 @@ static int opBOUND_l_a32(uint32_t fetchdat) static int opCLTS(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't CLTS\n"); x86gpf(NULL,0); @@ -755,7 +793,7 @@ static int opLOADALL(uint32_t fetchdat) return 1; } msw = (msw & 1) | readmemw(0, 0x806); - flags = (readmemw(0, 0x818) & 0xffd5) | 2; + cpu_state.flags = (readmemw(0, 0x818) & 0xffd5) | 2; flags_extract(); tr.seg = readmemw(0, 0x816); cpu_state.pc = readmemw(0, 0x81A); @@ -773,22 +811,22 @@ static int opLOADALL(uint32_t fetchdat) CX = readmemw(0, 0x832); AX = readmemw(0, 0x834); es = readmemw(0, 0x836) | (readmemb(0, 0x838) << 16); - _es.access = readmemb(0, 0x839); - _es.limit = readmemw(0, 0x83A); + cpu_state.seg_es.access = readmemb(0, 0x839); + cpu_state.seg_es.limit = readmemw(0, 0x83A); cs = readmemw(0, 0x83C) | (readmemb(0, 0x83E) << 16); - _cs.access = readmemb(0, 0x83F); - _cs.limit = readmemw(0, 0x840); + cpu_state.seg_cs.access = readmemb(0, 0x83F); + cpu_state.seg_cs.limit = readmemw(0, 0x840); ss = readmemw(0, 0x842) | (readmemb(0, 0x844) << 16); - _ss.access = readmemb(0, 0x845); - _ss.limit = readmemw(0, 0x846); - if (_ss.base == 0 && _ss.limit_low == 0 && _ss.limit_high == 0xffffffff) + cpu_state.seg_ss.access = readmemb(0, 0x845); + cpu_state.seg_ss.limit = readmemw(0, 0x846); + if (cpu_state.seg_ss.base == 0 && cpu_state.seg_ss.limit_low == 0 && cpu_state.seg_ss.limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; else cpu_cur_status |= CPU_STATUS_NOTFLATSS; ds = readmemw(0, 0x848) | (readmemb(0, 0x84A) << 16); - _ds.access = readmemb(0, 0x84B); - _ds.limit = readmemw(0, 0x84C); - if (_ds.base == 0 && _ds.limit_low == 0 && _ds.limit_high == 0xffffffff) + cpu_state.seg_ds.access = readmemb(0, 0x84B); + cpu_state.seg_ds.limit = readmemw(0, 0x84C); + if (cpu_state.seg_ds.base == 0 && cpu_state.seg_ds.limit_low == 0 && cpu_state.seg_ds.limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; else cpu_cur_status |= CPU_STATUS_NOTFLATDS; @@ -829,8 +867,8 @@ static void loadall_load_segment(uint32_t addr, x86seg *s) s->base = readmeml(0, addr + 4); s->limit = readmeml(0, addr + 8); - if (s == &_cs) use32 = (segdat3 & 0x40) ? 0x300 : 0; - if (s == &_ss) stack32 = (segdat3 & 0x40) ? 1 : 0; + if (s == &cpu_state.seg_cs) use32 = (segdat3 & 0x40) ? 0x300 : 0; + if (s == &cpu_state.seg_ss) stack32 = (segdat3 & 0x40) ? 1 : 0; cpu_cur_status &= ~(CPU_STATUS_USE32 | CPU_STATUS_STACK32); if (use32) cpu_cur_status |= CPU_STATUS_USE32; @@ -839,14 +877,14 @@ static void loadall_load_segment(uint32_t addr, x86seg *s) set_segment_limit(s, segdat3); - if (s == &_ds) + if (s == &cpu_state.seg_ds) { if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; else cpu_cur_status |= CPU_STATUS_NOTFLATDS; } - if (s == &_ss) + if (s == &cpu_state.seg_ss) { if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; @@ -860,8 +898,8 @@ static int opLOADALL386(uint32_t fetchdat) uint32_t la_addr = es + EDI; cr0 = readmeml(0, la_addr); - flags = readmemw(0, la_addr + 4); - eflags = readmemw(0, la_addr + 6); + cpu_state.flags = readmemw(0, la_addr + 4); + cpu_state.eflags = readmemw(0, la_addr + 6); flags_extract(); cpu_state.pc = readmeml(0, la_addr + 8); EDI = readmeml(0, la_addr + 0xC); @@ -887,12 +925,12 @@ static int opLOADALL386(uint32_t fetchdat) loadall_load_segment(la_addr + 0x60, &idt); loadall_load_segment(la_addr + 0x6c, &gdt); loadall_load_segment(la_addr + 0x78, &ldt); - loadall_load_segment(la_addr + 0x84, &_gs); - loadall_load_segment(la_addr + 0x90, &_fs); - loadall_load_segment(la_addr + 0x9c, &_ds); - loadall_load_segment(la_addr + 0xa8, &_ss); - loadall_load_segment(la_addr + 0xb4, &_cs); - loadall_load_segment(la_addr + 0xc0, &_es); + loadall_load_segment(la_addr + 0x84, &cpu_state.seg_gs); + loadall_load_segment(la_addr + 0x90, &cpu_state.seg_fs); + loadall_load_segment(la_addr + 0x9c, &cpu_state.seg_ds); + loadall_load_segment(la_addr + 0xa8, &cpu_state.seg_ss); + loadall_load_segment(la_addr + 0xb4, &cpu_state.seg_cs); + loadall_load_segment(la_addr + 0xc0, &cpu_state.seg_es); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); @@ -915,7 +953,7 @@ static int opCPUID(uint32_t fetchdat) static int opRDMSR(uint32_t fetchdat) { - if (cpu_hasMSR) + if (cpu_has_feature(CPU_FEATURE_MSR)) { cpu_RDMSR(); CLOCK_CYCLES(9); @@ -928,7 +966,7 @@ static int opRDMSR(uint32_t fetchdat) static int opWRMSR(uint32_t fetchdat) { - if (cpu_hasMSR) + if (cpu_has_feature(CPU_FEATURE_MSR)) { cpu_WRMSR(); CLOCK_CYCLES(9); diff --git a/src/cpu/x86_ops_mmx.h b/src/cpu/x86_ops_mmx.h index 1af186d0b..107710f77 100644 --- a/src/cpu/x86_ops_mmx.h +++ b/src/cpu/x86_ops_mmx.h @@ -11,12 +11,13 @@ } \ else \ { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ src.q = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; \ CLOCK_CYCLES(2); \ } #define MMX_ENTER() \ - if (!cpu_hasMMX) \ + if (!cpu_has_feature(CPU_FEATURE_MMX)) \ { \ cpu_state.pc = cpu_state.oldpc; \ x86illegal(); \ @@ -31,7 +32,7 @@ static int opEMMS(uint32_t fetchdat) { - if (!cpu_hasMMX) + if (!cpu_has_feature(CPU_FEATURE_MMX)) { cpu_state.pc = cpu_state.oldpc; x86illegal(); diff --git a/src/cpu/x86_ops_mmx_arith.h b/src/cpu/x86_ops_mmx_arith.h index 302a44eaa..e8e1f31e5 100644 --- a/src/cpu/x86_ops_mmx_arith.h +++ b/src/cpu/x86_ops_mmx_arith.h @@ -293,7 +293,8 @@ static int opPMULLW_a16(uint32_t fetchdat) else { MMX_REG src; - + + SEG_CHECK_READ(cpu_state.ea_seg); src.l[0] = readmeml(easeg, cpu_state.eaaddr); src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].w[0] *= src.w[0]; @@ -320,7 +321,8 @@ static int opPMULLW_a32(uint32_t fetchdat) else { MMX_REG src; - + + SEG_CHECK_READ(cpu_state.ea_seg); src.l[0] = readmeml(easeg, cpu_state.eaaddr); src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].w[0] *= src.w[0]; @@ -348,7 +350,8 @@ static int opPMULHW_a16(uint32_t fetchdat) else { MMX_REG src; - + + SEG_CHECK_READ(cpu_state.ea_seg); src.l[0] = readmeml(easeg, cpu_state.eaaddr); src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) >> 16; @@ -375,7 +378,8 @@ static int opPMULHW_a32(uint32_t fetchdat) else { MMX_REG src; - + + SEG_CHECK_READ(cpu_state.ea_seg); src.l[0] = readmeml(easeg, cpu_state.eaaddr); src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) >> 16; diff --git a/src/cpu/x86_ops_mmx_cmp.h b/src/cpu/x86_ops_mmx_cmp.h index eb401b83f..0fee95923 100644 --- a/src/cpu/x86_ops_mmx_cmp.h +++ b/src/cpu/x86_ops_mmx_cmp.h @@ -166,7 +166,7 @@ static int opPCMPEQD_a32(uint32_t fetchdat) MMX_ENTER(); - fetch_ea_16(fetchdat); + fetch_ea_32(fetchdat); MMX_GETSRC(); cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].l[0] == src.l[0]) ? 0xffffffff : 0; @@ -195,7 +195,7 @@ static int opPCMPGTD_a32(uint32_t fetchdat) MMX_ENTER(); - fetch_ea_16(fetchdat); + fetch_ea_32(fetchdat); MMX_GETSRC(); cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; diff --git a/src/cpu/x86_ops_mmx_mov.h b/src/cpu/x86_ops_mmx_mov.h index d96df747b..14d192244 100644 --- a/src/cpu/x86_ops_mmx_mov.h +++ b/src/cpu/x86_ops_mmx_mov.h @@ -13,6 +13,7 @@ static int opMOVD_l_mm_a16(uint32_t fetchdat) { uint32_t dst; + SEG_CHECK_READ(cpu_state.ea_seg); dst = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; cpu_state.MM[cpu_reg].l[0] = dst; cpu_state.MM[cpu_reg].l[1] = 0; @@ -36,6 +37,7 @@ static int opMOVD_l_mm_a32(uint32_t fetchdat) { uint32_t dst; + SEG_CHECK_READ(cpu_state.ea_seg); dst = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; cpu_state.MM[cpu_reg].l[0] = dst; cpu_state.MM[cpu_reg].l[1] = 0; @@ -57,6 +59,7 @@ static int opMOVD_mm_l_a16(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; CLOCK_CYCLES(2); @@ -75,6 +78,7 @@ static int opMOVD_mm_l_a32(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; CLOCK_CYCLES(2); @@ -96,6 +100,7 @@ static int opMOVQ_q_mm_a16(uint32_t fetchdat) { uint64_t dst; + SEG_CHECK_READ(cpu_state.ea_seg); dst = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; cpu_state.MM[cpu_reg].q = dst; CLOCK_CYCLES(2); @@ -115,7 +120,8 @@ static int opMOVQ_q_mm_a32(uint32_t fetchdat) else { uint64_t dst; - + + SEG_CHECK_READ(cpu_state.ea_seg); dst = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; cpu_state.MM[cpu_reg].q = dst; CLOCK_CYCLES(2); @@ -135,6 +141,7 @@ static int opMOVQ_mm_q_a16(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); writememq(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].q); if (cpu_state.abrt) return 1; CLOCK_CYCLES(2); @@ -153,6 +160,7 @@ static int opMOVQ_mm_q_a32(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); writememq(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].q); if (cpu_state.abrt) return 1; CLOCK_CYCLES(2); diff --git a/src/cpu/x86_ops_mmx_pack.h b/src/cpu/x86_ops_mmx_pack.h index 50b813cb3..170aa0e42 100644 --- a/src/cpu/x86_ops_mmx_pack.h +++ b/src/cpu/x86_ops_mmx_pack.h @@ -12,6 +12,7 @@ static int opPUNPCKLDQ_a16(uint32_t fetchdat) { uint32_t src; + SEG_CHECK_READ(cpu_state.ea_seg); src = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].l[1] = src; @@ -33,6 +34,7 @@ static int opPUNPCKLDQ_a32(uint32_t fetchdat) { uint32_t src; + SEG_CHECK_READ(cpu_state.ea_seg); src = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].l[1] = src; diff --git a/src/cpu/x86_ops_mmx_shift.h b/src/cpu/x86_ops_mmx_shift.h index ce60d32ef..edfe16276 100644 --- a/src/cpu/x86_ops_mmx_shift.h +++ b/src/cpu/x86_ops_mmx_shift.h @@ -6,6 +6,7 @@ } \ else \ { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ shift = readmemb(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; \ CLOCK_CYCLES(2); \ } diff --git a/src/cpu/x86_ops_mov.h b/src/cpu/x86_ops_mov.h index 1eadee54f..06aae8582 100644 --- a/src/cpu/x86_ops_mov.h +++ b/src/cpu/x86_ops_mov.h @@ -181,7 +181,8 @@ static int opMOV_b_imm_a16(uint32_t fetchdat) { uint8_t temp; fetch_ea_16(fetchdat); - ILLEGAL_ON((rmdat & 0x38) != 0); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = readmemb(cs,cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); seteab(temp); @@ -193,7 +194,8 @@ static int opMOV_b_imm_a32(uint32_t fetchdat) { uint8_t temp; fetch_ea_32(fetchdat); - ILLEGAL_ON((rmdat & 0x38) != 0); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getbyte(); if (cpu_state.abrt) return 1; CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); seteab(temp); @@ -206,7 +208,8 @@ static int opMOV_w_imm_a16(uint32_t fetchdat) { uint16_t temp; fetch_ea_16(fetchdat); - ILLEGAL_ON((rmdat & 0x38) != 0); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getword(); if (cpu_state.abrt) return 1; CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); seteaw(temp); @@ -218,7 +221,8 @@ static int opMOV_w_imm_a32(uint32_t fetchdat) { uint16_t temp; fetch_ea_32(fetchdat); - ILLEGAL_ON((rmdat & 0x38) != 0); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getword(); if (cpu_state.abrt) return 1; CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); seteaw(temp); @@ -230,7 +234,8 @@ static int opMOV_l_imm_a16(uint32_t fetchdat) { uint32_t temp; fetch_ea_16(fetchdat); - ILLEGAL_ON((rmdat & 0x38) != 0); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getlong(); if (cpu_state.abrt) return 1; CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); seteal(temp); @@ -242,7 +247,8 @@ static int opMOV_l_imm_a32(uint32_t fetchdat) { uint32_t temp; fetch_ea_32(fetchdat); - ILLEGAL_ON((rmdat & 0x38) != 0); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getlong(); if (cpu_state.abrt) return 1; CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); seteal(temp); @@ -256,6 +262,7 @@ static int opMOV_AL_a16(uint32_t fetchdat) { uint8_t temp; uint16_t addr = getwordf(); + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, addr, addr); temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AL = temp; @@ -267,6 +274,7 @@ static int opMOV_AL_a32(uint32_t fetchdat) { uint8_t temp; uint32_t addr = getlong(); + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, addr, addr); temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AL = temp; @@ -278,7 +286,8 @@ static int opMOV_AX_a16(uint32_t fetchdat) { uint16_t temp; uint16_t addr = getwordf(); - CHECK_READ(cpu_state.ea_seg, addr, addr + 1); + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr+1); temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AX = temp; CLOCK_CYCLES((is486) ? 1 : 4); @@ -289,7 +298,8 @@ static int opMOV_AX_a32(uint32_t fetchdat) { uint16_t temp; uint32_t addr = getlong(); - CHECK_READ(cpu_state.ea_seg, addr, addr + 1); + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr+1); temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AX = temp; CLOCK_CYCLES((is486) ? 1 : 4); @@ -300,7 +310,8 @@ static int opMOV_EAX_a16(uint32_t fetchdat) { uint32_t temp; uint16_t addr = getwordf(); - CHECK_READ(cpu_state.ea_seg, addr, addr + 3); + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr+3); temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; EAX = temp; CLOCK_CYCLES((is486) ? 1 : 4); @@ -311,7 +322,8 @@ static int opMOV_EAX_a32(uint32_t fetchdat) { uint32_t temp; uint32_t addr = getlong(); - CHECK_READ(cpu_state.ea_seg, addr, addr + 3); + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr+3); temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; EAX = temp; CLOCK_CYCLES((is486) ? 1 : 4); @@ -322,6 +334,7 @@ static int opMOV_EAX_a32(uint32_t fetchdat) static int opMOV_a16_AL(uint32_t fetchdat) { uint16_t addr = getwordf(); + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, addr, addr); writememb(cpu_state.ea_seg->base, addr, AL); CLOCK_CYCLES((is486) ? 1 : 2); @@ -331,6 +344,7 @@ static int opMOV_a16_AL(uint32_t fetchdat) static int opMOV_a32_AL(uint32_t fetchdat) { uint32_t addr = getlong(); + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, addr, addr); writememb(cpu_state.ea_seg->base, addr, AL); CLOCK_CYCLES((is486) ? 1 : 2); @@ -340,6 +354,7 @@ static int opMOV_a32_AL(uint32_t fetchdat) static int opMOV_a16_AX(uint32_t fetchdat) { uint16_t addr = getwordf(); + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, addr, addr + 1); writememw(cpu_state.ea_seg->base, addr, AX); CLOCK_CYCLES((is486) ? 1 : 2); @@ -349,6 +364,7 @@ static int opMOV_a16_AX(uint32_t fetchdat) static int opMOV_a32_AX(uint32_t fetchdat) { uint32_t addr = getlong(); if (cpu_state.abrt) return 1; + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, addr, addr + 1); writememw(cpu_state.ea_seg->base, addr, AX); CLOCK_CYCLES((is486) ? 1 : 2); @@ -358,6 +374,7 @@ static int opMOV_a32_AX(uint32_t fetchdat) static int opMOV_a16_EAX(uint32_t fetchdat) { uint16_t addr = getwordf(); + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, addr, addr + 3); writememl(cpu_state.ea_seg->base, addr, EAX); CLOCK_CYCLES((is486) ? 1 : 2); @@ -367,6 +384,7 @@ static int opMOV_a16_EAX(uint32_t fetchdat) static int opMOV_a32_EAX(uint32_t fetchdat) { uint32_t addr = getlong(); if (cpu_state.abrt) return 1; + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, addr, addr + 3); writememl(cpu_state.ea_seg->base, addr, EAX); CLOCK_CYCLES((is486) ? 1 : 2); @@ -378,8 +396,8 @@ static int opMOV_a32_EAX(uint32_t fetchdat) static int opLEA_w_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - /* ILLEGAL_ON(cpu_mod == 3); */ - cpu_state.regs[cpu_reg].w = (cpu_mod == 3) ? (cpu_state.last_ea & 0xffff) : cpu_state.eaaddr; + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); return 0; @@ -387,8 +405,8 @@ static int opLEA_w_a16(uint32_t fetchdat) static int opLEA_w_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - /* ILLEGAL_ON(cpu_mod == 3); */ - cpu_state.regs[cpu_reg].w = (cpu_mod == 3) ? (cpu_state.last_ea & 0xffff) : cpu_state.eaaddr; + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); return 0; @@ -397,8 +415,8 @@ static int opLEA_w_a32(uint32_t fetchdat) static int opLEA_l_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - /* ILLEGAL_ON(cpu_mod == 3); */ - cpu_state.regs[cpu_reg].l = ((cpu_mod == 3) ? cpu_state.last_ea : cpu_state.eaaddr) & 0xffff; + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].l = cpu_state.eaaddr & 0xffff; CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); return 0; @@ -406,8 +424,8 @@ static int opLEA_l_a16(uint32_t fetchdat) static int opLEA_l_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - /* ILLEGAL_ON(cpu_mod == 3); */ - cpu_state.regs[cpu_reg].l = (cpu_mod == 3) ? cpu_state.last_ea : cpu_state.eaaddr; + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].l = cpu_state.eaaddr; CLOCK_CYCLES(timing_rr); PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); return 0; @@ -419,9 +437,9 @@ static int opXLAT_a16(uint32_t fetchdat) { uint32_t addr = (BX + AL)&0xFFFF; uint8_t temp; - cpu_state.last_ea = addr; - temp = readmemb(cpu_state.ea_seg->base, addr); - if (cpu_state.abrt) return 1; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AL = temp; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); @@ -431,9 +449,9 @@ static int opXLAT_a32(uint32_t fetchdat) { uint32_t addr = EBX + AL; uint8_t temp; - cpu_state.last_ea = addr; - temp = readmemb(cpu_state.ea_seg->base, addr); - if (cpu_state.abrt) return 1; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AL = temp; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); @@ -451,6 +469,7 @@ static int opMOV_b_r_a16(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); seteab(getr8(cpu_reg)); CLOCK_CYCLES(is486 ? 1 : 2); @@ -469,6 +488,7 @@ static int opMOV_b_r_a32(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); seteab(getr8(cpu_reg)); CLOCK_CYCLES(is486 ? 1 : 2); @@ -487,6 +507,7 @@ static int opMOV_w_r_a16(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); seteaw(cpu_state.regs[cpu_reg].w); CLOCK_CYCLES(is486 ? 1 : 2); @@ -505,6 +526,7 @@ static int opMOV_w_r_a32(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); seteaw(cpu_state.regs[cpu_reg].w); CLOCK_CYCLES(is486 ? 1 : 2); @@ -523,6 +545,7 @@ static int opMOV_l_r_a16(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); seteal(cpu_state.regs[cpu_reg].l); CLOCK_CYCLES(is486 ? 1 : 2); @@ -541,6 +564,7 @@ static int opMOV_l_r_a32(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); seteal(cpu_state.regs[cpu_reg].l); CLOCK_CYCLES(is486 ? 1 : 2); @@ -561,6 +585,7 @@ static int opMOV_r_b_a16(uint32_t fetchdat) else { uint8_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); temp = geteab(); if (cpu_state.abrt) return 1; setr8(cpu_reg, temp); @@ -581,6 +606,7 @@ static int opMOV_r_b_a32(uint32_t fetchdat) else { uint8_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); temp = geteab(); if (cpu_state.abrt) return 1; setr8(cpu_reg, temp); @@ -601,6 +627,7 @@ static int opMOV_r_w_a16(uint32_t fetchdat) else { uint16_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; @@ -621,6 +648,7 @@ static int opMOV_r_w_a32(uint32_t fetchdat) else { uint16_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; @@ -641,6 +669,7 @@ static int opMOV_r_l_a16(uint32_t fetchdat) else { uint32_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); temp = geteal(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp; @@ -661,6 +690,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat) else { uint32_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); temp = geteal(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp; @@ -670,6 +700,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat) return 0; } +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) #define opCMOV(condition) \ static int opCMOV ## condition ## _w_a16(uint32_t fetchdat) \ { \ @@ -681,6 +712,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat) else \ { \ uint16_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); \ temp = geteaw(); if (cpu_state.abrt) return 1; \ cpu_state.regs[cpu_reg].w = temp; \ @@ -699,6 +731,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat) else \ { \ uint16_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); \ temp = geteaw(); if (cpu_state.abrt) return 1; \ cpu_state.regs[cpu_reg].w = temp; \ @@ -717,6 +750,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat) else \ { \ uint32_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); \ temp = geteal(); if (cpu_state.abrt) return 1; \ cpu_state.regs[cpu_reg].l = temp; \ @@ -736,6 +770,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat) { \ uint32_t temp; \ CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ temp = geteal(); if (cpu_state.abrt) return 1; \ cpu_state.regs[cpu_reg].l = temp; \ } \ @@ -760,3 +795,4 @@ opCMOV(L) opCMOV(NL) opCMOV(LE) opCMOV(NLE) +#endif diff --git a/src/cpu/x86_ops_mov_ctrl.h b/src/cpu/x86_ops_mov_ctrl.h index 9c715f14c..1b5e7db71 100644 --- a/src/cpu/x86_ops_mov_ctrl.h +++ b/src/cpu/x86_ops_mov_ctrl.h @@ -1,6 +1,6 @@ static int opMOV_r_CRx_a16(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't load from CRx\n"); x86gpf(NULL, 0); @@ -21,7 +21,7 @@ static int opMOV_r_CRx_a16(uint32_t fetchdat) cpu_state.regs[cpu_rm].l = cr3; break; case 4: - if (cpu_hasCR4) + if (cpu_has_feature(CPU_FEATURE_CR4)) { cpu_state.regs[cpu_rm].l = cr4; break; @@ -38,7 +38,7 @@ static int opMOV_r_CRx_a16(uint32_t fetchdat) } static int opMOV_r_CRx_a32(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't load from CRx\n"); x86gpf(NULL, 0); @@ -59,7 +59,7 @@ static int opMOV_r_CRx_a32(uint32_t fetchdat) cpu_state.regs[cpu_rm].l = cr3; break; case 4: - if (cpu_hasCR4) + if (cpu_has_feature(CPU_FEATURE_CR4)) { cpu_state.regs[cpu_rm].l = cr4; break; @@ -77,7 +77,7 @@ static int opMOV_r_CRx_a32(uint32_t fetchdat) static int opMOV_r_DRx_a16(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't load from DRx\n"); x86gpf(NULL, 0); @@ -91,7 +91,7 @@ static int opMOV_r_DRx_a16(uint32_t fetchdat) } static int opMOV_r_DRx_a32(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't load from DRx\n"); x86gpf(NULL, 0); @@ -108,7 +108,7 @@ static int opMOV_CRx_r_a16(uint32_t fetchdat) { uint32_t old_cr0 = cr0; - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't load CRx\n"); x86gpf(NULL,0); @@ -144,7 +144,7 @@ static int opMOV_CRx_r_a16(uint32_t fetchdat) flushmmucache(); break; case 4: - if (cpu_hasCR4) + if (cpu_has_feature(CPU_FEATURE_CR4)) { cr4 = cpu_state.regs[cpu_rm].l & cpu_CR4_mask; break; @@ -164,7 +164,7 @@ static int opMOV_CRx_r_a32(uint32_t fetchdat) { uint32_t old_cr0 = cr0; - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't load CRx\n"); x86gpf(NULL,0); @@ -200,7 +200,7 @@ static int opMOV_CRx_r_a32(uint32_t fetchdat) flushmmucache(); break; case 4: - if (cpu_hasCR4) + if (cpu_has_feature(CPU_FEATURE_CR4)) { cr4 = cpu_state.regs[cpu_rm].l & cpu_CR4_mask; break; @@ -219,7 +219,7 @@ static int opMOV_CRx_r_a32(uint32_t fetchdat) static int opMOV_DRx_r_a16(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't load DRx\n"); x86gpf(NULL, 0); @@ -233,7 +233,7 @@ static int opMOV_DRx_r_a16(uint32_t fetchdat) } static int opMOV_DRx_r_a32(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't load DRx\n"); x86gpf(NULL, 0); @@ -248,7 +248,7 @@ static int opMOV_DRx_r_a32(uint32_t fetchdat) static int opMOV_r_TRx_a16(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't load from TRx\n"); x86gpf(NULL, 0); @@ -262,7 +262,7 @@ static int opMOV_r_TRx_a16(uint32_t fetchdat) } static int opMOV_r_TRx_a32(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't load from TRx\n"); x86gpf(NULL, 0); @@ -277,7 +277,7 @@ static int opMOV_r_TRx_a32(uint32_t fetchdat) static int opMOV_TRx_r_a16(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't load TRx\n"); x86gpf(NULL, 0); @@ -290,7 +290,7 @@ static int opMOV_TRx_r_a16(uint32_t fetchdat) } static int opMOV_TRx_r_a32(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x386_dynarec_log("Can't load TRx\n"); x86gpf(NULL, 0); diff --git a/src/cpu/x86_ops_mov_seg.h b/src/cpu/x86_ops_mov_seg.h index 1e2f654b1..da7727143 100644 --- a/src/cpu/x86_ops_mov_seg.h +++ b/src/cpu/x86_ops_mov_seg.h @@ -1,7 +1,9 @@ static int opMOV_w_seg_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + switch (rmdat & 0x38) { case 0x00: /*ES*/ @@ -31,7 +33,9 @@ static int opMOV_w_seg_a16(uint32_t fetchdat) static int opMOV_w_seg_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + switch (rmdat & 0x38) { case 0x00: /*ES*/ @@ -62,7 +66,9 @@ static int opMOV_w_seg_a32(uint32_t fetchdat) static int opMOV_l_seg_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + switch (rmdat & 0x38) { case 0x00: /*ES*/ @@ -98,7 +104,9 @@ static int opMOV_l_seg_a16(uint32_t fetchdat) static int opMOV_l_seg_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + switch (rmdat & 0x38) { case 0x00: /*ES*/ @@ -137,34 +145,35 @@ static int opMOV_seg_w_a16(uint32_t fetchdat) uint16_t new_seg; fetch_ea_16(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_seg=geteaw(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) { case 0x00: /*ES*/ - loadseg(new_seg, &_es); + loadseg(new_seg, &cpu_state.seg_es); break; case 0x18: /*DS*/ - loadseg(new_seg, &_ds); + loadseg(new_seg, &cpu_state.seg_ds); break; case 0x10: /*SS*/ - loadseg(new_seg, &_ss); + loadseg(new_seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.oldpc = cpu_state.pc; cpu_state.op32 = use32; cpu_state.ssegs = 0; - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; fetchdat = fastreadl(cs + cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return 1; case 0x20: /*FS*/ - loadseg(new_seg, &_fs); + loadseg(new_seg, &cpu_state.seg_fs); break; case 0x28: /*GS*/ - loadseg(new_seg, &_gs); + loadseg(new_seg, &cpu_state.seg_gs); break; } @@ -177,34 +186,35 @@ static int opMOV_seg_w_a32(uint32_t fetchdat) uint16_t new_seg; fetch_ea_32(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_seg=geteaw(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) { case 0x00: /*ES*/ - loadseg(new_seg, &_es); + loadseg(new_seg, &cpu_state.seg_es); break; case 0x18: /*DS*/ - loadseg(new_seg, &_ds); + loadseg(new_seg, &cpu_state.seg_ds); break; case 0x10: /*SS*/ - loadseg(new_seg, &_ss); + loadseg(new_seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.oldpc = cpu_state.pc; cpu_state.op32 = use32; cpu_state.ssegs = 0; - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; fetchdat = fastreadl(cs + cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return 1; case 0x20: /*FS*/ - loadseg(new_seg, &_fs); + loadseg(new_seg, &cpu_state.seg_fs); break; case 0x28: /*GS*/ - loadseg(new_seg, &_gs); + loadseg(new_seg, &cpu_state.seg_gs); break; } @@ -220,9 +230,10 @@ static int opLDS_w_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmemw(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - loadseg(seg, &_ds); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = addr; CLOCK_CYCLES(7); @@ -235,9 +246,10 @@ static int opLDS_w_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmemw(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - loadseg(seg, &_ds); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = addr; CLOCK_CYCLES(7); @@ -251,9 +263,10 @@ static int opLDS_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmeml(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; - loadseg(seg, &_ds); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = addr; CLOCK_CYCLES(7); @@ -267,9 +280,10 @@ static int opLDS_l_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmeml(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; - loadseg(seg, &_ds); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = addr; CLOCK_CYCLES(7); @@ -283,9 +297,10 @@ static int opLSS_w_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmemw(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - loadseg(seg, &_ss); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = addr; CLOCK_CYCLES(7); @@ -298,9 +313,10 @@ static int opLSS_w_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmemw(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - loadseg(seg, &_ss); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = addr; CLOCK_CYCLES(7); @@ -314,9 +330,10 @@ static int opLSS_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmeml(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; - loadseg(seg, &_ss); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = addr; CLOCK_CYCLES(7); @@ -330,9 +347,10 @@ static int opLSS_l_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmeml(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; - loadseg(seg, &_ss); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = addr; CLOCK_CYCLES(7); @@ -346,6 +364,7 @@ static int opLSS_l_a32(uint32_t fetchdat) uint16_t addr, seg; \ \ fetch_ea_16(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ addr = readmemw(easeg, cpu_state.eaaddr); \ seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; \ @@ -362,6 +381,7 @@ static int opLSS_l_a32(uint32_t fetchdat) uint16_t addr, seg; \ \ fetch_ea_32(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ addr = readmemw(easeg, cpu_state.eaaddr); \ seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; \ @@ -379,6 +399,7 @@ static int opLSS_l_a32(uint32_t fetchdat) uint16_t seg; \ \ fetch_ea_16(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ addr = readmeml(easeg, cpu_state.eaaddr); \ seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; \ @@ -396,6 +417,7 @@ static int opLSS_l_a32(uint32_t fetchdat) uint16_t seg; \ \ fetch_ea_32(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ addr = readmeml(easeg, cpu_state.eaaddr); \ seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; \ @@ -407,6 +429,6 @@ static int opLSS_l_a32(uint32_t fetchdat) return 0; \ } -opLsel(ES, _es) -opLsel(FS, _fs) -opLsel(GS, _gs) +opLsel(ES, cpu_state.seg_es) +opLsel(FS, cpu_state.seg_fs) +opLsel(GS, cpu_state.seg_gs) diff --git a/src/cpu/x86_ops_movx.h b/src/cpu/x86_ops_movx.h index 2175a63c3..2e4fa2001 100644 --- a/src/cpu/x86_ops_movx.h +++ b/src/cpu/x86_ops_movx.h @@ -3,6 +3,8 @@ static int opMOVZX_w_b_a16(uint32_t fetchdat) uint8_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = (uint16_t)temp; @@ -15,6 +17,8 @@ static int opMOVZX_w_b_a32(uint32_t fetchdat) uint8_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = (uint16_t)temp; @@ -27,6 +31,8 @@ static int opMOVZX_l_b_a16(uint32_t fetchdat) uint8_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; @@ -39,6 +45,8 @@ static int opMOVZX_l_b_a32(uint32_t fetchdat) uint8_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; @@ -51,6 +59,8 @@ static int opMOVZX_w_w_a16(uint32_t fetchdat) uint16_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; @@ -63,6 +73,8 @@ static int opMOVZX_w_w_a32(uint32_t fetchdat) uint16_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; @@ -75,6 +87,8 @@ static int opMOVZX_l_w_a16(uint32_t fetchdat) uint16_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; @@ -87,6 +101,8 @@ static int opMOVZX_l_w_a32(uint32_t fetchdat) uint16_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; @@ -100,6 +116,8 @@ static int opMOVSX_w_b_a16(uint32_t fetchdat) uint8_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = (uint16_t)temp; if (temp & 0x80) @@ -114,6 +132,8 @@ static int opMOVSX_w_b_a32(uint32_t fetchdat) uint8_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = (uint16_t)temp; if (temp & 0x80) @@ -128,6 +148,8 @@ static int opMOVSX_l_b_a16(uint32_t fetchdat) uint8_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; if (temp & 0x80) @@ -142,6 +164,8 @@ static int opMOVSX_l_b_a32(uint32_t fetchdat) uint8_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; if (temp & 0x80) @@ -156,6 +180,8 @@ static int opMOVSX_l_w_a16(uint32_t fetchdat) uint16_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; if (temp & 0x8000) @@ -170,6 +196,8 @@ static int opMOVSX_l_w_a32(uint32_t fetchdat) uint16_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; if (temp & 0x8000) diff --git a/src/cpu/x86_ops_msr.h b/src/cpu/x86_ops_msr.h index a73316745..2a8bdcf4c 100644 --- a/src/cpu/x86_ops_msr.h +++ b/src/cpu/x86_ops_msr.h @@ -1,6 +1,6 @@ static int opRDTSC(uint32_t fetchdat) { - if (!cpu_hasrdtsc) + if (!cpu_has_feature(CPU_FEATURE_RDTSC)) { cpu_state.pc = cpu_state.oldpc; x86illegal(); diff --git a/src/cpu/x86_ops_mul.h b/src/cpu/x86_ops_mul.h index 98cf254cc..a96ce54a2 100644 --- a/src/cpu/x86_ops_mul.h +++ b/src/cpu/x86_ops_mul.h @@ -4,14 +4,16 @@ static int opIMUL_w_iw_a16(uint32_t fetchdat) int16_t tempw, tempw2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); tempw = geteaw(); if (cpu_state.abrt) return 1; tempw2 = getword(); if (cpu_state.abrt) return 1; templ = ((int)tempw) * ((int)tempw2); flags_rebuild(); - if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].w = templ & 0xffff; CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); @@ -24,14 +26,16 @@ static int opIMUL_w_iw_a32(uint32_t fetchdat) int16_t tempw, tempw2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); tempw = geteaw(); if (cpu_state.abrt) return 1; tempw2 = getword(); if (cpu_state.abrt) return 1; templ = ((int)tempw) * ((int)tempw2); flags_rebuild(); - if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].w = templ & 0xffff; CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); @@ -45,14 +49,16 @@ static int opIMUL_l_il_a16(uint32_t fetchdat) int32_t templ, templ2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); templ = geteal(); if (cpu_state.abrt) return 1; templ2 = getlong(); if (cpu_state.abrt) return 1; temp64 = ((int64_t)templ) * ((int64_t)templ2); flags_rebuild(); - if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; CLOCK_CYCLES(25); @@ -65,14 +71,16 @@ static int opIMUL_l_il_a32(uint32_t fetchdat) int32_t templ, templ2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); templ = geteal(); if (cpu_state.abrt) return 1; templ2 = getlong(); if (cpu_state.abrt) return 1; temp64 = ((int64_t)templ) * ((int64_t)templ2); flags_rebuild(); - if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; CLOCK_CYCLES(25); @@ -86,6 +94,8 @@ static int opIMUL_w_ib_a16(uint32_t fetchdat) int16_t tempw, tempw2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); tempw = geteaw(); if (cpu_state.abrt) return 1; tempw2 = getbyte(); if (cpu_state.abrt) return 1; @@ -93,8 +103,8 @@ static int opIMUL_w_ib_a16(uint32_t fetchdat) templ = ((int)tempw) * ((int)tempw2); flags_rebuild(); - if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].w = templ & 0xffff; CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); @@ -107,6 +117,8 @@ static int opIMUL_w_ib_a32(uint32_t fetchdat) int16_t tempw, tempw2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); tempw = geteaw(); if (cpu_state.abrt) return 1; tempw2 = getbyte(); if (cpu_state.abrt) return 1; @@ -114,8 +126,8 @@ static int opIMUL_w_ib_a32(uint32_t fetchdat) templ = ((int)tempw) * ((int)tempw2); flags_rebuild(); - if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].w = templ & 0xffff; CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); @@ -129,14 +141,17 @@ static int opIMUL_l_ib_a16(uint32_t fetchdat) int32_t templ, templ2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + templ = geteal(); if (cpu_state.abrt) return 1; templ2 = getbyte(); if (cpu_state.abrt) return 1; if (templ2 & 0x80) templ2 |= 0xffffff00; temp64 = ((int64_t)templ)*((int64_t)templ2); flags_rebuild(); - if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; CLOCK_CYCLES(20); @@ -149,14 +164,17 @@ static int opIMUL_l_ib_a32(uint32_t fetchdat) int32_t templ, templ2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + templ = geteal(); if (cpu_state.abrt) return 1; templ2 = getbyte(); if (cpu_state.abrt) return 1; if (templ2 & 0x80) templ2 |= 0xffffff00; temp64 = ((int64_t)templ)*((int64_t)templ2); flags_rebuild(); - if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; CLOCK_CYCLES(20); @@ -171,12 +189,15 @@ static int opIMUL_w_w_a16(uint32_t fetchdat) int32_t templ; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + templ = (int32_t)(int16_t)cpu_state.regs[cpu_reg].w * (int32_t)(int16_t)geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = templ & 0xFFFF; flags_rebuild(); - if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(18); PREFETCH_RUN(18, 2, rmdat, 1,0,0,0, 0); @@ -187,12 +208,15 @@ static int opIMUL_w_w_a32(uint32_t fetchdat) int32_t templ; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + templ = (int32_t)(int16_t)cpu_state.regs[cpu_reg].w * (int32_t)(int16_t)geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = templ & 0xFFFF; flags_rebuild(); - if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(18); PREFETCH_RUN(18, 2, rmdat, 1,0,0,0, 1); @@ -204,12 +228,15 @@ static int opIMUL_l_l_a16(uint32_t fetchdat) int64_t temp64; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp64 = (int64_t)(int32_t)cpu_state.regs[cpu_reg].l * (int64_t)(int32_t)geteal(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp64 & 0xFFFFFFFF; flags_rebuild(); - if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(30); PREFETCH_RUN(30, 2, rmdat, 0,1,0,0, 0); @@ -220,12 +247,15 @@ static int opIMUL_l_l_a32(uint32_t fetchdat) int64_t temp64; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp64 = (int64_t)(int32_t)cpu_state.regs[cpu_reg].l * (int64_t)(int32_t)geteal(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp64 & 0xFFFFFFFF; flags_rebuild(); - if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(30); PREFETCH_RUN(30, 2, rmdat, 0,1,0,0, 1); diff --git a/src/cpu/x86_ops_pmode.h b/src/cpu/x86_ops_pmode.h index d1d85f231..cdf89d98d 100644 --- a/src/cpu/x86_ops_pmode.h +++ b/src/cpu/x86_ops_pmode.h @@ -5,6 +5,9 @@ static int opARPL_a16(uint32_t fetchdat) NOTRM fetch_ea_16(fetchdat); /* x386_dynarec_log("ARPL_a16\n"); */ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp_seg = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); @@ -12,10 +15,10 @@ static int opARPL_a16(uint32_t fetchdat) { temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[cpu_reg].w & 3); seteaw(temp_seg); if (cpu_state.abrt) return 1; - flags |= Z_FLAG; + cpu_state.flags |= Z_FLAG; } else - flags &= ~Z_FLAG; + cpu_state.flags &= ~Z_FLAG; CLOCK_CYCLES(is486 ? 9 : 20); PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 0); @@ -28,6 +31,9 @@ static int opARPL_a32(uint32_t fetchdat) NOTRM fetch_ea_32(fetchdat); /* x386_dynarec_log("ARPL_a32\n"); */ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp_seg = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); @@ -35,10 +41,10 @@ static int opARPL_a32(uint32_t fetchdat) { temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[cpu_reg].w & 3); seteaw(temp_seg); if (cpu_state.abrt) return 1; - flags |= Z_FLAG; + cpu_state.flags |= Z_FLAG; } else - flags &= ~Z_FLAG; + cpu_state.flags &= ~Z_FLAG; CLOCK_CYCLES(is486 ? 9 : 20); PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 1); @@ -53,11 +59,13 @@ static int opARPL_a32(uint32_t fetchdat) \ NOTRM \ fetch_ea(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ \ sel = geteaw(); if (cpu_state.abrt) return 1; \ \ flags_rebuild(); \ - if (!(sel & 0xfffc)) { flags &= ~Z_FLAG; return 0; } /*Null selector*/ \ + if (!(sel & 0xfffc)) { cpu_state.flags &= ~Z_FLAG; return 0; } /*Null selector*/ \ valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ if (valid) \ { \ @@ -65,7 +73,7 @@ static int opARPL_a32(uint32_t fetchdat) desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ cpl_override = 0; if (cpu_state.abrt) return 1; \ } \ - flags &= ~Z_FLAG; \ + cpu_state.flags &= ~Z_FLAG; \ if ((desc & 0x1f00) == 0x000) valid = 0; \ if ((desc & 0x1f00) == 0x800) valid = 0; \ if ((desc & 0x1f00) == 0xa00) valid = 0; \ @@ -77,7 +85,7 @@ static int opARPL_a32(uint32_t fetchdat) } \ if (valid) \ { \ - flags |= Z_FLAG; \ + cpu_state.flags |= Z_FLAG; \ cpl_override = 1; \ if (is32) \ cpu_state.regs[cpu_reg].l = readmeml(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xffff00; \ @@ -103,10 +111,12 @@ opLAR(l_a32, fetch_ea_32, 1, 1) \ NOTRM \ fetch_ea(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ \ sel = geteaw(); if (cpu_state.abrt) return 1; \ flags_rebuild(); \ - flags &= ~Z_FLAG; \ + cpu_state.flags &= ~Z_FLAG; \ if (!(sel & 0xfffc)) return 0; /*Null selector*/ \ valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ if (valid) \ @@ -125,7 +135,7 @@ opLAR(l_a32, fetch_ea_32, 1, 1) } \ if (valid) \ { \ - flags |= Z_FLAG; \ + cpu_state.flags |= Z_FLAG; \ cpl_override = 1; \ if (is32) \ { \ @@ -163,22 +173,28 @@ static int op0F00_common(uint32_t fetchdat, int ea32) switch (rmdat & 0x38) { case 0x00: /*SLDT*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(ldt.seg); CLOCK_CYCLES(4); PREFETCH_RUN(4, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); break; case 0x08: /*STR*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(tr.seg); CLOCK_CYCLES(4); PREFETCH_RUN(4, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); break; case 0x10: /*LLDT*/ - if ((CPL || eflags&VM_FLAG) && (cr0&1)) + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) { x386_dynarec_log("Invalid LLDT!\n"); x86gpf(NULL,0); return 1; } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); sel = geteaw(); if (cpu_state.abrt) return 1; addr = (sel & ~7) + gdt.base; limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); @@ -199,12 +215,14 @@ static int op0F00_common(uint32_t fetchdat, int ea32) PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 0:1,2,0,0, ea32); break; case 0x18: /*LTR*/ - if ((CPL || eflags&VM_FLAG) && (cr0&1)) + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) { x386_dynarec_log("Invalid LTR!\n"); x86gpf(NULL,0); break; } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); sel = geteaw(); if (cpu_state.abrt) return 1; addr = (sel & ~7) + gdt.base; limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); @@ -228,9 +246,11 @@ static int op0F00_common(uint32_t fetchdat, int ea32) PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 0:1,2,0,0, ea32); break; case 0x20: /*VERR*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); sel = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); - flags &= ~Z_FLAG; + cpu_state.flags &= ~Z_FLAG; if (!(sel & 0xfffc)) return 0; /*Null selector*/ cpl_override = 1; valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); @@ -243,14 +263,16 @@ static int op0F00_common(uint32_t fetchdat, int ea32) if (dpl < CPL || dpl < (sel & 3)) valid = 0; } if ((desc & 0x0800) && !(desc & 0x0200)) valid = 0; /*Non-readable code*/ - if (valid) flags |= Z_FLAG; + if (valid) cpu_state.flags |= Z_FLAG; CLOCK_CYCLES(20); PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 1:2,0,0,0, ea32); break; case 0x28: /*VERW*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); sel = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); - flags &= ~Z_FLAG; + cpu_state.flags &= ~Z_FLAG; if (!(sel & 0xfffc)) return 0; /*Null selector*/ cpl_override = 1; valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); @@ -261,7 +283,7 @@ static int op0F00_common(uint32_t fetchdat, int ea32) if (dpl < CPL || dpl < (sel & 3)) valid = 0; if (desc & 0x0800) valid = 0; /*Code*/ if (!(desc & 0x0200)) valid = 0; /*Read-only data*/ - if (valid) flags |= Z_FLAG; + if (valid) cpu_state.flags |= Z_FLAG; CLOCK_CYCLES(20); PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 1:2,0,0,0, ea32); break; @@ -300,6 +322,8 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) switch (rmdat & 0x38) { case 0x00: /*SGDT*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(gdt.limit); base = gdt.base; /* is32 ? gdt.base : (gdt.base & 0xffffff); */ if (is286) @@ -309,6 +333,8 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) PREFETCH_RUN(7, 2, rmdat, 0,0,1,1, ea32); break; case 0x08: /*SIDT*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(idt.limit); base = idt.base; if (is286) @@ -318,13 +344,15 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) PREFETCH_RUN(7, 2, rmdat, 0,0,1,1, ea32); break; case 0x10: /*LGDT*/ - if ((CPL || eflags&VM_FLAG) && (cr0&1)) + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) { x386_dynarec_log("Invalid LGDT!\n"); x86gpf(NULL,0); break; } /* x386_dynarec_log("LGDT %08X:%08X\n", easeg, eaaddr); */ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); limit = geteaw(); base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; /* x386_dynarec_log(" %08X %04X\n", base, limit); */ @@ -335,13 +363,15 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) PREFETCH_RUN(11, 2, rmdat, 1,1,0,0, ea32); break; case 0x18: /*LIDT*/ - if ((CPL || eflags&VM_FLAG) && (cr0&1)) + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) { x386_dynarec_log("Invalid LIDT!\n"); x86gpf(NULL,0); break; } /* x386_dynarec_log("LIDT %08X:%08X\n", easeg, eaaddr); */ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); limit = geteaw(); base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; /* x386_dynarec_log(" %08X %04X\n", base, limit); */ @@ -353,6 +383,8 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) break; case 0x20: /*SMSW*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); if (is486) seteaw(msw); else if (is386) seteaw(msw | 0xFF00); else seteaw(msw | 0xFFF0); @@ -360,12 +392,14 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) PREFETCH_RUN(2, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); break; case 0x30: /*LMSW*/ - if ((CPL || eflags&VM_FLAG) && (msw&1)) + if ((CPL || cpu_state.eflags&VM_FLAG) && (msw&1)) { x386_dynarec_log("LMSW - ring not zero!\n"); x86gpf(NULL, 0); break; } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); tempw = geteaw(); if (cpu_state.abrt) return 1; if (msw & 1) tempw |= 1; if (is386) @@ -385,12 +419,13 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) case 0x38: /*INVLPG*/ if (is486) { - if ((CPL || eflags&VM_FLAG) && (cr0&1)) + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) { x386_dynarec_log("Invalid INVLPG!\n"); x86gpf(NULL, 0); break; } + SEG_CHECK_READ(cpu_state.ea_seg); mmu_invalidate(ds + cpu_state.eaaddr); CLOCK_CYCLES(12); PREFETCH_RUN(12, 2, rmdat, 0,0,0,0, ea32); diff --git a/src/cpu/x86_ops_prefix.h b/src/cpu/x86_ops_prefix.h index 8265c19f1..8d191103d 100644 --- a/src/cpu/x86_ops_prefix.h +++ b/src/cpu/x86_ops_prefix.h @@ -63,26 +63,26 @@ static int op ## name ## _l_a32(uint32_t fetchdat) \ return normal_opcode_table[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ } -op_seg(CS, _cs, x86_opcodes, x86_opcodes) -op_seg(DS, _ds, x86_opcodes, x86_opcodes) -op_seg(ES, _es, x86_opcodes, x86_opcodes) -op_seg(FS, _fs, x86_opcodes, x86_opcodes) -op_seg(GS, _gs, x86_opcodes, x86_opcodes) -op_seg(SS, _ss, x86_opcodes, x86_opcodes) +op_seg(CS, cpu_state.seg_cs, x86_opcodes, x86_opcodes) +op_seg(DS, cpu_state.seg_ds, x86_opcodes, x86_opcodes) +op_seg(ES, cpu_state.seg_es, x86_opcodes, x86_opcodes) +op_seg(FS, cpu_state.seg_fs, x86_opcodes, x86_opcodes) +op_seg(GS, cpu_state.seg_gs, x86_opcodes, x86_opcodes) +op_seg(SS, cpu_state.seg_ss, x86_opcodes, x86_opcodes) -op_seg(CS_REPE, _cs, x86_opcodes_REPE, x86_opcodes) -op_seg(DS_REPE, _ds, x86_opcodes_REPE, x86_opcodes) -op_seg(ES_REPE, _es, x86_opcodes_REPE, x86_opcodes) -op_seg(FS_REPE, _fs, x86_opcodes_REPE, x86_opcodes) -op_seg(GS_REPE, _gs, x86_opcodes_REPE, x86_opcodes) -op_seg(SS_REPE, _ss, x86_opcodes_REPE, x86_opcodes) +op_seg(CS_REPE, cpu_state.seg_cs, x86_opcodes_REPE, x86_opcodes) +op_seg(DS_REPE, cpu_state.seg_ds, x86_opcodes_REPE, x86_opcodes) +op_seg(ES_REPE, cpu_state.seg_es, x86_opcodes_REPE, x86_opcodes) +op_seg(FS_REPE, cpu_state.seg_fs, x86_opcodes_REPE, x86_opcodes) +op_seg(GS_REPE, cpu_state.seg_gs, x86_opcodes_REPE, x86_opcodes) +op_seg(SS_REPE, cpu_state.seg_ss, x86_opcodes_REPE, x86_opcodes) -op_seg(CS_REPNE, _cs, x86_opcodes_REPNE, x86_opcodes) -op_seg(DS_REPNE, _ds, x86_opcodes_REPNE, x86_opcodes) -op_seg(ES_REPNE, _es, x86_opcodes_REPNE, x86_opcodes) -op_seg(FS_REPNE, _fs, x86_opcodes_REPNE, x86_opcodes) -op_seg(GS_REPNE, _gs, x86_opcodes_REPNE, x86_opcodes) -op_seg(SS_REPNE, _ss, x86_opcodes_REPNE, x86_opcodes) +op_seg(CS_REPNE, cpu_state.seg_cs, x86_opcodes_REPNE, x86_opcodes) +op_seg(DS_REPNE, cpu_state.seg_ds, x86_opcodes_REPNE, x86_opcodes) +op_seg(ES_REPNE, cpu_state.seg_es, x86_opcodes_REPNE, x86_opcodes) +op_seg(FS_REPNE, cpu_state.seg_fs, x86_opcodes_REPNE, x86_opcodes) +op_seg(GS_REPNE, cpu_state.seg_gs, x86_opcodes_REPNE, x86_opcodes) +op_seg(SS_REPNE, cpu_state.seg_ss, x86_opcodes_REPNE, x86_opcodes) static int op_66(uint32_t fetchdat) /*Data size select*/ { diff --git a/src/cpu/x86_ops_rep.h b/src/cpu/x86_ops_rep.h index 065695706..efbb088ef 100644 --- a/src/cpu/x86_ops_rep.h +++ b/src/cpu/x86_ops_rep.h @@ -1,5 +1,3 @@ -extern int trap; - #define REP_OPS(size, CNT_REG, SRC_REG, DEST_REG) \ static int opREP_INSB_ ## size(uint32_t fetchdat) \ { \ @@ -9,11 +7,13 @@ static int opREP_INSB_ ## size(uint32_t fetchdat) { \ uint8_t temp; \ \ - check_io_perm(DX); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG); \ temp = inb(DX); \ writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) DEST_REG--; \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ else DEST_REG++; \ CNT_REG--; \ cycles -= 15; \ @@ -36,12 +36,14 @@ static int opREP_INSW_ ## size(uint32_t fetchdat) { \ uint16_t temp; \ \ - check_io_perm(DX); \ - check_io_perm(DX+1); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ temp = inw(DX); \ - writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) DEST_REG -= 2; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ else DEST_REG += 2; \ CNT_REG--; \ cycles -= 15; \ @@ -64,14 +66,16 @@ static int opREP_INSL_ ## size(uint32_t fetchdat) { \ uint32_t temp; \ \ - check_io_perm(DX); \ - check_io_perm(DX+1); \ - check_io_perm(DX+2); \ - check_io_perm(DX+3); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + check_io_perm(DX+2); \ + check_io_perm(DX+3); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ temp = inl(DX); \ - writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) DEST_REG -= 4; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ else DEST_REG += 4; \ CNT_REG--; \ cycles -= 15; \ @@ -93,10 +97,13 @@ static int opREP_OUTSB_ ## size(uint32_t fetchdat) \ if (CNT_REG > 0) \ { \ - uint8_t temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + uint8_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ check_io_perm(DX); \ outb(DX, temp); \ - if (flags & D_FLAG) SRC_REG--; \ + if (cpu_state.flags & D_FLAG) SRC_REG--; \ else SRC_REG++; \ CNT_REG--; \ cycles -= 14; \ @@ -117,11 +124,14 @@ static int opREP_OUTSW_ ## size(uint32_t fetchdat) \ if (CNT_REG > 0) \ { \ - uint16_t temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + uint16_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ check_io_perm(DX); \ check_io_perm(DX+1); \ outw(DX, temp); \ - if (flags & D_FLAG) SRC_REG -= 2; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 2; \ else SRC_REG += 2; \ CNT_REG--; \ cycles -= 14; \ @@ -142,13 +152,16 @@ static int opREP_OUTSL_ ## size(uint32_t fetchdat) \ if (CNT_REG > 0) \ { \ - uint32_t temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + uint32_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ check_io_perm(DX); \ check_io_perm(DX+1); \ check_io_perm(DX+2); \ check_io_perm(DX+3); \ outl(DX, temp); \ - if (flags & D_FLAG) SRC_REG -= 4; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 4; \ else SRC_REG += 4; \ CNT_REG--; \ cycles -= 14; \ @@ -170,15 +183,21 @@ static int opREP_MOVSB_ ## size(uint32_t fetchdat) int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + } \ while (CNT_REG > 0) \ { \ uint8_t temp; \ \ - CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG); \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ - writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ + if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ else { DEST_REG++; SRC_REG++; } \ CNT_REG--; \ cycles -= is486 ? 3 : 4; \ @@ -203,15 +222,21 @@ static int opREP_MOVSW_ ## size(uint32_t fetchdat) int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + } \ while (CNT_REG > 0) \ { \ uint16_t temp; \ \ - CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG); \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ - writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ else { DEST_REG += 2; SRC_REG += 2; } \ CNT_REG--; \ cycles -= is486 ? 3 : 4; \ @@ -236,15 +261,21 @@ static int opREP_MOVSL_ ## size(uint32_t fetchdat) int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + } \ while (CNT_REG > 0) \ { \ uint32_t temp; \ \ - CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG); \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ - writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ else { DEST_REG += 4; SRC_REG += 4; } \ CNT_REG--; \ cycles -= is486 ? 3 : 4; \ @@ -271,11 +302,13 @@ static int opREP_STOSB_ ## size(uint32_t fetchdat) int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ while (CNT_REG > 0) \ { \ - CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG); \ - writememb(es, DEST_REG, AL); if (cpu_state.abrt) return 1; \ - if (flags & D_FLAG) DEST_REG--; \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + writememb(es, DEST_REG, AL); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ else DEST_REG++; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ @@ -299,11 +332,13 @@ static int opREP_STOSW_ ## size(uint32_t fetchdat) int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ while (CNT_REG > 0) \ { \ - CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG+1); \ - writememw(es, DEST_REG, AX); if (cpu_state.abrt) return 1; \ - if (flags & D_FLAG) DEST_REG -= 2; \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + writememw(es, DEST_REG, AX); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ else DEST_REG += 2; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ @@ -327,11 +362,13 @@ static int opREP_STOSL_ ## size(uint32_t fetchdat) int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ while (CNT_REG > 0) \ { \ - CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG+3); \ - writememl(es, DEST_REG, EAX); if (cpu_state.abrt) return 1; \ - if (flags & D_FLAG) DEST_REG -= 4; \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + writememl(es, DEST_REG, EAX); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ else DEST_REG += 4; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ @@ -356,10 +393,13 @@ static int opREP_LODSB_ ## size(uint32_t fetchdat) int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ while (CNT_REG > 0) \ { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \ AL = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ - if (flags & D_FLAG) SRC_REG--; \ + if (cpu_state.flags & D_FLAG) SRC_REG--; \ else SRC_REG++; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ @@ -383,10 +423,13 @@ static int opREP_LODSW_ ## size(uint32_t fetchdat) int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ while (CNT_REG > 0) \ { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ AX = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ - if (flags & D_FLAG) SRC_REG -= 2; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 2; \ else SRC_REG += 2; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ @@ -410,10 +453,13 @@ static int opREP_LODSL_ ## size(uint32_t fetchdat) int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ while (CNT_REG > 0) \ { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ EAX = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ - if (flags & D_FLAG) SRC_REG -= 4; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 4; \ else SRC_REG += 4; \ CNT_REG--; \ cycles -= is486 ? 4 : 5; \ @@ -441,10 +487,15 @@ static int opREP_CMPSB_ ## size(uint32_t fetchdat) tempz = FV; \ if ((CNT_REG > 0) && (FV == tempz)) \ { \ - uint8_t temp = readmemb(cpu_state.ea_seg->base, SRC_REG); \ - uint8_t temp2 = readmemb(es, DEST_REG); if (cpu_state.abrt) return 1; \ + uint8_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + temp = readmemb(cpu_state.ea_seg->base, SRC_REG); \ + temp2 = readmemb(es, DEST_REG); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ + if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ else { DEST_REG++; SRC_REG++; } \ CNT_REG--; \ cycles -= is486 ? 7 : 9; \ @@ -468,10 +519,15 @@ static int opREP_CMPSW_ ## size(uint32_t fetchdat) tempz = FV; \ if ((CNT_REG > 0) && (FV == tempz)) \ { \ - uint16_t temp = readmemw(cpu_state.ea_seg->base, SRC_REG); \ - uint16_t temp2 = readmemw(es, DEST_REG); if (cpu_state.abrt) return 1; \ + uint16_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + temp = readmemw(cpu_state.ea_seg->base, SRC_REG); \ + temp2 = readmemw(es, DEST_REG); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ else { DEST_REG += 2; SRC_REG += 2; } \ CNT_REG--; \ cycles -= is486 ? 7 : 9; \ @@ -495,10 +551,15 @@ static int opREP_CMPSL_ ## size(uint32_t fetchdat) tempz = FV; \ if ((CNT_REG > 0) && (FV == tempz)) \ { \ - uint32_t temp = readmeml(cpu_state.ea_seg->base, SRC_REG); \ - uint32_t temp2 = readmeml(es, DEST_REG); if (cpu_state.abrt) return 1; \ + uint32_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + temp = readmeml(cpu_state.ea_seg->base, SRC_REG); \ + temp2 = readmeml(es, DEST_REG); if (cpu_state.abrt) return 1; \ \ - if (flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ else { DEST_REG += 4; SRC_REG += 4; } \ CNT_REG--; \ cycles -= is486 ? 7 : 9; \ @@ -523,12 +584,15 @@ static int opREP_SCASB_ ## size(uint32_t fetchdat) if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + SEG_CHECK_READ(&cpu_state.seg_es); \ while ((CNT_REG > 0) && (FV == tempz)) \ { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ uint8_t temp = readmemb(es, DEST_REG); if (cpu_state.abrt) break;\ setsub8(AL, temp); \ tempz = (ZF_SET()) ? 1 : 0; \ - if (flags & D_FLAG) DEST_REG--; \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ else DEST_REG++; \ CNT_REG--; \ cycles -= is486 ? 5 : 8; \ @@ -554,12 +618,15 @@ static int opREP_SCASW_ ## size(uint32_t fetchdat) if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + SEG_CHECK_READ(&cpu_state.seg_es); \ while ((CNT_REG > 0) && (FV == tempz)) \ { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ uint16_t temp = readmemw(es, DEST_REG); if (cpu_state.abrt) break;\ setsub16(AX, temp); \ tempz = (ZF_SET()) ? 1 : 0; \ - if (flags & D_FLAG) DEST_REG -= 2; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ else DEST_REG += 2; \ CNT_REG--; \ cycles -= is486 ? 5 : 8; \ @@ -585,12 +652,15 @@ static int opREP_SCASL_ ## size(uint32_t fetchdat) if (trap) \ cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + SEG_CHECK_READ(&cpu_state.seg_es); \ while ((CNT_REG > 0) && (FV == tempz)) \ { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ uint32_t temp = readmeml(es, DEST_REG); if (cpu_state.abrt) break;\ setsub32(EAX, temp); \ tempz = (ZF_SET()) ? 1 : 0; \ - if (flags & D_FLAG) DEST_REG -= 4; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ else DEST_REG += 4; \ CNT_REG--; \ cycles -= is486 ? 5 : 8; \ diff --git a/src/cpu/x86_ops_ret.h b/src/cpu/x86_ops_ret.h index 95872588c..75419e6d8 100644 --- a/src/cpu/x86_ops_ret.h +++ b/src/cpu/x86_ops_ret.h @@ -1,10 +1,10 @@ #define RETF_a16(stack_offset) \ - if ((msw&1) && !(eflags&VM_FLAG)) \ + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) \ { \ pmoderetf(0, stack_offset); \ return 1; \ } \ - oxpc = cpu_state.pc; \ + oxpc = cpu_state.pc; \ if (stack32) \ { \ cpu_state.pc = readmemw(ss, ESP); \ @@ -21,12 +21,12 @@ cycles -= timing_retf_rm; #define RETF_a32(stack_offset) \ - if ((msw&1) && !(eflags&VM_FLAG)) \ + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) \ { \ pmoderetf(1, stack_offset); \ return 1; \ } \ - oxpc = cpu_state.pc; \ + oxpc = cpu_state.pc; \ if (stack32) \ { \ cpu_state.pc = readmeml(ss, ESP); \ @@ -94,7 +94,7 @@ static int opIRET_286(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); return 1; @@ -108,19 +108,19 @@ static int opIRET_286(uint32_t fetchdat) else { uint16_t new_cs; - oxpc = cpu_state.pc; + oxpc = cpu_state.pc; if (stack32) { cpu_state.pc = readmemw(ss, ESP); new_cs = readmemw(ss, ESP + 2); - flags = (flags & 0x7000) | (readmemw(ss, ESP + 4) & 0xffd5) | 2; + cpu_state.flags = (cpu_state.flags & 0x7000) | (readmemw(ss, ESP + 4) & 0xffd5) | 2; ESP += 6; } else { cpu_state.pc = readmemw(ss, SP); new_cs = readmemw(ss, ((SP + 2) & 0xffff)); - flags = (flags & 0x7000) | (readmemw(ss, ((SP + 4) & 0xffff)) & 0x0fd5) | 2; + cpu_state.flags = (cpu_state.flags & 0x7000) | (readmemw(ss, ((SP + 4) & 0xffff)) & 0x0fd5) | 2; SP += 6; } loadcs(new_cs); @@ -139,7 +139,7 @@ static int opIRET(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { if (cr4 & CR4_VME) { @@ -151,17 +151,17 @@ static int opIRET(uint32_t fetchdat) if (cpu_state.abrt) return 1; - if ((new_flags & T_FLAG) || ((new_flags & I_FLAG) && (eflags & VIP_FLAG))) + if ((new_flags & T_FLAG) || ((new_flags & I_FLAG) && (cpu_state.eflags & VIP_FLAG))) { x86gpf(NULL, 0); return 1; } SP += 6; if (new_flags & I_FLAG) - eflags |= VIF_FLAG; + cpu_state.eflags |= VIF_FLAG; else - eflags &= ~VIF_FLAG; - flags = (flags & 0x3300) | (new_flags & 0x4cd5) | 2; + cpu_state.eflags &= ~VIF_FLAG; + cpu_state.flags = (cpu_state.flags & 0x3300) | (new_flags & 0x4cd5) | 2; loadcs(new_cs); cpu_state.pc = new_pc; @@ -184,19 +184,19 @@ static int opIRET(uint32_t fetchdat) else { uint16_t new_cs; - oxpc = cpu_state.pc; + oxpc = cpu_state.pc; if (stack32) { cpu_state.pc = readmemw(ss, ESP); new_cs = readmemw(ss, ESP + 2); - flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; + cpu_state.flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; ESP += 6; } else { cpu_state.pc = readmemw(ss, SP); new_cs = readmemw(ss, ((SP + 2) & 0xffff)); - flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; + cpu_state.flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; SP += 6; } loadcs(new_cs); @@ -216,7 +216,7 @@ static int opIRETD(uint32_t fetchdat) { int cycles_old = cycles; UN_USED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); return 1; @@ -230,21 +230,21 @@ static int opIRETD(uint32_t fetchdat) else { uint16_t new_cs; - oxpc = cpu_state.pc; + oxpc = cpu_state.pc; if (stack32) { cpu_state.pc = readmeml(ss, ESP); new_cs = readmemw(ss, ESP + 4); - flags = (readmemw(ss, ESP + 8) & 0xffd5) | 2; - eflags = readmemw(ss, ESP + 10); + cpu_state.flags = (readmemw(ss, ESP + 8) & 0xffd5) | 2; + cpu_state.eflags = readmemw(ss, ESP + 10); ESP += 12; } else { cpu_state.pc = readmeml(ss, SP); new_cs = readmemw(ss, ((SP + 4) & 0xffff)); - flags = (readmemw(ss,(SP + 8) & 0xffff) & 0xffd5) | 2; - eflags = readmemw(ss, (SP + 10) & 0xffff); + cpu_state.flags = (readmemw(ss,(SP + 8) & 0xffff) & 0xffd5) | 2; + cpu_state.eflags = readmemw(ss, (SP + 10) & 0xffff); SP += 12; } loadcs(new_cs); diff --git a/src/cpu/x86_ops_set.h b/src/cpu/x86_ops_set.h index 0094b85d4..f6fd50e69 100644 --- a/src/cpu/x86_ops_set.h +++ b/src/cpu/x86_ops_set.h @@ -2,6 +2,8 @@ static int opSET ## condition ## _a16(uint32_t fetchdat) \ { \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ seteab((cond_ ## condition) ? 1 : 0); \ CLOCK_CYCLES(4); \ return cpu_state.abrt; \ @@ -10,6 +12,8 @@ static int opSET ## condition ## _a32(uint32_t fetchdat) \ { \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ seteab((cond_ ## condition) ? 1 : 0); \ CLOCK_CYCLES(4); \ return cpu_state.abrt; \ diff --git a/src/cpu/x86_ops_shift.h b/src/cpu/x86_ops_shift.h index 5f0f57631..5cf44943d 100644 --- a/src/cpu/x86_ops_shift.h +++ b/src/cpu/x86_ops_shift.h @@ -6,36 +6,25 @@ switch (rmdat & 0x38) \ { \ case 0x00: /*ROL b, c*/ \ - while (c > 0) \ - { \ - temp2 = (temp & 0x80) ? 1 : 0; \ - temp = (temp << 1) | temp2; \ - c--; \ - } \ - seteab(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \ + temp = (temp << (c & 7)) | (temp >> (8-(c & 7))); \ + seteab(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp & 1) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 7)) & 1) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ case 0x08: /*ROR b,CL*/ \ - while (c > 0) \ - { \ - temp2 = temp & 1; \ - temp >>= 1; \ - if (temp2) temp |= 0x80; \ - c--; \ - } \ - seteab(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \ + temp = (temp >> (c & 7)) | (temp << (8-(c & 7))); \ + seteab(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp & 0x80) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ - break; \ + break; \ case 0x10: /*RCL b,CL*/ \ - temp2 = flags & C_FLAG; \ + temp2 = cpu_state.flags & C_FLAG; \ if (is486) CLOCK_CYCLES_ALWAYS(c); \ while (c > 0) \ { \ @@ -45,14 +34,14 @@ c--; \ } \ seteab(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((cpu_state.flags & C_FLAG) ^ (temp >> 7)) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ case 0x18: /*RCR b,CL*/ \ - temp2 = flags & C_FLAG; \ + temp2 = cpu_state.flags & C_FLAG; \ if (is486) CLOCK_CYCLES_ALWAYS(c); \ while (c > 0) \ { \ @@ -62,9 +51,9 @@ c--; \ } \ seteab(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ @@ -98,36 +87,25 @@ switch (rmdat & 0x38) \ { \ case 0x00: /*ROL w, c*/ \ - while (c > 0) \ - { \ - temp2 = (temp & 0x8000) ? 1 : 0; \ - temp = (temp << 1) | temp2; \ - c--; \ - } \ - seteaw(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + temp = (temp << (c & 15)) | (temp >> (16-(c & 15))); \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp & 1) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 15)) & 1) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ - case 0x08: /*ROR w, c*/ \ - while (c > 0) \ - { \ - temp2 = temp & 1; \ - temp >>= 1; \ - if (temp2) temp |= 0x8000; \ - c--; \ - } \ - seteaw(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + case 0x08: /*ROR w,CL*/ \ + temp = (temp >> (c & 15)) | (temp << (16-(c & 15))); \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp & 0x8000) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ case 0x10: /*RCL w, c*/ \ - temp2 = flags & C_FLAG; \ + temp2 = cpu_state.flags & C_FLAG; \ if (is486) CLOCK_CYCLES_ALWAYS(c); \ while (c > 0) \ { \ @@ -137,14 +115,14 @@ c--; \ } \ seteaw(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((cpu_state.flags & C_FLAG) ^ (temp >> 15)) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ case 0x18: /*RCR w, c*/ \ - temp2 = flags & C_FLAG; \ + temp2 = cpu_state.flags & C_FLAG; \ if (is486) CLOCK_CYCLES_ALWAYS(c); \ while (c > 0) \ { \ @@ -154,9 +132,9 @@ c--; \ } \ seteaw(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ @@ -190,33 +168,22 @@ switch (rmdat & 0x38) \ { \ case 0x00: /*ROL l, c*/ \ - while (c > 0) \ - { \ - temp2 = (temp & 0x80000000) ? 1 : 0; \ - temp = (temp << 1) | temp2; \ - c--; \ - } \ - seteal(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + temp = (temp << c) | (temp >> (32-c)); \ + seteal(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp & 1) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 31)) & 1) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ - case 0x08: /*ROR l, c*/ \ - while (c > 0) \ - { \ - temp2 = temp & 1; \ - temp >>= 1; \ - if (temp2) temp |= 0x80000000; \ - c--; \ - } \ - seteal(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + case 0x08: /*ROR l,CL*/ \ + temp = (temp >> c) | (temp << (32-c)); \ + seteal(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp & 0x80000000) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ case 0x10: /*RCL l, c*/ \ temp2 = CF_SET(); \ @@ -229,14 +196,14 @@ c--; \ } \ seteal(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((cpu_state.flags & C_FLAG) ^ (temp >> 31)) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ break; \ case 0x18: /*RCR l, c*/ \ - temp2 = flags & C_FLAG; \ + temp2 = cpu_state.flags & C_FLAG; \ if (is486) CLOCK_CYCLES_ALWAYS(c); \ while (c > 0) \ { \ @@ -246,9 +213,9 @@ c--; \ } \ seteal(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ break; \ @@ -281,6 +248,8 @@ static int opC0_a16(uint32_t fetchdat) uint8_t temp, temp2 = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; PREFETCH_PREFIX(); temp = geteab(); if (cpu_state.abrt) return 1; @@ -294,6 +263,8 @@ static int opC0_a32(uint32_t fetchdat) uint8_t temp, temp2 = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; PREFETCH_PREFIX(); temp = geteab(); if (cpu_state.abrt) return 1; @@ -307,6 +278,8 @@ static int opC1_w_a16(uint32_t fetchdat) uint16_t temp, temp2 = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; PREFETCH_PREFIX(); temp = geteaw(); if (cpu_state.abrt) return 1; @@ -320,6 +293,8 @@ static int opC1_w_a32(uint32_t fetchdat) uint16_t temp, temp2 = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; PREFETCH_PREFIX(); temp = geteaw(); if (cpu_state.abrt) return 1; @@ -333,6 +308,8 @@ static int opC1_l_a16(uint32_t fetchdat) uint32_t temp, temp2 = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; PREFETCH_PREFIX(); temp = geteal(); if (cpu_state.abrt) return 1; @@ -346,6 +323,8 @@ static int opC1_l_a32(uint32_t fetchdat) uint32_t temp, temp2 = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; PREFETCH_PREFIX(); temp = geteal(); if (cpu_state.abrt) return 1; @@ -360,6 +339,8 @@ static int opD0_a16(uint32_t fetchdat) uint8_t temp, temp2 = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; OP_SHIFT_b(c, 0); return 0; @@ -371,6 +352,8 @@ static int opD0_a32(uint32_t fetchdat) uint8_t temp, temp2 = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; OP_SHIFT_b(c, 1); return 0; @@ -382,6 +365,8 @@ static int opD1_w_a16(uint32_t fetchdat) uint16_t temp, temp2 = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; OP_SHIFT_w(c, 0); return 0; @@ -393,6 +378,8 @@ static int opD1_w_a32(uint32_t fetchdat) uint16_t temp, temp2 = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; OP_SHIFT_w(c, 1); return 0; @@ -404,6 +391,8 @@ static int opD1_l_a16(uint32_t fetchdat) uint32_t temp, temp2 = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; OP_SHIFT_l(c, 0); return 0; @@ -415,6 +404,8 @@ static int opD1_l_a32(uint32_t fetchdat) uint32_t temp, temp2 = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; OP_SHIFT_l(c, 1); return 0; @@ -427,6 +418,8 @@ static int opD2_a16(uint32_t fetchdat) uint8_t temp, temp2 = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = CL & 31; temp = geteab(); if (cpu_state.abrt) return 1; OP_SHIFT_b(c, 0); @@ -439,6 +432,8 @@ static int opD2_a32(uint32_t fetchdat) uint8_t temp, temp2 = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = CL & 31; temp = geteab(); if (cpu_state.abrt) return 1; OP_SHIFT_b(c, 1); @@ -451,6 +446,8 @@ static int opD3_w_a16(uint32_t fetchdat) uint16_t temp, temp2 = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = CL & 31; temp = geteaw(); if (cpu_state.abrt) return 1; OP_SHIFT_w(c, 0); @@ -463,6 +460,8 @@ static int opD3_w_a32(uint32_t fetchdat) uint16_t temp, temp2 = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = CL & 31; temp = geteaw(); if (cpu_state.abrt) return 1; OP_SHIFT_w(c, 1); @@ -475,6 +474,8 @@ static int opD3_l_a16(uint32_t fetchdat) uint32_t temp, temp2 = 0; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = CL & 31; temp = geteal(); if (cpu_state.abrt) return 1; OP_SHIFT_l(c, 0); @@ -487,6 +488,8 @@ static int opD3_l_a32(uint32_t fetchdat) uint32_t temp, temp2 = 0; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = CL & 31; temp = geteal(); if (cpu_state.abrt) return 1; OP_SHIFT_l(c, 1); @@ -507,7 +510,7 @@ static int opD3_l_a32(uint32_t fetchdat) seteaw(tempw); if (cpu_state.abrt) return 1; \ setznp16(tempw); \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ } #define SHLD_l() \ @@ -520,7 +523,7 @@ static int opD3_l_a32(uint32_t fetchdat) seteal(templ); if (cpu_state.abrt) return 1; \ setznp32(templ); \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ } @@ -536,7 +539,7 @@ static int opD3_l_a32(uint32_t fetchdat) seteaw(tempw); if (cpu_state.abrt) return 1; \ setznp16(tempw); \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ } #define SHRD_l() \ @@ -549,7 +552,7 @@ static int opD3_l_a32(uint32_t fetchdat) seteal(templ); if (cpu_state.abrt) return 1; \ setznp32(templ); \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ } #define opSHxD(operation) \ @@ -558,6 +561,8 @@ static int opD3_l_a32(uint32_t fetchdat) int count; \ \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ count = getbyte() & 31; \ operation() \ \ @@ -570,6 +575,8 @@ static int opD3_l_a32(uint32_t fetchdat) int count; \ \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ count = CL & 31; \ operation() \ \ @@ -582,6 +589,8 @@ static int opD3_l_a32(uint32_t fetchdat) int count; \ \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ count = getbyte() & 31; \ operation() \ \ @@ -594,6 +603,8 @@ static int opD3_l_a32(uint32_t fetchdat) int count; \ \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ count = CL & 31; \ operation() \ \ diff --git a/src/cpu/x86_ops_stack.h b/src/cpu/x86_ops_stack.h index 621f602b3..20b0aa766 100644 --- a/src/cpu/x86_ops_stack.h +++ b/src/cpu/x86_ops_stack.h @@ -236,6 +236,8 @@ static int opPOPW_a16(uint32_t fetchdat) temp = POP_W(); if (cpu_state.abrt) return 1; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(temp); if (cpu_state.abrt) { @@ -255,6 +257,8 @@ static int opPOPW_a32(uint32_t fetchdat) temp = POP_W(); if (cpu_state.abrt) return 1; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(temp); if (cpu_state.abrt) { @@ -274,7 +278,9 @@ static int opPOPL_a16(uint32_t fetchdat) temp = POP_L(); if (cpu_state.abrt) return 1; - fetch_ea_16(fetchdat); + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(temp); if (cpu_state.abrt) { @@ -294,6 +300,8 @@ static int opPOPL_a32(uint32_t fetchdat) temp = POP_L(); if (cpu_state.abrt) return 1; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(temp); if (cpu_state.abrt) { @@ -469,10 +477,10 @@ PUSH_SEG_OPS(FS) PUSH_SEG_OPS(GS) PUSH_SEG_OPS(SS) -POP_SEG_OPS(DS, &_ds) -POP_SEG_OPS(ES, &_es) -POP_SEG_OPS(FS, &_fs) -POP_SEG_OPS(GS, &_gs) +POP_SEG_OPS(DS, &cpu_state.seg_ds) +POP_SEG_OPS(ES, &cpu_state.seg_es) +POP_SEG_OPS(FS, &cpu_state.seg_fs) +POP_SEG_OPS(GS, &cpu_state.seg_gs) static int opPOP_SS_w(uint32_t fetchdat) @@ -480,14 +488,14 @@ static int opPOP_SS_w(uint32_t fetchdat) uint16_t temp_seg; uint32_t temp_esp = ESP; temp_seg = POP_W(); if (cpu_state.abrt) return 1; - loadseg(temp_seg, &_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } + loadseg(temp_seg, &cpu_state.seg_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } CLOCK_CYCLES(is486 ? 3 : 7); PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); cpu_state.oldpc = cpu_state.pc; cpu_state.op32 = use32; cpu_state.ssegs = 0; - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; fetchdat = fastreadl(cs + cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; @@ -500,14 +508,14 @@ static int opPOP_SS_l(uint32_t fetchdat) uint32_t temp_seg; uint32_t temp_esp = ESP; temp_seg = POP_L(); if (cpu_state.abrt) return 1; - loadseg(temp_seg & 0xffff, &_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } + loadseg(temp_seg & 0xffff, &cpu_state.seg_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } CLOCK_CYCLES(is486 ? 3 : 7); PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); cpu_state.oldpc = cpu_state.pc; cpu_state.op32 = use32; cpu_state.ssegs = 0; - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; fetchdat = fastreadl(cs + cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; diff --git a/src/cpu/x86_ops_string.h b/src/cpu/x86_ops_string.h index 8c8ba6816..41e368cc7 100644 --- a/src/cpu/x86_ops_string.h +++ b/src/cpu/x86_ops_string.h @@ -1,8 +1,12 @@ static int opMOVSB_a16(uint32_t fetchdat) { - uint8_t temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; writememb(es, DI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) { DI--; SI--; } + if (cpu_state.flags & D_FLAG) { DI--; SI--; } else { DI++; SI++; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,1,0, 0); @@ -10,9 +14,13 @@ static int opMOVSB_a16(uint32_t fetchdat) } static int opMOVSB_a32(uint32_t fetchdat) { - uint8_t temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; writememb(es, EDI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) { EDI--; ESI--; } + if (cpu_state.flags & D_FLAG) { EDI--; ESI--; } else { EDI++; ESI++; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,1,0, 1); @@ -21,9 +29,13 @@ static int opMOVSB_a32(uint32_t fetchdat) static int opMOVSW_a16(uint32_t fetchdat) { - uint16_t temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; writememw(es, DI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) { DI -= 2; SI -= 2; } + if (cpu_state.flags & D_FLAG) { DI -= 2; SI -= 2; } else { DI += 2; SI += 2; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,1,0, 0); @@ -31,9 +43,13 @@ static int opMOVSW_a16(uint32_t fetchdat) } static int opMOVSW_a32(uint32_t fetchdat) { - uint16_t temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; writememw(es, EDI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) { EDI -= 2; ESI -= 2; } + if (cpu_state.flags & D_FLAG) { EDI -= 2; ESI -= 2; } else { EDI += 2; ESI += 2; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,1,0, 1); @@ -42,9 +58,13 @@ static int opMOVSW_a32(uint32_t fetchdat) static int opMOVSL_a16(uint32_t fetchdat) { - uint32_t temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; writememl(es, DI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) { DI -= 4; SI -= 4; } + if (cpu_state.flags & D_FLAG) { DI -= 4; SI -= 4; } else { DI += 4; SI += 4; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 0,1,0,1, 0); @@ -52,9 +72,13 @@ static int opMOVSL_a16(uint32_t fetchdat) } static int opMOVSL_a32(uint32_t fetchdat) { - uint32_t temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; writememl(es, EDI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) { EDI -= 4; ESI -= 4; } + if (cpu_state.flags & D_FLAG) { EDI -= 4; ESI -= 4; } else { EDI += 4; ESI += 4; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 0,1,0,1, 1); @@ -64,10 +88,14 @@ static int opMOVSL_a32(uint32_t fetchdat) static int opCMPSB_a16(uint32_t fetchdat) { - uint8_t src = readmemb(cpu_state.ea_seg->base, SI); - uint8_t dst = readmemb(es, DI); if (cpu_state.abrt) return 1; + uint8_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmemb(cpu_state.ea_seg->base, SI); + dst = readmemb(es, DI); if (cpu_state.abrt) return 1; setsub8(src, dst); - if (flags & D_FLAG) { DI--; SI--; } + if (cpu_state.flags & D_FLAG) { DI--; SI--; } else { DI++; SI++; } CLOCK_CYCLES((is486) ? 8 : 10); PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 0); @@ -75,10 +103,14 @@ static int opCMPSB_a16(uint32_t fetchdat) } static int opCMPSB_a32(uint32_t fetchdat) { - uint8_t src = readmemb(cpu_state.ea_seg->base, ESI); - uint8_t dst = readmemb(es, EDI); if (cpu_state.abrt) return 1; + uint8_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmemb(cpu_state.ea_seg->base, ESI); + dst = readmemb(es, EDI); if (cpu_state.abrt) return 1; setsub8(src, dst); - if (flags & D_FLAG) { EDI--; ESI--; } + if (cpu_state.flags & D_FLAG) { EDI--; ESI--; } else { EDI++; ESI++; } CLOCK_CYCLES((is486) ? 8 : 10); PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 1); @@ -87,10 +119,14 @@ static int opCMPSB_a32(uint32_t fetchdat) static int opCMPSW_a16(uint32_t fetchdat) { - uint16_t src = readmemw(cpu_state.ea_seg->base, SI); - uint16_t dst = readmemw(es, DI); if (cpu_state.abrt) return 1; + uint16_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmemw(cpu_state.ea_seg->base, SI); + dst = readmemw(es, DI); if (cpu_state.abrt) return 1; setsub16(src, dst); - if (flags & D_FLAG) { DI -= 2; SI -= 2; } + if (cpu_state.flags & D_FLAG) { DI -= 2; SI -= 2; } else { DI += 2; SI += 2; } CLOCK_CYCLES((is486) ? 8 : 10); PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 0); @@ -98,10 +134,14 @@ static int opCMPSW_a16(uint32_t fetchdat) } static int opCMPSW_a32(uint32_t fetchdat) { - uint16_t src = readmemw(cpu_state.ea_seg->base, ESI); - uint16_t dst = readmemw(es, EDI); if (cpu_state.abrt) return 1; + uint16_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmemw(cpu_state.ea_seg->base, ESI); + dst = readmemw(es, EDI); if (cpu_state.abrt) return 1; setsub16(src, dst); - if (flags & D_FLAG) { EDI -= 2; ESI -= 2; } + if (cpu_state.flags & D_FLAG) { EDI -= 2; ESI -= 2; } else { EDI += 2; ESI += 2; } CLOCK_CYCLES((is486) ? 8 : 10); PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 1); @@ -110,10 +150,14 @@ static int opCMPSW_a32(uint32_t fetchdat) static int opCMPSL_a16(uint32_t fetchdat) { - uint32_t src = readmeml(cpu_state.ea_seg->base, SI); - uint32_t dst = readmeml(es, DI); if (cpu_state.abrt) return 1; + uint32_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmeml(cpu_state.ea_seg->base, SI); + dst = readmeml(es, DI); if (cpu_state.abrt) return 1; setsub32(src, dst); - if (flags & D_FLAG) { DI -= 4; SI -= 4; } + if (cpu_state.flags & D_FLAG) { DI -= 4; SI -= 4; } else { DI += 4; SI += 4; } CLOCK_CYCLES((is486) ? 8 : 10); PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 0,2,0,0, 0); @@ -121,10 +165,14 @@ static int opCMPSL_a16(uint32_t fetchdat) } static int opCMPSL_a32(uint32_t fetchdat) { - uint32_t src = readmeml(cpu_state.ea_seg->base, ESI); - uint32_t dst = readmeml(es, EDI); if (cpu_state.abrt) return 1; + uint32_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmeml(cpu_state.ea_seg->base, ESI); + dst = readmeml(es, EDI); if (cpu_state.abrt) return 1; setsub32(src, dst); - if (flags & D_FLAG) { EDI -= 4; ESI -= 4; } + if (cpu_state.flags & D_FLAG) { EDI -= 4; ESI -= 4; } else { EDI += 4; ESI += 4; } CLOCK_CYCLES((is486) ? 8 : 10); PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 0,2,0,0, 1); @@ -133,8 +181,9 @@ static int opCMPSL_a32(uint32_t fetchdat) static int opSTOSB_a16(uint32_t fetchdat) { + SEG_CHECK_WRITE(&cpu_state.seg_es); writememb(es, DI, AL); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) DI--; + if (cpu_state.flags & D_FLAG) DI--; else DI++; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); @@ -142,8 +191,9 @@ static int opSTOSB_a16(uint32_t fetchdat) } static int opSTOSB_a32(uint32_t fetchdat) { + SEG_CHECK_WRITE(&cpu_state.seg_es); writememb(es, EDI, AL); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) EDI--; + if (cpu_state.flags & D_FLAG) EDI--; else EDI++; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1); @@ -152,8 +202,9 @@ static int opSTOSB_a32(uint32_t fetchdat) static int opSTOSW_a16(uint32_t fetchdat) { + SEG_CHECK_WRITE(&cpu_state.seg_es); writememw(es, DI, AX); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) DI -= 2; + if (cpu_state.flags & D_FLAG) DI -= 2; else DI += 2; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); @@ -161,8 +212,9 @@ static int opSTOSW_a16(uint32_t fetchdat) } static int opSTOSW_a32(uint32_t fetchdat) { + SEG_CHECK_WRITE(&cpu_state.seg_es); writememw(es, EDI, AX); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) EDI -= 2; + if (cpu_state.flags & D_FLAG) EDI -= 2; else EDI += 2; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1); @@ -171,8 +223,9 @@ static int opSTOSW_a32(uint32_t fetchdat) static int opSTOSL_a16(uint32_t fetchdat) { + SEG_CHECK_WRITE(&cpu_state.seg_es); writememl(es, DI, EAX); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) DI -= 4; + if (cpu_state.flags & D_FLAG) DI -= 4; else DI += 4; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,1, 0); @@ -180,8 +233,9 @@ static int opSTOSL_a16(uint32_t fetchdat) } static int opSTOSL_a32(uint32_t fetchdat) { + SEG_CHECK_WRITE(&cpu_state.seg_es); writememl(es, EDI, EAX); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) EDI -= 4; + if (cpu_state.flags & D_FLAG) EDI -= 4; else EDI += 4; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,1, 1); @@ -191,9 +245,12 @@ static int opSTOSL_a32(uint32_t fetchdat) static int opLODSB_a16(uint32_t fetchdat) { - uint8_t temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; AL = temp; - if (flags & D_FLAG) SI--; + if (cpu_state.flags & D_FLAG) SI--; else SI++; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); @@ -201,9 +258,12 @@ static int opLODSB_a16(uint32_t fetchdat) } static int opLODSB_a32(uint32_t fetchdat) { - uint8_t temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; AL = temp; - if (flags & D_FLAG) ESI--; + if (cpu_state.flags & D_FLAG) ESI--; else ESI++; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); @@ -212,9 +272,12 @@ static int opLODSB_a32(uint32_t fetchdat) static int opLODSW_a16(uint32_t fetchdat) { - uint16_t temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; AX = temp; - if (flags & D_FLAG) SI -= 2; + if (cpu_state.flags & D_FLAG) SI -= 2; else SI += 2; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); @@ -222,9 +285,12 @@ static int opLODSW_a16(uint32_t fetchdat) } static int opLODSW_a32(uint32_t fetchdat) { - uint16_t temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; AX = temp; - if (flags & D_FLAG) ESI -= 2; + if (cpu_state.flags & D_FLAG) ESI -= 2; else ESI += 2; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); @@ -233,9 +299,12 @@ static int opLODSW_a32(uint32_t fetchdat) static int opLODSL_a16(uint32_t fetchdat) { - uint32_t temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; EAX = temp; - if (flags & D_FLAG) SI -= 4; + if (cpu_state.flags & D_FLAG) SI -= 4; else SI += 4; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 0,1,0,0, 0); @@ -243,9 +312,12 @@ static int opLODSL_a16(uint32_t fetchdat) } static int opLODSL_a32(uint32_t fetchdat) { - uint32_t temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; EAX = temp; - if (flags & D_FLAG) ESI -= 4; + if (cpu_state.flags & D_FLAG) ESI -= 4; else ESI += 4; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 0,1,0,0, 1); @@ -255,9 +327,12 @@ static int opLODSL_a32(uint32_t fetchdat) static int opSCASB_a16(uint32_t fetchdat) { - uint8_t temp = readmemb(es, DI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemb(es, DI); if (cpu_state.abrt) return 1; setsub8(AL, temp); - if (flags & D_FLAG) DI--; + if (cpu_state.flags & D_FLAG) DI--; else DI++; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,0,0, 0); @@ -265,9 +340,12 @@ static int opSCASB_a16(uint32_t fetchdat) } static int opSCASB_a32(uint32_t fetchdat) { - uint8_t temp = readmemb(es, EDI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemb(es, EDI); if (cpu_state.abrt) return 1; setsub8(AL, temp); - if (flags & D_FLAG) EDI--; + if (cpu_state.flags & D_FLAG) EDI--; else EDI++; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1); @@ -276,9 +354,12 @@ static int opSCASB_a32(uint32_t fetchdat) static int opSCASW_a16(uint32_t fetchdat) { - uint16_t temp = readmemw(es, DI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemw(es, DI); if (cpu_state.abrt) return 1; setsub16(AX, temp); - if (flags & D_FLAG) DI -= 2; + if (cpu_state.flags & D_FLAG) DI -= 2; else DI += 2; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,0,0, 0); @@ -286,9 +367,12 @@ static int opSCASW_a16(uint32_t fetchdat) } static int opSCASW_a32(uint32_t fetchdat) { - uint16_t temp = readmemw(es, EDI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemw(es, EDI); if (cpu_state.abrt) return 1; setsub16(AX, temp); - if (flags & D_FLAG) EDI -= 2; + if (cpu_state.flags & D_FLAG) EDI -= 2; else EDI += 2; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1); @@ -297,9 +381,12 @@ static int opSCASW_a32(uint32_t fetchdat) static int opSCASL_a16(uint32_t fetchdat) { - uint32_t temp = readmeml(es, DI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmeml(es, DI); if (cpu_state.abrt) return 1; setsub32(EAX, temp); - if (flags & D_FLAG) DI -= 4; + if (cpu_state.flags & D_FLAG) DI -= 4; else DI += 4; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 0,1,0,0, 0); @@ -307,9 +394,12 @@ static int opSCASL_a16(uint32_t fetchdat) } static int opSCASL_a32(uint32_t fetchdat) { - uint32_t temp = readmeml(es, EDI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmeml(es, EDI); if (cpu_state.abrt) return 1; setsub32(EAX, temp); - if (flags & D_FLAG) EDI -= 4; + if (cpu_state.flags & D_FLAG) EDI -= 4; else EDI += 4; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 0,1,0,0, 1); @@ -319,10 +409,12 @@ static int opSCASL_a32(uint32_t fetchdat) static int opINSB_a16(uint32_t fetchdat) { uint8_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); temp = inb(DX); writememb(es, DI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) DI--; + if (cpu_state.flags & D_FLAG) DI--; else DI++; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0); @@ -331,10 +423,12 @@ static int opINSB_a16(uint32_t fetchdat) static int opINSB_a32(uint32_t fetchdat) { uint8_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); temp = inb(DX); writememb(es, EDI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) EDI--; + if (cpu_state.flags & D_FLAG) EDI--; else EDI++; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1); @@ -344,11 +438,13 @@ static int opINSB_a32(uint32_t fetchdat) static int opINSW_a16(uint32_t fetchdat) { uint16_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); check_io_perm(DX + 1); temp = inw(DX); writememw(es, DI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) DI -= 2; + if (cpu_state.flags & D_FLAG) DI -= 2; else DI += 2; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0); @@ -357,11 +453,13 @@ static int opINSW_a16(uint32_t fetchdat) static int opINSW_a32(uint32_t fetchdat) { uint16_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); check_io_perm(DX + 1); temp = inw(DX); writememw(es, EDI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) EDI -= 2; + if (cpu_state.flags & D_FLAG) EDI -= 2; else EDI += 2; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1); @@ -371,13 +469,15 @@ static int opINSW_a32(uint32_t fetchdat) static int opINSL_a16(uint32_t fetchdat) { uint32_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); check_io_perm(DX + 1); check_io_perm(DX + 2); check_io_perm(DX + 3); temp = inl(DX); writememl(es, DI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) DI -= 4; + if (cpu_state.flags & D_FLAG) DI -= 4; else DI += 4; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 0,1,0,1, 0); @@ -386,13 +486,15 @@ static int opINSL_a16(uint32_t fetchdat) static int opINSL_a32(uint32_t fetchdat) { uint32_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); check_io_perm(DX + 1); check_io_perm(DX + 2); check_io_perm(DX + 3); temp = inl(DX); writememl(es, EDI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) EDI -= 4; + if (cpu_state.flags & D_FLAG) EDI -= 4; else EDI += 4; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 0,1,0,1, 1); @@ -401,9 +503,12 @@ static int opINSL_a32(uint32_t fetchdat) static int opOUTSB_a16(uint32_t fetchdat) { - uint8_t temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; check_io_perm(DX); - if (flags & D_FLAG) SI--; + if (cpu_state.flags & D_FLAG) SI--; else SI++; outb(DX, temp); CLOCK_CYCLES(14); @@ -412,9 +517,12 @@ static int opOUTSB_a16(uint32_t fetchdat) } static int opOUTSB_a32(uint32_t fetchdat) { - uint8_t temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; check_io_perm(DX); - if (flags & D_FLAG) ESI--; + if (cpu_state.flags & D_FLAG) ESI--; else ESI++; outb(DX, temp); CLOCK_CYCLES(14); @@ -424,10 +532,13 @@ static int opOUTSB_a32(uint32_t fetchdat) static int opOUTSW_a16(uint32_t fetchdat) { - uint16_t temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; check_io_perm(DX); check_io_perm(DX + 1); - if (flags & D_FLAG) SI -= 2; + if (cpu_state.flags & D_FLAG) SI -= 2; else SI += 2; outw(DX, temp); CLOCK_CYCLES(14); @@ -436,10 +547,13 @@ static int opOUTSW_a16(uint32_t fetchdat) } static int opOUTSW_a32(uint32_t fetchdat) { - uint16_t temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; check_io_perm(DX); check_io_perm(DX + 1); - if (flags & D_FLAG) ESI -= 2; + if (cpu_state.flags & D_FLAG) ESI -= 2; else ESI += 2; outw(DX, temp); CLOCK_CYCLES(14); @@ -449,12 +563,15 @@ static int opOUTSW_a32(uint32_t fetchdat) static int opOUTSL_a16(uint32_t fetchdat) { - uint32_t temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; check_io_perm(DX); check_io_perm(DX + 1); check_io_perm(DX + 2); check_io_perm(DX + 3); - if (flags & D_FLAG) SI -= 4; + if (cpu_state.flags & D_FLAG) SI -= 4; else SI += 4; outl(EDX, temp); CLOCK_CYCLES(14); @@ -463,12 +580,15 @@ static int opOUTSL_a16(uint32_t fetchdat) } static int opOUTSL_a32(uint32_t fetchdat) { - uint32_t temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; check_io_perm(DX); check_io_perm(DX + 1); check_io_perm(DX + 2); check_io_perm(DX + 3); - if (flags & D_FLAG) ESI -= 4; + if (cpu_state.flags & D_FLAG) ESI -= 4; else ESI += 4; outl(EDX, temp); CLOCK_CYCLES(14); diff --git a/src/cpu/x86_ops_xchg.h b/src/cpu/x86_ops_xchg.h index 77191ae43..3880f70e7 100644 --- a/src/cpu/x86_ops_xchg.h +++ b/src/cpu/x86_ops_xchg.h @@ -2,6 +2,8 @@ static int opXCHG_b_a16(uint32_t fetchdat) { uint8_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; seteab(getr8(cpu_reg)); if (cpu_state.abrt) return 1; setr8(cpu_reg, temp); @@ -13,6 +15,8 @@ static int opXCHG_b_a32(uint32_t fetchdat) { uint8_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; seteab(getr8(cpu_reg)); if (cpu_state.abrt) return 1; setr8(cpu_reg, temp); @@ -25,6 +29,8 @@ static int opXCHG_w_a16(uint32_t fetchdat) { uint16_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; @@ -36,6 +42,8 @@ static int opXCHG_w_a32(uint32_t fetchdat) { uint16_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; @@ -48,6 +56,8 @@ static int opXCHG_l_a16(uint32_t fetchdat) { uint32_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp; @@ -59,6 +69,8 @@ static int opXCHG_l_a32(uint32_t fetchdat) { uint32_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp; diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index c4e8229f1..d2dd5e8ad 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -27,11 +27,12 @@ #include "../86box.h" #include "cpu.h" #include "../device.h" +#include "../timer.h" #include "../machine/machine.h" #include "../mem.h" #include "../nvr.h" #include "x86.h" -#include "386.h" +#include "x86_flags.h" #include "386_common.h" @@ -80,13 +81,14 @@ x86seg_log(const char *fmt, ...) #endif -void x86abort(const char *format, ...) +void x86abort(const char *fmt, ...) { va_list ap; - va_start(ap, format); - vfprintf(stdlog, format, ap); + + va_start(ap, fmt); + pclog_ex(fmt, ap); va_end(ap); - fflush(stdlog); + nvr_save(); #ifdef ENABLE_808X_LOG dumpregs(1); @@ -103,7 +105,7 @@ static void seg_reset(x86seg *s) s->limit = 0xFFFF; s->limit_low = 0; s->limit_high = 0xffff; - if(s == &_cs) + if(s == &cpu_state.seg_cs) { // TODO - When the PC is reset, initialization of the CS descriptor must be like the annotated line below. //s->base = AT ? (cpu_16bitbus ? 0xFF0000 : 0xFFFF0000) : 0xFFFF0; @@ -120,19 +122,19 @@ static void seg_reset(x86seg *s) void x86seg_reset() { - seg_reset(&_cs); - seg_reset(&_ds); - seg_reset(&_es); - seg_reset(&_fs); - seg_reset(&_gs); - seg_reset(&_ss); + seg_reset(&cpu_state.seg_cs); + seg_reset(&cpu_state.seg_ds); + seg_reset(&cpu_state.seg_es); + seg_reset(&cpu_state.seg_fs); + seg_reset(&cpu_state.seg_gs); + seg_reset(&cpu_state.seg_ss); } void x86_doabrt(int x86_abrt) { CS = oldcs; cpu_state.pc = cpu_state.oldpc; - _cs.access = (oldcpl << 5) | 0x80; + cpu_state.seg_cs.access = (oldcpl << 5) | 0x80; if (msw & 1) pmodeint(x86_abrt, 0); @@ -141,22 +143,22 @@ void x86_doabrt(int x86_abrt) uint32_t addr = (x86_abrt << 2) + idt.base; if (stack32) { - writememw(ss,ESP-2,flags); + writememw(ss,ESP-2,cpu_state.flags); writememw(ss,ESP-4,CS); writememw(ss,ESP-6,cpu_state.pc); ESP-=6; } else { - writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); writememw(ss,((SP-4)&0xFFFF),CS); writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); SP-=6; } - flags&=~I_FLAG; - flags&=~T_FLAG; - oxpc=cpu_state.pc; + cpu_state.flags&=~I_FLAG; + cpu_state.flags&=~T_FLAG; + oxpc=cpu_state.pc; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); return; @@ -257,14 +259,14 @@ void do_seg_load(x86seg *s, uint16_t *segdat) s->limit_low = s->limit + 1; } - if (s == &_ds) + if (s == &cpu_state.seg_ds) { if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; else cpu_cur_status |= CPU_STATUS_NOTFLATDS; } - if (s == &_ss) + if (s == &cpu_state.seg_ss) { if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; @@ -331,11 +333,11 @@ void loadseg(uint16_t seg, x86seg *s) uint32_t addr; int dpl; - if (msw&1 && !(eflags&VM_FLAG)) + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) { if (!(seg&~3)) { - if (s==&_ss) + if (s==&cpu_state.seg_ss) { x86ss(NULL,0); return; @@ -343,14 +345,18 @@ void loadseg(uint16_t seg, x86seg *s) s->seg=0; s->access = 0x80; s->base=-1; - if (s == &_ds) + if (s == &cpu_state.seg_ds) cpu_cur_status |= CPU_STATUS_NOTFLATDS; return; } addr=seg&~7; if (seg&4) { +#if 0 if (addr>=ldt.limit) +#else + if ((addr+7)>ldt.limit) +#endif { x86gpf("loadseg(): Bigger than LDT limit",seg&~3); return; @@ -359,7 +365,11 @@ void loadseg(uint16_t seg, x86seg *s) } else { +#if 0 if (addr>=gdt.limit) +#else + if ((addr+7)>gdt.limit) +#endif { x86gpf("loadseg(): Bigger than GDT limit",seg&~3); return; @@ -372,7 +382,7 @@ void loadseg(uint16_t seg, x86seg *s) segdat[2]=readmemw(0,addr+4); segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; dpl=(segdat[2]>>13)&3; - if (s==&_ss) + if (s==&cpu_state.seg_ss) { if (!(seg&~3)) { @@ -399,7 +409,7 @@ void loadseg(uint16_t seg, x86seg *s) } set_stack32((segdat[3] & 0x40) ? 1 : 0); } - else if (s!=&_cs) + else if (s!=&cpu_state.seg_cs) { x86seg_log("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); x86seg_log("Seg type %03X\n",segdat[2]&0x1F00); @@ -431,7 +441,7 @@ void loadseg(uint16_t seg, x86seg *s) do_seg_load(s, segdat); #ifndef CS_ACCESSED - if (s != &_cs) + if (s != &cpu_state.seg_cs) { #endif #ifdef SEL_ACCESSED @@ -444,9 +454,9 @@ void loadseg(uint16_t seg, x86seg *s) #endif s->checked = 0; #ifdef USE_DYNAREC - if (s == &_ds) + if (s == &cpu_state.seg_ds) codegen_flat_ds = 0; - if (s == &_ss) + if (s == &cpu_state.seg_ss) codegen_flat_ss = 0; #endif } @@ -455,25 +465,25 @@ void loadseg(uint16_t seg, x86seg *s) s->access = (3 << 5) | 2 | 0x80; s->base = seg << 4; s->seg = seg; - if (s == &_ss) - set_stack32(0); s->checked = 1; #ifdef USE_DYNAREC - if (s == &_ds) + if (s == &cpu_state.seg_ds) codegen_flat_ds = 0; - if (s == &_ss) + if (s == &cpu_state.seg_ss) codegen_flat_ss = 0; #endif + if (s == &cpu_state.seg_ss && (cpu_state.eflags & VM_FLAG)) + set_stack32(0); } - if (s == &_ds) + if (s == &cpu_state.seg_ds) { if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; else cpu_cur_status |= CPU_STATUS_NOTFLATDS; } - if (s == &_ss) + if (s == &cpu_state.seg_ss) { if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; @@ -491,7 +501,7 @@ void loadcs(uint16_t seg) uint16_t segdat[4]; uint32_t addr; x86seg_log("Load CS %04X\n",seg); - if (msw&1 && !(eflags&VM_FLAG)) + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) { if (!(seg&~3)) { @@ -549,10 +559,10 @@ void loadcs(uint16_t seg) } set_use32(segdat[3] & 0x40); CS=(seg&~3)|CPL; - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); use32=(segdat[3]&0x40)?0x300:0; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - + #ifdef CS_ACCESSED cpl_override = 1; writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ @@ -576,24 +586,24 @@ void loadcs(uint16_t seg) } else { - _cs.base=seg<<4; - _cs.limit=0xFFFF; - _cs.limit_low = 0; - _cs.limit_high = 0xffff; + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; CS=seg & 0xFFFF; - if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; - else _cs.access=(0<<5) | 2 | 0x80; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); } } -void loadcsjmp(uint16_t seg, uint32_t oxpc) +void loadcsjmp(uint16_t seg, uint32_t old_pc) { uint16_t segdat[4]; uint32_t addr; uint16_t type,seg2; uint32_t newpc; - if (msw&1 && !(eflags&VM_FLAG)) + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) { if (!(seg&~3)) { @@ -661,7 +671,7 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) CS = (seg & ~3) | CPL; segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); cycles -= timing_jmp_pm; } @@ -757,8 +767,9 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) } case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ CS=seg2; - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + set_use32(segdat[3]&0x40); cpu_state.pc=newpc; @@ -779,11 +790,11 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) case 0x100: /*286 Task gate*/ case 0x900: /*386 Task gate*/ - cpu_state.pc=oxpc; + cpu_state.pc=old_pc; optype=JMP; cpl_override=1; taskswitch286(seg,segdat,segdat[2]&0x800); - flags &= ~NT_FLAG; + cpu_state.flags &= ~NT_FLAG; cpl_override=0; return; @@ -795,13 +806,13 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) } else { - _cs.base=seg<<4; - _cs.limit=0xFFFF; - _cs.limit_low = 0; - _cs.limit_high = 0xffff; + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; CS=seg; - if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; - else _cs.access=(0<<5) | 2 | 0x80; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); cycles -= timing_jmp_rm; } @@ -885,7 +896,7 @@ void loadcscall(uint16_t seg) int csout = output; - if (msw&1 && !(eflags&VM_FLAG)) + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) { if (csout) x86seg_log("Protected mode CS load! %04X\n",seg); if (!(seg&~3)) @@ -964,8 +975,9 @@ void loadcscall(uint16_t seg) else /*On non-conforming segments, set RPL = CPL*/ seg = (seg & ~3) | CPL; CS=seg; - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + if (csout) x86seg_log("Complete\n"); cycles -= timing_call_pm; } @@ -1080,7 +1092,11 @@ void loadcscall(uint16_t seg) addr=newss&~7; if (newss&4) { +#if 0 if (addr>=ldt.limit) +#else + if ((addr+7)>ldt.limit) +#endif { x86abort("Bigger than LDT limit %04X %08X %04X CSC SS\n",newss,addr,ldt.limit); x86ts(NULL,newss&~3); @@ -1090,7 +1106,11 @@ void loadcscall(uint16_t seg) } else { +#if 0 if (addr>=gdt.limit) +#else + if ((addr+7)>gdt.limit) +#endif { x86abort("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); x86ts(NULL,newss&~3); @@ -1126,7 +1146,7 @@ void loadcscall(uint16_t seg) if (stack32) ESP=newsp; else SP=newsp; - do_seg_load(&_ss, segdat2); + do_seg_load(&cpu_state.seg_ss, segdat2); x86seg_log("Set access 1\n"); @@ -1137,8 +1157,9 @@ void loadcscall(uint16_t seg) #endif CS=seg2; - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + set_use32(segdat[3]&0x40); cpu_state.pc=newpc; @@ -1216,7 +1237,7 @@ void loadcscall(uint16_t seg) } case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ CS=seg2; - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); set_use32(segdat[3]&0x40); cpu_state.pc=newpc; @@ -1251,13 +1272,13 @@ void loadcscall(uint16_t seg) } else { - _cs.base=seg<<4; - _cs.limit=0xFFFF; - _cs.limit_low = 0; - _cs.limit_high = 0xffff; + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; CS=seg; - if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; - else _cs.access=(0<<5) | 2 | 0x80; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); } } @@ -1269,7 +1290,7 @@ void pmoderetf(int is32, uint16_t off) uint32_t addr, oaddr; uint16_t segdat[4],segdat2[4],seg,newss; uint32_t oldsp=ESP; - x86seg_log("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,eflags); + x86seg_log("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,cpu_state.eflags); if (is32) { newpc=POPL(); @@ -1367,8 +1388,8 @@ void pmoderetf(int is32, uint16_t off) if (segdat[2] & 0x400) segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); CS = seg; - do_seg_load(&_cs, segdat); - _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); set_use32(segdat[3] & 0x40); @@ -1481,7 +1502,7 @@ void pmoderetf(int is32, uint16_t off) set_stack32((segdat2[3] & 0x40) ? 1 : 0); if (stack32) ESP=newsp; else SP=newsp; - do_seg_load(&_ss, segdat2); + do_seg_load(&cpu_state.seg_ss, segdat2); #ifdef SEL_ACCESSED cpl_override = 1; @@ -1498,24 +1519,24 @@ void pmoderetf(int is32, uint16_t off) cpu_state.pc=newpc; CS=seg; - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); set_use32(segdat[3] & 0x40); if (stack32) ESP+=off; else SP+=off; - check_seg_valid(&_ds); - check_seg_valid(&_es); - check_seg_valid(&_fs); - check_seg_valid(&_gs); + check_seg_valid(&cpu_state.seg_ds); + check_seg_valid(&cpu_state.seg_es); + check_seg_valid(&cpu_state.seg_fs); + check_seg_valid(&cpu_state.seg_gs); cycles -= timing_retf_pm_outer; } } void restore_stack() { - ss=oldss; _ss.limit=oldsslimit; + ss=oldss; cpu_state.seg_ss.limit=oldsslimit; } void pmodeint(int num, int soft) @@ -1529,7 +1550,7 @@ void pmodeint(int num, int soft) uint16_t seg = 0; int new_cpl; - if (eflags&VM_FLAG && IOPL!=3 && soft) + if (cpu_state.eflags&VM_FLAG && IOPL!=3 && soft) { x86seg_log("V86 banned int\n"); x86gpf(NULL,0); @@ -1628,7 +1649,7 @@ void pmodeint(int num, int soft) x86np("Int gate CS not present\n", segdat[1] & 0xfffc); return; } - if ((eflags&VM_FLAG) && DPL2) + if ((cpu_state.eflags&VM_FLAG) && DPL2) { x86gpf(NULL,segdat[1]&0xFFFC); return; @@ -1698,7 +1719,7 @@ void pmodeint(int num, int soft) set_stack32((segdat3[3] & 0x40) ? 1 : 0); if (stack32) ESP=newsp; else SP=newsp; - do_seg_load(&_ss, segdat3); + do_seg_load(&cpu_state.seg_ss, segdat3); #ifdef CS_ACCESSED cpl_override = 1; @@ -1710,20 +1731,20 @@ void pmodeint(int num, int soft) cpl_override=1; if (type>=0x800) { - if (eflags & VM_FLAG) + if (cpu_state.eflags & VM_FLAG) { PUSHL(GS); PUSHL(FS); PUSHL(DS); PUSHL(ES); if (cpu_state.abrt) return; - loadseg(0,&_ds); - loadseg(0,&_es); - loadseg(0,&_fs); - loadseg(0,&_gs); + loadseg(0,&cpu_state.seg_ds); + loadseg(0,&cpu_state.seg_es); + loadseg(0,&cpu_state.seg_fs); + loadseg(0,&cpu_state.seg_gs); } PUSHL(oldss); PUSHL(oldsp); - PUSHL(flags|(eflags<<16)); + PUSHL(cpu_state.flags|(cpu_state.eflags<<16)); PUSHL(CS); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; } @@ -1731,12 +1752,12 @@ void pmodeint(int num, int soft) { PUSHW(oldss); PUSHW(oldsp); - PUSHW(flags); + PUSHW(cpu_state.flags); PUSHW(CS); PUSHW(cpu_state.pc); if (cpu_state.abrt) return; } cpl_override=0; - _cs.access=0 | 0x80; + cpu_state.seg_cs.access=0 | 0x80; cycles -= timing_int_pm_outer - timing_int_pm; break; } @@ -1751,20 +1772,20 @@ void pmodeint(int num, int soft) x86np("Int gate CS not present\n", segdat[1] & 0xfffc); return; } - if ((eflags & VM_FLAG) && DPL20x800) { - PUSHL(flags|(eflags<<16)); + PUSHL(cpu_state.flags|(cpu_state.eflags<<16)); PUSHL(CS); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; } else { - PUSHW(flags); + PUSHW(cpu_state.flags); PUSHW(CS); PUSHW(cpu_state.pc); if (cpu_state.abrt) return; } @@ -1774,9 +1795,9 @@ void pmodeint(int num, int soft) x86gpf(NULL,seg&~3); return; } - do_seg_load(&_cs, segdat2); + do_seg_load(&cpu_state.seg_cs, segdat2); CS = (seg & ~3) | new_cpl; - _cs.access = (_cs.access & ~(3 << 5)) | (new_cpl << 5); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | (new_cpl << 5); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); if (type>0x800) cpu_state.pc=segdat[0]|(segdat[3]<<16); else cpu_state.pc=segdat[0]; @@ -1788,13 +1809,13 @@ void pmodeint(int num, int soft) cpl_override = 0; #endif - eflags&=~VM_FLAG; + cpu_state.eflags&=~VM_FLAG; cpu_cur_status &= ~CPU_STATUS_V86; if (!(type&0x100)) { - flags&=~I_FLAG; + cpu_state.flags&=~I_FLAG; } - flags&=~(T_FLAG|NT_FLAG); + cpu_state.flags&=~(T_FLAG|NT_FLAG); cycles -= timing_int_pm; break; @@ -1853,14 +1874,14 @@ void pmodeiret(int is32) uint16_t seg; uint32_t addr, oaddr; uint32_t oldsp=ESP; - if (is386 && (eflags&VM_FLAG)) + if (is386 && (cpu_state.eflags&VM_FLAG)) { if (IOPL!=3) { x86gpf(NULL,0); return; } - oxpc=cpu_state.pc; + oxpc=cpu_state.pc; if (is32) { newpc=POPL(); @@ -1873,19 +1894,19 @@ void pmodeiret(int is32) seg=POPW(); tempflags=POPW(); if (cpu_state.abrt) return; } - cpu_state.pc=newpc; - _cs.base=seg<<4; - _cs.limit=0xFFFF; - _cs.limit_low = 0; - _cs.limit_high = 0xffff; - _cs.access |= 0x80; + cpu_state.pc = newpc; + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + cpu_state.seg_cs.access |= 0x80; CS=seg; - flags=(flags&0x3000)|(tempflags&0xCFD5)|2; + cpu_state.flags=(cpu_state.flags&0x3000)|(tempflags&0xCFD5)|2; cycles -= timing_iret_rm; return; } - if (flags&NT_FLAG) + if (cpu_state.flags&NT_FLAG) { seg=readmemw(tr.base,0); addr=seg&~7; @@ -1913,7 +1934,7 @@ void pmodeiret(int is32) cpl_override=0; return; } - oxpc=cpu_state.pc; + oxpc=cpu_state.pc; flagmask=0xFFFF; if (CPL) flagmask&=~0x3000; if (IOPL>16; + cpu_state.eflags=tempflags>>16; cpu_cur_status |= CPU_STATUS_V86; - loadseg(segs[0],&_es); - do_seg_v86_init(&_es); - loadseg(segs[1],&_ds); - do_seg_v86_init(&_ds); + loadseg(segs[0],&cpu_state.seg_es); + do_seg_v86_init(&cpu_state.seg_es); + loadseg(segs[1],&cpu_state.seg_ds); + do_seg_v86_init(&cpu_state.seg_ds); cpu_cur_status |= CPU_STATUS_NOTFLATDS; - loadseg(segs[2],&_fs); - do_seg_v86_init(&_fs); - loadseg(segs[3],&_gs); - do_seg_v86_init(&_gs); + loadseg(segs[2],&cpu_state.seg_fs); + do_seg_v86_init(&cpu_state.seg_fs); + loadseg(segs[3],&cpu_state.seg_gs); + do_seg_v86_init(&cpu_state.seg_gs); cpu_state.pc=newpc; - _cs.base=seg<<4; - _cs.limit=0xFFFF; - _cs.limit_low = 0; - _cs.limit_high = 0xffff; + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; CS=seg; - _cs.access=(3<<5) | 2 | 0x80; + cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - + ESP=newsp; - loadseg(newss,&_ss); - do_seg_v86_init(&_ss); + loadseg(newss,&cpu_state.seg_ss); + do_seg_v86_init(&cpu_state.seg_ss); cpu_cur_status |= CPU_STATUS_NOTFLATSS; use32=0; cpu_cur_status &= ~CPU_STATUS_USE32; - flags=(tempflags&0xFFD5)|2; + cpu_state.flags=(tempflags&0xFFD5)|2; cycles -= timing_iret_v86; return; } @@ -2040,8 +2061,8 @@ void pmodeiret(int is32) if ((seg&3) == CPL) { CS=seg; - do_seg_load(&_cs, segdat); - _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); set_use32(segdat[3]&0x40); @@ -2129,7 +2150,7 @@ void pmodeiret(int is32) set_stack32((segdat2[3] & 0x40) ? 1 : 0); if (stack32) ESP=newsp; else SP=newsp; - do_seg_load(&_ss, segdat2); + do_seg_load(&cpu_state.seg_ss, segdat2); #ifdef SEL_ACCESSED cpl_override = 1; @@ -2145,20 +2166,20 @@ void pmodeiret(int is32) segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); CS=seg; - do_seg_load(&_cs, segdat); - _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); set_use32(segdat[3] & 0x40); - check_seg_valid(&_ds); - check_seg_valid(&_es); - check_seg_valid(&_fs); - check_seg_valid(&_gs); + check_seg_valid(&cpu_state.seg_ds); + check_seg_valid(&cpu_state.seg_es); + check_seg_valid(&cpu_state.seg_fs); + check_seg_valid(&cpu_state.seg_gs); cycles -= timing_iret_pm_outer; } cpu_state.pc=newpc; - flags=(flags&~flagmask)|(tempflags&flagmask&0xFFD5)|2; - if (is32) eflags=tempflags>>16; + cpu_state.flags=(cpu_state.flags&~flagmask)|(tempflags&flagmask&0xFFD5)|2; + if (is32) cpu_state.eflags=tempflags>>16; } void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) @@ -2205,12 +2226,12 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) } if (cpu_state.abrt) return; - if (optype==IRET) flags&=~NT_FLAG; + if (optype==IRET) cpu_state.flags&=~NT_FLAG; cpu_386_flags_rebuild(); writememl(tr.base,0x1C,cr3); writememl(tr.base,0x20,cpu_state.pc); - writememl(tr.base,0x24,flags|(eflags<<16)); + writememl(tr.base,0x24,cpu_state.flags|(cpu_state.eflags<<16)); writememl(tr.base,0x28,EAX); writememl(tr.base,0x2C,ECX); @@ -2276,8 +2297,8 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) flushmmucache(); cpu_state.pc=new_pc; - flags=new_flags; - eflags=new_flags>>16; + cpu_state.flags=new_flags; + cpu_state.eflags=new_flags>>16; cpu_386_flags_extract(); ldt.seg=new_ldt; @@ -2290,7 +2311,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) } ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); - if (eflags & VM_FLAG) + if (cpu_state.eflags & VM_FLAG) { loadcs(new_cs); set_use32(0); @@ -2353,7 +2374,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) } CS=new_cs; - do_seg_load(&_cs, segdat2); + do_seg_load(&cpu_state.seg_cs, segdat2); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); set_use32(segdat2[3] & 0x40); cpu_cur_status &= ~CPU_STATUS_V86; @@ -2368,11 +2389,11 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) ESI=new_esi; EDI=new_edi; - loadseg(new_es,&_es); - loadseg(new_ss,&_ss); - loadseg(new_ds,&_ds); - loadseg(new_fs,&_fs); - loadseg(new_gs,&_gs); + loadseg(new_es,&cpu_state.seg_es); + loadseg(new_ss,&cpu_state.seg_ss); + loadseg(new_ds,&cpu_state.seg_ds); + loadseg(new_fs,&cpu_state.seg_fs); + loadseg(new_gs,&cpu_state.seg_gs); } else { @@ -2393,11 +2414,11 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) } if (cpu_state.abrt) return; - if (optype==IRET) flags&=~NT_FLAG; + if (optype==IRET) cpu_state.flags&=~NT_FLAG; cpu_386_flags_rebuild(); writememw(tr.base,0x0E,cpu_state.pc); - writememw(tr.base,0x10,flags); + writememw(tr.base,0x10,cpu_state.flags); writememw(tr.base,0x12,AX); writememw(tr.base,0x14,CX); @@ -2454,7 +2475,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) msw |= 8; cpu_state.pc=new_pc; - flags=new_flags; + cpu_state.flags=new_flags; cpu_386_flags_extract(); ldt.seg=new_ldt; @@ -2526,7 +2547,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) } CS=new_cs; - do_seg_load(&_cs, segdat2); + do_seg_load(&cpu_state.seg_cs, segdat2); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); set_use32(0); @@ -2539,13 +2560,13 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) ESI=new_esi | 0xFFFF0000; EDI=new_edi | 0xFFFF0000; - loadseg(new_es,&_es); - loadseg(new_ss,&_ss); - loadseg(new_ds,&_ds); + loadseg(new_es,&cpu_state.seg_es); + loadseg(new_ss,&cpu_state.seg_ss); + loadseg(new_ds,&cpu_state.seg_ds); if (is386) { - loadseg(0,&_fs); - loadseg(0,&_gs); + loadseg(0,&cpu_state.seg_fs); + loadseg(0,&cpu_state.seg_gs); } } diff --git a/src/cpu/x87.c b/src/cpu/x87.c index ed1c16828..abc2f48a4 100644 --- a/src/cpu/x87.c +++ b/src/cpu/x87.c @@ -65,6 +65,7 @@ void x87_settag(uint16_t new_tag) cpu_state.tag[7] = (new_tag >> 14) & 3; } + #ifdef ENABLE_808X_LOG void x87_dumpregs() { diff --git a/src/cpu/x87.h b/src/cpu/x87.h index 5e3db1960..6d2cb3ca9 100644 --- a/src/cpu/x87.h +++ b/src/cpu/x87.h @@ -1,6 +1,24 @@ uint32_t x87_pc_off,x87_op_off; uint16_t x87_pc_seg,x87_op_seg; +static __inline void x87_set_mmx() +{ + uint64_t *p; + cpu_state.TOP = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0; + cpu_state.ismmx = 1; +} + +static __inline void x87_emms() +{ + uint64_t *p; + p = (uint64_t *)cpu_state.tag; + *p = 0; + cpu_state.ismmx = 0; +} + + uint16_t x87_gettag(); void x87_settag(uint16_t new_tag); diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index 65ead134e..bf54afa40 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -1,42 +1,24 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * x87 FPU instructions core. * - * Version: @(#)x87_ops.h 1.0.7 2018/10/17 + * Version: @(#)x87_ops.h 1.0.8 2019/06/11 * * Authors: Fred N. van Kempen, * Sarah Walker, * leilei, * Miran Grca, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 leilei. - * Copyright 2016-2018 Miran Grca. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 leilei. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. */ #include #include @@ -63,41 +45,47 @@ static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZ #define STATUS_ZERODIVIDE 4 +#ifdef FPU_8087 #define x87_div(dst, src1, src2) do \ { \ if (((double)src2) == 0.0) \ { \ - cpu_state.npxs |= STATUS_ZERODIVIDE; \ - if (cpu_state.npxc & STATUS_ZERODIVIDE) \ + cpu_state.npxs |= STATUS_ZERODIVIDE; \ + if (cpu_state.npxc & STATUS_ZERODIVIDE) \ dst = src1 / (double)src2; \ else \ { \ fpu_log("FPU : divide by zero\n"); \ - picint(1 << 13); \ + if (!(cpu_state.npxc & 0x80)) { \ + cpu_state.npxs |= 0x80; \ + nmi = 1; \ + } \ + return 1; \ } \ - return 1; \ } \ else \ dst = src1 / (double)src2; \ } while (0) +#else +#define x87_div(dst, src1, src2) do \ + { \ + if (((double)src2) == 0.0) \ + { \ + cpu_state.npxs |= STATUS_ZERODIVIDE; \ + if (cpu_state.npxc & STATUS_ZERODIVIDE) \ + dst = src1 / (double)src2; \ + else \ + { \ + fpu_log("FPU : divide by zero\n"); \ + picint(1 << 13); \ + return 1; \ + } \ + } \ + else \ + dst = src1 / (double)src2; \ + } while (0) +#endif -static __inline void x87_set_mmx() -{ - uint64_t *p; - cpu_state.TOP = 0; - p = (uint64_t *)cpu_state.tag; - *p = 0; - cpu_state.ismmx = 1; -} - -static __inline void x87_emms() -{ - uint64_t *p; - p = (uint64_t *)cpu_state.tag; - *p = 0x0303030303030303ll; - cpu_state.ismmx = 0; -} - static __inline void x87_checkexceptions() { } @@ -286,44 +274,24 @@ static __inline void x87_stmmx(MMX_REG r) writememw(easeg, cpu_state.eaaddr + 8, 0xffff); } +#include + static __inline uint16_t x87_compare(double a, double b) { #if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 uint32_t result; + double ea = a, eb = b; + const uint64_t ia = 0x3fec1a6ff866a936ull; + const uint64_t ib = 0x3fec1a6ff866a938ull; - if (!is386) - { - if (((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) - { - /* fpu_log("Comparing infinity\n"); */ -#ifndef _MSC_VER - __asm volatile ("" : : : "memory"); - - __asm( - "fldl %2\n" - "fldl %1\n" - "fclex\n" - "fcompp\n" - "fnstsw %0\n" - : "=m" (result) - : "m" (a), "m" (a) - ); -#else - _ReadWriteBarrier(); - __asm - { - fld a - fld a - fclex - fcompp - fnstsw result - } -#endif + /* Hack to make CHKCOP happy. */ + if (!memcmp(&ea, &ia, 8) && !memcmp(&eb, &ib, 8)) + return C3; + + if (!is386 && !(cpu_state.npxc & 0x1000) && + ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) + eb = ea; - return result & (C0|C2|C3); - } - } - #ifndef _MSC_VER /* Memory barrier, to force GCC to write to the input parameters * before the compare rather than after */ @@ -336,14 +304,14 @@ static __inline uint16_t x87_compare(double a, double b) "fcompp\n" "fnstsw %0\n" : "=m" (result) - : "m" (a), "m" (b) + : "m" (ea), "m" (eb) ); #else _ReadWriteBarrier(); _asm { - fld b - fld a + fld eb + fld ea fclex fcompp fnstsw result @@ -355,43 +323,32 @@ static __inline uint16_t x87_compare(double a, double b) /* Generic C version is known to give incorrect results in some * situations, eg comparison of infinity (Unreal) */ uint32_t result = 0; + double ea = a, eb = b; - if (is386) - { - if (((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) - { - result |= C3; - return result; - } + if (!is386 && !(cpu_state.npxc & 0x1000) && + ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) + eb = ea; - if (a == b) - result |= C3; - else if (a < b) - result |= C0; - } - else - { - if (a == b) - result |= C3; - else if (a < b) - result |= C0; - } + if (ea == eb) + result |= C3; + else if (ea < eb) + result |= C0; return result; #endif } -static __inline uint16_t x87_ucompare(double a, double b) +static inline uint16_t x87_ucompare(double a, double b) { -#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 || defined __amd64__ uint32_t result; - + #ifndef _MSC_VER /* Memory barrier, to force GCC to write to the input parameters * before the compare rather than after */ - __asm volatile ("" : : : "memory"); + asm volatile ("" : : : "memory"); - __asm( + asm( "fldl %2\n" "fldl %1\n" "fclex\n" @@ -439,6 +396,11 @@ typedef union uint64_t i; } x87_td; +#ifdef FPU_8087 +#define FP_ENTER() { \ + fpucount++; \ + } +#else #define FP_ENTER() do \ { \ if (cr0 & 0xc) \ @@ -448,11 +410,13 @@ typedef union } \ fpucount++; \ } while (0) +#endif #include "x87_ops_arith.h" #include "x87_ops_misc.h" #include "x87_ops_loadstore.h" +#ifndef FPU_8087 static int op_nofpu_a16(uint32_t fetchdat) { if (cr0 & 0xc) @@ -479,7 +443,16 @@ static int op_nofpu_a32(uint32_t fetchdat) return 0; } } +#endif +#ifdef FPU_8087 +static int FPU_ILLEGAL_a16(uint32_t fetchdat) +{ + geteaw(); + wait(timing_rr, 0); + return 0; +} +#else static int FPU_ILLEGAL_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); @@ -495,8 +468,261 @@ static int FPU_ILLEGAL_a32(uint32_t fetchdat) PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); return 0; } +#endif #define ILLEGAL_a16 FPU_ILLEGAL_a16 + +#ifdef FPU_8087 +const OpFn OP_TABLE(fpu_8087_d8)[32] = +{ + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; + +const OpFn OP_TABLE(fpu_8087_d9)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, ILLEGAL_a16, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a16, ILLEGAL_a16, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, ILLEGAL_a16, opFRNDINT, opFSCALE, ILLEGAL_a16, ILLEGAL_a16 +}; + +const OpFn OP_TABLE(fpu_8087_da)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; + +const OpFn OP_TABLE(fpu_8087_db)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFI, opFI, opFCLEX, opFINIT, ILLEGAL_a16, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; + +const OpFn OP_TABLE(fpu_8087_dc)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, ILLEGAL_a16, ILLEGAL_a16, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +const OpFn OP_TABLE(fpu_8087_dd)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; + +const OpFn OP_TABLE(fpu_8087_de)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_8087_df)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +#else #define ILLEGAL_a32 FPU_ILLEGAL_a32 const OpFn OP_TABLE(fpu_d8_a16)[32] = @@ -824,6 +1050,7 @@ const OpFn OP_TABLE(fpu_da_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, }; +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) const OpFn OP_TABLE(fpu_686_da_a16)[256] = { opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, @@ -900,6 +1127,7 @@ const OpFn OP_TABLE(fpu_686_da_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, }; +#endif const OpFn OP_TABLE(fpu_287_db_a16)[256] = { @@ -1055,6 +1283,7 @@ const OpFn OP_TABLE(fpu_db_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, }; +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) const OpFn OP_TABLE(fpu_686_db_a16)[256] = { opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, @@ -1131,6 +1360,7 @@ const OpFn OP_TABLE(fpu_686_db_a32)[256] = opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, }; +#endif const OpFn OP_TABLE(fpu_287_dc_a16)[32] = { @@ -1626,6 +1856,7 @@ const OpFn OP_TABLE(fpu_df_a32)[256] = ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, }; +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) const OpFn OP_TABLE(fpu_686_df_a16)[256] = { opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, @@ -1702,6 +1933,7 @@ const OpFn OP_TABLE(fpu_686_df_a32)[256] = opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, }; +#endif const OpFn OP_TABLE(nofpu_a16)[256] = { @@ -1779,3 +2011,6 @@ const OpFn OP_TABLE(nofpu_a32)[256] = op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, }; +#endif + +#undef ILLEGAL diff --git a/src/cpu/x87_ops_arith.h b/src/cpu/x87_ops_arith.h index 391078475..720a5c469 100644 --- a/src/cpu/x87_ops_arith.h +++ b/src/cpu/x87_ops_arith.h @@ -4,13 +4,14 @@ static int opFADD ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ if ((cpu_state.npxc >> 10) & 3) \ fesetround(rounding_modes[(cpu_state.npxc >> 10) & 3]); \ ST(0) += use_var; \ if ((cpu_state.npxc >> 10) & 3) \ fesetround(FE_TONEAREST); \ - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ CLOCK_CYCLES(8); \ return 0; \ } \ @@ -19,6 +20,7 @@ static int opFCOM ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ cpu_state.npxs &= ~(C0|C2|C3); \ cpu_state.npxs |= x87_compare(ST(0), (double)use_var); \ @@ -30,6 +32,7 @@ static int opFCOMP ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ cpu_state.npxs &= ~(C0|C2|C3); \ cpu_state.npxs |= x87_compare(ST(0), (double)use_var); \ @@ -42,9 +45,10 @@ static int opFDIV ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ x87_div(ST(0), ST(0), use_var); \ - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ CLOCK_CYCLES(73); \ return 0; \ } \ @@ -53,9 +57,10 @@ static int opFDIVR ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ x87_div(ST(0), use_var, ST(0)); \ - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ CLOCK_CYCLES(73); \ return 0; \ } \ @@ -64,6 +69,7 @@ static int opFMUL ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ ST(0) *= use_var; \ cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ @@ -75,9 +81,10 @@ static int opFSUB ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ ST(0) -= use_var; \ - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ CLOCK_CYCLES(8); \ return 0; \ } \ @@ -86,23 +93,32 @@ static int opFSUBR ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ ST(0) = use_var - ST(0); \ - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ CLOCK_CYCLES(8); \ return 0; \ } opFPU(s, x87_ts, 16, t.i, geteal, t.s) +#ifndef FPU_8087 opFPU(s, x87_ts, 32, t.i, geteal, t.s) +#endif opFPU(d, x87_td, 16, t.i, geteaq, t.d) +#ifndef FPU_8087 opFPU(d, x87_td, 32, t.i, geteaq, t.d) +#endif opFPU(iw, uint16_t, 16, t, geteaw, (double)(int16_t)t) +#ifndef FPU_8087 opFPU(iw, uint16_t, 32, t, geteaw, (double)(int16_t)t) +#endif opFPU(il, uint32_t, 16, t, geteal, (double)(int32_t)t) +#ifndef FPU_8087 opFPU(il, uint32_t, 32, t, geteal, (double)(int32_t)t) +#endif @@ -111,7 +127,6 @@ static int opFADD(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FADD\n"); ST(0) = ST(0) + ST(fetchdat & 7); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(8); @@ -121,7 +136,6 @@ static int opFADDr(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FADD\n"); ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; CLOCK_CYCLES(8); @@ -131,7 +145,6 @@ static int opFADDP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FADDP\n"); ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; x87_pop(); @@ -143,7 +156,6 @@ static int opFCOM(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FCOM\n"); cpu_state.npxs &= ~(C0|C2|C3); if (ST(0) == ST(fetchdat & 7)) cpu_state.npxs |= C3; else if (ST(0) < ST(fetchdat & 7)) cpu_state.npxs |= C0; @@ -155,7 +167,6 @@ static int opFCOMP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FCOMP\n"); cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_compare(ST(0), ST(fetchdat & 7)); x87_pop(); @@ -168,7 +179,6 @@ static int opFCOMPP(uint32_t fetchdat) uint64_t *p, *q; FP_ENTER(); cpu_state.pc++; - fpu_log("FCOMPP\n"); cpu_state.npxs &= ~(C0|C2|C3); p = (uint64_t *)&ST(0); q = (uint64_t *)&ST(1); @@ -182,11 +192,11 @@ static int opFCOMPP(uint32_t fetchdat) CLOCK_CYCLES(4); return 0; } +#ifndef FPU_8087 static int opFUCOMPP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FUCOMPP\n", easeg, cpu_state.eaaddr); cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_ucompare(ST(0), ST(1)); x87_pop(); @@ -195,15 +205,15 @@ static int opFUCOMPP(uint32_t fetchdat) return 0; } +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) static int opFCOMI(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FICOM\n"); flags_rebuild(); - flags &= ~(Z_FLAG | P_FLAG | C_FLAG); - if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; - else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; CLOCK_CYCLES(4); return 0; } @@ -211,21 +221,21 @@ static int opFCOMIP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FICOMP\n"); flags_rebuild(); - flags &= ~(Z_FLAG | P_FLAG | C_FLAG); - if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; - else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; x87_pop(); CLOCK_CYCLES(4); return 0; } +#endif +#endif static int opFDIV(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FDIV\n"); x87_div(ST(0), ST(0), ST(fetchdat & 7)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(73); @@ -235,7 +245,6 @@ static int opFDIVr(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FDIV\n"); x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; CLOCK_CYCLES(73); @@ -245,7 +254,6 @@ static int opFDIVP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FDIVP\n"); x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; x87_pop(); @@ -257,7 +265,6 @@ static int opFDIVR(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FDIVR\n"); x87_div(ST(0), ST(fetchdat&7), ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(73); @@ -267,7 +274,6 @@ static int opFDIVRr(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FDIVR\n"); x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; CLOCK_CYCLES(73); @@ -277,7 +283,6 @@ static int opFDIVRP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FDIVR\n"); x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; x87_pop(); @@ -289,7 +294,6 @@ static int opFMUL(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FMUL\n"); ST(0) = ST(0) * ST(fetchdat & 7); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(16); @@ -299,7 +303,6 @@ static int opFMULr(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FMUL\n"); ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; CLOCK_CYCLES(16); @@ -309,7 +312,6 @@ static int opFMULP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FMULP\n"); ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; x87_pop(); @@ -321,7 +323,6 @@ static int opFSUB(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FSUB\n"); ST(0) = ST(0) - ST(fetchdat & 7); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(8); @@ -331,7 +332,6 @@ static int opFSUBr(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FSUB\n"); ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; CLOCK_CYCLES(8); @@ -341,7 +341,6 @@ static int opFSUBP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FSUBP\n"); ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; x87_pop(); @@ -353,7 +352,6 @@ static int opFSUBR(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FSUBR\n"); ST(0) = ST(fetchdat & 7) - ST(0); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(8); @@ -363,7 +361,6 @@ static int opFSUBRr(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FSUBR\n"); ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; CLOCK_CYCLES(8); @@ -373,7 +370,6 @@ static int opFSUBRP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FSUBRP\n"); ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; x87_pop(); @@ -381,11 +377,11 @@ static int opFSUBRP(uint32_t fetchdat) return 0; } +#ifndef FPU_8087 static int opFUCOM(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FUCOM\n"); cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); CLOCK_CYCLES(4); @@ -396,7 +392,6 @@ static int opFUCOMP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FUCOMP\n"); cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); x87_pop(); @@ -404,15 +399,15 @@ static int opFUCOMP(uint32_t fetchdat) return 0; } +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) static int opFUCOMI(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FUCOMI\n"); flags_rebuild(); - flags &= ~(Z_FLAG | P_FLAG | C_FLAG); - if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; - else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; CLOCK_CYCLES(4); return 0; } @@ -420,12 +415,13 @@ static int opFUCOMIP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FUCOMIP\n"); flags_rebuild(); - flags &= ~(Z_FLAG | P_FLAG | C_FLAG); - if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; - else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; x87_pop(); CLOCK_CYCLES(4); return 0; } +#endif +#endif diff --git a/src/cpu/x87_ops_loadstore.h b/src/cpu/x87_ops_loadstore.h index 80e5ba391..a5cb3910f 100644 --- a/src/cpu/x87_ops_loadstore.h +++ b/src/cpu/x87_ops_loadstore.h @@ -8,12 +8,12 @@ * * x87 FPU instructions core. * - * Version: @(#)x87_ops_loadstore.h 1.0.1 2017/10/17 + * Version: @(#)x87_ops_loadstore.h 1.0.2 2019/06/11 * * Author: Sarah Walker, * Miran Grca, - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016-2017 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ static int opFILDiw_a16(uint32_t fetchdat) @@ -21,32 +21,32 @@ static int opFILDiw_a16(uint32_t fetchdat) int16_t temp; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FILDw %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; - fpu_log(" %f\n", (double)temp); x87_push((double)temp); CLOCK_CYCLES(13); return 0; } +#ifndef FPU_8087 static int opFILDiw_a32(uint32_t fetchdat) { int16_t temp; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FILDw %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; - fpu_log(" %f\n", (double)temp); x87_push((double)temp); CLOCK_CYCLES(13); return 0; } +#endif static int opFISTiw_a16(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp64 = x87_fround(ST(0)); /* if (temp64 > 32767 || temp64 < -32768) fatal("FISTw overflow %i\n", temp64);*/ @@ -54,12 +54,13 @@ static int opFISTiw_a16(uint32_t fetchdat) CLOCK_CYCLES(29); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFISTiw_a32(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp64 = x87_fround(ST(0)); /* if (temp64 > 32767 || temp64 < -32768) fatal("FISTw overflow %i\n", temp64);*/ @@ -67,13 +68,14 @@ static int opFISTiw_a32(uint32_t fetchdat) CLOCK_CYCLES(29); return cpu_state.abrt; } +#endif static int opFISTPiw_a16(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp64 = x87_fround(ST(0)); /* if (temp64 > 32767 || temp64 < -32768) fatal("FISTw overflow %i\n", temp64);*/ @@ -82,12 +84,13 @@ static int opFISTPiw_a16(uint32_t fetchdat) CLOCK_CYCLES(29); return 0; } +#ifndef FPU_8087 static int opFISTPiw_a32(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp64 = x87_fround(ST(0)); /* if (temp64 > 32767 || temp64 < -32768) fatal("FISTw overflow %i\n", temp64);*/ @@ -96,15 +99,15 @@ static int opFISTPiw_a32(uint32_t fetchdat) CLOCK_CYCLES(29); return 0; } +#endif static int opFILDiq_a16(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FILDl %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); temp64 = geteaq(); if (cpu_state.abrt) return 1; - fpu_log(" %f %08X %08X\n", (double)temp64, readmeml(easeg,cpu_state.eaaddr), readmeml(easeg,cpu_state.eaaddr+4)); x87_push((double)temp64); cpu_state.MM[cpu_state.TOP].q = temp64; cpu_state.tag[cpu_state.TOP] |= TAG_UINT64; @@ -112,14 +115,14 @@ static int opFILDiq_a16(uint32_t fetchdat) CLOCK_CYCLES(10); return 0; } +#ifndef FPU_8087 static int opFILDiq_a32(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FILDl %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); temp64 = geteaq(); if (cpu_state.abrt) return 1; - fpu_log(" %f %08X %08X\n", (double)temp64, readmeml(easeg,cpu_state.eaaddr), readmeml(easeg,cpu_state.eaaddr+4)); x87_push((double)temp64); cpu_state.MM[cpu_state.TOP].q = temp64; cpu_state.tag[cpu_state.TOP] |= TAG_UINT64; @@ -127,6 +130,7 @@ static int opFILDiq_a32(uint32_t fetchdat) CLOCK_CYCLES(10); return 0; } +#endif static int FBSTP_a16(uint32_t fetchdat) { @@ -134,7 +138,7 @@ static int FBSTP_a16(uint32_t fetchdat) int c; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FBSTP %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); tempd = ST(0); if (tempd < 0.0) tempd = -tempd; @@ -154,13 +158,14 @@ static int FBSTP_a16(uint32_t fetchdat) x87_pop(); return 0; } +#ifndef FPU_8087 static int FBSTP_a32(uint32_t fetchdat) { double tempd; int c; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FBSTP %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); tempd = ST(0); if (tempd < 0.0) tempd = -tempd; @@ -180,13 +185,14 @@ static int FBSTP_a32(uint32_t fetchdat) x87_pop(); return 0; } +#endif static int FISTPiq_a16(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FISTPl %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (cpu_state.tag[cpu_state.TOP] & TAG_UINT64) temp64 = cpu_state.MM[cpu_state.TOP].q; else @@ -196,12 +202,13 @@ static int FISTPiq_a16(uint32_t fetchdat) CLOCK_CYCLES(29); return 0; } +#ifndef FPU_8087 static int FISTPiq_a32(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FISTPl %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (cpu_state.tag[cpu_state.TOP] & TAG_UINT64) temp64 = cpu_state.MM[cpu_state.TOP].q; else @@ -211,38 +218,39 @@ static int FISTPiq_a32(uint32_t fetchdat) CLOCK_CYCLES(29); return 0; } +#endif static int opFILDil_a16(uint32_t fetchdat) { int32_t templ; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FILDs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); templ = geteal(); if (cpu_state.abrt) return 1; - fpu_log(" %f %08X %i\n", (double)templ, templ, templ); x87_push((double)templ); CLOCK_CYCLES(9); return 0; } +#ifndef FPU_8087 static int opFILDil_a32(uint32_t fetchdat) { int32_t templ; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FILDs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); templ = geteal(); if (cpu_state.abrt) return 1; - fpu_log(" %f %08X %i\n", (double)templ, templ, templ); x87_push((double)templ); CLOCK_CYCLES(9); return 0; } +#endif static int opFISTil_a16(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp64 = x87_fround(ST(0)); /* if (temp64 > 2147483647 || temp64 < -2147483647) fatal("FISTl out of range! %i\n", temp64);*/ @@ -250,12 +258,13 @@ static int opFISTil_a16(uint32_t fetchdat) CLOCK_CYCLES(28); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFISTil_a32(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp64 = x87_fround(ST(0)); /* if (temp64 > 2147483647 || temp64 < -2147483647) fatal("FISTl out of range! %i\n", temp64);*/ @@ -263,13 +272,14 @@ static int opFISTil_a32(uint32_t fetchdat) CLOCK_CYCLES(28); return cpu_state.abrt; } +#endif static int opFISTPil_a16(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp64 = x87_fround(ST(0)); /* if (temp64 > 2147483647 || temp64 < -2147483647) fatal("FISTl out of range! %i\n", temp64);*/ @@ -278,12 +288,13 @@ static int opFISTPil_a16(uint32_t fetchdat) CLOCK_CYCLES(28); return 0; } +#ifndef FPU_8087 static int opFISTPil_a32(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp64 = x87_fround(ST(0)); /* if (temp64 > 2147483647 || temp64 < -2147483647) fatal("FISTl out of range! %i\n", temp64);*/ @@ -292,197 +303,208 @@ static int opFISTPil_a32(uint32_t fetchdat) CLOCK_CYCLES(28); return 0; } +#endif static int opFLDe_a16(uint32_t fetchdat) { double t; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FLDe %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); t=x87_ld80(); if (cpu_state.abrt) return 1; - fpu_log(" %f\n", t); x87_push(t); CLOCK_CYCLES(6); return 0; } +#ifndef FPU_8087 static int opFLDe_a32(uint32_t fetchdat) { double t; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FLDe %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); t=x87_ld80(); if (cpu_state.abrt) return 1; - fpu_log(" %f\n", t); x87_push(t); CLOCK_CYCLES(6); return 0; } +#endif static int opFSTPe_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FSTPe %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); x87_st80(ST(0)); if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(6); return 0; } +#ifndef FPU_8087 static int opFSTPe_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FSTPe %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); x87_st80(ST(0)); if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(6); return 0; } +#endif static int opFLDd_a16(uint32_t fetchdat) { x87_td t; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FLDd %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); t.i = geteaq(); if (cpu_state.abrt) return 1; - fpu_log(" %f\n", t.d); x87_push(t.d); CLOCK_CYCLES(3); return 0; } +#ifndef FPU_8087 static int opFLDd_a32(uint32_t fetchdat) { x87_td t; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FLDd %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); t.i = geteaq(); if (cpu_state.abrt) return 1; - fpu_log(" %f\n", t.d); x87_push(t.d); CLOCK_CYCLES(3); return 0; } +#endif static int opFSTd_a16(uint32_t fetchdat) { x87_td t; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); t.d = ST(0); seteaq(t.i); CLOCK_CYCLES(8); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFSTd_a32(uint32_t fetchdat) { x87_td t; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); t.d = ST(0); seteaq(t.i); CLOCK_CYCLES(8); return cpu_state.abrt; } +#endif static int opFSTPd_a16(uint32_t fetchdat) { x87_td t; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); - fpu_log("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); t.d = ST(0); seteaq(t.i); if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(8); return 0; } +#ifndef FPU_8087 static int opFSTPd_a32(uint32_t fetchdat) { x87_td t; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); - fpu_log("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); t.d = ST(0); seteaq(t.i); if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(8); return 0; } +#endif static int opFLDs_a16(uint32_t fetchdat) { x87_ts ts; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FLDs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); ts.i = geteal(); if (cpu_state.abrt) return 1; - fpu_log(" %f\n", ts.s); x87_push((double)ts.s); CLOCK_CYCLES(3); return 0; } +#ifndef FPU_8087 static int opFLDs_a32(uint32_t fetchdat) { x87_ts ts; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FLDs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); ts.i = geteal(); if (cpu_state.abrt) return 1; - fpu_log(" %f\n", ts.s); x87_push((double)ts.s); CLOCK_CYCLES(3); return 0; } +#endif static int opFSTs_a16(uint32_t fetchdat) { x87_ts ts; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); ts.s = (float)ST(0); seteal(ts.i); CLOCK_CYCLES(7); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFSTs_a32(uint32_t fetchdat) { x87_ts ts; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); ts.s = (float)ST(0); seteal(ts.i); CLOCK_CYCLES(7); return cpu_state.abrt; } +#endif static int opFSTPs_a16(uint32_t fetchdat) { x87_ts ts; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); ts.s = (float)ST(0); seteal(ts.i); if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(7); return 0; } +#ifndef FPU_8087 static int opFSTPs_a32(uint32_t fetchdat) { x87_ts ts; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); ts.s = (float)ST(0); seteal(ts.i); if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(7); return 0; } +#endif diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index 267b302ba..36dbd8a76 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -1,12 +1,24 @@ +#ifdef FPU_8087 +static int opFI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxc &= ~0x80; + if (rmdat == 0xe1) + cpu_state.npxc |= 0x80; + wait(3, 0); + return 0; +} +#else static int opFSTSW_AX(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FSTSW\n"); AX = cpu_state.npxs; CLOCK_CYCLES(3); return 0; } +#endif @@ -32,7 +44,11 @@ static int opFINIT(uint32_t fetchdat) uint64_t *p; FP_ENTER(); cpu_state.pc++; +#ifdef FPU_8087 + cpu_state.npxc = 0x3FF; +#else cpu_state.npxc = 0x37F; +#endif cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); cpu_state.npxs = 0; p = (uint64_t *)cpu_state.tag; @@ -40,6 +56,7 @@ static int opFINIT(uint32_t fetchdat) cpu_state.TOP = 0; cpu_state.ismmx = 0; CLOCK_CYCLES(17); + CPU_BLOCK_END(); return 0; } @@ -48,7 +65,6 @@ static int opFFREE(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FFREE\n"); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3; CLOCK_CYCLES(3); return 0; @@ -58,7 +74,6 @@ static int opFFREEP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FFREE\n"); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3; if (cpu_state.abrt) return 1; x87_pop(); CLOCK_CYCLES(3); @@ -69,7 +84,6 @@ static int opFST(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FST\n"); ST(fetchdat & 7) = ST(0); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; CLOCK_CYCLES(3); @@ -80,7 +94,6 @@ static int opFSTP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FSTP\n"); ST(fetchdat & 7) = ST(0); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; x87_pop(); @@ -135,30 +148,32 @@ static int FSTOR() cpu_state.ismmx = 1; CLOCK_CYCLES((cr0 & 1) ? 34 : 44); - fpu_log("FRSTOR %08X:%08X %i %i %04X\n", easeg, cpu_state.eaaddr, cpu_state.ismmx, cpu_state.TOP, x87_gettag()); return cpu_state.abrt; } static int opFSTOR_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); FSTOR(); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFSTOR_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); FSTOR(); return cpu_state.abrt; } +#endif static int FSAVE() { uint64_t *p; FP_ENTER(); - fpu_log("FSAVE %08X:%08X %i\n", easeg, cpu_state.eaaddr, cpu_state.ismmx); cpu_state.npxs = (cpu_state.npxs & ~(7 << 11)) | (cpu_state.TOP << 11); switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) @@ -305,35 +320,41 @@ static int opFSAVE_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); FSAVE(); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFSAVE_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); FSAVE(); return cpu_state.abrt; } +#endif static int opFSTSW_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FSTSW %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw((cpu_state.npxs & 0xC7FF) | (cpu_state.TOP << 11)); CLOCK_CYCLES(3); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFSTSW_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FSTSW %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw((cpu_state.npxs & 0xC7FF) | (cpu_state.TOP << 11)); CLOCK_CYCLES(3); return cpu_state.abrt; } +#endif static int opFLD(uint32_t fetchdat) @@ -343,7 +364,6 @@ static int opFLD(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; - fpu_log("FLD %f\n", ST(fetchdat & 7)); old_tag = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; old_i64 = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; x87_push(ST(fetchdat&7)); @@ -360,7 +380,6 @@ static int opFXCH(uint32_t fetchdat) uint64_t old_i64; FP_ENTER(); cpu_state.pc++; - fpu_log("FXCH\n"); td = ST(0); ST(0) = ST(fetchdat&7); ST(fetchdat&7) = td; @@ -379,7 +398,6 @@ static int opFCHS(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FCHS\n"); ST(0) = -ST(0); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(6); @@ -390,7 +408,6 @@ static int opFABS(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FABS %f\n", ST(0)); ST(0) = fabs(ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(3); @@ -401,7 +418,6 @@ static int opFTST(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FTST\n"); cpu_state.npxs &= ~(C0|C2|C3); if (ST(0) == 0.0) cpu_state.npxs |= C3; else if (ST(0) < 0.0) cpu_state.npxs |= C0; @@ -413,9 +429,8 @@ static int opFXAM(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FXAM %i %f\n", cpu_state.tag[cpu_state.TOP&7], ST(0)); cpu_state.npxs &= ~(C0|C1|C2|C3); - if (cpu_state.tag[cpu_state.TOP&7] == 3) cpu_state.npxs |= (C0|C3); + if (cpu_state.tag[cpu_state.TOP&7] == 3) cpu_state.npxs |= (C0|C3); else if (ST(0) == 0.0) cpu_state.npxs |= C3; else cpu_state.npxs |= C2; if (ST(0) < 0.0) cpu_state.npxs |= C1; @@ -427,7 +442,6 @@ static int opFLD1(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FLD1\n"); x87_push(1.0); CLOCK_CYCLES(4); return 0; @@ -437,7 +451,6 @@ static int opFLDL2T(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FLDL2T\n"); x87_push(3.3219280948873623); CLOCK_CYCLES(8); return 0; @@ -447,7 +460,6 @@ static int opFLDL2E(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FLDL2E\n"); x87_push(1.4426950408889634); CLOCK_CYCLES(8); return 0; @@ -457,7 +469,6 @@ static int opFLDPI(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FLDPI\n"); x87_push(3.141592653589793); CLOCK_CYCLES(8); return 0; @@ -467,7 +478,6 @@ static int opFLDEG2(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FLDEG2\n"); x87_push(0.3010299956639812); CLOCK_CYCLES(8); return 0; @@ -477,7 +487,6 @@ static int opFLDLN2(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FLDLN2\n"); x87_push_u64(0x3fe62e42fefa39f0ull); CLOCK_CYCLES(8); return 0; @@ -487,7 +496,6 @@ static int opFLDZ(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FLDZ\n"); x87_push(0.0); cpu_state.tag[cpu_state.TOP&7] = 1; CLOCK_CYCLES(4); @@ -498,7 +506,6 @@ static int opF2XM1(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("F2XM1\n"); ST(0) = pow(2.0, ST(0)) - 1.0; cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(200); @@ -509,7 +516,6 @@ static int opFYL2X(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FYL2X\n"); ST(1) = ST(1) * (log(ST(0)) / log(2.0)); cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64; x87_pop(); @@ -521,7 +527,6 @@ static int opFYL2XP1(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FYL2XP1\n"); ST(1) = ST(1) * (log1p(ST(0)) / log(2.0)); cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64; x87_pop(); @@ -533,7 +538,6 @@ static int opFPTAN(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FPTAN\n"); ST(0) = tan(ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; x87_push(1.0); @@ -546,7 +550,6 @@ static int opFPATAN(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FPATAN\n"); ST(1) = atan2(ST(1), ST(0)); cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64; x87_pop(); @@ -558,7 +561,6 @@ static int opFDECSTP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FDECSTP\n"); cpu_state.TOP = (cpu_state.TOP - 1) & 7; CLOCK_CYCLES(4); return 0; @@ -568,7 +570,6 @@ static int opFINCSTP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FDECSTP\n"); cpu_state.TOP = (cpu_state.TOP + 1) & 7; CLOCK_CYCLES(4); return 0; @@ -579,11 +580,9 @@ static int opFPREM(uint32_t fetchdat) int64_t temp64; FP_ENTER(); cpu_state.pc++; - fpu_log("FPREM %f %f ", ST(0), ST(1)); temp64 = (int64_t)(ST(0) / ST(1)); ST(0) = ST(0) - (ST(1) * (double)temp64); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - fpu_log("%f\n", ST(0)); cpu_state.npxs &= ~(C0|C1|C2|C3); if (temp64 & 4) cpu_state.npxs|=C0; if (temp64 & 2) cpu_state.npxs|=C3; @@ -591,16 +590,15 @@ static int opFPREM(uint32_t fetchdat) CLOCK_CYCLES(100); return 0; } +#ifndef FPU_8087 static int opFPREM1(uint32_t fetchdat) { int64_t temp64; FP_ENTER(); cpu_state.pc++; - fpu_log("FPREM1 %f %f ", ST(0), ST(1)); temp64 = (int64_t)(ST(0) / ST(1)); ST(0) = ST(0) - (ST(1) * (double)temp64); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - fpu_log("%f\n", ST(0)); cpu_state.npxs &= ~(C0|C1|C2|C3); if (temp64 & 4) cpu_state.npxs|=C0; if (temp64 & 2) cpu_state.npxs|=C3; @@ -608,24 +606,24 @@ static int opFPREM1(uint32_t fetchdat) CLOCK_CYCLES(100); return 0; } +#endif static int opFSQRT(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FSQRT\n"); ST(0) = sqrt(ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; CLOCK_CYCLES(83); return 0; } +#ifndef FPU_8087 static int opFSINCOS(uint32_t fetchdat) { double td; FP_ENTER(); cpu_state.pc++; - fpu_log("FSINCOS\n"); td = ST(0); ST(0) = sin(td); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; @@ -634,15 +632,14 @@ static int opFSINCOS(uint32_t fetchdat) CLOCK_CYCLES(330); return 0; } +#endif static int opFRNDINT(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FRNDINT %g ", ST(0)); ST(0) = (double)x87_fround(ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - fpu_log("%g\n", ST(0)); CLOCK_CYCLES(21); return 0; } @@ -652,7 +649,6 @@ static int opFSCALE(uint32_t fetchdat) int64_t temp64; FP_ENTER(); cpu_state.pc++; - fpu_log("FSCALE\n"); temp64 = (int64_t)ST(1); ST(0) = ST(0) * pow(2.0, (double)temp64); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; @@ -660,11 +656,11 @@ static int opFSCALE(uint32_t fetchdat) return 0; } +#ifndef FPU_8087 static int opFSIN(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FSIN\n"); ST(0) = sin(ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; cpu_state.npxs &= ~C2; @@ -676,19 +672,18 @@ static int opFCOS(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - fpu_log("FCOS\n"); ST(0) = cos(ST(0)); cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; cpu_state.npxs &= ~C2; CLOCK_CYCLES(300); return 0; } +#endif static int FLDENV() { FP_ENTER(); - fpu_log("FLDENV %08X:%08X\n", easeg, cpu_state.eaaddr); switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) { case 0x000: /*16-bit real mode*/ @@ -716,23 +711,27 @@ static int opFLDENV_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); FLDENV(); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFLDENV_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); FLDENV(); return cpu_state.abrt; } +#endif static int opFLDCW_a16(uint32_t fetchdat) { uint16_t tempw; FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FLDCW %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); tempw = geteaw(); if (cpu_state.abrt) return 1; cpu_state.npxc = tempw; @@ -740,12 +739,13 @@ static int opFLDCW_a16(uint32_t fetchdat) CLOCK_CYCLES(4); return 0; } +#ifndef FPU_8087 static int opFLDCW_a32(uint32_t fetchdat) { uint16_t tempw; FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FLDCW %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_READ(cpu_state.ea_seg); tempw = geteaw(); if (cpu_state.abrt) return 1; cpu_state.npxc = tempw; @@ -753,11 +753,11 @@ static int opFLDCW_a32(uint32_t fetchdat) CLOCK_CYCLES(4); return 0; } +#endif static int FSTENV() { FP_ENTER(); - fpu_log("FSTENV %08X:%08X\n", easeg, cpu_state.eaaddr); switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) { case 0x000: /*16-bit real mode*/ @@ -802,42 +802,49 @@ static int opFSTENV_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); FSTENV(); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFSTENV_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); FSTENV(); return cpu_state.abrt; } +#endif static int opFSTCW_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); - fpu_log("FSTCW %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(cpu_state.npxc); CLOCK_CYCLES(3); return cpu_state.abrt; } +#ifndef FPU_8087 static int opFSTCW_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); - fpu_log("FSTCW %08X:%08X\n", easeg, cpu_state.eaaddr); + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(cpu_state.npxc); CLOCK_CYCLES(3); return cpu_state.abrt; } +#endif +#ifndef FPU_8087 +#if defined(DEV_BRANCH) && (defined(USE_CYRIX_6X86) || defined(USE_I686)) #define opFCMOV(condition) \ static int opFCMOV ## condition(uint32_t fetchdat) \ { \ FP_ENTER(); \ cpu_state.pc++; \ - fpu_log("FCMOV %f\n", ST(fetchdat & 7)); \ if (cond_ ## condition) \ { \ cpu_state.tag[cpu_state.TOP] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; \ @@ -859,3 +866,5 @@ opFCMOV(NB) opFCMOV(NE) opFCMOV(NBE) opFCMOV(NU) +#endif +#endif diff --git a/src/cpu_new/386.c b/src/cpu_new/386.c new file mode 100644 index 000000000..2b2268920 --- /dev/null +++ b/src/cpu_new/386.c @@ -0,0 +1,303 @@ +#include +#include +#include +#include +#include +#include +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "../timer.h" +#include "x86.h" +#include "x87.h" +#include "../nmi.h" +#include "../mem.h" +#include "../pic.h" +#include "../pit.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "386_common.h" +#include "codegen.h" + + +#ifdef ENABLE_386_LOG +int x386_do_log = ENABLE_386_LOG; + + +void +x386_log(const char *fmt, ...) +{ + va_list ap; + + if (x386_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define x386_log(fmt, ...) +#endif + + +#undef CPU_BLOCK_END +#define CPU_BLOCK_END() + + +extern int codegen_flags_changed; + +int tempc, oldcpl, optype, inttype, oddeven = 0; +int timetolive; + +uint16_t oldcs; + +uint32_t oldds, oldss, olddslimit, oldsslimit, + olddslimitw, oldsslimitw; +uint32_t oxpc; +uint32_t rmdat32; +uint32_t backupregs[16]; + +x86seg _oldds; + + +static __inline void +fetch_ea_32_long(uint32_t rmdat) +{ + uint8_t sib; + uint32_t addr; + + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + if (cpu_rm == 4) { + sib = rmdat >> 8; + + switch (cpu_mod) { + case 0: + cpu_state.eaaddr = cpu_state.regs[sib & 7].l; + cpu_state.pc++; + break; + case 1: + cpu_state.pc++; + cpu_state.eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; + break; + case 2: + cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; + cpu_state.pc += 5; + break; + } + /*SIB byte present*/ + if ((sib & 7) == 5 && !cpu_mod) + cpu_state.eaaddr = getlong(); + else if ((sib & 6) == 4 && !cpu_state.ssegs) { + easeg = ss; + cpu_state.ea_seg = &cpu_state.seg_ss; + } + if (((sib >> 3) & 7) != 4) + cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); + } else { + cpu_state.eaaddr = cpu_state.regs[cpu_rm].l; + if (cpu_mod) { + if (cpu_rm == 5 && !cpu_state.ssegs) { + easeg = ss; + cpu_state.ea_seg = &cpu_state.seg_ss; + } + if (cpu_mod == 1) { + cpu_state.eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); + cpu_state.pc++; + } else + cpu_state.eaaddr += getlong(); + } else if (cpu_rm == 5) + cpu_state.eaaddr = getlong(); + } + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { + addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + + +static __inline void +fetch_ea_16_long(uint32_t rmdat) +{ + uint32_t addr; + + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + if (!cpu_mod && cpu_rm == 6) + cpu_state.eaaddr = getword(); + else { + switch (cpu_mod) { + case 0: + cpu_state.eaaddr = 0; + break; + case 1: + cpu_state.eaaddr = (uint16_t)(int8_t)(rmdat >> 8); cpu_state.pc++; + break; + case 2: + cpu_state.eaaddr = getword(); + break; + } + cpu_state.eaaddr += (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs) { + easeg = ss; + cpu_state.ea_seg = &cpu_state.seg_ss; + } + cpu_state.eaaddr &= 0xFFFF; + } + + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { + addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + + +#define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 0; } +#define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 0 + +#include "x86_flags.h" + +#define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ +#define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 +#define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++ +#define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2 + + +#define OP_TABLE(name) ops_ ## name + +#define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "x86_ops.h" + + +void +exec386(int cycs) +{ + uint8_t opcode; + int vector, tempi, cycdiff, oldcyc; + int cycle_period, ins_cycles; + uint32_t addr; + + cycles += cycs; + + while (cycles > 0) { + cycle_period = (timer_target - (uint32_t)tsc) + 1; + + x86_was_reset = 0; + cycdiff = 0; + oldcyc = cycles; + while (cycdiff < cycle_period) { + ins_cycles = cycles; + + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + + cpu_state.ea_seg = &cpu_state.seg_ds; + cpu_state.ssegs = 0; + + fetchdat = fastreadl(cs + cpu_state.pc); + + if (!cpu_state.abrt) { + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; + + cpu_state.pc++; + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + if (x86_was_reset) + break; + } + + if (cpu_state.abrt) { + flags_rebuild(); + tempi = cpu_state.abrt; + cpu_state.abrt = 0; + x86_doabrt(tempi); + if (cpu_state.abrt) { + cpu_state.abrt = 0; + cpu_state.pc = cpu_state.oldpc; + x386_log("Double fault %i\n", ins); + pmodeint(8, 0); + if (cpu_state.abrt) { + cpu_state.abrt = 0; + softresetx86(); + cpu_set_edx(); +#ifdef ENABLE_386_LOG + x386_log("Triple fault - reset\n"); +#endif + } + } + } + + ins_cycles -= cycles; + tsc += ins_cycles; + + cycdiff = oldcyc - cycles; + + if (trap) { + flags_rebuild(); + if (msw&1) + pmodeint(1,0); + else { + writememw(ss, (SP - 2) & 0xFFFF, cpu_state.flags); + writememw(ss, (SP - 4) & 0xFFFF, CS); + writememw(ss, (SP - 6) & 0xFFFF, cpu_state.pc); + SP -= 6; + addr = (1 << 2) + idt.base; + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; + cpu_state.pc = readmemw(0, addr); + loadcs(readmemw(0, addr + 2)); + } + } else if (nmi && nmi_enable && nmi_mask) { + cpu_state.oldpc = cpu_state.pc; + x86_int(2); + nmi_enable = 0; + if (nmi_auto_clear) { + nmi_auto_clear = 0; + nmi = 0; + } + } else if ((cpu_state.flags & I_FLAG) && pic_intpending) { + vector = picinterrupt(); + if (vector != 0xFF) { + flags_rebuild(); + if (msw & 1) + pmodeint(vector, 0); + else { + writememw(ss, (SP - 2) & 0xFFFF, cpu_state.flags); + writememw(ss, (SP - 4) & 0xFFFF, CS); + writememw(ss, (SP - 6) & 0xFFFF, cpu_state.pc); + SP -= 6; + addr = (vector << 2) + idt.base; + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; + cpu_state.pc = readmemw(0, addr); + loadcs(readmemw(0, addr + 2)); + } + } + } + + ins++; + + if (timetolive) { + timetolive--; + if (!timetolive) + fatal("Life expired\n"); + } + } + + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) + timer_process(); + } +} diff --git a/src/cpu_new/386_common.c b/src/cpu_new/386_common.c new file mode 100644 index 000000000..32b65e0bf --- /dev/null +++ b/src/cpu_new/386_common.c @@ -0,0 +1,292 @@ +#include +#include +#include +#include +#include +#include +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "../timer.h" +#include "x86.h" +#include "x87.h" +#include "../nmi.h" +#include "../mem.h" +#include "../pic.h" +#include "../pit.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "386_common.h" +#include "x86_flags.h" +#include "codegen.h" + +x86seg gdt, ldt, idt, tr; + +uint32_t cr2, cr3, cr4; +uint32_t dr[8]; + +uint32_t use32; +int stack32; +int optype; + +int trap; + +uint32_t rmdat; + +uint32_t *eal_r, *eal_w; + +int nmi_enable = 1; + +int cpl_override=0; + +int fpucount=0; + +uint16_t cpu_cur_status = 0; + +uint32_t pccache; +uint8_t *pccache2; + + +#ifdef ENABLE_386_COMMON_LOG +int x386_common_do_log = ENABLE_386_COMMON_LOG; + + +void +x386_common_log(const char *fmt, ...) +{ + va_list ap; + + if (x386_common_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define x386_common_log(fmt, ...) +#endif + + +void x86_int(int num) +{ + uint32_t addr; + flags_rebuild(); + cpu_state.pc=cpu_state.oldpc; + if (msw&1) + { + pmodeint(num,0); + } + else + { + addr = (num << 2) + idt.base; + + if ((num << 2) + 3 > idt.limit) + { + if (idt.limit < 35) + { + cpu_state.abrt = 0; + softresetx86(); + cpu_set_edx(); +#ifdef ENABLE_386_COMMON_LOG + x386_log("Triple fault in real mode - reset\n"); +#endif + } + else + x86_int(8); + } + else + { + if (stack32) + { + writememw(ss,ESP-2,cpu_state.flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + cycles-=70; + CPU_BLOCK_END(); +} + +void x86_int_sw(int num) +{ + uint32_t addr; + flags_rebuild(); + cycles -= timing_int; + if (msw&1) + { + pmodeint(num,1); + } + else + { + addr = (num << 2) + idt.base; + + if ((num << 2) + 3 > idt.limit) + { + x86_int(13); + } + else + { + if (stack32) + { + writememw(ss,ESP-2,cpu_state.flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + cycles -= timing_int_rm; + } + } + trap = 0; + CPU_BLOCK_END(); +} + +int x86_int_sw_rm(int num) +{ + uint32_t addr; + uint16_t new_pc, new_cs; + + flags_rebuild(); + cycles -= timing_int; + + addr = num << 2; + new_pc = readmemw(0, addr); + new_cs = readmemw(0, addr + 2); + + if (cpu_state.abrt) return 1; + + writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); + if (cpu_state.abrt) + return 1; + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + if (cpu_state.abrt) + return 1; + SP-=6; + + cpu_state.eflags &= ~VIF_FLAG; + cpu_state.flags &= ~T_FLAG; + cpu_state.pc = new_pc; + loadcs(new_cs); + + cycles -= timing_int_rm; + trap = 0; + CPU_BLOCK_END(); + + return 0; +} + +void x86illegal() +{ + x86_int(6); +} + +int checkio(int port) +{ + uint16_t t; + uint8_t d; + cpl_override = 1; + t = readmemw(tr.base, 0x66); + cpl_override = 0; + if (cpu_state.abrt) return 0; + if ((t+(port>>3))>tr.limit) return 1; + cpl_override = 1; + d = readmembl(tr.base + t + (port >> 3)); + cpl_override = 0; + return d&(1<<(port&7)); +} + +#define divexcp() { \ + x386_common_log("Divide exception at %04X(%06X):%04X\n",CS,cs,cpu_state.pc); \ + x86_int(0); \ +} + +int divl(uint32_t val) +{ + uint64_t num, quo; + uint32_t rem, quo32; + + if (val==0) + { + divexcp(); + return 1; + } + + num=(((uint64_t)EDX)<<32)|EAX; + quo=num/val; + rem=num%val; + quo32=(uint32_t)(quo&0xFFFFFFFF); + + if (quo!=(uint64_t)quo32) + { + divexcp(); + return 1; + } + EDX=rem; + EAX=quo32; + return 0; +} +int idivl(int32_t val) +{ + int64_t num, quo; + int32_t rem, quo32; + + if (val==0) + { + divexcp(); + return 1; + } + + num=(((uint64_t)EDX)<<32)|EAX; + quo=num/val; + rem=num%val; + quo32=(int32_t)(quo&0xFFFFFFFF); + + if (quo!=(int64_t)quo32) + { + divexcp(); + return 1; + } + EDX=rem; + EAX=quo32; + return 0; +} + + +void cpu_386_flags_extract() +{ + flags_extract(); +} +void cpu_386_flags_rebuild() +{ + flags_rebuild(); +} diff --git a/src/cpu_new/386_common.h b/src/cpu_new/386_common.h new file mode 100644 index 000000000..84661f193 --- /dev/null +++ b/src/cpu_new/386_common.h @@ -0,0 +1,317 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Common 386 CPU code. + * + * Version: @(#)386_common.h 1.0.1 2019/02/19 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ + +#ifndef _386_COMMON_H_ +#define _386_COMMON_H_ + +#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1)?readmembl((s)+(a)): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uint32_t)((s) + (a))) ) +#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 1))?readmemwl((s)+(a)):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 3))?readmemll((s)+(a)):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 7))?readmemql((s)+(a)):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) + +#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1) writemembl((s)+(a),v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v +#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 1)) writememwl((s)+(a),v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v +#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 3)) writememll((s)+(a),v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v +#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 7)) writememql((s)+(a),v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v + +int checkio(int port); + +#define check_io_perm(port) if (!IOPLp || (cpu_state.eflags&VM_FLAG)) \ + { \ + int tempi = checkio(port); \ + if (cpu_state.abrt) return 1; \ + if (tempi) \ + { \ + x86gpf(NULL,0); \ + return 1; \ + } \ + } + +#define SEG_CHECK_READ(seg) \ + do \ + { \ + if ((seg)->base == 0xffffffff) \ + { \ + x86gpf("Segment can't read", 0);\ + return 1; \ + } \ + } while (0) + +#define SEG_CHECK_WRITE(seg) \ + do \ + { \ + if ((seg)->base == 0xffffffff) \ + { \ + x86gpf("Segment can't write", 0);\ + return 1; \ + } \ + } while (0) + +#define CHECK_READ(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) \ + { \ + x86gpf("Limit check (READ)", 0); \ + return 1; \ + } \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &cpu_state.seg_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ + return 1; \ + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 0); \ + (void) mmutranslatereal((chseg)->base + high, 0); \ + if (cpu_state.abrt) \ + return 1; \ + } + +#define CHECK_READ_REP(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ + { \ + x86gpf("Limit check (READ)", 0); \ + break; \ + } \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &cpu_state.seg_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ + break; \ + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 0); \ + (void) mmutranslatereal((chseg)->base + high, 0); \ + if (cpu_state.abrt) \ + break; \ + } + +#define CHECK_WRITE(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && ((chseg)->access & 8))) \ + { \ + x86gpf("Limit check (WRITE)", 0); \ + return 1; \ + } \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &cpu_state.seg_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Write to seg not present", (chseg)->seg & 0xfffc); \ + return 1; \ + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 1); \ + (void) mmutranslatereal((chseg)->base + high, 1); \ + if (cpu_state.abrt) \ + return 1; \ + } + +#define CHECK_WRITE_REP(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ + { \ + x86gpf("Limit check (WRITE REP)", 0); \ + break; \ + } \ + if (msw&1 && !(cpu_state.eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &cpu_state.seg_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Write (REP) to seg not present", (chseg)->seg & 0xfffc); \ + break; \ + } \ + if (cr0 >> 31) { \ + (void) mmutranslatereal((chseg)->base + low, 1); \ + (void) mmutranslatereal((chseg)->base + high, 1); \ + if (cpu_state.abrt) \ + break; \ + } + + +#define NOTRM if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\ + { \ + x86_int(6); \ + return 1; \ + } + + + + +static inline uint8_t fastreadb(uint32_t a) +{ + uint8_t *t; + + if ((a >> 12) == pccache) + return *((uint8_t *)&pccache2[a]); + t = getpccache(a); + if (cpu_state.abrt) + return 0; + pccache = a >> 12; + pccache2 = t; + return *((uint8_t *)&pccache2[a]); +} + +static inline uint16_t fastreadw(uint32_t a) +{ + uint8_t *t; + uint16_t val; + if ((a&0xFFF)>0xFFE) + { + val = fastreadb(a); + val |= (fastreadb(a + 1) << 8); + return val; + } + if ((a>>12)==pccache) return *((uint16_t *)&pccache2[a]); + t = getpccache(a); + if (cpu_state.abrt) + return 0; + + pccache = a >> 12; + pccache2 = t; + return *((uint16_t *)&pccache2[a]); +} + +static inline uint32_t fastreadl(uint32_t a) +{ + uint8_t *t; + uint32_t val; + if ((a&0xFFF)<0xFFD) + { + if ((a>>12)!=pccache) + { + t = getpccache(a); + if (cpu_state.abrt) + return 0; + pccache2 = t; + pccache=a>>12; + } + return *((uint32_t *)&pccache2[a]); + } + val = fastreadw(a); + val |= (fastreadw(a + 2) << 16); + return val; +} + +static inline void *get_ram_ptr(uint32_t a) +{ + if ((a >> 12) == pccache) + return &pccache2[a]; + else + { + uint8_t *t = getpccache(a); + return &t[a]; + } +} + +static inline uint8_t getbyte() +{ + cpu_state.pc++; + return fastreadb(cs + (cpu_state.pc - 1)); +} + +static inline uint16_t getword() +{ + cpu_state.pc+=2; + return fastreadw(cs+(cpu_state.pc-2)); +} + +static inline uint32_t getlong() +{ + cpu_state.pc+=4; + return fastreadl(cs+(cpu_state.pc-4)); +} + +static inline uint64_t getquad() +{ + cpu_state.pc+=8; + return fastreadl(cs+(cpu_state.pc-8)) | ((uint64_t)fastreadl(cs+(cpu_state.pc-4)) << 32); +} + + + +static inline uint8_t geteab() +{ + if (cpu_mod == 3) + return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm&3].b.l; + if (eal_r) + return *(uint8_t *)eal_r; + return readmemb(easeg,cpu_state.eaaddr); +} + +static inline uint16_t geteaw() +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + if (eal_r) + return *(uint16_t *)eal_r; + return readmemw(easeg,cpu_state.eaaddr); +} + +static inline uint32_t geteal() +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].l; + if (eal_r) + return *eal_r; + return readmeml(easeg,cpu_state.eaaddr); +} + +static inline uint64_t geteaq() +{ + return readmemq(easeg,cpu_state.eaaddr); +} + +static inline uint8_t geteab_mem() +{ + if (eal_r) return *(uint8_t *)eal_r; + return readmemb(easeg,cpu_state.eaaddr); +} +static inline uint16_t geteaw_mem() +{ + if (eal_r) return *(uint16_t *)eal_r; + return readmemw(easeg,cpu_state.eaaddr); +} +static inline uint32_t geteal_mem() +{ + if (eal_r) return *eal_r; + return readmeml(easeg,cpu_state.eaaddr); +} + +static inline void seteaq(uint64_t v) +{ + writememql(easeg+cpu_state.eaaddr, v); +} + +#define seteab(v) if (cpu_mod!=3) { CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); if (eal_w) *(uint8_t *)eal_w=v; else writemembl(easeg+cpu_state.eaaddr,v); } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v +#define seteaw(v) if (cpu_mod!=3) { CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v +#define seteal(v) if (cpu_mod!=3) { CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v + +#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writemembl(easeg+cpu_state.eaaddr,v); +#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); +#define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); + +#define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ +#define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 +#define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++ +#define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2 + +#endif diff --git a/src/cpu_new/386_dynarec.c b/src/cpu_new/386_dynarec.c new file mode 100644 index 000000000..cbd8f063e --- /dev/null +++ b/src/cpu_new/386_dynarec.c @@ -0,0 +1,661 @@ +#include +#include +#include +#include +#include +#include +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "../io.h" +#include "../mem.h" +#include "../nmi.h" +#include "../pic.h" +#include "../timer.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#ifdef USE_DYNAREC +#include "codegen.h" +#include "codegen_backend.h" +#endif +#include "386_common.h" + + +#ifdef ENABLE_386_DYNAREC_LOG +int x386_dynarec_do_log = ENABLE_386_DYNAREC_LOG; + + +void +x386_dynarec_log(const char *fmt, ...) +{ + va_list ap; + + if (x386_dynarec_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define x386_dynarec_log(fmt, ...) +#endif + + +#define CPU_BLOCK_END() cpu_block_end = 1 + +int inrecomp = 0; +int cpu_recomp_blocks, cpu_recomp_full_ins, cpu_new_blocks; +int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched; + +int cpu_block_end = 0; + + +static __inline void fetch_ea_32_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + if (cpu_rm == 4) + { + uint8_t sib = rmdat >> 8; + + switch (cpu_mod) + { + case 0: + cpu_state.eaaddr = cpu_state.regs[sib & 7].l; + cpu_state.pc++; + break; + case 1: + cpu_state.pc++; + cpu_state.eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; + break; + case 2: + cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; + cpu_state.pc += 5; + break; + } + /*SIB byte present*/ + if ((sib & 7) == 5 && !cpu_mod) + cpu_state.eaaddr = getlong(); + else if ((sib & 6) == 4 && !cpu_state.ssegs) + { + easeg = ss; + cpu_state.ea_seg = &cpu_state.seg_ss; + } + if (((sib >> 3) & 7) != 4) + cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); + } + else + { + cpu_state.eaaddr = cpu_state.regs[cpu_rm].l; + if (cpu_mod) + { + if (cpu_rm == 5 && !cpu_state.ssegs) + { + easeg = ss; + cpu_state.ea_seg = &cpu_state.seg_ss; + } + if (cpu_mod == 1) + { + cpu_state.eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); + cpu_state.pc++; + } + else + { + cpu_state.eaaddr += getlong(); + } + } + else if (cpu_rm == 5) + { + cpu_state.eaaddr = getlong(); + } + } + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } + cpu_state.last_ea = cpu_state.eaaddr; +} + +static __inline void fetch_ea_16_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + if (!cpu_mod && cpu_rm == 6) + { + cpu_state.eaaddr = getword(); + } + else + { + switch (cpu_mod) + { + case 0: + cpu_state.eaaddr = 0; + break; + case 1: + cpu_state.eaaddr = (uint16_t)(int8_t)(rmdat >> 8); cpu_state.pc++; + break; + case 2: + cpu_state.eaaddr = getword(); + break; + } + cpu_state.eaaddr += (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs) + { + easeg = ss; + cpu_state.ea_seg = &cpu_state.seg_ss; + } + cpu_state.eaaddr &= 0xFFFF; + } + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } + cpu_state.last_ea = cpu_state.eaaddr; +} + +#define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 1; } +#define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 1 + +#include "x86_flags.h" + + +/*Prefetch emulation is a fairly simplistic model: + - All instruction bytes must be fetched before it starts. + - Cycles used for non-instruction memory accesses are counted and subtracted + from the total cycles taken + - Any remaining cycles are used to refill the prefetch queue. + + Note that this is only used for 286 / 386 systems. It is disabled when the + internal cache on 486+ CPUs is enabled. +*/ +static int prefetch_bytes = 0; +static int prefetch_prefixes = 0; + +static void prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int reads_l, int writes, int writes_l, int ea32) +{ + int mem_cycles = reads*cpu_cycles_read + reads_l*cpu_cycles_read_l + writes*cpu_cycles_write + writes_l*cpu_cycles_write_l; + + if (instr_cycles < mem_cycles) + instr_cycles = mem_cycles; + + prefetch_bytes -= prefetch_prefixes; + prefetch_bytes -= bytes; + if (modrm != -1) + { + if (ea32) + { + if ((modrm & 7) == 4) + { + if ((modrm & 0x700) == 0x500) + prefetch_bytes -= 5; + else if ((modrm & 0xc0) == 0x40) + prefetch_bytes -= 2; + else if ((modrm & 0xc0) == 0x80) + prefetch_bytes -= 5; + } + else + { + if ((modrm & 0xc7) == 0x05) + prefetch_bytes -= 4; + else if ((modrm & 0xc0) == 0x40) + prefetch_bytes--; + else if ((modrm & 0xc0) == 0x80) + prefetch_bytes -= 4; + } + } + else + { + if ((modrm & 0xc7) == 0x06) + prefetch_bytes -= 2; + else if ((modrm & 0xc0) != 0xc0) + prefetch_bytes -= ((modrm & 0xc0) >> 6); + } + } + + /* Fill up prefetch queue */ + while (prefetch_bytes < 0) + { + prefetch_bytes += cpu_prefetch_width; + cycles -= cpu_prefetch_cycles; + } + + /* Subtract cycles used for memory access by instruction */ + instr_cycles -= mem_cycles; + + while (instr_cycles >= cpu_prefetch_cycles) + { + prefetch_bytes += cpu_prefetch_width; + instr_cycles -= cpu_prefetch_cycles; + } + + prefetch_prefixes = 0; + if (prefetch_bytes > 16) + prefetch_bytes = 16; +} + +static void prefetch_flush() +{ + prefetch_bytes = 0; +} + +#define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, reads_l, writes, writes_l, ea32) \ + do { if (cpu_prefetch_cycles) prefetch_run(instr_cycles, bytes, modrm, reads, reads_l, writes, writes_l, ea32); } while (0) + +#define PREFETCH_PREFIX() do { if (cpu_prefetch_cycles) prefetch_prefixes++; } while (0) +#define PREFETCH_FLUSH() prefetch_flush() + + +#define OP_TABLE(name) ops_ ## name +#define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "386_ops.h" + + +#define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG)) + +#ifdef USE_DYNAREC +static int cycles_main = 0; + + +void exec386_dynarec(int cycs) +{ + int vector; + uint32_t addr; + int tempi; + int cycdiff; + int oldcyc; + int cyc_period = cycs / 2000; /*5us*/ + + cycles_main += cycs; + while (cycles_main > 0) + { + int cycles_start; + + cycles += cyc_period; + cycles_start = cycles; + + while (cycles>0) + { + oldcyc=cycles; + if (!CACHE_ON()) /*Interpret block*/ + { + cpu_block_end = 0; + x86_was_reset = 0; + while (!cpu_block_end) + { + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + + cpu_state.ea_seg = &cpu_state.seg_ds; + cpu_state.ssegs = 0; + + fetchdat = fastreadl(cs + cpu_state.pc); + + if (!cpu_state.abrt) + { + uint8_t opcode = fetchdat & 0xFF; + fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; + + cpu_state.pc++; + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + } + + if (((cs + cpu_state.pc) >> 12) != pccache) + CPU_BLOCK_END(); + + if (cpu_state.abrt) + CPU_BLOCK_END(); + if (trap) + CPU_BLOCK_END(); + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + + ins++; + } + } + else + { + uint32_t phys_addr = get_phys(cs+cpu_state.pc); + int hash = HASH(phys_addr); + codeblock_t *block = &codeblock[codeblock_hash[hash]]; + int valid_block = 0; + + if (!cpu_state.abrt) + { + page_t *page = &pages[phys_addr >> 12]; + + /*Block must match current CS, PC, code segment size, + and physical address. The physical address check will + also catch any page faults at this stage*/ + valid_block = (block->pc == cs + cpu_state.pc) && (block->_cs == cs) && + (block->phys == phys_addr) && !((block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && + ((block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK)); + if (!valid_block) + { + uint64_t mask = (uint64_t)1 << ((phys_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + int byte_offset = (phys_addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + uint64_t byte_mask = 1ull << (PAGE_BYTE_MASK_MASK & 0x3f); + + if ((page->code_present_mask & mask) || (page->byte_code_present_mask[byte_offset] & byte_mask)) + { + /*Walk page tree to see if we find the correct block*/ + codeblock_t *new_block = codeblock_tree_find(phys_addr, cs); + if (new_block) + { + valid_block = (new_block->pc == cs + cpu_state.pc) && (new_block->_cs == cs) && + (new_block->phys == phys_addr) && !((new_block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && + ((new_block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK)); + if (valid_block) + { + block = new_block; + codeblock_hash[hash] = get_block_nr(block); + } + } + } + } + + if (valid_block && (block->page_mask & *block->dirty_mask)) + { + codegen_check_flush(page, page->dirty_mask, phys_addr); + if (block->pc == BLOCK_PC_INVALID) + valid_block = 0; + else if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + block->flags &= ~CODEBLOCK_WAS_RECOMPILED; + } + if (valid_block && block->page_mask2) + { + /*We don't want the second page to cause a page + fault at this stage - that would break any + code crossing a page boundary where the first + page is present but the second isn't. Instead + allow the first page to be interpreted and for + the page fault to occur when the page boundary + is actually crossed.*/ + uint32_t phys_addr_2 = get_phys_noabrt(block->pc + ((block->flags & CODEBLOCK_BYTE_MASK) ? 0x40 : 0x400)); + page_t *page_2 = &pages[phys_addr_2 >> 12]; + if ((block->phys_2 ^ phys_addr_2) & ~0xfff) + valid_block = 0; + else if (block->page_mask2 & *block->dirty_mask2) + { + codegen_check_flush(page_2, page_2->dirty_mask, phys_addr_2); + if (block->pc == BLOCK_PC_INVALID) + valid_block = 0; + else if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + block->flags &= ~CODEBLOCK_WAS_RECOMPILED; + } + } + if (valid_block && (block->flags & CODEBLOCK_IN_DIRTY_LIST)) + { + block->flags &= ~CODEBLOCK_WAS_RECOMPILED; + if (block->flags & CODEBLOCK_BYTE_MASK) + block->flags |= CODEBLOCK_NO_IMMEDIATES; + else + block->flags |= CODEBLOCK_BYTE_MASK; + } + if (valid_block && (block->flags & CODEBLOCK_WAS_RECOMPILED) && (block->flags & CODEBLOCK_STATIC_TOP) && block->TOP != (cpu_state.TOP & 7)) + { + /*FPU top-of-stack does not match the value this block was compiled + with, re-compile using dynamic top-of-stack*/ + block->flags &= ~(CODEBLOCK_STATIC_TOP | CODEBLOCK_WAS_RECOMPILED); + } + } + + if (valid_block && (block->flags & CODEBLOCK_WAS_RECOMPILED)) + { + void (*code)() = (void *)&block->data[BLOCK_START]; + + inrecomp=1; + code(); + inrecomp=0; + + cpu_recomp_blocks++; + } + else if (valid_block && !cpu_state.abrt) + { + uint32_t start_pc = cs+cpu_state.pc; + const int max_block_size = (block->flags & CODEBLOCK_BYTE_MASK) ? ((128 - 25) - (start_pc & 0x3f)) : 1000; + + cpu_block_end = 0; + x86_was_reset = 0; + + cpu_new_blocks++; + + codegen_block_start_recompile(block); + codegen_in_recompile = 1; + + while (!cpu_block_end) + { + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + + cpu_state.ea_seg = &cpu_state.seg_ds; + cpu_state.ssegs = 0; + + fetchdat = fastreadl(cs + cpu_state.pc); + + if (!cpu_state.abrt) + { + uint8_t opcode = fetchdat & 0xFF; + fetchdat >>= 8; + + trap = cpu_state.flags & T_FLAG; + + cpu_state.pc++; + + codegen_generate_call(opcode, x86_opcodes[(opcode | cpu_state.op32) & 0x3ff], fetchdat, cpu_state.pc, cpu_state.pc-1); + + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + + if (x86_was_reset) + break; + } + + /*Cap source code at 4000 bytes per block; this + will prevent any block from spanning more than + 2 pages. In practice this limit will never be + hit, as host block size is only 2kB*/ + if (((cs+cpu_state.pc) - start_pc) >= max_block_size) + CPU_BLOCK_END(); + + if (trap) + CPU_BLOCK_END(); + + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + + if (cpu_state.abrt) + { + codegen_block_remove(); + CPU_BLOCK_END(); + } + + ins++; + } + + if (!cpu_state.abrt && !x86_was_reset) + codegen_block_end_recompile(block); + + if (x86_was_reset) + codegen_reset(); + + codegen_in_recompile = 0; + } + else if (!cpu_state.abrt) + { + /*Mark block but do not recompile*/ + uint32_t start_pc = cs+cpu_state.pc; + const int max_block_size = (block->flags & CODEBLOCK_BYTE_MASK) ? ((128 - 25) - (start_pc & 0x3f)) : 1000; + + cpu_block_end = 0; + x86_was_reset = 0; + + codegen_block_init(phys_addr); + + while (!cpu_block_end) + { + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + + cpu_state.ea_seg = &cpu_state.seg_ds; + cpu_state.ssegs = 0; + + codegen_endpc = (cs + cpu_state.pc) + 8; + fetchdat = fastreadl(cs + cpu_state.pc); + + if (!cpu_state.abrt) + { + uint8_t opcode = fetchdat & 0xFF; + fetchdat >>= 8; + + trap = cpu_state.flags & T_FLAG; + + cpu_state.pc++; + + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + + if (x86_was_reset) + break; + } + + /*Cap source code at 4000 bytes per block; this + will prevent any block from spanning more than + 2 pages. In practice this limit will never be + hit, as host block size is only 2kB*/ + if (((cs+cpu_state.pc) - start_pc) >= max_block_size) + CPU_BLOCK_END(); + + if (trap) + CPU_BLOCK_END(); + + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + + if (cpu_state.abrt) + { + codegen_block_remove(); + CPU_BLOCK_END(); + } + + ins++; + } + + if (!cpu_state.abrt && !x86_was_reset) + codegen_block_end(); + + if (x86_was_reset) + codegen_reset(); + } + else + cpu_state.oldpc = cpu_state.pc; + + } + + cycdiff=oldcyc-cycles; + tsc += cycdiff; + + if (cpu_state.abrt) + { + flags_rebuild(); + tempi = cpu_state.abrt; + cpu_state.abrt = 0; + x86_doabrt(tempi); + if (cpu_state.abrt) + { + cpu_state.abrt = 0; + cpu_state.pc = cpu_state.oldpc; + x386_dynarec_log("Double fault %i\n", ins); + pmodeint(8, 0); + if (cpu_state.abrt) + { + cpu_state.abrt = 0; + softresetx86(); + cpu_set_edx(); +#ifdef ENABLE_386_DYNAREC_LOG + x386_dynarec_log("Triple fault - reset\n"); +#endif + } + } + } + + if (trap) + { + trap = 0; + flags_rebuild(); + if (msw&1) + { + pmodeint(1,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,cpu_state.flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr = (1 << 2) + idt.base; + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + else if (nmi && nmi_enable && nmi_mask) + { + cpu_state.oldpc = cpu_state.pc; + x86_int(2); + nmi_enable = 0; + if (nmi_auto_clear) + { + nmi_auto_clear = 0; + nmi = 0; + } + } + else if ((cpu_state.flags & I_FLAG) && pic_intpending) + { + vector = picinterrupt(); + if (vector != -1) + { + CPU_BLOCK_END(); + flags_rebuild(); + if (msw&1) + { + pmodeint(vector,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,cpu_state.flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr=vector<<2; + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + } + } + + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); + cycles_main -= (cycles_start - cycles); + } +} +#endif diff --git a/src/cpu_new/386_dynarec_ops.c b/src/cpu_new/386_dynarec_ops.c new file mode 100644 index 000000000..343ab13c3 --- /dev/null +++ b/src/cpu_new/386_dynarec_ops.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "x86_flags.h" +#include "../io.h" +#include "../mem.h" +#include "../nmi.h" +#include "../pic.h" +#include "codegen.h" + +#define CPU_BLOCK_END() cpu_block_end = 1 + +#include "386_common.h" + + +static inline void fetch_ea_32_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +static inline void fetch_ea_16_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +#define fetch_ea_16(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_16_long(rmdat); +#define fetch_ea_32(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_32_long(rmdat); + + +#define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, read_ls, writes, write_ls, ea32) +#define PREFETCH_PREFIX() +#define PREFETCH_FLUSH() + +#define OP_TABLE(name) dynarec_ops_ ## name +/*Temporary*/ +#define CLOCK_CYCLES(c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "386_ops.h" diff --git a/src/cpu_new/386_ops.h b/src/cpu_new/386_ops.h new file mode 100644 index 000000000..64332dd29 --- /dev/null +++ b/src/cpu_new/386_ops.h @@ -0,0 +1,1822 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * 286/386+ instruction handlers list. + * + * Version: @(#)386_ops.h 1.0.5 2018/10/17 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * leilei, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include "x86_ops.h" + + +#define ILLEGAL_ON(cond) \ + do \ + { \ + if ((cond)) \ + { \ + cpu_state.pc = cpu_state.oldpc; \ + x86illegal(); \ + return 0; \ + } \ + } while (0) + +static __inline void PUSH_W(uint16_t val) +{ + if (stack32) + { + writememw(ss, ESP - 2, val); if (cpu_state.abrt) return; + ESP -= 2; + cpu_state.last_ea = ESP; + } + else + { + writememw(ss, (SP - 2) & 0xFFFF, val); if (cpu_state.abrt) return; + SP -= 2; + cpu_state.last_ea = SP; + } +} + +static __inline void PUSH_L(uint32_t val) +{ + if (stack32) + { + writememl(ss, ESP - 4, val); if (cpu_state.abrt) return; + ESP -= 4; + cpu_state.last_ea = ESP; + } + else + { + writememl(ss, (SP - 4) & 0xFFFF, val); if (cpu_state.abrt) return; + SP -= 4; + cpu_state.last_ea = SP; + } +} + +static __inline uint16_t POP_W() +{ + uint16_t ret; + if (stack32) + { + ret = readmemw(ss, ESP); if (cpu_state.abrt) return 0; + ESP += 2; + cpu_state.last_ea = ESP; + } + else + { + ret = readmemw(ss, SP); if (cpu_state.abrt) return 0; + SP += 2; + cpu_state.last_ea = SP; + } + return ret; +} + +static __inline uint32_t POP_L() +{ + uint32_t ret; + if (stack32) + { + ret = readmeml(ss, ESP); if (cpu_state.abrt) return 0; + ESP += 4; + cpu_state.last_ea = ESP; + } + else + { + ret = readmeml(ss, SP); if (cpu_state.abrt) return 0; + SP += 4; + cpu_state.last_ea = SP; + } + return ret; +} + +static __inline uint16_t POP_W_seg(uint32_t seg) +{ + uint16_t ret; + if (stack32) + { + ret = readmemw(seg, ESP); if (cpu_state.abrt) return 0; + ESP += 2; + cpu_state.last_ea = ESP; + } + else + { + ret = readmemw(seg, SP); if (cpu_state.abrt) return 0; + SP += 2; + cpu_state.last_ea = SP; + } + return ret; +} + +static __inline uint32_t POP_L_seg(uint32_t seg) +{ + uint32_t ret; + if (stack32) + { + ret = readmeml(seg, ESP); if (cpu_state.abrt) return 0; + ESP += 4; + cpu_state.last_ea = ESP; + } + else + { + ret = readmeml(seg, SP); if (cpu_state.abrt) return 0; + SP += 4; + cpu_state.last_ea = SP; + } + return ret; +} + +static int fopcode; + +static int ILLEGAL(uint32_t fetchdat) +{ + cpu_state.pc = cpu_state.oldpc; + + pclog("Illegal instruction %08X (%02X)\n", fetchdat, fopcode); + x86illegal(); + return 0; +} + +static int internal_illegal(char *s) +{ + cpu_state.pc = cpu_state.oldpc; + x86gpf(s, 0); + return cpu_state.abrt; +} + +#ifdef ENABLE_386_DYNAREC_LOG +extern void x386_dynarec_log(const char *fmt, ...); +#else +#ifndef x386_dynarec_log +#define x386_dynarec_log(fmt, ...) +#endif +#endif + +#include "x86seg.h" +# include "x86_ops_amd.h" +#include "x86_ops_arith.h" +#include "x86_ops_atomic.h" +#include "x86_ops_bcd.h" +#include "x86_ops_bit.h" +#include "x86_ops_bitscan.h" +#include "x86_ops_call.h" +#include "x86_ops_flag.h" +#include "x86_ops_fpu.h" +#include "x86_ops_inc_dec.h" +#include "x86_ops_int.h" +#include "x86_ops_io.h" +#include "x86_ops_jump.h" +#include "x86_ops_misc.h" +#include "x87_ops.h" +#if defined(DEV_BRANCH) && defined(USE_I686) +# include "x86_ops_i686.h" +#endif +#include "x86_ops_mmx.h" +#include "x86_ops_3dnow.h" +#include "x86_ops_mmx_arith.h" +#include "x86_ops_mmx_cmp.h" +#include "x86_ops_mmx_logic.h" +#include "x86_ops_mmx_mov.h" +#include "x86_ops_mmx_pack.h" +#include "x86_ops_mmx_shift.h" +#include "x86_ops_mov.h" +#include "x86_ops_mov_ctrl.h" +#include "x86_ops_mov_seg.h" +#include "x86_ops_movx.h" +#include "x86_ops_msr.h" +#include "x86_ops_mul.h" +#include "x86_ops_pmode.h" +#include "x86_ops_prefix.h" +#include "x86_ops_rep.h" +#include "x86_ops_ret.h" +#include "x86_ops_set.h" +#include "x86_ops_shift.h" +#include "x86_ops_stack.h" +#include "x86_ops_string.h" +#include "x86_ops_xchg.h" + + +static int op0F_w_a16(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + fopcode = opcode; + cpu_state.pc++; + + PREFETCH_PREFIX(); + + return x86_opcodes_0f[opcode](fetchdat >> 8); +} +static int op0F_l_a16(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + fopcode = opcode; + cpu_state.pc++; + + PREFETCH_PREFIX(); + + return x86_opcodes_0f[opcode | 0x100](fetchdat >> 8); +} +static int op0F_w_a32(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + fopcode = opcode; + cpu_state.pc++; + + PREFETCH_PREFIX(); + + return x86_opcodes_0f[opcode | 0x200](fetchdat >> 8); +} +static int op0F_l_a32(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + fopcode = opcode; + cpu_state.pc++; + + PREFETCH_PREFIX(); + + return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8); +} + + +const OpFn OP_TABLE(286_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(386_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, ILLEGAL, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, ILLEGAL, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, ILLEGAL, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, ILLEGAL, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(486_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(winchip_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +const OpFn OP_TABLE(winchip2_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opPREFETCH_a16, opFEMMS, op3DNOW_a16, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opPREFETCH_a16, opFEMMS, op3DNOW_a16, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opPREFETCH_a32, opFEMMS, op3DNOW_a32, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opPREFETCH_a32, opFEMMS, op3DNOW_a32, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +const OpFn OP_TABLE(pentium_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(pentiummmx_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +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, +}; + +const OpFn OP_TABLE(k62_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opPREFETCH_a16, opFEMMS, op3DNOW_a16, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, opPREFETCH_a16, opFEMMS, op3DNOW_a16, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, 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, opPREFETCH_a32, opFEMMS, op3DNOW_a32, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, 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, opPREFETCH_a32, opFEMMS, op3DNOW_a32, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +const OpFn OP_TABLE(c6x86mx_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +#ifdef DEV_BRANCH +#ifdef USE_I686 +const OpFn OP_TABLE(pentiumpro_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +#if 0 +const OpFn OP_TABLE(pentium2_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; +#endif + +const OpFn OP_TABLE(pentium2d_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,opFXSAVESTOR_a16,opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,opFXSAVESTOR_a16,opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,opFXSAVESTOR_a32,opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,opFXSAVESTOR_a32,opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; +#endif +#endif + +const OpFn OP_TABLE(286)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, +}; + +const OpFn OP_TABLE(386)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, opFS_w_a16, opGS_w_a16, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_l_rmw_a16,opADD_b_rm_a16, opADD_l_rm_a16, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a16, opOR_l_rmw_a16, opOR_b_rm_a16, opOR_l_rm_a16, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a16, +/*10*/ opADC_b_rmw_a16,opADC_l_rmw_a16,opADC_b_rm_a16, opADC_l_rm_a16, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a16,opSBB_l_rmw_a16,opSBB_b_rm_a16, opSBB_l_rm_a16, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l, +/*20*/ opAND_b_rmw_a16,opAND_l_rmw_a16,opAND_b_rm_a16, opAND_l_rm_a16, opAND_AL_imm, opAND_EAX_imm, opES_l_a16, opDAA, opSUB_b_rmw_a16,opSUB_l_rmw_a16,opSUB_b_rm_a16, opSUB_l_rm_a16, opSUB_AL_imm, opSUB_EAX_imm, opCS_l_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_l_rmw_a16,opXOR_b_rm_a16, opXOR_l_rm_a16, opXOR_AL_imm, opXOR_EAX_imm, opSS_l_a16, opAAA, opCMP_b_rmw_a16,opCMP_l_rmw_a16,opCMP_b_rm_a16, opCMP_l_rm_a16, opCMP_AL_imm, opCMP_EAX_imm, opDS_l_a16, opAAS, + +/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a16, opARPL_a16, opFS_l_a16, opGS_l_a16, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a16,opPUSH_imm_bl, opIMUL_l_ib_a16,opINSB_a16, opINSL_a16, opOUTSB_a16, opOUTSL_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_l_a16, op80_a16, op83_l_a16, opTEST_b_a16, opTEST_l_a16, opXCHG_b_a16, opXCHG_l_a16, opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, opMOV_l_seg_a16,opLEA_l_a16, opMOV_seg_w_a16,opPOPL_a16, +/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_EAX_a16, opMOV_a16_AL, opMOV_a16_EAX, opMOVSB_a16, opMOVSL_a16, opCMPSB_a16, opCMPSL_a16, opTEST_AL, opTEST_EAX, opSTOSB_a16, opSTOSL_a16, opLODSB_a16, opLODSL_a16, opSCASB_a16, opSCASL_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm, + +/*c0*/ opC0_a16, opC1_l_a16, opRET_l_imm, opRET_l, opLES_l_a16, opLDS_l_a16, opMOV_b_imm_a16,opMOV_l_imm_a16,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, +/*d0*/ opD0_a16, opD1_l_a16, opD2_a16, opD3_l_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_l_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_l_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a32,opADD_w_rmw_a32,opADD_b_rm_a32, opADD_w_rm_a32, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a32, opOR_w_rmw_a32, opOR_b_rm_a32, opOR_w_rm_a32, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a32, +/*10*/ opADC_b_rmw_a32,opADC_w_rmw_a32,opADC_b_rm_a32, opADC_w_rm_a32, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a32,opSBB_w_rmw_a32,opSBB_b_rm_a32, opSBB_w_rm_a32, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a32,opAND_w_rmw_a32,opAND_b_rm_a32, opAND_w_rm_a32, opAND_AL_imm, opAND_AX_imm, opES_w_a32, opDAA, opSUB_b_rmw_a32,opSUB_w_rmw_a32,opSUB_b_rm_a32, opSUB_w_rm_a32, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a32, opDAS, +/*30*/ opXOR_b_rmw_a32,opXOR_w_rmw_a32,opXOR_b_rm_a32, opXOR_w_rm_a32, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a32, opAAA, opCMP_b_rmw_a32,opCMP_w_rmw_a32,opCMP_b_rm_a32, opCMP_w_rm_a32, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a32, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a32, opARPL_a32, opFS_w_a32, opGS_w_a32, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a32,opPUSH_imm_bw, opIMUL_w_ib_a32,opINSB_a32, opINSW_a32, opOUTSB_a32, opOUTSW_a32, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a32, op81_w_a32, op80_a32, op83_w_a32, opTEST_b_a32, opTEST_w_a32, opXCHG_b_a32, opXCHG_w_a32, opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, opMOV_w_seg_a32,opLEA_w_a32, opMOV_seg_w_a32,opPOPW_a32, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a32, opMOV_AX_a32, opMOV_a32_AL, opMOV_a32_AX, opMOVSB_a32, opMOVSW_a32, opCMPSB_a32, opCMPSW_a32, opTEST_AL, opTEST_AX, opSTOSB_a32, opSTOSW_a32, opLODSB_a32, opLODSW_a32, opSCASB_a32, opSCASW_a32, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a32, opC1_w_a32, opRET_w_imm, opRET_w, opLES_w_a32, opLDS_w_a32, opMOV_b_imm_a32,opMOV_w_imm_a32,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a32, opD1_w_a32, opD2_a32, opD3_w_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, +/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_w_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_w_a32, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a32,opADD_l_rmw_a32,opADD_b_rm_a32, opADD_l_rm_a32, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a32, opOR_l_rmw_a32, opOR_b_rm_a32, opOR_l_rm_a32, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a32, +/*10*/ opADC_b_rmw_a32,opADC_l_rmw_a32,opADC_b_rm_a32, opADC_l_rm_a32, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a32,opSBB_l_rmw_a32,opSBB_b_rm_a32, opSBB_l_rm_a32, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l, +/*20*/ opAND_b_rmw_a32,opAND_l_rmw_a32,opAND_b_rm_a32, opAND_l_rm_a32, opAND_AL_imm, opAND_EAX_imm, opES_l_a32, opDAA, opSUB_b_rmw_a32,opSUB_l_rmw_a32,opSUB_b_rm_a32, opSUB_l_rm_a32, opSUB_AL_imm, opSUB_EAX_imm, opCS_l_a32, opDAS, +/*30*/ opXOR_b_rmw_a32,opXOR_l_rmw_a32,opXOR_b_rm_a32, opXOR_l_rm_a32, opXOR_AL_imm, opXOR_EAX_imm, opSS_l_a32, opAAA, opCMP_b_rmw_a32,opCMP_l_rmw_a32,opCMP_b_rm_a32, opCMP_l_rm_a32, opCMP_AL_imm, opCMP_EAX_imm, opDS_l_a32, opAAS, + +/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a32, opARPL_a32, opFS_l_a32, opGS_l_a32, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a32,opPUSH_imm_bl, opIMUL_l_ib_a32,opINSB_a32, opINSL_a32, opOUTSB_a32, opOUTSL_a32, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a32, op81_l_a32, op80_a32, op83_l_a32, opTEST_b_a32, opTEST_l_a32, opXCHG_b_a32, opXCHG_l_a32, opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, opMOV_l_seg_a32,opLEA_l_a32, opMOV_seg_w_a32,opPOPL_a32, +/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a32, opMOV_EAX_a32, opMOV_a32_AL, opMOV_a32_EAX, opMOVSB_a32, opMOVSL_a32, opCMPSB_a32, opCMPSL_a32, opTEST_AL, opTEST_EAX, opSTOSB_a32, opSTOSL_a32, opLODSB_a32, opLODSL_a32, opSCASB_a32, opSCASL_a32, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm, + +/*c0*/ opC0_a32, opC1_l_a32, opRET_l_imm, opRET_l, opLES_l_a32, opLDS_l_a32, opMOV_b_imm_a32,opMOV_l_imm_a32,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, +/*d0*/ opD0_a32, opD1_l_a32, opD2_a32, opD3_l_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, +/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_l_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_l_a32, +}; + +const OpFn OP_TABLE(REPE)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPE_w_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPE_w_a16,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPE_w_a16,0, 0, 0, 0, 0, 0, 0, opDS_REPE_w_a16,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPE_w_a16,opGS_REPE_w_a16,op_66_REPE, op_67_REPE, 0, 0, 0, 0, opREP_INSB_a16, opREP_INSW_a16, opREP_OUTSB_a16,opREP_OUTSW_a16, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a16,opREP_MOVSW_a16,opREP_CMPSB_a16_E,opREP_CMPSW_a16_E,0, 0, opREP_STOSB_a16,opREP_STOSW_a16,opREP_LODSB_a16,opREP_LODSW_a16,opREP_SCASB_a16_E,opREP_SCASW_a16_E, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPE_l_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPE_l_a16,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPE_l_a16,0, 0, 0, 0, 0, 0, 0, opDS_REPE_l_a16,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPE_l_a16,opGS_REPE_l_a16,op_66_REPE, op_67_REPE, 0, 0, 0, 0, opREP_INSB_a16, opREP_INSL_a16, opREP_OUTSB_a16,opREP_OUTSL_a16, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a16,opREP_MOVSL_a16,opREP_CMPSB_a16_E,opREP_CMPSL_a16_E,0, 0, opREP_STOSB_a16,opREP_STOSL_a16,opREP_LODSB_a16,opREP_LODSL_a16,opREP_SCASB_a16_E,opREP_SCASL_a16_E, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPE_w_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPE_w_a32,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPE_w_a32,0, 0, 0, 0, 0, 0, 0, opDS_REPE_w_a32,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPE_w_a32,opGS_REPE_w_a32,op_66_REPE, op_67_REPE, 0, 0, 0, 0, opREP_INSB_a32, opREP_INSW_a32, opREP_OUTSB_a32,opREP_OUTSW_a32, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a32,opREP_MOVSW_a32,opREP_CMPSB_a32_E,opREP_CMPSW_a32_E,0, 0, opREP_STOSB_a32,opREP_STOSW_a32,opREP_LODSB_a32,opREP_LODSW_a32,opREP_SCASB_a32_E,opREP_SCASW_a32_E, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPE_l_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPE_l_a32,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPE_l_a32,0, 0, 0, 0, 0, 0, 0, opDS_REPE_l_a32,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPE_l_a32,opGS_REPE_l_a32,op_66_REPE, op_67_REPE, 0, 0, 0, 0, opREP_INSB_a32, opREP_INSL_a32, opREP_OUTSB_a32,opREP_OUTSL_a32, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a32,opREP_MOVSL_a32,opREP_CMPSB_a32_E,opREP_CMPSL_a32_E,0, 0, opREP_STOSB_a32,opREP_STOSL_a32,opREP_LODSB_a32,opREP_LODSL_a32,opREP_SCASB_a32_E,opREP_SCASL_a32_E, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const OpFn OP_TABLE(REPNE)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPNE_w_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_w_a16,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPNE_w_a16,0, 0, 0, 0, 0, 0, 0, opDS_REPNE_w_a16,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPNE_w_a16,opGS_REPNE_w_a16,op_66_REPNE, op_67_REPNE, 0, 0, 0, 0, opREP_INSB_a16, opREP_INSW_a16, opREP_OUTSB_a16,opREP_OUTSW_a16, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a16,opREP_MOVSW_a16,opREP_CMPSB_a16_NE,opREP_CMPSW_a16_NE,0, 0, opREP_STOSB_a16,opREP_STOSW_a16,opREP_LODSB_a16,opREP_LODSW_a16,opREP_SCASB_a16_NE,opREP_SCASW_a16_NE, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPNE_l_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_l_a16,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPNE_l_a16,0, 0, 0, 0, 0, 0, 0, opDS_REPNE_l_a16,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPNE_l_a16,opGS_REPNE_l_a16,op_66_REPNE, op_67_REPNE, 0, 0, 0, 0, opREP_INSB_a16, opREP_INSL_a16, opREP_OUTSB_a16,opREP_OUTSL_a16, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a16,opREP_MOVSL_a16,opREP_CMPSB_a16_NE,opREP_CMPSL_a16_NE,0, 0, opREP_STOSB_a16,opREP_STOSL_a16,opREP_LODSB_a16,opREP_LODSL_a16,opREP_SCASB_a16_NE,opREP_SCASL_a16_NE, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPNE_w_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_w_a32,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPNE_w_a32,0, 0, 0, 0, 0, 0, 0, opDS_REPNE_w_a32,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPNE_w_a32,opGS_REPNE_w_a32,op_66_REPNE, op_67_REPNE, 0, 0, 0, 0, opREP_INSB_a32, opREP_INSW_a32, opREP_OUTSB_a32,opREP_OUTSW_a32, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a32,opREP_MOVSW_a32,opREP_CMPSB_a32_NE,opREP_CMPSW_a32_NE,0, 0, opREP_STOSB_a32,opREP_STOSW_a32,opREP_LODSB_a32,opREP_LODSW_a32,opREP_SCASB_a32_NE,opREP_SCASW_a32_NE, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPNE_l_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_l_a32,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPNE_l_a32,0, 0, 0, 0, 0, 0, 0, opDS_REPNE_l_a32,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPNE_l_a32,opGS_REPNE_l_a32,op_66_REPNE, op_67_REPNE, 0, 0, 0, 0, opREP_INSB_a32, opREP_INSL_a32, opREP_OUTSB_a32,opREP_OUTSL_a32, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a32,opREP_MOVSL_a32,opREP_CMPSB_a32_NE,opREP_CMPSL_a32_NE,0, 0, opREP_STOSB_a32,opREP_STOSL_a32,opREP_LODSB_a32,opREP_LODSL_a32,opREP_SCASB_a32_NE,opREP_SCASL_a32_NE, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; diff --git a/src/cpu_new/808x.c b/src/cpu_new/808x.c new file mode 100644 index 000000000..285f9644b --- /dev/null +++ b/src/cpu_new/808x.c @@ -0,0 +1,2883 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * 808x CPU emulation, mostly ported from reenigne's XTCE, which + * is cycle-accurate. + * + * Version: @(#)808x.c 1.0.9 2019/02/13 + * + * Authors: Andrew Jenner, + * Miran Grca, + * + * Copyright 2015-2019 Andrew Jenner. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../nmi.h" +#include "../pic.h" +#include "../timer.h" + +/* The opcode of the instruction currently being executed. */ +uint8_t opcode; + +/* The tables to speed up the setting of the Z, N, and P cpu_state.flags. */ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +/* A 16-bit zero, needed because some speed-up arrays contain pointers to it. */ +uint16_t zero = 0; + +/* MOD and R/M stuff. */ +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; +uint32_t rmdat; + +/* XT CPU multiplier. */ +uint64_t xt_cpu_multi; + +/* Is the CPU 8088 or 8086. */ +int is8086 = 0; + +/* Variables for handling the non-maskable interrupts. */ +int nmi = 0, nmi_auto_clear = 0; + +/* Was the CPU ever reset? */ +int x86_was_reset = 0; + +/* Amount of instructions executed - used to calculate the % shown in the title bar. */ +int ins = 0; + +/* Is the TRAP flag on? */ +int trap = 0; + +/* The current effective address's segment. */ +uint32_t easeg; + + +/* The prefetch queue (4 bytes for 8088, 6 bytes for 8086). */ +static uint8_t pfq[6]; + +/* Variables to aid with the prefetch queue operation. */ +static int biu_cycles = 0, pfq_pos = 0; + +/* The IP equivalent of the current prefetch queue position. */ +static uint16_t pfq_ip; + +/* Pointer tables needed for segment overrides. */ +static uint32_t *opseg[4]; +static x86seg *_opseg[4]; + +static int noint = 0; +static int in_lock = 0; +static int cpu_alu_op, pfq_size; + +static uint16_t cpu_src = 0, cpu_dest = 0; +static uint16_t cpu_data = 0, last_addr = 0x0000; + +static uint32_t *ovr_seg = NULL; +static int prefetching = 1, completed = 1; +static int in_rep = 0, repeating = 0; +static int oldc, clear_lock = 0; +static int refresh = 0, takeint = 0; +static int cycdiff; + + +/* Various things needed for 8087. */ +#define OP_TABLE(name) ops_ ## name + +#define CPU_BLOCK_END() +#define SEG_CHECK_READ(seg) +#define SEG_CHECK_WRITE(seg) +#define CHECK_READ(a, b, c) +#define CHECK_WRITE(a, b, c) +#define UN_USED(x) (void)(x) +#define fetch_ea_16(val) +#define fetch_ea_32(val) +#define PREFETCH_RUN(a, b, c, d, e, f, g, h) + +#define CYCLES(val) \ + { \ + wait(val, 0); \ + } + +#define CLOCK_CYCLES(val) \ + { \ + wait(val, 0); \ + } + +typedef int (*OpFn)(uint32_t fetchdat); + + +static int tempc_fpu = 0; + + +#ifdef ENABLE_808X_LOG +void dumpregs(int); + +int x808x_do_log = ENABLE_808X_LOG; +int indump = 0; + + +static void +x808x_log(const char *fmt, ...) +{ + va_list ap; + + if (x808x_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} + + +void +dumpregs(int force) +{ + int c; + char *seg_names[4] = { "ES", "CS", "SS", "DS" }; + + /* Only dump when needed, and only once.. */ + if (indump || (!force && !dump_on_exit)) + return; + + x808x_log("EIP=%08X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n", + cpu_state.pc, CS, DS, ES, SS, cpu_state.flags); + x808x_log("Old CS:EIP: %04X:%08X; %i ins\n", oldcs, cpu_state.oldpc, ins); + for (c = 0; c < 4; c++) { + x808x_log("%s : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_names[c], _opseg[c]->base, _opseg[c]->limit, + _opseg[c]->access, _opseg[c]->limit_low, _opseg[c]->limit_high); + } + if (is386) { + x808x_log("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_fs, cpu_state.seg_fs.limit, cpu_state.seg_fs.access, cpu_state.seg_fs.limit_low, cpu_state.seg_fs.limit_high); + x808x_log("GS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + gs, cpu_state.seg_gs.limit, cpu_state.seg_gs.access, cpu_state.seg_gs.limit_low, cpu_state.seg_gs.limit_high); + x808x_log("GDT : base=%06X limit=%04X\n", gdt.base, gdt.limit); + x808x_log("LDT : base=%06X limit=%04X\n", ldt.base, ldt.limit); + x808x_log("IDT : base=%06X limit=%04X\n", idt.base, idt.limit); + x808x_log("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + x808x_log("386 in %s mode: %i-bit data, %-i-bit stack\n", + (msw & 1) ? ((cpu_state.eflags & VM_FLAG) ? "V86" : "protected") : "real", + (use32) ? 32 : 16, (stack32) ? 32 : 16); + x808x_log("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n", cr0, cr2, cr3, cr4); + x808x_log("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n", + EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP); + } else { + x808x_log("808x/286 in %s mode\n", (msw & 1) ? "protected" : "real"); + x808x_log("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n", + AX, BX, CX, DX, DI, SI, BP, SP); + } + x808x_log("Entries in readlookup : %i writelookup : %i\n", readlnum, writelnum); + x87_dumpregs(); + indump = 0; +} +#else +#define x808x_log(fmt, ...) +#endif + + +static void pfq_add(int c, int add); +static void set_pzs(int bits); + + +uint16_t +get_last_addr(void) +{ + return last_addr; +} + + +static int +irq_pending(void) +{ + uint8_t temp; + + if (takeint && !noint) + temp = 1; + else + temp = (nmi && nmi_enable && nmi_mask) || ((cpu_state.flags & T_FLAG) && !noint); + + takeint = (cpu_state.flags & I_FLAG) && (pic.pend &~ pic.mask); + + return temp; +} + + +static void +clock_start(void) +{ + cycdiff = cycles; +} + + +static void +clock_end(void) +{ + int diff = cycdiff - cycles; + + /* On 808x systems, clock speed is usually crystal frequency divided by an integer. */ + tsc += (uint64_t)diff * ((uint64_t)xt_cpu_multi >> 32ULL); /* Shift xt_cpu_multi by 32 bits to the right and then multiply. */ + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); +} + + +static void +fetch_and_bus(int c, int bus) +{ + if (refresh > 0) { + /* Finish the current fetch, if any. */ + cycles -= ((4 - (biu_cycles & 3)) & 3); + pfq_add((4 - (biu_cycles & 3)) & 3, 1); + /* Add 4 memory access cycles. */ + cycles -= 4; + pfq_add(4, 0); + + refresh--; + } + + pfq_add(c, !bus); + clock_end(); + clock_start(); +} + + +static void +wait(int c, int bus) +{ + cycles -= c; + + fetch_and_bus(c, bus); +} + + +/* This is for external subtraction of cycles. */ +void +sub_cycles(int c) +{ + cycles -= c; + + if (!is286) + fetch_and_bus(c, 1); +} + + +#undef readmemb +#undef readmemw +#undef readmeml +#undef readmemq + +/* Common read function. */ +static uint8_t +readmemb_common(uint32_t a) +{ + uint8_t ret; + + if (readlookup2 == NULL) + ret = readmembl(a); + else { + if (readlookup2[(a) >> 12] == ((uintptr_t) -1)) + ret = readmembl(a); + else + ret = *(uint8_t *)(readlookup2[(a) >> 12] + (a)); + } + + return ret; +} + +/* Reads a byte from the memory and advances the BIU. */ +static uint8_t +readmemb(uint32_t a) +{ + uint8_t ret; + + wait(4, 1); + ret = readmemb_common(a); + + return ret; +} + + +/* Reads a byte from the memory but does not advance the BIU. */ +static uint8_t +readmembf(uint32_t a) +{ + uint8_t ret; + + a = cs + (a & 0xffff); + ret = readmemb_common(a); + + return ret; +} + + +/* Reads a word from the memory and advances the BIU. */ +static uint16_t +readmemw_common(uint32_t s, uint16_t a) +{ + uint16_t ret; + + ret = readmemb_common(s + a); + ret |= readmemb_common(s + ((a + 1) & 0xffff)) << 8; + + return ret; +} + + +static uint16_t +readmemw(uint32_t s, uint16_t a) +{ + uint16_t ret; + + if (is8086 && !(a & 1)) + wait(4, 1); + else + wait(8, 1); + ret = readmemw_common(s, a); + + return ret; +} + + +static uint16_t +readmemwf(uint16_t a) +{ + uint16_t ret; + + ret = readmemw_common(cs, a & 0xffff); + + return ret; +} + + +static uint16_t +readmem(uint32_t s) +{ + if (opcode & 1) + return readmemw(s, cpu_state.eaaddr); + else + return (uint16_t) readmemb(s + cpu_state.eaaddr); +} + + +static uint32_t +readmeml(uint32_t s, uint16_t a) +{ + uint32_t temp; + + temp = (uint32_t) (readmemw(s, a + 2)) << 16; + temp |= readmemw(s, a); + + return temp; +} + + +static uint64_t +readmemq(uint32_t s, uint16_t a) +{ + uint64_t temp; + + temp = (uint64_t) (readmeml(s, a + 4)) << 32; + temp |= readmeml(s, a); + + return temp; +} + + +static void +writememb_common(uint32_t a, uint8_t v) +{ + if (writelookup2 == NULL) + writemembl(a, v); + else { + if (writelookup2[(a) >> 12] == ((uintptr_t) -1)) + writemembl(a, v); + else + *(uint8_t *)(writelookup2[a >> 12] + a) = v; + } + + if ((a >= 0xf0000) && (a <= 0xfffff)) + last_addr = a & 0xffff; +} + + +/* Writes a byte to the memory and advances the BIU. */ +static void +writememb(uint32_t s, uint32_t a, uint8_t v) +{ + wait(4, 1); + writememb_common(s + a, v); +} + + +/* Writes a word to the memory and advances the BIU. */ +static void +writememw(uint32_t s, uint32_t a, uint16_t v) +{ + if (is8086 && !(a & 1)) + wait(4, 1); + else + wait(8, 1); + writememb_common(s + a, v & 0xff); + writememb_common(s + ((a + 1) & 0xffff), v >> 8); +} + + +static void +writemem(uint32_t s, uint16_t v) +{ + if (opcode & 1) + return writememw(s, cpu_state.eaaddr, v); + else + return writememb(s, cpu_state.eaaddr, (uint8_t) (v & 0xff)); +} + + +static void +writememl(uint32_t s, uint32_t a, uint32_t v) +{ + writememw(s, a, v & 0xffff); + writememw(s, a + 2, v >> 16); +} + + +static void +writememq(uint32_t s, uint32_t a, uint64_t v) +{ + writememl(s, a, v & 0xffffffff); + writememl(s, a + 4, v >> 32); +} + + +static void +pfq_write(void) +{ + uint16_t tempw; + + if (is8086 && (pfq_pos < (pfq_size - 1))) { + /* The 8086 fetches 2 bytes at a time, and only if there's at least 2 bytes + free in the queue. */ + tempw = readmemwf(pfq_ip); + *(uint16_t *) &(pfq[pfq_pos]) = tempw; + pfq_ip += 2; + pfq_pos += 2; + } else if (!is8086 && (pfq_pos < pfq_size)) { + /* The 8088 fetches 1 byte at a time, and only if there's at least 1 byte + free in the queue. */ + pfq[pfq_pos] = readmembf(pfq_ip); + pfq_ip++; + pfq_pos++; + } +} + + +static uint8_t +pfq_read(void) +{ + uint8_t temp, i; + + temp = pfq[0]; + for (i = 0; i < (pfq_size - 1); i++) + pfq[i] = pfq[i + 1]; + pfq_pos--; + cpu_state.pc = (cpu_state.pc + 1) & 0xffff; + return temp; +} + + +/* Fetches a byte from the prefetch queue, or from memory if the queue has + been drained. */ +static uint8_t +pfq_fetchb_common(void) +{ + uint8_t temp; + + if (pfq_pos == 0) { + /* Reset prefetch queue internal position. */ + pfq_ip = cpu_state.pc; + /* Fill the queue. */ + wait(4 - (biu_cycles & 3), 0); + } + + /* Fetch. */ + temp = pfq_read(); + return temp; +} + + +static uint8_t +pfq_fetchb(void) +{ + uint8_t ret; + + ret = pfq_fetchb_common(); + wait(1, 0); + return ret; +} + + +/* Fetches a word from the prefetch queue, or from memory if the queue has + been drained. */ +static uint16_t +pfq_fetchw(void) +{ + uint16_t temp; + + temp = pfq_fetchb_common(); + wait(1, 0); + temp |= (pfq_fetchb_common() << 8); + + return temp; +} + + +static uint16_t +pfq_fetch() +{ + if (opcode & 1) + return pfq_fetchw(); + else + return (uint16_t) pfq_fetchb(); +} + + +/* Adds bytes to the prefetch queue based on the instruction's cycle count. */ +static void +pfq_add(int c, int add) +{ + int d; + + if ((c <= 0) || (pfq_pos >= pfq_size)) + return; + + for (d = 0; d < c; d++) { + biu_cycles = (biu_cycles + 1) & 0x03; + if (prefetching && add && (biu_cycles == 0x00)) + pfq_write(); + } +} + + +/* Clear the prefetch queue - called on reset and on anything that affects either CS or IP. */ +static void +pfq_clear() +{ + pfq_pos = 0; + prefetching = 0; +} + + +static void +set_ip(uint16_t new_ip) { + pfq_ip = cpu_state.pc = new_ip; + prefetching = 1; +} + + +/* Memory refresh read - called by reads and writes on DMA channel 0. */ +void +refreshread(void) { + refresh++; +} + + +/* Preparation of the various arrays needed to speed up the MOD and R/M work. */ +static void +makemod1table(void) +{ + mod1add[0][0] = &BX; + mod1add[0][1] = &BX; + mod1add[0][2] = &BP; + mod1add[0][3] = &BP; + mod1add[0][4] = &SI; + mod1add[0][5] = &DI; + mod1add[0][6] = &BP; + mod1add[0][7] = &BX; + mod1add[1][0] = &SI; + mod1add[1][1] = &DI; + mod1add[1][2] = &SI; + mod1add[1][3] = &DI; + mod1add[1][4] = &zero; + mod1add[1][5] = &zero; + mod1add[1][6] = &zero; + mod1add[1][7] = &zero; + mod1seg[0] = &ds; + mod1seg[1] = &ds; + mod1seg[2] = &ss; + mod1seg[3] = &ss; + mod1seg[4] = &ds; + mod1seg[5] = &ds; + mod1seg[6] = &ss; + mod1seg[7] = &ds; + opseg[0] = &es; + opseg[1] = &cs; + opseg[2] = &ss; + opseg[3] = &ds; + _opseg[0] = &cpu_state.seg_es; + _opseg[1] = &cpu_state.seg_cs; + _opseg[2] = &cpu_state.seg_ss; + _opseg[3] = &cpu_state.seg_ds; +} + + +static uint16_t +sign_extend(uint8_t data) +{ + return data + (data < 0x80 ? 0 : 0xff00); +} + + +/* Fetches the effective address from the prefetch queue according to MOD and R/M. */ +static void +do_mod_rm(void) +{ + rmdat = pfq_fetchb(); + cpu_reg = (rmdat >> 3) & 7; + cpu_mod = (rmdat >> 6) & 3; + cpu_rm = rmdat & 7; + + if (cpu_mod == 3) + return; + + wait(1, 0); + if ((rmdat & 0xc7) == 0x06) { + wait(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + easeg = ovr_seg ? *ovr_seg : ds; + wait(1, 0); + return; + } else switch (cpu_rm) { + case 0: + case 3: + wait(2, 0); + break; + case 1: + case 2: + wait(3, 0); + break; + } + cpu_state.eaaddr = (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + easeg = ovr_seg ? *ovr_seg : *mod1seg[cpu_rm]; + switch (rmdat & 0xc0) { + case 0x40: + wait(3, 0); + cpu_state.eaaddr += sign_extend(pfq_fetchb()); + break; + case 0x80: + wait(3, 0); + cpu_state.eaaddr += pfq_fetchw(); + break; + } + cpu_state.eaaddr &= 0xffff; + wait(2, 0); +} + + +#undef getr8 +#define getr8(r) ((r & 4) ? cpu_state.regs[r & 3].b.h : cpu_state.regs[r & 3].b.l) + +#undef setr8 +#define setr8(r,v) if (r & 4) cpu_state.regs[r & 3].b.h = v; \ + else cpu_state.regs[r & 3].b.l = v; + + +/* Reads a byte from the effective address. */ +static uint8_t +geteab(void) +{ + if (cpu_mod == 3) + return (getr8(cpu_rm)); + + return readmemb(easeg + cpu_state.eaaddr); +} + + +/* Reads a word from the effective address. */ +static uint16_t +geteaw(void) +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + + return readmemw(easeg, cpu_state.eaaddr); +} + + +/* Neede for 8087 - memory only. */ +static uint32_t +geteal(void) +{ + if (cpu_mod == 3) { + fatal("808x register geteal()\n"); + return 0xffffffff; + } + + return readmeml(easeg, cpu_state.eaaddr); +} + + +/* Neede for 8087 - memory only. */ +static uint64_t +geteaq(void) +{ + if (cpu_mod == 3) { + fatal("808x register geteaq()\n"); + return 0xffffffff; + } + + return readmemq(easeg, cpu_state.eaaddr); +} + + +static void +read_ea(int memory_only, int bits) +{ + if (cpu_mod != 3) { + if (bits == 16) + cpu_data = readmemw(easeg, cpu_state.eaaddr); + else + cpu_data = readmemb(easeg + cpu_state.eaaddr); + return; + } + if (!memory_only) { + if (bits == 8) { + cpu_data = getr8(cpu_rm); + } else + cpu_data = cpu_state.regs[cpu_rm].w; + } +} + + +static void +read_ea2(int bits) +{ + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; + if (bits == 16) + cpu_data = readmemw(easeg, cpu_state.eaaddr); + else + cpu_data = readmemb(easeg + cpu_state.eaaddr); +} + + +/* Writes a byte to the effective address. */ +static void +seteab(uint8_t val) +{ + if (cpu_mod == 3) { + setr8(cpu_rm, val); + } else + writememb(easeg, cpu_state.eaaddr, val); +} + + +/* Writes a word to the effective address. */ +static void +seteaw(uint16_t val) +{ + if (cpu_mod == 3) + cpu_state.regs[cpu_rm].w = val; + else + writememw(easeg, cpu_state.eaaddr, val); +} + + +static void +seteal(uint32_t val) +{ + if (cpu_mod == 3) { + fatal("808x register seteal()\n"); + return; + } else + writememl(easeg, cpu_state.eaaddr, val); +} + + +static void +seteaq(uint64_t val) +{ + if (cpu_mod == 3) { + fatal("808x register seteaq()\n"); + return; + } else + writememq(easeg, cpu_state.eaaddr, val); +} + + +/* Leave out the 686 stuff as it's not needed and + complicates compiling. */ +#define FPU_8087 +#define tempc tempc_fpu +#include "x87.h" +#include "x87_ops.h" +#undef tempc +#undef FPU_8087 + + +/* Prepare the ZNP table needed to speed up the setting of the Z, N, and P cpu_state.flags. */ +static void +makeznptable(void) +{ + int c, d, e; + for (c = 0; c < 256; c++) { + d = 0; + for (e = 0; e < 8; e++) { + if (c & (1 << e)) + d++; + } + if (d & 1) + znptable8[c] = 0; + else + znptable8[c] = P_FLAG; +#ifdef ENABLE_808X_LOG + if (c == 0xb1) + x808x_log("znp8 b1 = %i %02X\n", d, znptable8[c]); +#endif + if (!c) + znptable8[c] |= Z_FLAG; + if (c & 0x80) + znptable8[c] |= N_FLAG; + } + + for (c = 0; c < 65536; c++) { + d = 0; + for (e = 0; e < 8; e++) { + if (c & (1 << e)) + d++; + } + if (d & 1) + znptable16[c] = 0; + else + znptable16[c] = P_FLAG; +#ifdef ENABLE_808X_LOG + if (c == 0xb1) + x808x_log("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) + x808x_log("znp16 65b1 = %i %02X\n", d, znptable16[c]); +#endif + if (!c) + znptable16[c] |= Z_FLAG; + if (c & 0x8000) + znptable16[c] |= N_FLAG; + } +} + + +/* Common reset function. */ +static void +reset_common(int hard) +{ + biu_cycles = 0; + in_rep = 0; + in_lock = 0; + completed = 1; + repeating = 0; + clear_lock = 0; + refresh = 0; + + if (hard) { +#ifdef ENABLE_808X_LOG + x808x_log("x86 reset\n"); +#endif + ins = 0; + } + use32 = 0; + cpu_cur_status = 0; + stack32 = 0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw = 0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + cpu_state.eflags = 0; + cgate32 = 0; + if (AT) { + loadcs(0xF000); + cpu_state.pc = 0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + } else { + loadcs(0xFFFF); + cpu_state.pc = 0; + rammask = 0xfffff; + } + idt.base = 0; + idt.limit = is386 ? 0x03FF : 0xFFFF; + cpu_state.flags = 2; + trap = 0; + ovr_seg = NULL; + in_lock = 0; + + EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0; + + if (hard) { + makeznptable(); + resetreadlookup(); + makemod1table(); + resetmcr(); + pfq_clear(); + cpu_set_edx(); + mmu_perm = 4; + pfq_size = (is8086) ? 6 : 4; + } + x86seg_reset(); +#ifdef USE_DYNAREC + if (hard) + codegen_reset(); +#endif + if (!hard) + flushmmucache(); + x86_was_reset = 1; + cpu_alt_reset = 0; + + prefetching = 1; + takeint = 0; +} + + +/* Hard reset. */ +void +resetx86(void) +{ + reset_common(1); +} + + +/* Soft reset. */ +void +softresetx86(void) +{ + reset_common(0); +} + + +/* Pushes a word to the stack. */ +static void +push(uint16_t *val) +{ + SP -= 2; + cpu_state.eaaddr = (SP & 0xffff); + writememw(ss, cpu_state.eaaddr, *val); +} + + +/* Pops a word from the stack. */ +static uint16_t +pop(void) +{ + cpu_state.eaaddr = (SP & 0xffff); + SP += 2; + return readmemw(ss, cpu_state.eaaddr); +} + + +static void +access(int num, int bits) +{ + switch (num) { + case 0: case 61: case 63: case 64: + case 67: case 69: case 71: case 72: + default: + break; + case 1: case 6: case 7: case 8: + case 9: case 17: case 20: case 21: + case 24: case 28: case 47: case 48: + case 49: case 50: case 51: case 55: + case 56: case 62: case 66: case 68: + wait(1, 0); + break; + case 3: case 11: case 15: case 22: + case 23: case 25: case 26: case 35: + case 44: case 45: case 46: case 52: + case 53: case 54: + wait(2, 0); + break; + case 16: case 18: case 19: case 27: + case 32: case 37: case 42: + wait(3, 0); + break; + case 10: case 12: case 13: case 14: + case 29: case 30: case 33: case 34: + case 39: case 41: case 60: + wait(4, 0); + break; + case 4: case 70: + wait(5, 0); + break; + case 31: case 38: case 40: + wait(6, 0); + break; + case 5: + if (opcode == 0xcc) + wait(7, 0); + else + wait(4, 0); + break; + case 36: + wait(1, 0); + pfq_clear(); + wait (1, 0); + if (cpu_mod != 3) + wait(1, 0); + wait(3, 0); + break; + case 43: + wait(2, 0); + pfq_clear(); + wait(1, 0); + break; + case 57: + if (cpu_mod != 3) + wait(2, 0); + wait(4, 0); + break; + case 58: + if (cpu_mod != 3) + wait(1, 0); + wait(4, 0); + break; + case 59: + wait(2, 0); + pfq_clear(); + if (cpu_mod != 3) + wait(1, 0); + wait(3, 0); + break; + case 65: + wait(1, 0); + pfq_clear(); + wait(2, 0); + if (cpu_mod != 3) + wait(1, 0); + break; + } +} + + +/* Calls an interrupt. */ +static void +interrupt(uint16_t addr) +{ + uint16_t old_cs, old_ip; + uint16_t new_cs, new_ip; + uint16_t tempf; + + addr <<= 2; + cpu_state.eaaddr = addr; + old_cs = CS; + access(5, 16); + new_ip = readmemw(0, cpu_state.eaaddr); + wait(1, 0); + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; + access(6, 16); + new_cs = readmemw(0, cpu_state.eaaddr); + pfq_clear(); + access(39, 16); + tempf = cpu_state.flags & 0x0fd7; + push(&tempf); + cpu_state.flags &= ~(I_FLAG | T_FLAG); + access(40, 16); + push(&old_cs); + old_ip = cpu_state.pc; + loadcs(new_cs); + access(68, 16); + set_ip(new_ip); + access(41, 16); + push(&old_ip); +} + + +static void +check_interrupts(void) +{ + int temp; + + if (irq_pending()) { + if ((cpu_state.flags & T_FLAG) && !noint) { + interrupt(1); + return; + } + if (nmi && nmi_enable && nmi_mask) { + nmi_enable = 0; + interrupt(2); + return; + } + temp = picinterrupt(); + if (temp != -1) { + repeating = 0; + completed = 1; + ovr_seg = NULL; + in_lock = 0; + clear_lock = 0; + ovr_seg = NULL; + wait(9, 0); + interrupt((uint16_t) (temp & 0xffff)); + } + } +} + + +static int +rep_action(int bits) +{ + uint16_t t; + + if (in_rep == 0) + return 0; + wait(2, 0); + t = CX; + if (irq_pending() && (repeating != 0)) { + access(71, bits); + pfq_clear(); + set_ip(cpu_state.pc - 2); + t = 0; + } + if (t == 0) { + wait(1, 0); + completed = 1; + repeating = 0; + return 1; + } + --CX; + completed = 0; + wait(2, 0); + if (!repeating) + wait(2, 0); + return 0; +} + + +static uint16_t +jump(uint16_t delta) +{ + uint16_t old_ip; + access(67, 8); + pfq_clear(); + wait(5, 0); + old_ip = cpu_state.pc; + set_ip((cpu_state.pc + delta) & 0xffff); + return old_ip; +} + + +static void +jump_short(void) +{ + jump(sign_extend((uint8_t) cpu_data)); +} + + +static uint16_t +jump_near(void) +{ + return jump(pfq_fetchw()); +} + + +/* Performs a conditional jump. */ +static void +jcc(uint8_t opcode, int cond) +{ + /* int8_t offset; */ + + wait(1, 0); + cpu_data = pfq_fetchb(); + wait(1, 0); + if ((!cond) == (opcode & 0x01)) + jump_short(); +} + + +static void +set_cf(int cond) +{ + cpu_state.flags = (cpu_state.flags & ~C_FLAG) | (cond ? C_FLAG : 0); +} + + +static void +set_if(int cond) +{ + cpu_state.flags = (cpu_state.flags & ~I_FLAG) | (cond ? I_FLAG : 0); +} + + +static void +set_df(int cond) +{ + cpu_state.flags = (cpu_state.flags & ~D_FLAG) | (cond ? D_FLAG : 0); +} + + +static void +bitwise(int bits, uint16_t data) +{ + cpu_data = data; + cpu_state.flags &= ~(C_FLAG | A_FLAG | V_FLAG); + set_pzs(bits); +} + + +static void +test(int bits, uint16_t dest, uint16_t src) +{ + cpu_dest = dest; + cpu_src = src; + bitwise(bits, (cpu_dest & cpu_src)); +} + + +static void +set_of(int of) +{ + cpu_state.flags = (cpu_state.flags & ~0x800) | (of ? 0x800 : 0); +} + + +static int +top_bit(uint16_t w, int bits) +{ + if (bits == 16) + return ((w & 0x8000) != 0); + else + return ((w & 0x80) != 0); +} + + +static void +set_of_add(int bits) +{ + set_of(top_bit((cpu_data ^ cpu_src) & (cpu_data ^ cpu_dest), bits)); +} + + +static void +set_of_sub(int bits) +{ + set_of(top_bit((cpu_dest ^ cpu_src) & (cpu_data ^ cpu_dest), bits)); +} + + +static void +set_af(int af) +{ + cpu_state.flags = (cpu_state.flags & ~0x10) | (af ? 0x10 : 0); +} + + +static void +do_af(void) +{ + set_af(((cpu_data ^ cpu_src ^ cpu_dest) & 0x10) != 0); +} + + +static void +set_apzs(int bits) +{ + set_pzs(bits); + do_af(); +} + + +static void +add(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_data = cpu_dest + cpu_src; + set_apzs(bits); + set_of_add(bits); + + /* Anything - FF with carry on is basically anything + 0x100: value stays + unchanged but carry goes on. */ + if ((cpu_alu_op == 2) && !(cpu_src & size_mask) && (cpu_state.flags & C_FLAG)) + cpu_state.flags |= C_FLAG; + else + set_cf((cpu_src & size_mask) > (cpu_data & size_mask)); +} + + +static void +sub(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_data = cpu_dest - cpu_src; + set_apzs(bits); + set_of_sub(bits); + + /* Anything - FF with carry on is basically anything - 0x100: value stays + unchanged but carry goes on. */ + if ((cpu_alu_op == 3) && !(cpu_src & size_mask) && (cpu_state.flags & C_FLAG)) + cpu_state.flags |= C_FLAG; + else + set_cf((cpu_src & size_mask) > (cpu_dest & size_mask)); +} + + +static void +alu_op(int bits) +{ + switch(cpu_alu_op) { + case 1: + bitwise(bits, (cpu_dest | cpu_src)); + break; + case 2: + if (cpu_state.flags & C_FLAG) + cpu_src++; + /* Fall through. */ + case 0: + add(bits); + break; + case 3: + if (cpu_state.flags & C_FLAG) + cpu_src++; + /* Fall through. */ + case 5: case 7: + sub(bits); + break; + case 4: + test(bits, cpu_dest, cpu_src); + break; + case 6: + bitwise(bits, (cpu_dest ^ cpu_src)); + break; + } +} + + +static void +set_sf(int bits) +{ + cpu_state.flags = (cpu_state.flags & ~0x80) | (top_bit(cpu_data, bits) ? 0x80 : 0); +} + + +static void +set_pf(void) +{ + static uint8_t table[0x100] = { + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0, + 4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4}; + + cpu_state.flags = (cpu_state.flags & ~4) | table[cpu_data & 0xff]; +} + + +static void +mul(uint16_t a, uint16_t b) +{ + int negate = 0; + int bit_count = 8; + int carry, i; + uint16_t high_bit = 0x80; + uint16_t size_mask; + uint16_t c, r; + + size_mask = (1 << bit_count) - 1; + + if (opcode != 0xd5) { + if (opcode & 1) { + bit_count = 16; + high_bit = 0x8000; + } else + wait(8, 0); + + size_mask = (1 << bit_count) - 1; + + if ((rmdat & 0x38) == 0x28) { + if (!top_bit(a, bit_count)) { + if (top_bit(b, bit_count)) { + wait(1, 0); + if ((b & size_mask) != ((opcode & 1) ? 0x8000 : 0x80)) + wait(1, 0); + b = ~b + 1; + negate = 1; + } + } else { + wait(1, 0); + a = ~a + 1; + negate = 1; + if (top_bit(b, bit_count)) { + b = ~b + 1; + negate = 0; + } else + wait(4, 0); + } + wait(10, 0); + } + wait(3, 0); + } + + c = 0; + a &= size_mask; + carry = (a & 1) != 0; + a >>= 1; + for (i = 0; i < bit_count; ++i) { + wait(7, 0); + if (carry) { + cpu_src = c; + cpu_dest = b; + add(bit_count); + c = cpu_data & size_mask; + wait(1, 0); + carry = !!(cpu_state.flags & C_FLAG); + } + r = (c >> 1) + (carry ? high_bit : 0); + carry = (c & 1) != 0; + c = r; + r = (a >> 1) + (carry ? high_bit : 0); + carry = (a & 1) != 0; + a = r; + } + if (negate) { + c = ~c; + a = (~a + 1) & size_mask; + if (a == 0) + ++c; + wait(9, 0); + } + cpu_data = a; + cpu_dest = c; + + set_sf(bit_count); + set_pf(); +} + + +static void +set_of_rotate(int bits) +{ + set_of(top_bit(cpu_data ^ cpu_dest, bits)); +} + + +static void +set_zf(int bits) +{ + int size_mask = (1 << bits) - 1; + + cpu_state.flags = (cpu_state.flags & ~0x40) | (((cpu_data & size_mask) == 0) ? 0x40 : 0); +} + + +static void +set_pzs(int bits) +{ + set_pf(); + set_zf(bits); + set_sf(bits); +} + + +static void +set_co_mul(int carry) +{ + set_cf(carry); + set_of(carry); + if (!carry) + wait(1, 0); +} + + +/* Was div(), renamed to avoid conflicts with stdlib div(). */ +static int +x86_div(uint16_t l, uint16_t h) +{ + int b, bit_count = 8; + int negative = 0; + int dividend_negative = 0; + int size_mask, carry; + uint16_t r; + + if (opcode & 1) { + l = AX; + h = DX; + bit_count = 16; + } + + size_mask = (1 << bit_count) - 1; + + if (opcode != 0xd4) { + if ((rmdat & 0x38) == 0x38) { + if (top_bit(h, bit_count)) { + h = ~h; + l = (~l + 1) & size_mask; + if (l == 0) + ++h; + h &= size_mask; + negative = 1; + dividend_negative = 1; + wait(4, 0); + } + if (top_bit(cpu_src, bit_count)) { + cpu_src = ~cpu_src + 1; + negative = !negative; + } else + wait(1, 0); + wait(9, 0); + } + wait(3, 0); + } + wait(8, 0); + cpu_src &= size_mask; + if (h >= cpu_src) { + if (opcode != 0xd4) + wait(1, 0); + interrupt(0); + return 0; + } + if (opcode != 0xd4) + wait(1, 0); + wait(2, 0); + carry = 1; + for (b = 0; b < bit_count; ++b) { + r = (l << 1) + (carry ? 1 : 0); + carry = top_bit(l, bit_count); + l = r; + r = (h << 1) + (carry ? 1 : 0); + carry = top_bit(h, bit_count); + h = r; + wait(8, 0); + if (carry) { + carry = 0; + h -= cpu_src; + if (b == bit_count - 1) + wait(2, 0); + } else { + carry = cpu_src > h; + if (!carry) { + h -= cpu_src; + wait(1, 0); + if (b == bit_count - 1) + wait(2, 0); + } + } + } + l = ~((l << 1) + (carry ? 1 : 0)); + if (opcode != 0xd4 && (rmdat & 0x38) == 0x38) { + wait(4, 0); + if (top_bit(l, bit_count)) { + if (cpu_mod == 3) + wait(1, 0); + interrupt(0); + return 0; + } + wait(7, 0); + if (negative) + l = ~l + 1; + if (dividend_negative) + h = ~h + 1; + } + if (opcode == 0xd4) { + AL = h & 0xff; + AH = l & 0xff; + } else { + AH = h & 0xff; + AL = l & 0xff; + if (opcode & 1) { + DX = h; + AX = l; + } + } + return 1; +} + + +static uint16_t +string_increment(int bits) +{ + int d = bits >> 3; + if (cpu_state.flags & D_FLAG) + cpu_state.eaaddr -= d; + else + cpu_state.eaaddr += d; + cpu_state.eaaddr &= 0xffff; + return cpu_state.eaaddr; +} + + +static void +lods(int bits) +{ + cpu_state.eaaddr = SI; + if (bits == 16) + cpu_data = readmemw((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); + else + cpu_data = readmemb((ovr_seg ? *ovr_seg : ds) + cpu_state.eaaddr); + SI = string_increment(bits); +} + + +static void +stos(int bits) +{ + cpu_state.eaaddr = DI; + if (bits == 16) + writememw(es, cpu_state.eaaddr, cpu_data); + else + writememb(es, cpu_state.eaaddr, (uint8_t) (cpu_data & 0xff)); + DI = string_increment(bits); +} + + +static void +da(void) +{ + set_pzs(8); + wait(2, 0); +} + + +static void +aa(void) +{ + set_of(0); + AL &= 0x0f; + wait(6, 0); +} + + +static void +set_ca(void) +{ + set_cf(1); + set_af(1); +} + + +static void +clear_ca(void) +{ + set_cf(0); + set_af(0); +} + + +static uint16_t +get_ea(void) +{ + if (opcode & 1) + return geteaw(); + else + return (uint16_t) geteab(); +} + + +static uint16_t +get_reg(uint8_t reg) +{ + if (opcode & 1) + return cpu_state.regs[reg].w; + else + return (uint16_t) getr8(reg); +} + + +static void +set_ea(uint16_t val) +{ + if (opcode & 1) + seteaw(val); + else + seteab((uint8_t) (val & 0xff)); +} + + +static void +set_reg(uint8_t reg, uint16_t val) +{ + if (opcode & 1) + cpu_state.regs[reg].w = val; + else + setr8(reg, (uint8_t) (val & 0xff)); +} + + +static void +cpu_data_opff_rm(void) { + if (!(opcode & 1)) { + if (cpu_mod != 3) + cpu_data |= 0xff00; + else + cpu_data = cpu_state.regs[cpu_rm].w; + } +} + + +/* Executes instructions up to the specified number of cycles. */ +void +execx86(int cycs) +{ + uint8_t temp = 0, temp2; + uint16_t addr, tempw; + uint16_t new_cs, new_ip; + int bits; + + cycles += cycs; + + while (cycles > 0) { + clock_start(); + + if (!repeating) { + cpu_state.oldpc = cpu_state.pc; + opcode = pfq_fetchb(); + oldc = cpu_state.flags & C_FLAG; + if (clear_lock) { + in_lock = 0; + clear_lock = 0; + } + wait(1, 0); + } + + completed = 1; + switch (opcode) { + case 0x06: case 0x0E: case 0x16: case 0x1E: /* PUSH seg */ + access(29, 16); + push(&(_opseg[(opcode >> 3) & 0x03]->seg)); + break; + case 0x07: case 0x0F: case 0x17: case 0x1F: /* POP seg */ + access(22, 16); + if (opcode == 0x0F) { + loadcs(pop()); + pfq_pos = 0; + } else + loadseg(pop(), _opseg[(opcode >> 3) & 0x03]); + wait(1, 0); + /* All POP segment instructions suppress interrupts for one instruction. */ + noint = 1; + break; + + case 0x26: /*ES:*/ + case 0x2E: /*CS:*/ + case 0x36: /*SS:*/ + case 0x3E: /*DS:*/ + wait(1, 0); + ovr_seg = opseg[(opcode >> 3) & 0x03]; + completed = 0; + break; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x38: case 0x39: case 0x3a: case 0x3b: + /* alu rm, r / r, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(46, bits); + tempw = get_ea(); + cpu_alu_op = (opcode >> 3) & 7; + if ((opcode & 2) == 0) { + cpu_dest = tempw; + cpu_src = get_reg(cpu_reg); + } else { + cpu_dest = get_reg(cpu_reg); + cpu_src = tempw; + } + if (cpu_mod != 3) + wait(2, 0); + wait(1, 0); + alu_op(bits); + if (cpu_alu_op != 7) { + if ((opcode & 2) == 0) { + access(10, bits); + set_ea(cpu_data); + if (cpu_mod == 3) + wait(1, 0); + } else { + set_reg(cpu_reg, cpu_data); + wait(1, 0); + } + } else + wait(1, 0); + break; + + case 0x04: case 0x05: case 0x0c: case 0x0d: + case 0x14: case 0x15: case 0x1c: case 0x1d: + case 0x24: case 0x25: case 0x2c: case 0x2d: + case 0x34: case 0x35: case 0x3c: case 0x3d: + /* alu A, imm */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_data = pfq_fetch(); + cpu_dest = get_reg(0); /* AX/AL */ + cpu_src = cpu_data; + cpu_alu_op = (opcode >> 3) & 7; + alu_op(bits); + if (cpu_alu_op != 7) + set_reg(0, cpu_data); + wait(1, 0); + break; + + case 0x27: /*DAA*/ + wait(1, 0); + if ((cpu_state.flags & A_FLAG) || (AL & 0x0f) > 9) { + cpu_data = AL + 6; + AL = (uint8_t) cpu_data; + set_af(1); + if ((cpu_data & 0x100) != 0) + set_cf(1); + } + if ((cpu_state.flags & C_FLAG) || AL > 0x9f) { + AL += 0x60; + set_cf(1); + } + da(); + break; + case 0x2F: /*DAS*/ + wait(1, 0); + temp = AL; + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + cpu_data = AL - 6; + AL = (uint8_t) cpu_data; + set_af(1); + if ((cpu_data & 0x100) != 0) + set_cf(1); + } + if ((cpu_state.flags & C_FLAG) || temp > 0x9f) { + AL -= 0x60; + set_cf(1); + } + da(); + break; + case 0x37: /*AAA*/ + wait(1, 0); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + AL += 6; + ++AH; + set_ca(); + } else { + clear_ca(); + wait(1, 0); + } + aa(); + break; + case 0x3F: /*AAS*/ + wait(1, 0); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + AL -= 6; + --AH; + set_ca(); + } else { + clear_ca(); + wait(1, 0); + } + aa(); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4A: case 0x4B: + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + /* INCDEC rw */ + wait(1, 0); + cpu_dest = cpu_state.regs[opcode & 7].w; + cpu_src = 1; + bits = 16; + if ((opcode & 8) == 0) { + cpu_data = cpu_dest + cpu_src; + set_of_add(bits); + } else { + cpu_data = cpu_dest - cpu_src; + set_of_sub(bits); + } + do_af(); + set_pzs(16); + cpu_state.regs[opcode & 7].w = cpu_data; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + access(30, 16); + push(&(cpu_state.regs[opcode & 0x07].w)); + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + access(23, 16); + cpu_state.regs[opcode & 0x07].w = pop(); + wait(1, 0); + break; + + case 0x60: /*JO alias*/ + case 0x70: /*JO*/ + case 0x61: /*JNO alias*/ + case 0x71: /*JNO*/ + jcc(opcode, cpu_state.flags & V_FLAG); + break; + case 0x62: /*JB alias*/ + case 0x72: /*JB*/ + case 0x63: /*JNB alias*/ + case 0x73: /*JNB*/ + jcc(opcode, cpu_state.flags & C_FLAG); + break; + case 0x64: /*JE alias*/ + case 0x74: /*JE*/ + case 0x65: /*JNE alias*/ + case 0x75: /*JNE*/ + jcc(opcode, cpu_state.flags & Z_FLAG); + break; + case 0x66: /*JBE alias*/ + case 0x76: /*JBE*/ + case 0x67: /*JNBE alias*/ + case 0x77: /*JNBE*/ + jcc(opcode, cpu_state.flags & (C_FLAG | Z_FLAG)); + break; + case 0x68: /*JS alias*/ + case 0x78: /*JS*/ + case 0x69: /*JNS alias*/ + case 0x79: /*JNS*/ + jcc(opcode, cpu_state.flags & N_FLAG); + break; + case 0x6A: /*JP alias*/ + case 0x7A: /*JP*/ + case 0x6B: /*JNP alias*/ + case 0x7B: /*JNP*/ + jcc(opcode, cpu_state.flags & P_FLAG); + break; + case 0x6C: /*JL alias*/ + case 0x7C: /*JL*/ + case 0x6D: /*JNL alias*/ + case 0x7D: /*JNL*/ + temp = (cpu_state.flags & N_FLAG) ? 1 : 0; + temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; + jcc(opcode, temp ^ temp2); + break; + case 0x6E: /*JLE alias*/ + case 0x7E: /*JLE*/ + case 0x6F: /*JNLE alias*/ + case 0x7F: /*JNLE*/ + temp = (cpu_state.flags & N_FLAG) ? 1 : 0; + temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; + jcc(opcode, (cpu_state.flags & Z_FLAG) || (temp != temp2)); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + /* alu rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(47, bits); + cpu_data = get_ea(); + cpu_dest = cpu_data; + if (cpu_mod != 3) + wait(3, 0); + if (opcode == 0x81) { + if (cpu_mod == 3) + wait(1, 0); + cpu_src = pfq_fetchw(); + } else { + if (cpu_mod == 3) + wait(1, 0); + if (opcode == 0x83) + cpu_src = sign_extend(pfq_fetchb()); + else + cpu_src = pfq_fetchb() | 0xff00; + } + wait(1, 0); + cpu_alu_op = (rmdat & 0x38) >> 3; + alu_op(bits); + if (cpu_alu_op != 7) { + access(11, bits); + set_ea(cpu_data); + } else { + if (cpu_mod != 3) + wait(1, 0); + } + break; + + case 0x84: case 0x85: + /* TEST rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(48, bits); + cpu_data = get_ea(); + test(bits, cpu_data, get_reg(cpu_reg)); + if (cpu_mod == 3) + wait(2, 0); + wait(2, 0); + break; + case 0x86: case 0x87: + /* XCHG rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(49, bits); + cpu_data = get_ea(); + cpu_src = get_reg(cpu_reg); + set_reg(cpu_reg, cpu_data); + wait(3, 0); + access(12, bits); + set_ea(cpu_src); + break; + + case 0x88: case 0x89: + /* MOV rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait(1, 0); + access(13, bits); + set_ea(get_reg(cpu_reg)); + break; + case 0x8A: case 0x8B: + /* MOV reg, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(50, bits); + set_reg(cpu_reg, get_ea()); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0x8C: /*MOV w,sreg*/ + do_mod_rm(); + if (cpu_mod == 3) + wait(1, 0); + access(14, 16); + seteaw(_opseg[(rmdat & 0x18) >> 3]->seg); + break; + + case 0x8D: /*LEA*/ + do_mod_rm(); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0x8E: /*MOV sreg,w*/ + do_mod_rm(); + access(51, 16); + tempw = geteaw(); + if ((rmdat & 0x18) == 0x08) { + loadcs(tempw); + pfq_pos = 0; + } else + loadseg(tempw, _opseg[(rmdat & 0x18) >> 3]); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + if (((rmdat & 0x18) >> 3) == 2) + noint = 1; + break; + + case 0x8F: /*POPW*/ + do_mod_rm(); + wait(1, 0); + cpu_src = cpu_state.eaaddr; + access(24, 16); + if (cpu_mod != 3) + wait(2, 0); + cpu_data = pop(); + cpu_state.eaaddr = cpu_src; + wait(2, 0); + access(15, 16); + seteaw(cpu_data); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + /* XCHG AX, rw */ + wait(1, 0); + cpu_data = cpu_state.regs[opcode & 7].w; + cpu_state.regs[opcode & 7].w = AX; + AX = cpu_data; + wait(1, 0); + break; + + case 0x98: /*CBW*/ + wait(1, 0); + AX = sign_extend(AL); + break; + case 0x99: /*CWD*/ + wait(4, 0); + if (!top_bit(AX, 16)) + DX = 0; + else { + wait(1, 0); + DX = 0xffff; + } + break; + case 0x9A: /*CALL FAR*/ + wait(1, 0); + new_ip = pfq_fetchw(); + wait(1, 0); + new_cs = pfq_fetchw(); + pfq_clear(); + access(31, 16); + push(&(CS)); + access(60, 16); + cpu_state.oldpc = cpu_state.pc; + loadcs(new_cs); + set_ip(new_ip); + access(32, 16); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x9B: /*WAIT*/ + if (!repeating) + wait(2, 0); + wait(5, 0); +#ifdef NO_HACK + if (irq_pending()) { + wait(7, 0); + check_interrupts(); + } else { + repeating = 1; + completed = 0; + clock_end(); + } +#else + wait(7, 0); + check_interrupts(); +#endif + break; + case 0x9C: /*PUSHF*/ + access(33, 16); + tempw = (cpu_state.flags & 0x0fd7) | 0xf000; + push(&tempw); + break; + case 0x9D: /*POPF*/ + access(25, 16); + cpu_state.flags = pop() | 2; + wait(1, 0); + break; + case 0x9E: /*SAHF*/ + wait(1, 0); + cpu_state.flags = (cpu_state.flags & 0xff02) | AH; + wait(2, 0); + break; + case 0x9F: /*LAHF*/ + wait(1, 0); + AH = cpu_state.flags & 0xd7; + break; + + case 0xA0: case 0xA1: + /* MOV A, [iw] */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + access(1, bits); + set_reg(0, readmem((ovr_seg ? *ovr_seg : ds))); + wait(1, 0); + break; + case 0xA2: case 0xA3: + /* MOV [iw], A */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + access(7, bits); + writemem((ovr_seg ? *ovr_seg : ds), get_reg(0)); + break; + + case 0xA4: case 0xA5: /* MOVS */ + case 0xAC: case 0xAD: /* LODS */ + bits = 8 << (opcode & 1); + if (!repeating) { + wait(1, 0); + if ((opcode & 8) == 0 && in_rep != 0) + wait(1, 0); + } + if (rep_action(bits)) { + wait(1, 0); + if ((opcode & 8) != 0) + wait(1, 0); + break; + } + if (in_rep != 0 && (opcode & 8) != 0) + wait(1, 0); + access(20, bits); + lods(bits); + if ((opcode & 8) == 0) { + access(27, bits); + stos(bits); + } else { + set_reg(0, cpu_data); + if (in_rep != 0) + wait(2, 0); + } + if (in_rep == 0) { + wait(3, 0); + if ((opcode & 8) != 0) + wait(1, 0); + break; + } + repeating = 1; + clock_end(); + break; + + case 0xA6: case 0xA7: /* CMPS */ + case 0xAE: case 0xAF: /* SCAS */ + bits = 8 << (opcode & 1); + if (!repeating) + wait(1, 0); + if (rep_action(bits)) { + wait(2, 0); + break; + } + if (in_rep != 0) + wait(1, 0); + wait(1, 0); + cpu_dest = get_reg(0); + if ((opcode & 8) == 0) { + access(21, bits); + lods(bits); + wait(1, 0); + cpu_dest = cpu_data; + } + access(2, bits); + cpu_state.eaaddr = DI; + cpu_data = readmem(es); + DI = string_increment(bits); + cpu_src = cpu_data; + sub(bits); + wait(2, 0); + if (in_rep == 0) { + wait(3, 0); + break; + } + if ((!!(cpu_state.flags & Z_FLAG)) == (in_rep == 1)) { + completed = 1; + wait(4, 0); + break; + } + repeating = 1; + clock_end(); + break; + + case 0xA8: case 0xA9: + /* TEST A, imm */ + bits = 8 << (opcode & 1); + wait(1, 0); + cpu_data = pfq_fetch(); + test(bits, get_reg(0), cpu_data); + wait(1, 0); + break; + + case 0xAA: case 0xAB: /* STOS */ + bits = 8 << (opcode & 1); + if (!repeating) { + wait(1, 0); + if (in_rep != 0) + wait(1, 0); + } + if (rep_action(bits)) { + wait(1, 0); + break; + } + cpu_data = AX; + access(28, bits); + stos(bits); + if (in_rep == 0) { + wait(3, 0); + break; + } + repeating = 1; + clock_end(); + break; + + case 0xB0: case 0xB1: case 0xB2: case 0xB3: /*MOV cpu_reg,#8*/ + case 0xB4: case 0xB5: case 0xB6: case 0xB7: + wait(1, 0); + if (opcode & 0x04) + cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); + else + cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); + wait(1, 0); + break; + + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV cpu_reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + wait(1, 0); + cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); + wait(1, 0); + break; + + case 0xC0: case 0xC1: case 0xC2: case 0xC3: + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + /* RET */ + bits = 8 + (opcode & 0x08); + if ((opcode & 9) != 1) + wait(1, 0); + if (!(opcode & 1)) { + cpu_src = pfq_fetchw(); + wait(1, 0); + } + if ((opcode & 9) == 9) + wait(1, 0); + pfq_clear(); + access(26, bits); + new_ip = pop(); + wait(2, 0); + if ((opcode & 8) == 0) + new_cs = CS; + else { + access(42, bits); + new_cs = pop(); + if (opcode & 1) + wait(1, 0); + } + if (!(opcode & 1)) { + SP += cpu_src; + wait(1, 0); + } + loadcs(new_cs); + access(72, bits); + set_ip(new_ip); + break; + + case 0xC4: case 0xC5: + /* LsS rw, rmd */ + do_mod_rm(); + bits = 16; + access(52, bits); + read_ea(1, bits); + cpu_state.regs[cpu_reg].w = cpu_data; + access(57, bits); + read_ea2(bits); + loadseg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es); + wait(1, 0); + break; + + case 0xC6: case 0xC7: + /* MOV rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + cpu_data = pfq_fetch(); + if (cpu_mod == 3) + wait(1, 0); + access(16, bits); + set_ea(cpu_data); + break; + + case 0xCC: /*INT 3*/ + interrupt(3); + break; + case 0xCD: /*INT*/ + wait(1, 0); + interrupt(pfq_fetchb()); + break; + case 0xCE: /*INTO*/ + wait(3, 0); + if (cpu_state.flags & V_FLAG) { + wait(2, 0); + interrupt(4); + } + break; + + case 0xCF: /*IRET*/ + access(43, 8); + new_ip = pop(); + wait(3, 0); + access(44, 8); + new_cs = pop(); + loadcs(new_cs); + access(62, 8); + set_ip(new_ip); + access(45, 8); + cpu_state.flags = pop() | 2; + wait(5, 0); + noint = 1; + nmi_enable = 1; + break; + + case 0xD0: case 0xD1: case 0xD2: case 0xD3: + /* rot rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + if (cpu_mod == 3) + wait(1, 0); + access(53, bits); + cpu_data = get_ea(); + if ((opcode & 2) == 0) { + cpu_src = 1; + wait((cpu_mod != 3) ? 4 : 0, 0); + } else { + cpu_src = CL; + wait((cpu_mod != 3) ? 9 : 6, 0); + } + while (cpu_src != 0) { + cpu_dest = cpu_data; + oldc = cpu_state.flags & C_FLAG; + switch (rmdat & 0x38) { + case 0x00: /* ROL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + cpu_data |= ((cpu_state.flags & C_FLAG) ? 1 : 0); + set_of_rotate(bits); + break; + case 0x08: /* ROR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (cpu_state.flags & C_FLAG) + cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000); + set_of_rotate(bits); + break; + case 0x10: /* RCL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data = (cpu_data << 1) | (oldc ? 1 : 0); + set_of_rotate(bits); + break; + case 0x18: /* RCR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (oldc) + cpu_data |= (!(opcode & 0x01) ? 0x80 : 0x8000); + set_cf((cpu_dest & 1) != 0); + set_of_rotate(bits); + break; + case 0x20: /* SHL */ + set_cf(top_bit(cpu_data, bits)); + cpu_data <<= 1; + set_of_rotate(bits); + set_pzs(bits); + break; + case 0x28: /* SHR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + set_of_rotate(bits); + set_af(1); + set_pzs(bits); + break; + case 0x30: /* SETMO - undocumented? */ + bitwise(bits, 0xffff); + set_cf(0); + set_of_rotate(bits); + set_af(0); + set_pzs(bits); + break; + case 0x38: /* SAR */ + set_cf((cpu_data & 1) != 0); + cpu_data >>= 1; + if (!(opcode & 1)) + cpu_data |= (cpu_dest & 0x80); + else + cpu_data |= (cpu_dest & 0x8000); + set_of_rotate(bits); + set_af(1); + set_pzs(bits); + break; + } + if ((opcode & 2) != 0) + wait(4, 0); + --cpu_src; + } + access(17, bits); + set_ea(cpu_data); + break; + + case 0xD4: /*AAM*/ + wait(1, 0); + cpu_src = pfq_fetchb(); + if (x86_div(AL, 0)) + set_pzs(16); + break; + case 0xD5: /*AAD*/ + wait(1, 0); + mul(pfq_fetchb(), AH); + AL += cpu_data; + AH = 0x00; + set_pzs(16); + break; + case 0xD6: /*SALC*/ + wait(1, 0); + AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; + wait(1, 0); + break; + case 0xD7: /*XLATB*/ + cpu_state.eaaddr = (BX + AL) & 0xffff; + access(4, 8); + AL = readmemb((ovr_seg ? *ovr_seg : ds) + cpu_state.eaaddr); + wait(1, 0); + break; + + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDD: case 0xDC: case 0xDE: case 0xDF: + /* esc i, r, rm */ + do_mod_rm(); + access(54, 16); + tempw = cpu_state.pc; + if (!hasfpu) + geteaw(); + else switch(opcode) { + case 0xD8: + ops_fpu_8087_d8[(rmdat >> 3) & 0x1f]((uint32_t) rmdat); + break; + case 0xD9: + ops_fpu_8087_d9[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDA: + ops_fpu_8087_da[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDB: + ops_fpu_8087_db[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDC: + ops_fpu_8087_dc[(rmdat >> 3) & 0x1f]((uint32_t) rmdat); + break; + case 0xDD: + ops_fpu_8087_dd[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDE: + ops_fpu_8087_de[rmdat & 0xff]((uint32_t) rmdat); + break; + case 0xDF: + ops_fpu_8087_df[rmdat & 0xff]((uint32_t) rmdat); + break; + } + cpu_state.pc = tempw; /* Do this as the x87 code advances it, which is needed on + the 286+ core, but not here. */ + wait(1, 0); + if (cpu_mod != 3) + wait(2, 0); + break; + + case 0xE0: case 0xE1: case 0xE2: case 0xE3: + /* LOOP */ + wait(3, 0); + cpu_data = pfq_fetchb(); + if (opcode != 0xe2) + wait(1, 0); + if (opcode != 0xe3) { + --CX; + oldc = (CX != 0); + switch (opcode) { + case 0xE0: + if (cpu_state.flags & Z_FLAG) + oldc = 0; + break; + case 0xE1: + if (!(cpu_state.flags & Z_FLAG)) + oldc = 0; + break; + } + } else + oldc = (CX == 0); + if (oldc) + jump_short(); + break; + + case 0xE4: case 0xE5: case 0xE6: case 0xE7: + case 0xEC: case 0xED: case 0xEE: case 0xEF: + bits = 8 << (opcode & 1); + if ((opcode & 0x0e) != 0x0c) + wait(1, 0); + if ((opcode & 8) == 0) + cpu_data = pfq_fetchb(); + else + cpu_data = DX; + cpu_state.eaaddr = cpu_data; + if ((opcode & 2) == 0) { + access(3, bits); + if ((opcode & 1) && is8086 && !(cpu_data & 1)) { + AX = inw(cpu_data); + wait(4, 1); /* I/O access and wait state. */ + } else { + AL = inb(cpu_data); + if (opcode & 1) + AH = inb(cpu_data + 1); + wait(bits >> 1, 1); /* I/O access. */ + } + wait(1, 0); + } else { + if ((opcode & 8) == 0) + access(8, bits); + else + access(9, bits); + if ((opcode & 1) && is8086 && !(cpu_data & 1)) { + outw(cpu_data, AX); + wait(4, 1); + } else { + outb(cpu_data, AL); + if (opcode & 1) + outb(cpu_data + 1, AH); + wait(bits >> 1, 1); /* I/O access. */ + } + } + break; + + case 0xE8: /*CALL rel 16*/ + wait(1, 0); + cpu_state.oldpc = jump_near(); + access(34, 8); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0xE9: /*JMP rel 16*/ + wait(1, 0); + jump_near(); + break; + case 0xEA: /*JMP far*/ + wait(1, 0); + addr = pfq_fetchw(); + wait(1, 0); + tempw = pfq_fetchw(); + loadcs(tempw); + access(70, 8); + pfq_clear(); + set_ip(addr); + break; + case 0xEB: /*JMP rel*/ + wait(1, 0); + cpu_data = (int8_t) pfq_fetchb(); + jump_short(); + wait(1, 0); + break; + + case 0xF0: case 0xF1: /*LOCK - F1 is alias*/ + in_lock = 1; + wait(1, 0); + completed = 0; + break; + + case 0xF2: /*REPNE*/ + case 0xF3: /*REPE*/ + wait(1, 0); + in_rep = (opcode == 0xf2 ? 1 : 2); + completed = 0; + break; + + case 0xF4: /*HLT*/ + if (!repeating) { + wait(1, 0); + pfq_clear(); + } + wait(1, 0); + if (irq_pending()) { + wait(cycles & 1, 0); + check_interrupts(); + } else { + repeating = 1; + completed = 0; + clock_end(); + } + break; + case 0xF5: /*CMC*/ + wait(1, 0); + cpu_state.flags ^= C_FLAG; + break; + + case 0xF6: case 0xF7: + bits = 8 << (opcode & 1); + do_mod_rm(); + access(55, bits); + cpu_data = get_ea(); + switch (rmdat & 0x38) { + case 0x00: case 0x08: + /* TEST */ + wait(2, 0); + if (cpu_mod != 3) + wait(1, 0); + cpu_src = pfq_fetch(); + wait(1, 0); + test(bits, cpu_data, cpu_src); + if (cpu_mod != 3) + wait(1, 0); + break; + case 0x10: /* NOT */ + case 0x18: /* NEG */ + wait(2, 0); + if ((rmdat & 0x38) == 0x10) + cpu_data = ~cpu_data; + else { + cpu_src = cpu_data; + cpu_dest = 0; + sub(bits); + } + access(18, bits); + set_ea(cpu_data); + break; + case 0x20: /* MUL */ + case 0x28: /* IMUL */ + wait(1, 0); + if (opcode & 1) { + mul(AX, cpu_data); + AX = cpu_data; + DX = cpu_dest; + cpu_data |= DX; + set_co_mul(DX != ((AX & 0x8000) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xffff)); + } else { + mul(AL, cpu_data); + AL = (uint8_t) cpu_data; + AH = (uint8_t) cpu_dest; + cpu_data |= AH; + set_co_mul(AH != ((AL & 0x80) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xff)); + } + /* NOTE: When implementing the V20, care should be taken to not change + the zero flag. */ + set_zf(bits); + if (cpu_mod != 3) + wait(1, 0); + break; + case 0x30: /* DIV */ + case 0x38: /* IDIV */ + if (cpu_mod != 3) + wait(1, 0); + cpu_src = cpu_data; + if (x86_div(AL, AH)) + wait(1, 0); + break; + } + break; + + case 0xF8: case 0xF9: + /* CLCSTC */ + wait(1, 0); + set_cf(opcode & 1); + break; + case 0xFA: case 0xFB: + /* CLISTI */ + wait(1, 0); + set_if(opcode & 1); + break; + case 0xFC: case 0xFD: + /* CLDSTD */ + wait(1, 0); + set_df(opcode & 1); + break; + + case 0xFE: case 0xFF: + /* misc */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(56, bits); + read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); + switch (rmdat & 0x38) { + case 0x00: /* INC rm */ + case 0x08: /* DEC rm */ + cpu_dest = cpu_data; + cpu_src = 1; + if ((rmdat & 0x38) == 0x00) { + cpu_data = cpu_dest + cpu_src; + set_of_add(bits); + } else { + cpu_data = cpu_dest - cpu_src; + set_of_sub(bits); + } + do_af(); + set_pzs(bits); + wait(2, 0); + access(19, bits); + set_ea(cpu_data); + break; + case 0x10: /* CALL rm */ + cpu_data_opff_rm(); + access(63, bits); + wait(1, 0); + pfq_clear(); + wait(4, 0); + if (cpu_mod != 3) + wait(1, 0); + wait(1, 0); /* Wait. */ + cpu_state.oldpc = cpu_state.pc; + set_ip(cpu_data); + wait(2, 0); + access(35, bits); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x18: /* CALL rmd */ + new_ip = cpu_data; + access(58, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + access(36, bits); + push(&(CS)); + access(64, bits); + wait(4, 0); + cpu_state.oldpc = cpu_state.pc; + loadcs(new_cs); + set_ip(new_ip); + access(37, bits); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x20: /* JMP rm */ + cpu_data_opff_rm(); + access(65, bits); + set_ip(cpu_data); + break; + case 0x28: /* JMP rmd */ + new_ip = cpu_data; + access(59, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + loadcs(new_cs); + access(66, bits); + set_ip(new_ip); + break; + case 0x30: /* PUSH rm */ + case 0x38: + if (cpu_mod != 3) + wait(1, 0); + access(38, bits); + push(&(cpu_data)); + break; + } + break; + + default: + x808x_log("Illegal opcode: %02X\n", opcode); + pfq_fetchb(); + wait(8, 0); + break; + } + + if (completed) { + repeating = 0; + ovr_seg = NULL; + in_rep = 0; + if (in_lock) + clear_lock = 1; + clock_end(); + check_interrupts(); + + if (noint) + noint = 0; + } + + ins++; + } +} diff --git a/src/cpu_new/codegen.c b/src/cpu_new/codegen.c new file mode 100644 index 000000000..243f61791 --- /dev/null +++ b/src/cpu_new/codegen.c @@ -0,0 +1,772 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86_ops.h" +#include "codegen.h" +#include "x86.h" + +#include "386_common.h" + +#include "codegen_accumulate.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" + +#define MAX_INSTRUCTION_COUNT 50 + +static struct +{ + uint32_t pc; + int op_ssegs; + x86seg *op_ea_seg; + uint32_t op_32; + int first_uop; + int TOP; +} codegen_instructions[MAX_INSTRUCTION_COUNT]; + +int codegen_get_instruction_uop(codeblock_t *block, uint32_t pc, int *first_instruction, int *TOP) +{ + int c; + + for (c = 0; c < block->ins; c++) + { + if (codegen_instructions[c].pc == pc) + { + *first_instruction = c; + *TOP = codegen_instructions[c].TOP; + return codegen_instructions[c].first_uop; + } + } + + *first_instruction = block->ins; + return -1; +} + +void codegen_set_loop_start(ir_data_t *ir, int first_instruction) +{ + uop_MOV_IMM(ir, IREG_op32, codegen_instructions[first_instruction].op_32); + uop_MOV_PTR(ir, IREG_ea_seg, (void *)codegen_instructions[first_instruction].op_ea_seg); + uop_MOV_IMM(ir, IREG_ssegs, codegen_instructions[first_instruction].op_ssegs); +} + +int has_ea; + +codeblock_t *codeblock; +uint16_t *codeblock_hash; + +void (*codegen_timing_start)(); +void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat); +void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc); +void (*codegen_timing_block_start)(); +void (*codegen_timing_block_end)(); +int (*codegen_timing_jump_cycles)(); + +void codegen_timing_set(codegen_timing_t *timing) +{ + codegen_timing_start = timing->start; + codegen_timing_prefix = timing->prefix; + codegen_timing_opcode = timing->opcode; + codegen_timing_block_start = timing->block_start; + codegen_timing_block_end = timing->block_end; + codegen_timing_jump_cycles = timing->jump_cycles; +} + +int codegen_in_recompile; + +static int last_op_ssegs; +static x86seg *last_op_ea_seg; +static uint32_t last_op_32; + +void codegen_generate_reset() +{ + last_op_ssegs = -1; + last_op_ea_seg = NULL; + last_op_32 = -1; + has_ea = 0; +} + +void codegen_check_seg_read(codeblock_t *block, ir_data_t *ir, x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (cpu_state.eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) + return; + if (seg->checked) + return; + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + return; + + uop_CMP_IMM_JZ(ir, ireg_seg_base(seg), (uint32_t)-1, codegen_gpf_rout); + + seg->checked = 1; +} +void codegen_check_seg_write(codeblock_t *block, ir_data_t *ir, x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (cpu_state.eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) + return; + if (seg->checked) + return; + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + return; + + uop_CMP_IMM_JZ(ir, ireg_seg_base(seg), (uint32_t)-1, codegen_gpf_rout); + + seg->checked = 1; +} + +static x86seg *codegen_generate_ea_16_long(ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + uint32_t old_pc = (*op_pc) + 1; + if (!cpu_mod && cpu_rm == 6) + { + uint16_t addr = (fetchdat >> 8) & 0xffff; + uop_MOV_IMM(ir, IREG_eaaddr, addr); + (*op_pc) += 2; + } + else + { + int base_reg, index_reg, offset; + + switch (cpu_rm & 7) + { + case 0: case 1: case 7: + base_reg = IREG_EBX; + break; + case 2: case 3: case 6: + base_reg = IREG_EBP; + break; + case 4: + base_reg = IREG_ESI; + break; + case 5: + base_reg = IREG_EDI; + break; + } + uop_MOV(ir, IREG_eaaddr, base_reg); + + if (!(cpu_rm & 4)) + { + if (!(cpu_rm & 1)) + index_reg = IREG_ESI; + else + index_reg = IREG_EDI; + + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, index_reg); + } + + switch (cpu_mod) + { + case 1: + offset = (int)(int8_t)((fetchdat >> 8) & 0xff); + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, offset); + (*op_pc)++; + break; + case 2: + offset = (fetchdat >> 8) & 0xffff; + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, offset); + (*op_pc) += 2; + break; + } + + uop_AND_IMM(ir, IREG_eaaddr, IREG_eaaddr, 0xffff); + + if (mod1seg[cpu_rm] == &ss && !op_ssegs) + { + op_ea_seg = &cpu_state.seg_ss; + } + } + + codegen_mark_code_present(ir->block, cs+old_pc, ((*op_pc)+1)-old_pc); + return op_ea_seg; +} + +static x86seg *codegen_generate_ea_32_long(ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + codeblock_t *block = ir->block; + uint32_t old_pc = (*op_pc) + 1; + uint32_t new_eaaddr; + int extra_bytes = 0; + + if (cpu_rm == 4) + { + uint8_t sib = fetchdat >> 8; + (*op_pc)++; + + switch (cpu_mod) + { + case 0: + if ((sib & 7) == 5) + { + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_eaaddr, cs + (*op_pc) + 1); + extra_bytes = 1; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); + extra_bytes = 5; + } + (*op_pc) += 4; + } + else + { + uop_MOV(ir, IREG_eaaddr, sib & 7); + extra_bytes = 1; + } + break; + case 1: + new_eaaddr = (uint32_t)(int8_t)((fetchdat >> 16) & 0xff); + uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, sib & 7); + (*op_pc)++; + extra_bytes = 2; + break; + case 2: + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_eaaddr, cs + (*op_pc) + 1); + extra_bytes = 1; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); + extra_bytes = 5; + } + (*op_pc) += 4; + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, sib & 7); + break; + } + if (stack_offset && (sib & 7) == 4 && (cpu_mod || (sib & 7) != 5)) /*ESP*/ + { + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, stack_offset); +// addbyte(0x05); +// addlong(stack_offset); + } + if (((sib & 7) == 4 || (cpu_mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &cpu_state.seg_ss; + if (((sib >> 3) & 7) != 4) + { + switch (sib >> 6) + { + case 0: + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7); + break; + case 1: + uop_ADD_LSHIFT(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7, 1); + break; + case 2: + uop_ADD_LSHIFT(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7, 2); + break; + case 3: + uop_ADD_LSHIFT(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7, 3); + break; + } + } + } + else + { + if (!cpu_mod && cpu_rm == 5) + { + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_eaaddr, cs + (*op_pc) + 1); + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); + extra_bytes = 4; + } + + (*op_pc) += 4; + } + else + { + uop_MOV(ir, IREG_eaaddr, cpu_rm); + if (cpu_mod) + { + if (cpu_rm == 5 && !op_ssegs) + op_ea_seg = &cpu_state.seg_ss; + if (cpu_mod == 1) + { + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, (uint32_t)(int8_t)(fetchdat >> 8)); + (*op_pc)++; + extra_bytes = 1; + } + else + { + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + (*op_pc) + 1); + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, IREG_temp0); + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, new_eaaddr); + extra_bytes = 4; + } + (*op_pc) += 4; + } + } + } + } + + if (extra_bytes) + codegen_mark_code_present(ir->block, cs+old_pc, extra_bytes); + + return op_ea_seg; +} + +x86seg *codegen_generate_ea(ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32, int stack_offset) +{ + cpu_mod = (fetchdat >> 6) & 3; + cpu_reg = (fetchdat >> 3) & 7; + cpu_rm = fetchdat & 7; + + if ((fetchdat & 0xc0) == 0xc0) + return NULL; + if (op_32 & 0x200) + return codegen_generate_ea_32_long(ir, op_ea_seg, fetchdat, op_ssegs, op_pc, stack_offset); + + return codegen_generate_ea_16_long(ir, op_ea_seg, fetchdat, op_ssegs, op_pc); +} + +static uint8_t opcode_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*20*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*f0*/ +}; +static uint8_t opcode_0f_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ + 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, /*a0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, /*b0*/ + + 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*d0*/ + 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*e0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0 /*f0*/ +}; + +void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc) +{ + codeblock_t *block = &codeblock[block_current]; + ir_data_t *ir = codegen_get_ir_data(); + uint32_t op_pc = new_pc; + OpFn *op_table = (OpFn *) x86_dynarec_opcodes; + RecompOpFn *recomp_op_table = recomp_opcodes; + int opcode_shift = 0; + int opcode_mask = 0x3ff; + uint32_t recomp_opcode_mask = 0x1ff; + uint32_t op_32 = use32; + int over = 0; + int test_modrm = 1; + int pc_off = 0; + uint32_t next_pc = 0; +#ifdef DEBUG_EXTRA + uint8_t last_prefix = 0; +#endif + op_ea_seg = &cpu_state.seg_ds; + op_ssegs = 0; + + codegen_timing_start(); + + while (!over) + { + switch (opcode) + { + case 0x0f: +#ifdef DEBUG_EXTRA + last_prefix = 0x0f; +#endif + op_table = (OpFn *) x86_dynarec_opcodes_0f; + recomp_op_table = recomp_opcodes_0f; + over = 1; + break; + + case 0x26: /*ES:*/ + op_ea_seg = &cpu_state.seg_es; + op_ssegs = 1; + break; + case 0x2e: /*CS:*/ + op_ea_seg = &cpu_state.seg_cs; + op_ssegs = 1; + break; + case 0x36: /*SS:*/ + op_ea_seg = &cpu_state.seg_ss; + op_ssegs = 1; + break; + case 0x3e: /*DS:*/ + op_ea_seg = &cpu_state.seg_ds; + op_ssegs = 1; + break; + case 0x64: /*FS:*/ + op_ea_seg = &cpu_state.seg_fs; + op_ssegs = 1; + break; + case 0x65: /*GS:*/ + op_ea_seg = &cpu_state.seg_gs; + op_ssegs = 1; + break; + + case 0x66: /*Data size select*/ + op_32 = ((use32 & 0x100) ^ 0x100) | (op_32 & 0x200); + break; + case 0x67: /*Address size select*/ + op_32 = ((use32 & 0x200) ^ 0x200) | (op_32 & 0x100); + break; + + case 0xd8: +#ifdef DEBUG_EXTRA + last_prefix = 0xd8; +#endif + op_table = (op_32 & 0x200) ? (OpFn *) x86_dynarec_opcodes_d8_a32 : (OpFn *) x86_dynarec_opcodes_d8_a16; + recomp_op_table = recomp_opcodes_d8; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xd9: +#ifdef DEBUG_EXTRA + last_prefix = 0xd9; +#endif + op_table = (op_32 & 0x200) ? (OpFn *) x86_dynarec_opcodes_d9_a32 : (OpFn *) x86_dynarec_opcodes_d9_a16; + recomp_op_table = recomp_opcodes_d9; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xda: +#ifdef DEBUG_EXTRA + last_prefix = 0xda; +#endif + op_table = (op_32 & 0x200) ? (OpFn *) x86_dynarec_opcodes_da_a32 : (OpFn *) x86_dynarec_opcodes_da_a16; + recomp_op_table = recomp_opcodes_da; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdb: +#ifdef DEBUG_EXTRA + last_prefix = 0xdb; +#endif + op_table = (op_32 & 0x200) ? (OpFn *) x86_dynarec_opcodes_db_a32 : (OpFn *) x86_dynarec_opcodes_db_a16; + recomp_op_table = recomp_opcodes_db; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdc: +#ifdef DEBUG_EXTRA + last_prefix = 0xdc; +#endif + op_table = (op_32 & 0x200) ? (OpFn *) x86_dynarec_opcodes_dc_a32 : (OpFn *) x86_dynarec_opcodes_dc_a16; + recomp_op_table = recomp_opcodes_dc; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdd: +#ifdef DEBUG_EXTRA + last_prefix = 0xdd; +#endif + op_table = (op_32 & 0x200) ? (OpFn *) x86_dynarec_opcodes_dd_a32 : (OpFn *) x86_dynarec_opcodes_dd_a16; + recomp_op_table = recomp_opcodes_dd; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xde: +#ifdef DEBUG_EXTRA + last_prefix = 0xde; +#endif + op_table = (op_32 & 0x200) ? (OpFn *) x86_dynarec_opcodes_de_a32 : (OpFn *) x86_dynarec_opcodes_de_a16; + recomp_op_table = recomp_opcodes_de; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdf: +#ifdef DEBUG_EXTRA + last_prefix = 0xdf; +#endif + op_table = (op_32 & 0x200) ? (OpFn *) x86_dynarec_opcodes_df_a32 : (OpFn *) x86_dynarec_opcodes_df_a16; + recomp_op_table = recomp_opcodes_df; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + + case 0xf0: /*LOCK*/ + break; + + case 0xf2: /*REPNE*/ +#ifdef DEBUG_EXTRA + last_prefix = 0xf2; +#endif + op_table = (OpFn *) x86_dynarec_opcodes_REPNE; + recomp_op_table = NULL;//recomp_opcodes_REPNE; + break; + case 0xf3: /*REPE*/ +#ifdef DEBUG_EXTRA + last_prefix = 0xf3; +#endif + op_table = (OpFn *) x86_dynarec_opcodes_REPE; + recomp_op_table = NULL;//recomp_opcodes_REPE; + break; + + default: + goto generate_call; + } + fetchdat = fastreadl(cs + op_pc); + codegen_timing_prefix(opcode, fetchdat); + if (cpu_state.abrt) + return; + opcode = fetchdat & 0xff; + if (!pc_off) + fetchdat >>= 8; + + op_pc++; + } + +generate_call: + codegen_instructions[block->ins].pc = cpu_state.oldpc; + codegen_instructions[block->ins].op_ssegs = last_op_ssegs; + codegen_instructions[block->ins].op_ea_seg = last_op_ea_seg; + codegen_instructions[block->ins].op_32 = last_op_32; + codegen_instructions[block->ins].TOP = cpu_state.TOP; + codegen_instructions[block->ins].first_uop = ir->wr_pos; + + codegen_timing_opcode(opcode, fetchdat, op_32, op_pc); + + codegen_accumulate(ACCREG_ins, 1); + codegen_accumulate(ACCREG_cycles, -codegen_block_cycles); + codegen_block_cycles = 0; + + if ((op_table == x86_dynarec_opcodes && + ((opcode & 0xf0) == 0x70 || (opcode & 0xfc) == 0xe0 || opcode == 0xc2 || + (opcode & 0xfe) == 0xca || (opcode & 0xfc) == 0xcc || (opcode & 0xfc) == 0xe8 || + (opcode == 0xff && ((fetchdat & 0x38) >= 0x10 && (fetchdat & 0x38) < 0x30)))) || + (op_table == x86_dynarec_opcodes_0f && ((opcode & 0xf0) == 0x80))) + { + /*On some CPUs (eg K6), a jump/branch instruction may be able to pair with + subsequent instructions, so no cycles may have been deducted for it yet. + To prevent having zero cycle blocks (eg with a jump instruction pointing + to itself), apply the cycles that would be taken if this jump is taken, + then reverse it for subsequent instructions if the jump is not taken*/ + int jump_cycles = codegen_timing_jump_cycles(); + + if (jump_cycles) + codegen_accumulate(ACCREG_cycles, -jump_cycles); + codegen_accumulate_flush(ir); + if (jump_cycles) + codegen_accumulate(ACCREG_cycles, jump_cycles); + } + + if (op_table == x86_dynarec_opcodes_0f && opcode == 0x0f) + { + /*3DNow opcodes are stored after ModR/M, SIB and any offset*/ + uint8_t modrm = fetchdat & 0xff; + uint8_t sib = (fetchdat >> 8) & 0xff; + uint32_t opcode_pc = op_pc + 1; + uint8_t opcode_3dnow; + + if ((modrm & 0xc0) != 0xc0) + { + if (op_32 & 0x200) + { + if ((modrm & 7) == 4) + { + /* Has SIB*/ + opcode_pc++; + if ((modrm & 0xc0) == 0x40) + opcode_pc++; + else if ((modrm & 0xc0) == 0x80) + opcode_pc += 4; + else if ((sib & 0x07) == 0x05) + opcode_pc += 4; + } + else + { + if ((modrm & 0xc0) == 0x40) + opcode_pc++; + else if ((modrm & 0xc0) == 0x80) + opcode_pc += 4; + else if ((modrm & 0xc7) == 0x05) + opcode_pc += 4; + } + } + else + { + if ((modrm & 0xc0) == 0x40) + opcode_pc++; + else if ((modrm & 0xc0) == 0x80) + opcode_pc += 2; + else if ((modrm & 0xc7) == 0x06) + opcode_pc += 2; + } + } + + opcode_3dnow = fastreadb(cs + opcode_pc); + if (recomp_opcodes_3DNOW[opcode_3dnow]) + { + next_pc = opcode_pc + 1; + + op_table = (OpFn *) x86_dynarec_opcodes_3DNOW; + recomp_op_table = recomp_opcodes_3DNOW; + opcode = opcode_3dnow; + recomp_opcode_mask = 0xff; + opcode_mask = 0xff; + } + } + codegen_mark_code_present(block, cs+old_pc, (op_pc - old_pc) - pc_off); + /* It is apparently a prefixed instruction. */ + if (recomp_op_table && recomp_op_table[(opcode | op_32) & recomp_opcode_mask]) + { + uint32_t new_pc = recomp_op_table[(opcode | op_32) & recomp_opcode_mask](block, ir, opcode, fetchdat, op_32, op_pc); + if (new_pc) + { + if (new_pc != -1) + uop_MOV_IMM(ir, IREG_pc, new_pc); + + codegen_endpc = (cs + cpu_state.pc) + 8; + + block->ins++; + + if (block->ins >= MAX_INSTRUCTION_COUNT) + CPU_BLOCK_END(); + + return; + } + } + + if ((op_table == x86_dynarec_opcodes_REPNE || op_table == x86_dynarec_opcodes_REPE) && !op_table[opcode | op_32]) + { + op_table = (OpFn *) x86_dynarec_opcodes; + recomp_op_table = recomp_opcodes; + } + + op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; + + if (!test_modrm || + (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || + (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode]) || + (op_table == x86_dynarec_opcodes_3DNOW)) + { + int stack_offset = 0; + + if (op_table == x86_dynarec_opcodes && opcode == 0x8f) /*POP*/ + stack_offset = (op_32 & 0x100) ? 4 : 2; + + cpu_mod = (fetchdat >> 6) & 3; + cpu_reg = (fetchdat >> 3) & 7; + cpu_rm = fetchdat & 7; + + uop_MOV_IMM(ir, IREG_rm_mod_reg, cpu_rm | (cpu_mod << 8) | (cpu_reg << 16)); + + op_pc += pc_off; + if (cpu_mod != 3 && !(op_32 & 0x200)) + { + op_ea_seg = codegen_generate_ea_16_long(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc); + } + if (cpu_mod != 3 && (op_32 & 0x200)) + { + op_ea_seg = codegen_generate_ea_32_long(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset); + } + op_pc -= pc_off; + } + +#ifdef DEBUG_EXTRA + uop_LOG_INSTR(ir, opcode | (last_prefix << 8)); +#endif + codegen_accumulate_flush(ir); + if (op_table == x86_dynarec_opcodes_3DNOW) + uop_MOV_IMM(ir, IREG_pc, next_pc); + else + uop_MOV_IMM(ir, IREG_pc, op_pc+pc_off); + uop_MOV_IMM(ir, IREG_oldpc, old_pc); + if (op_32 != last_op_32) + uop_MOV_IMM(ir, IREG_op32, op_32); + if (op_ea_seg != last_op_ea_seg) + uop_MOV_PTR(ir, IREG_ea_seg, (void *)op_ea_seg); + if (op_ssegs != last_op_ssegs) + uop_MOV_IMM(ir, IREG_ssegs, op_ssegs); + uop_LOAD_FUNC_ARG_IMM(ir, 0, fetchdat); + uop_CALL_INSTRUCTION_FUNC(ir, op); + codegen_mark_code_present(block, cs+cpu_state.pc, 8); + + last_op_32 = op_32; + last_op_ea_seg = op_ea_seg; + last_op_ssegs = op_ssegs; + //codegen_block_ins++; + + block->ins++; + + if (block->ins >= MAX_INSTRUCTION_COUNT) + CPU_BLOCK_END(); + + codegen_endpc = (cs + cpu_state.pc) + 8; + +// if (has_ea) +// fatal("Has EA\n"); +} diff --git a/src/cpu_new/codegen.h b/src/cpu_new/codegen.h new file mode 100644 index 000000000..d4f2563f6 --- /dev/null +++ b/src/cpu_new/codegen.h @@ -0,0 +1,414 @@ +#ifndef _CODEGEN_H_ +#define _CODEGEN_H_ + +#include "mem.h" +#include "x86_ops.h" + +/*Handling self-modifying code (of which there is a lot on x86) : + + PCem tracks a 'dirty mask' for each physical page, in which each bit + represents 64 bytes. This is only tracked for pages that have code in - when a + page first has a codeblock generated, it is evicted from the writelookup and + added to the page_lookup for this purpose. When in the page_lookup, each write + will go through the mem_write_ram*_page() functions and set the dirty mask + appropriately. + + Each codeblock also contains a code mask (actually two masks, one for each + page the block is/may be in), again with each bit representing 64 bytes. + + Each page has a list of codeblocks present in it. As each codeblock can span + up to two pages, two lists are present. + + When a codeblock is about to be executed, the code masks are compared with the + dirty masks for the relevant pages. If either intersect, then + codegen_check_flush() is called on the affected page(s), and all affected + blocks are evicted. + + The 64 byte granularity appears to work reasonably well for most cases, + avoiding most unnecessary evictions (eg when code & data are stored in the + same page). +*/ + +typedef struct codeblock_t +{ + uint32_t pc; + uint32_t _cs; + uint32_t phys, phys_2; + uint16_t status; + uint16_t flags; + uint8_t ins; + uint8_t TOP; + + /*Pointers for codeblock tree, used to search for blocks when hash lookup + fails.*/ + uint16_t parent, left, right; + + uint8_t *data; + + uint64_t page_mask, page_mask2; + uint64_t *dirty_mask, *dirty_mask2; + + /*Previous and next pointers, for the codeblock list associated with + each physical page. Two sets of pointers, as a codeblock can be + present in two pages.*/ + uint16_t prev, next; + uint16_t prev_2, next_2; + + /*First mem_block_t used by this block. Any subsequent mem_block_ts + will be in the list starting at head_mem_block->next.*/ + struct mem_block_t *head_mem_block; +} codeblock_t; + +extern codeblock_t *codeblock; + +extern uint16_t *codeblock_hash; + +extern uint8_t *block_write_data; + +/*Code block uses FPU*/ +#define CODEBLOCK_HAS_FPU 1 +/*Code block is always entered with the same FPU top-of-stack*/ +#define CODEBLOCK_STATIC_TOP 2 +/*Code block has been compiled*/ +#define CODEBLOCK_WAS_RECOMPILED 4 +/*Code block is in free list and is not valid*/ +#define CODEBLOCK_IN_FREE_LIST 8 +/*Code block spans two pages, page_mask2 and dirty_mask2 are valid*/ +#define CODEBLOCK_HAS_PAGE2 0x10 +/*Code block is using a byte mask for code present and dirty*/ +#define CODEBLOCK_BYTE_MASK 0x20 +/*Code block is in dirty list*/ +#define CODEBLOCK_IN_DIRTY_LIST 0x40 +/*Code block is not inlining immediate parameters, parameters must be fetched from memory*/ +#define CODEBLOCK_NO_IMMEDIATES 0x80 + +#define BLOCK_PC_INVALID 0xffffffff + +#define BLOCK_INVALID 0 + +static inline int get_block_nr(codeblock_t *block) +{ + return ((uintptr_t)block - (uintptr_t)codeblock) / sizeof(codeblock_t); +} + +static inline codeblock_t *codeblock_tree_find(uint32_t phys, uint32_t _cs) +{ + codeblock_t *block; + uint64_t a = _cs | ((uint64_t)phys << 32); + + if (!pages[phys >> 12].head) + return NULL; + + block = &codeblock[pages[phys >> 12].head]; + while (block) + { + uint64_t block_cmp = block->_cs | ((uint64_t)block->phys << 32); + if (a == block_cmp) + { + if (!((block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && + ((block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK))) + break; + } + if (a < block_cmp) + block = block->left ? &codeblock[block->left] : NULL; + else + block = block->right ? &codeblock[block->right] : NULL; + } + + return block; +} + +static inline void codeblock_tree_add(codeblock_t *new_block) +{ + codeblock_t *block = &codeblock[pages[new_block->phys >> 12].head]; + uint64_t a = new_block->_cs | ((uint64_t)new_block->phys << 32); + + if (!pages[new_block->phys >> 12].head) + { + pages[new_block->phys >> 12].head = get_block_nr(new_block); + new_block->parent = new_block->left = new_block->right = BLOCK_INVALID; + } + else + { + codeblock_t *old_block = NULL; + uint64_t old_block_cmp = 0; + + while (block) + { + old_block = block; + old_block_cmp = old_block->_cs | ((uint64_t)old_block->phys << 32); + + if (a < old_block_cmp) + block = block->left ? &codeblock[block->left] : NULL; + else + block = block->right ? &codeblock[block->right] : NULL; + } + + if (a < old_block_cmp) + old_block->left = get_block_nr(new_block); + else + old_block->right = get_block_nr(new_block); + + new_block->parent = get_block_nr(old_block); + new_block->left = new_block->right = BLOCK_INVALID; + } +} + +static inline void codeblock_tree_delete(codeblock_t *block) +{ + uint16_t parent_nr = block->parent; + codeblock_t *parent; + + if (block->parent) + parent = &codeblock[block->parent]; + else + parent = NULL; + + if (!block->left && !block->right) + { + /*Easy case - remove from parent*/ + if (!parent) + pages[block->phys >> 12].head = BLOCK_INVALID; + else + { + uint16_t block_nr = get_block_nr(block); + + if (parent->left == block_nr) + parent->left = BLOCK_INVALID; + if (parent->right == block_nr) + parent->right = BLOCK_INVALID; + } + return; + } + else if (!block->left) + { + /*Only right node*/ + if (!parent_nr) + { + pages[block->phys >> 12].head = block->right; + codeblock[pages[block->phys >> 12].head].parent = BLOCK_INVALID; + } + else + { + uint16_t block_nr = get_block_nr(block); + + if (parent->left == block_nr) + { + parent->left = block->right; + codeblock[parent->left].parent = parent_nr; + } + if (parent->right == block_nr) + { + parent->right = block->right; + codeblock[parent->right].parent = parent_nr; + } + } + return; + } + else if (!block->right) + { + /*Only left node*/ + if (!parent_nr) + { + pages[block->phys >> 12].head = block->left; + codeblock[pages[block->phys >> 12].head].parent = BLOCK_INVALID; + } + else + { + uint16_t block_nr = get_block_nr(block); + + if (parent->left == block_nr) + { + parent->left = block->left; + codeblock[parent->left].parent = parent_nr; + } + if (parent->right == block_nr) + { + parent->right = block->left; + codeblock[parent->right].parent = parent_nr; + } + } + return; + } + else + { + /*Difficult case - node has two children. Walk right child to find lowest node*/ + codeblock_t *lowest = &codeblock[block->right], *highest; + codeblock_t *old_parent; + uint16_t lowest_nr; + + while (lowest->left) + lowest = &codeblock[lowest->left]; + lowest_nr = get_block_nr(lowest); + + old_parent = &codeblock[lowest->parent]; + + /*Replace deleted node with lowest node*/ + if (!parent_nr) + pages[block->phys >> 12].head = lowest_nr; + else + { + uint16_t block_nr = get_block_nr(block); + + if (parent->left == block_nr) + parent->left = lowest_nr; + if (parent->right == block_nr) + parent->right = lowest_nr; + } + + lowest->parent = parent_nr; + lowest->left = block->left; + if (lowest->left) + codeblock[lowest->left].parent = lowest_nr; + + old_parent->left = BLOCK_INVALID; + + highest = &codeblock[lowest->right]; + if (!lowest->right) + { + if (lowest_nr != block->right) + { + lowest->right = block->right; + codeblock[block->right].parent = lowest_nr; + } + return; + } + + while (highest->right) + highest = &codeblock[highest->right]; + + if (block->right && block->right != lowest_nr) + { + highest->right = block->right; + codeblock[block->right].parent = get_block_nr(highest); + } + } +} + +#define PAGE_MASK_MASK 63 +#define PAGE_MASK_SHIFT 6 + +void codegen_mark_code_present_multibyte(codeblock_t *block, uint32_t start_pc, int len); + +static inline void codegen_mark_code_present(codeblock_t *block, uint32_t start_pc, int len) +{ + if (len == 1) + { + if (block->flags & CODEBLOCK_BYTE_MASK) + { + if (!((start_pc ^ block->pc) & ~0x3f)) /*Starts in second page*/ + block->page_mask |= ((uint64_t)1 << (start_pc & PAGE_MASK_MASK)); + else + block->page_mask2 |= ((uint64_t)1 << (start_pc & PAGE_MASK_MASK)); + } + else + { + if (!((start_pc ^ block->pc) & ~0xfff)) /*Starts in second page*/ + block->page_mask |= ((uint64_t)1 << ((start_pc >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK)); + else + block->page_mask2 |= ((uint64_t)1 << ((start_pc >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK)); + } + } + else + codegen_mark_code_present_multibyte(block, start_pc, len); +} + +void codegen_init(); +void codegen_close(); +void codegen_reset(); +void codegen_block_init(uint32_t phys_addr); +void codegen_block_remove(); +void codegen_block_start_recompile(codeblock_t *block); +void codegen_block_end_recompile(codeblock_t *block); +void codegen_block_end(); +void codegen_delete_block(codeblock_t *block); +void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc); +void codegen_generate_seg_restore(); +void codegen_set_op32(); +void codegen_flush(); +void codegen_check_flush(struct page_t *page, uint64_t mask, uint32_t phys_addr); +struct ir_data_t; +x86seg *codegen_generate_ea(struct ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32, int stack_offset); +void codegen_check_seg_read(codeblock_t *block, struct ir_data_t *ir, x86seg *seg); +void codegen_check_seg_write(codeblock_t *block, struct ir_data_t *ir, x86seg *seg); + +int codegen_purge_purgable_list(); +/*Delete a random code block to free memory. This is obviously quite expensive, and + will only be called when the allocator is out of memory*/ +void codegen_delete_random_block(int required_mem_block); + +extern int cpu_block_end; +extern uint32_t codegen_endpc; + +extern int cpu_recomp_blocks, cpu_recomp_full_ins, cpu_new_blocks; +extern int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched; +extern int cpu_recomp_flushes, cpu_recomp_flushes_latched; +extern int cpu_recomp_evicted, cpu_recomp_evicted_latched; +extern int cpu_recomp_reuse, cpu_recomp_reuse_latched; +extern int cpu_recomp_removed, cpu_recomp_removed_latched; + +extern int cpu_reps, cpu_reps_latched; +extern int cpu_notreps, cpu_notreps_latched; + +extern int codegen_block_cycles; + +extern void (*codegen_timing_start)(); +extern void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat); +extern void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc); +extern void (*codegen_timing_block_start)(); +extern void (*codegen_timing_block_end)(); +extern int (*codegen_timing_jump_cycles)(); + +typedef struct codegen_timing_t +{ + void (*start)(); + void (*prefix)(uint8_t prefix, uint32_t fetchdat); + void (*opcode)(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc); + void (*block_start)(); + void (*block_end)(); + int (*jump_cycles)(); +} codegen_timing_t; + +extern codegen_timing_t codegen_timing_pentium; +extern codegen_timing_t codegen_timing_686; +extern codegen_timing_t codegen_timing_486; +extern codegen_timing_t codegen_timing_winchip; +extern codegen_timing_t codegen_timing_winchip2; +extern codegen_timing_t codegen_timing_k6; + +void codegen_timing_set(codegen_timing_t *timing); + +extern int block_current; +extern int block_pos; + +#define CPU_BLOCK_END() cpu_block_end = 1 + +/*Current physical page of block being recompiled. -1 if no recompilation taking place */ +extern uint32_t recomp_page; + +extern x86seg *op_ea_seg; +extern int op_ssegs; +extern uint32_t op_old_pc; + +/*Set to 1 if flags have been changed in the block being recompiled, and hence + flags_op is known and can be relied on */ +extern int codegen_flags_changed; + +extern int codegen_fpu_entered; +extern int codegen_mmx_entered; + +extern int codegen_fpu_loaded_iq[8]; +extern int codegen_reg_loaded[8]; + +extern int codegen_in_recompile; + +void codegen_generate_reset(); + +int codegen_get_instruction_uop(codeblock_t *block, uint32_t pc, int *first_instruction, int *TOP); +void codegen_set_loop_start(struct ir_data_t *ir, int first_instruction); + +#ifdef DEBUG_EXTRA +extern uint32_t instr_counts[256*256]; +#endif + +#endif diff --git a/src/cpu_new/codegen_accumulate.c b/src/cpu_new/codegen_accumulate.c new file mode 100644 index 000000000..c9b85ba78 --- /dev/null +++ b/src/cpu_new/codegen_accumulate.c @@ -0,0 +1,46 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" + +static struct +{ + int count; + int dest_reg; +} acc_regs[] = +{ + [ACCREG_ins] = {0, IREG_ins}, + [ACCREG_cycles] = {0, IREG_cycles}, +}; + +void codegen_accumulate(int acc_reg, int delta) +{ + acc_regs[acc_reg].count += delta; +} + +void codegen_accumulate_flush(ir_data_t *ir) +{ + int c; + + for (c = 0; c < ACCREG_COUNT; c++) + { + if (acc_regs[c].count) + { + uop_ADD_IMM(ir, acc_regs[c].dest_reg, acc_regs[c].dest_reg, acc_regs[c].count); + } + + acc_regs[c].count = 0; + } +} + +void codegen_accumulate_reset() +{ + int c; + + for (c = 0; c < ACCREG_COUNT; c++) + acc_regs[c].count = 0; +} diff --git a/src/cpu_new/codegen_accumulate.h b/src/cpu_new/codegen_accumulate.h new file mode 100644 index 000000000..55d7c8eba --- /dev/null +++ b/src/cpu_new/codegen_accumulate.h @@ -0,0 +1,13 @@ +enum +{ + ACCREG_ins = 0, + ACCREG_cycles = 1, + + ACCREG_COUNT +}; + +struct ir_data_t; + +void codegen_accumulate(int acc_reg, int delta); +void codegen_accumulate_flush(struct ir_data_t *ir); +void codegen_accumulate_reset(); diff --git a/src/cpu_new/codegen_allocator.c b/src/cpu_new/codegen_allocator.c new file mode 100644 index 000000000..b78c4df12 --- /dev/null +++ b/src/cpu_new/codegen_allocator.c @@ -0,0 +1,125 @@ +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" + +typedef struct mem_block_t +{ + uint32_t offset; /*Offset into mem_block_alloc*/ + uint32_t next; + uint16_t code_block; +} mem_block_t; + +static mem_block_t mem_blocks[MEM_BLOCK_NR]; +static uint32_t mem_block_free_list; +static uint8_t *mem_block_alloc = NULL; + +int codegen_allocator_usage = 0; + +void codegen_allocator_init() +{ + int c; + +#if defined WIN32 || defined _WIN32 || defined _WIN32 + mem_block_alloc = VirtualAlloc(NULL, MEM_BLOCK_NR * MEM_BLOCK_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + mem_block_alloc = mmap(0, MEM_BLOCK_NR * MEM_BLOCK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, 0, 0); +#endif + + for (c = 0; c < MEM_BLOCK_NR; c++) + { + mem_blocks[c].offset = c * MEM_BLOCK_SIZE; + mem_blocks[c].code_block = BLOCK_INVALID; + if (c < MEM_BLOCK_NR-1) + mem_blocks[c].next = c+2; + else + mem_blocks[c].next = 0; + } + mem_block_free_list = 1; +} + +mem_block_t *codegen_allocator_allocate(mem_block_t *parent, int code_block) +{ + mem_block_t *block; + uint32_t block_nr; + + while (!mem_block_free_list) + { + /*Pick a random memory block and free the owning code block*/ + block_nr = rand() & MEM_BLOCK_MASK; + block = &mem_blocks[block_nr]; + + if (block->code_block && block->code_block != code_block) + codegen_delete_block(&codeblock[block->code_block]); + } + + /*Remove from free list*/ + block_nr = mem_block_free_list; + block = &mem_blocks[block_nr-1]; + mem_block_free_list = block->next; + + block->code_block = code_block; + if (parent) + { + /*Add to parent list*/ + block->next = parent->next; + parent->next = block_nr; + } + else + block->next = 0; + + codegen_allocator_usage++; + return block; +} +void codegen_allocator_free(mem_block_t *block) +{ + int block_nr = (((uintptr_t)block - (uintptr_t)mem_blocks) / sizeof(mem_block_t)) + 1; + + while (1) + { + int next_block_nr = block->next; + codegen_allocator_usage--; + + block->next = mem_block_free_list; + block->code_block = BLOCK_INVALID; + mem_block_free_list = block_nr; + block_nr = next_block_nr; + + if (block_nr) + block = &mem_blocks[block_nr - 1]; + else + break; + } +} + +uint8_t *codeblock_allocator_get_ptr(mem_block_t *block) +{ + return &mem_block_alloc[block->offset]; +} + +void codegen_allocator_clean_blocks(struct mem_block_t *block) +{ +#if defined __ARM_EABI__ || defined __aarch64__ + while (1) + { + __clear_cache(&mem_block_alloc[block->offset], &mem_block_alloc[block->offset + MEM_BLOCK_SIZE]); + if (block->next) + block = &mem_blocks[block->next - 1]; + else + break; + } +#endif +} diff --git a/src/cpu_new/codegen_allocator.h b/src/cpu_new/codegen_allocator.h new file mode 100644 index 000000000..90fa1c0b6 --- /dev/null +++ b/src/cpu_new/codegen_allocator.h @@ -0,0 +1,39 @@ +#ifndef _CODEGEN_ALLOCATOR_H_ +#define _CODEGEN_ALLOCATOR_H_ + +/*The allocator handles all allocation of executable memory. Since the two-pass + recompiler design makes applying hard limits to codeblock size difficult, the + allocator allows memory to be provided as and when required. + + The allocator provides a block size of a little under 1 kB (slightly lower to + limit cache aliasing). Each generated codeblock is allocated one block by default, + and will allocate additional block(s) once the existing memory is sorted. Blocks + are chained together by jump instructions. + + Due to the chaining, the total memory size is limited by the range of a jump + instruction. ARMv7 is restricted to +/- 32 MB, ARMv8 to +/- 128 MB, x86 to + +/- 2GB. As a result, total memory size is limited to 32 MB on ARMv7*/ +#ifdef __ARM_EABI__ +#define MEM_BLOCK_NR 32768 +#else +#define MEM_BLOCK_NR 131072 +#endif + +#define MEM_BLOCK_MASK (MEM_BLOCK_NR-1) +#define MEM_BLOCK_SIZE 0x3c0 + +void codegen_allocator_init(); +/*Allocate a mem_block_t, and the associated backing memory. + If parent is non-NULL, then the new block will be added to the list in + parent->next*/ +struct mem_block_t *codegen_allocator_allocate(struct mem_block_t *parent, int code_block); +/*Free a mem_block_t, and any subsequent blocks in the list at block->next*/ +void codegen_allocator_free(struct mem_block_t *block); +/*Get a pointer to the backing memory associated with block*/ +uint8_t *codeblock_allocator_get_ptr(struct mem_block_t *block); +/*Cache clean memory block list*/ +void codegen_allocator_clean_blocks(struct mem_block_t *block); + +extern int codegen_allocator_usage; + +#endif diff --git a/src/cpu_new/codegen_backend.h b/src/cpu_new/codegen_backend.h new file mode 100644 index 000000000..89beeee1c --- /dev/null +++ b/src/cpu_new/codegen_backend.h @@ -0,0 +1,41 @@ +#ifndef _CODEGEN_BACKEND_H_ +#define _CODEGEN_BACKEND_H_ + +#if defined __amd64__ +#include "codegen_backend_x86-64.h" +#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 +#include "codegen_backend_x86.h" +#elif defined __ARM_EABI__ +#include "codegen_backend_arm.h" +#elif defined __aarch64__ +#include "codegen_backend_arm64.h" +#else +#error Dynamic recompiler not implemented on your platform +#endif + +void codegen_backend_init(); +void codegen_backend_prologue(codeblock_t *block); +void codegen_backend_epilogue(codeblock_t *block); + +struct ir_data_t; +struct uop_t; + +struct ir_data_t *codegen_get_ir_data(); + +typedef int (*uOpFn)(codeblock_t *codeblock, struct uop_t *uop); + +extern const uOpFn uop_handlers[]; + +/*Register will not be preserved across function calls*/ +#define HOST_REG_FLAG_VOLATILE (1 << 0) + +typedef struct host_reg_def_t +{ + int reg; + int flags; +} host_reg_def_t; + +extern host_reg_def_t codegen_host_reg_list[CODEGEN_HOST_REGS]; +extern host_reg_def_t codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS]; + +#endif diff --git a/src/cpu_new/codegen_backend_arm.c b/src/cpu_new/codegen_backend_arm.c new file mode 100644 index 000000000..ddabbb5c5 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm.c @@ -0,0 +1,370 @@ +#ifdef __ARM_EABI__ + +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_arm_defs.h" +#include "codegen_backend_arm_ops.h" +#include "codegen_reg.h" +#include "x86.h" +#include "x87.h" + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +void *codegen_mem_load_byte; +void *codegen_mem_load_word; +void *codegen_mem_load_long; +void *codegen_mem_load_quad; +void *codegen_mem_load_single; +void *codegen_mem_load_double; + +void *codegen_mem_store_byte; +void *codegen_mem_store_word; +void *codegen_mem_store_long; +void *codegen_mem_store_quad; +void *codegen_mem_store_single; +void *codegen_mem_store_double; + +void *codegen_fp_round; + +void *codegen_gpf_rout; +void *codegen_exit_rout; + +host_reg_def_t codegen_host_reg_list[CODEGEN_HOST_REGS] = +{ + {REG_R4, 0}, + {REG_R5, 0}, + {REG_R6, 0}, + {REG_R7, 0}, + {REG_R8, 0}, + {REG_R9, 0}, + {REG_R11, 0} +}; + +host_reg_def_t codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = +{ + {REG_D8, 0}, + {REG_D9, 0}, + {REG_D10, 0}, + {REG_D11, 0}, + {REG_D12, 0}, + {REG_D13, 0}, + {REG_D14, 0}, + {REG_D15, 0} +}; + +static void build_load_routine(codeblock_t *block, int size, int is_float) +{ + uint32_t *branch_offset; + uint32_t *misaligned_offset; + + /*In - R0 = address + Out - R0 = data, R1 = abrt*/ + /*MOV R1, R0, LSR #12 + MOV R2, #readlookup2 + LDR R1, [R2, R1, LSL #2] + CMP R1, #-1 + BNE + + LDRB R0, [R1, R0] + MOV R1, #0 + MOV PC, LR + * STR LR, [SP, -4]! + BL readmembl + LDRB R1, cpu_state.abrt + LDR PC, [SP], #4 + */ + codegen_alloc(block, 80); + host_arm_MOV_REG_LSR(block, REG_R1, REG_R0, 12); + host_arm_MOV_IMM(block, REG_R2, (uint32_t)readlookup2); + host_arm_LDR_REG_LSL(block, REG_R1, REG_R2, REG_R1, 2); + if (size != 1) + { + host_arm_TST_IMM(block, REG_R0, size-1); + misaligned_offset = host_arm_BNE_(block); + } + host_arm_CMP_IMM(block, REG_R1, -1); + branch_offset = host_arm_BEQ_(block); + if (size == 1 && !is_float) + host_arm_LDRB_REG(block, REG_R0, REG_R1, REG_R0); + else if (size == 2 && !is_float) + host_arm_LDRH_REG(block, REG_R0, REG_R1, REG_R0); + else if (size == 4 && !is_float) + host_arm_LDR_REG(block, REG_R0, REG_R1, REG_R0); + else if (size == 4 && is_float) + { + host_arm_ADD_REG(block, REG_R0, REG_R0, REG_R1); + host_arm_VLDR_S(block, REG_D_TEMP, REG_R0, 0); + } + else if (size == 8) + { + host_arm_ADD_REG(block, REG_R0, REG_R0, REG_R1); + host_arm_VLDR_D(block, REG_D_TEMP, REG_R0, 0); + } + host_arm_MOV_IMM(block, REG_R1, 0); + host_arm_MOV_REG(block, REG_PC, REG_LR); + + *branch_offset |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 8) & 0x3fffffc) >> 2; + if (size != 1) + *misaligned_offset |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 8) & 0x3fffffc) >> 2; + host_arm_STR_IMM_WB(block, REG_LR, REG_HOST_SP, -4); + if (size == 1) + host_arm_BL(block, (uintptr_t)readmembl); + else if (size == 2) + host_arm_BL(block, (uintptr_t)readmemwl); + else if (size == 4) + host_arm_BL(block, (uintptr_t)readmemll); + else if (size == 8) + host_arm_BL(block, (uintptr_t)readmemql); + else + fatal("build_load_routine - unknown size %i\n", size); + if (size == 4 && is_float) + host_arm_VMOV_S_32(block, REG_D_TEMP, REG_R0); + else if (size == 8) + host_arm_VMOV_D_64(block, REG_D_TEMP, REG_R0, REG_R1); + host_arm_LDRB_ABS(block, REG_R1, &cpu_state.abrt); + host_arm_LDR_IMM_POST(block, REG_PC, REG_HOST_SP, 4); +} + +static void build_store_routine(codeblock_t *block, int size, int is_float) +{ + uint32_t *branch_offset; + uint32_t *misaligned_offset; + + /*In - R0 = address + Out - R0 = data, R1 = abrt*/ + /*MOV R1, R0, LSR #12 + MOV R2, #readlookup2 + LDR R1, [R2, R1, LSL #2] + CMP R1, #-1 + BNE + + LDRB R0, [R1, R0] + MOV R1, #0 + MOV PC, LR + * STR LR, [SP, -4]! + BL readmembl + LDRB R1, cpu_state.abrt + LDR PC, [SP], #4 + */ + codegen_alloc(block, 80); + host_arm_MOV_REG_LSR(block, REG_R2, REG_R0, 12); + host_arm_MOV_IMM(block, REG_R3, (uint32_t)writelookup2); + host_arm_LDR_REG_LSL(block, REG_R2, REG_R3, REG_R2, 2); + if (size != 1) + { + host_arm_TST_IMM(block, REG_R0, size-1); + misaligned_offset = host_arm_BNE_(block); + } + host_arm_CMP_IMM(block, REG_R2, -1); + branch_offset = host_arm_BEQ_(block); + if (size == 1 && !is_float) + host_arm_STRB_REG(block, REG_R1, REG_R2, REG_R0); + else if (size == 2 && !is_float) + host_arm_STRH_REG(block, REG_R1, REG_R2, REG_R0); + else if (size == 4 && !is_float) + host_arm_STR_REG(block, REG_R1, REG_R2, REG_R0); + else if (size == 4 && is_float) + { + host_arm_ADD_REG(block, REG_R0, REG_R0, REG_R2); + host_arm_VSTR_S(block, REG_D_TEMP, REG_R0, 0); + } + else if (size == 8) + { + host_arm_ADD_REG(block, REG_R0, REG_R0, REG_R2); + host_arm_VSTR_D(block, REG_D_TEMP, REG_R0, 0); + } + host_arm_MOV_IMM(block, REG_R1, 0); + host_arm_MOV_REG(block, REG_PC, REG_LR); + + *branch_offset |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 8) & 0x3fffffc) >> 2; + if (size != 1) + *misaligned_offset |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 8) & 0x3fffffc) >> 2; + host_arm_STR_IMM_WB(block, REG_LR, REG_HOST_SP, -4); + if (size == 4 && is_float) + host_arm_VMOV_32_S(block, REG_R1, REG_D_TEMP); + else if (size == 8) + host_arm_VMOV_64_D(block, REG_R2, REG_R3, REG_D_TEMP); + if (size == 1) + host_arm_BL(block, (uintptr_t)writemembl); + else if (size == 2) + host_arm_BL(block, (uintptr_t)writememwl); + else if (size == 4) + host_arm_BL(block, (uintptr_t)writememll); + else if (size == 8) + host_arm_BL_r1(block, (uintptr_t)writememql); + else + fatal("build_store_routine - unknown size %i\n", size); + host_arm_LDRB_ABS(block, REG_R1, &cpu_state.abrt); + host_arm_LDR_IMM_POST(block, REG_PC, REG_HOST_SP, 4); +} + +static void build_loadstore_routines(codeblock_t *block) +{ + codegen_mem_load_byte = &block_write_data[block_pos]; + build_load_routine(block, 1, 0); + codegen_mem_load_word = &block_write_data[block_pos]; + build_load_routine(block, 2, 0); + codegen_mem_load_long = &block_write_data[block_pos]; + build_load_routine(block, 4, 0); + codegen_mem_load_quad = &block_write_data[block_pos]; + build_load_routine(block, 8, 0); + codegen_mem_load_single = &block_write_data[block_pos]; + build_load_routine(block, 4, 1); + codegen_mem_load_double = &block_write_data[block_pos]; + build_load_routine(block, 8, 1); + + codegen_mem_store_byte = &block_write_data[block_pos]; + build_store_routine(block, 1, 0); + codegen_mem_store_word = &block_write_data[block_pos]; + build_store_routine(block, 2, 0); + codegen_mem_store_long = &block_write_data[block_pos]; + build_store_routine(block, 4, 0); + codegen_mem_store_quad = &block_write_data[block_pos]; + build_store_routine(block, 8, 0); + codegen_mem_store_single = &block_write_data[block_pos]; + build_store_routine(block, 4, 1); + codegen_mem_store_double = &block_write_data[block_pos]; + build_store_routine(block, 8, 1); +} + +/*VFP has a specific round-to-zero instruction, and the default rounding mode + is nearest. For round up/down, temporarily change the rounding mode in FPCSR*/ +#define FPCSR_ROUNDING_MASK (3 << 22) +#define FPCSR_ROUNDING_UP (1 << 22) +#define FPCSR_ROUNDING_DOWN (2 << 22) + +static void build_fp_round_routine(codeblock_t *block) +{ + uint32_t *jump_table; + + codegen_alloc(block, 80); + + host_arm_MOV_REG(block, REG_TEMP2, REG_LR); + host_arm_MOV_REG(block, REG_LR, REG_TEMP2); + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.new_fp_control - (uintptr_t)&cpu_state); + host_arm_LDR_REG(block, REG_PC, REG_PC, REG_TEMP); + host_arm_NOP(block); + + jump_table = (uint32_t *)&block_write_data[block_pos]; + host_arm_NOP(block); + host_arm_NOP(block); + host_arm_NOP(block); + host_arm_NOP(block); + + jump_table[X87_ROUNDING_NEAREST] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //tie even + host_arm_VCVTR_IS_D(block, REG_D_TEMP, REG_D_TEMP); + host_arm_MOV_REG(block, REG_PC, REG_LR); + + jump_table[X87_ROUNDING_UP] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //pos inf + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.old_fp_control - (uintptr_t)&cpu_state); + host_arm_BIC_IMM(block, REG_TEMP2, REG_TEMP, FPCSR_ROUNDING_MASK); + host_arm_ORR_IMM(block, REG_TEMP2, REG_TEMP2, FPCSR_ROUNDING_UP); + host_arm_VMSR_FPSCR(block, REG_TEMP2); + host_arm_VCVTR_IS_D(block, REG_D_TEMP, REG_D_TEMP); + host_arm_VMSR_FPSCR(block, REG_TEMP); + host_arm_MOV_REG(block, REG_PC, REG_LR); + + jump_table[X87_ROUNDING_DOWN] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //neg inf + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.old_fp_control - (uintptr_t)&cpu_state); + host_arm_BIC_IMM(block, REG_TEMP2, REG_TEMP, FPCSR_ROUNDING_MASK); + host_arm_ORR_IMM(block, REG_TEMP2, REG_TEMP, FPCSR_ROUNDING_DOWN); + host_arm_VMSR_FPSCR(block, REG_TEMP2); + host_arm_VCVTR_IS_D(block, REG_D_TEMP, REG_D_TEMP); + host_arm_VMSR_FPSCR(block, REG_TEMP); + host_arm_MOV_REG(block, REG_PC, REG_LR); + + jump_table[X87_ROUNDING_CHOP] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //zero + host_arm_VCVT_IS_D(block, REG_D_TEMP, REG_D_TEMP); + host_arm_MOV_REG(block, REG_PC, REG_LR); +} + +void codegen_backend_init() +{ + codeblock_t *block; + int c; + + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); + codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); + + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + + for (c = 0; c < BLOCK_SIZE; c++) + codeblock[c].pc = BLOCK_PC_INVALID; + + block_current = 0; + block_pos = 0; + block = &codeblock[block_current]; + block->head_mem_block = codegen_allocator_allocate(NULL, block_current); + block->data = codeblock_allocator_get_ptr(block->head_mem_block); + block_write_data = block->data; + build_loadstore_routines(&codeblock[block_current]); +printf("block_pos=%i\n", block_pos); + + codegen_fp_round = &block_write_data[block_pos]; + build_fp_round_routine(&codeblock[block_current]); + + codegen_alloc(block, 80); + codegen_gpf_rout = &block_write_data[block_pos]; + host_arm_MOV_IMM(block, REG_R0, 0); + host_arm_MOV_IMM(block, REG_R1, 0); + host_arm_call(block, x86gpf); + + codegen_exit_rout = &block_write_data[block_pos]; + host_arm_ADD_IMM(block, REG_HOST_SP, REG_HOST_SP, 0x40); + host_arm_LDMIA_WB(block, REG_HOST_SP, REG_MASK_LOCAL | REG_MASK_PC); + + block_write_data = NULL; +//fatal("block_pos=%i\n", block_pos); + asm("vmrs %0, fpscr\n" + : "=r" (cpu_state.old_fp_control) + ); + if ((cpu_state.old_fp_control >> 22) & 3) + fatal("VFP not in nearest rounding mode\n"); +} + +void codegen_set_rounding_mode(int mode) +{ + if (mode < 0 || mode > 3) + fatal("codegen_set_rounding_mode - invalid mode\n"); + cpu_state.new_fp_control = mode << 2; +} + +/*R10 - cpu_state*/ +void codegen_backend_prologue(codeblock_t *block) +{ + block_pos = BLOCK_START; + + /*Entry code*/ + + host_arm_STMDB_WB(block, REG_HOST_SP, REG_MASK_LOCAL | REG_MASK_LR); + host_arm_SUB_IMM(block, REG_HOST_SP, REG_HOST_SP, 0x40); + host_arm_MOV_IMM(block, REG_CPUSTATE, (uint32_t)&cpu_state); + if (block->flags & CODEBLOCK_HAS_FPU) + { + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.TOP - (uintptr_t)&cpu_state); + host_arm_SUB_IMM(block, REG_TEMP, REG_TEMP, block->TOP); + host_arm_STR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + } +} + +void codegen_backend_epilogue(codeblock_t *block) +{ + host_arm_ADD_IMM(block, REG_HOST_SP, REG_HOST_SP, 0x40); + host_arm_LDMIA_WB(block, REG_HOST_SP, REG_MASK_LOCAL | REG_MASK_PC); + + codegen_allocator_clean_blocks(block->head_mem_block); +} + +#endif diff --git a/src/cpu_new/codegen_backend_arm.h b/src/cpu_new/codegen_backend_arm.h new file mode 100644 index 000000000..87dc2d8a0 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm.h @@ -0,0 +1,24 @@ +#include "codegen_backend_arm_defs.h" + +#define BLOCK_SIZE 0x4000 +#define BLOCK_MASK 0x3fff +#define BLOCK_START 0 + +#define HASH_SIZE 0x20000 +#define HASH_MASK 0x1ffff + +#define HASH(l) ((l) & 0x1ffff) + +#define BLOCK_MAX 0x3c0 + +void host_arm_ADD_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_LDMIA_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask); +void host_arm_LDR_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset); +void host_arm_MOV_IMM(codeblock_t *block, int dst_reg, uint32_t imm); +void host_arm_STMDB_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask); +void host_arm_SUB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); + +void host_arm_call(codeblock_t *block, void *dst_addr); +void host_arm_nop(codeblock_t *block); + +void codegen_alloc(codeblock_t *block, int size); \ No newline at end of file diff --git a/src/cpu_new/codegen_backend_arm64.c b/src/cpu_new/codegen_backend_arm64.c new file mode 100644 index 000000000..32489000f --- /dev/null +++ b/src/cpu_new/codegen_backend_arm64.c @@ -0,0 +1,384 @@ +#ifdef __aarch64__ + +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_arm64_defs.h" +#include "codegen_backend_arm64_ops.h" +#include "codegen_reg.h" +#include "x86.h" +#include "x87.h" + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +void *codegen_mem_load_byte; +void *codegen_mem_load_word; +void *codegen_mem_load_long; +void *codegen_mem_load_quad; +void *codegen_mem_load_single; +void *codegen_mem_load_double; + +void *codegen_mem_store_byte; +void *codegen_mem_store_word; +void *codegen_mem_store_long; +void *codegen_mem_store_quad; +void *codegen_mem_store_single; +void *codegen_mem_store_double; + +void *codegen_fp_round; +void *codegen_fp_round_quad; + +void *codegen_gpf_rout; +void *codegen_exit_rout; + +host_reg_def_t codegen_host_reg_list[CODEGEN_HOST_REGS] = +{ + {REG_X19, 0}, + {REG_X20, 0}, + {REG_X21, 0}, + {REG_X22, 0}, + {REG_X23, 0}, + {REG_X24, 0}, + {REG_X25, 0}, + {REG_X26, 0}, + {REG_X27, 0}, + {REG_X28, 0} +}; + +host_reg_def_t codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = +{ + {REG_V8, 0}, + {REG_V9, 0}, + {REG_V10, 0}, + {REG_V11, 0}, + {REG_V12, 0}, + {REG_V13, 0}, + {REG_V14, 0}, + {REG_V15, 0} +}; + +static void build_load_routine(codeblock_t *block, int size, int is_float) +{ + uint32_t *branch_offset; + uint32_t *misaligned_offset; + int offset; + + /*In - W0 = address + Out - W0 = data, W1 = abrt*/ + /*MOV W1, W0, LSR #12 + MOV X2, #readlookup2 + LDR X1, [X2, X1, LSL #3] + CMP X1, #-1 + BEQ + + LDRB W0, [X1, X0] + MOV W1, #0 + RET + * STP X29, X30, [SP, #-16] + BL readmembl + LDRB R1, cpu_state.abrt + LDP X29, X30, [SP, #-16] + RET + */ + codegen_alloc(block, 80); + host_arm64_MOV_REG_LSR(block, REG_W1, REG_W0, 12); + host_arm64_MOVX_IMM(block, REG_X2, (uint64_t)readlookup2); + host_arm64_LDRX_REG_LSL3(block, REG_X1, REG_X2, REG_X1); + if (size != 1) + { + host_arm64_TST_IMM(block, REG_W0, size-1); + misaligned_offset = host_arm64_BNE_(block); + } + host_arm64_CMPX_IMM(block, REG_X1, -1); + branch_offset = host_arm64_BEQ_(block); + if (size == 1 && !is_float) + host_arm64_LDRB_REG(block, REG_W0, REG_W1, REG_W0); + else if (size == 2 && !is_float) + host_arm64_LDRH_REG(block, REG_W0, REG_W1, REG_W0); + else if (size == 4 && !is_float) + host_arm64_LDR_REG(block, REG_W0, REG_W1, REG_W0); + else if (size == 4 && is_float) + host_arm64_LDR_REG_F32(block, REG_V_TEMP, REG_W1, REG_W0); + else if (size == 8) + host_arm64_LDR_REG_F64(block, REG_V_TEMP, REG_W1, REG_W0); + host_arm64_MOVZ_IMM(block, REG_W1, 0); + host_arm64_RET(block, REG_X30); + + host_arm64_branch_set_offset(branch_offset, &block_write_data[block_pos]); + if (size != 1) + host_arm64_branch_set_offset(misaligned_offset, &block_write_data[block_pos]); + host_arm64_STP_PREIDX_X(block, REG_X29, REG_X30, REG_XSP, -16); + if (size == 1) + host_arm64_call(block, (void *)readmembl); + else if (size == 2) + host_arm64_call(block, (void *)readmemwl); + else if (size == 4) + host_arm64_call(block, (void *)readmemll); + else if (size == 8) + host_arm64_call(block, (void *)readmemql); + else + fatal("build_load_routine - unknown size %i\n", size); + codegen_direct_read_8(block, REG_W1, &cpu_state.abrt); + if (size == 4 && is_float) + host_arm64_FMOV_S_W(block, REG_V_TEMP, REG_W0); + else if (size == 8) + host_arm64_FMOV_D_Q(block, REG_V_TEMP, REG_X0); + host_arm64_LDP_POSTIDX_X(block, REG_X29, REG_X30, REG_XSP, 16); + host_arm64_RET(block, REG_X30); +} + +static void build_store_routine(codeblock_t *block, int size, int is_float) +{ + uint32_t *branch_offset; + uint32_t *misaligned_offset; + int offset; + + /*In - R0 = address, R1 = data + Out - R1 = abrt*/ + /*MOV W2, W0, LSR #12 + MOV X3, #writelookup2 + LDR X2, [X3, X2, LSL #3] + CMP X2, #-1 + BEQ + + STRB W1, [X2, X0] + MOV W1, #0 + RET + * STP X29, X30, [SP, #-16] + BL writemembl + LDRB R1, cpu_state.abrt + LDP X29, X30, [SP, #-16] + RET + */ + codegen_alloc(block, 80); + host_arm64_MOV_REG_LSR(block, REG_W2, REG_W0, 12); + host_arm64_MOVX_IMM(block, REG_X3, (uint64_t)writelookup2); + host_arm64_LDRX_REG_LSL3(block, REG_X2, REG_X3, REG_X2); + if (size != 1) + { + host_arm64_TST_IMM(block, REG_W0, size-1); + misaligned_offset = host_arm64_BNE_(block); + } + host_arm64_CMPX_IMM(block, REG_X2, -1); + branch_offset = host_arm64_BEQ_(block); + if (size == 1 && !is_float) + host_arm64_STRB_REG(block, REG_X1, REG_X2, REG_X0); + else if (size == 2 && !is_float) + host_arm64_STRH_REG(block, REG_X1, REG_X2, REG_X0); + else if (size == 4 && !is_float) + host_arm64_STR_REG(block, REG_X1, REG_X2, REG_X0); + else if (size == 4 && is_float) + host_arm64_STR_REG_F32(block, REG_V_TEMP, REG_X2, REG_X0); + else if (size == 8) + host_arm64_STR_REG_F64(block, REG_V_TEMP, REG_X2, REG_X0); + host_arm64_MOVZ_IMM(block, REG_X1, 0); + host_arm64_RET(block, REG_X30); + + host_arm64_branch_set_offset(branch_offset, &block_write_data[block_pos]); + if (size != 1) + host_arm64_branch_set_offset(misaligned_offset, &block_write_data[block_pos]); + host_arm64_STP_PREIDX_X(block, REG_X29, REG_X30, REG_XSP, -16); + if (size == 4 && is_float) + host_arm64_FMOV_W_S(block, REG_W1, REG_V_TEMP); + else if (size == 8) + host_arm64_FMOV_Q_D(block, REG_X1, REG_V_TEMP); + if (size == 1) + host_arm64_call(block, (void *)writemembl); + else if (size == 2) + host_arm64_call(block, (void *)writememwl); + else if (size == 4) + host_arm64_call(block, (void *)writememll); + else if (size == 8) + host_arm64_call(block, (void *)writememql); + else + fatal("build_store_routine - unknown size %i\n", size); + codegen_direct_read_8(block, REG_W1, &cpu_state.abrt); + host_arm64_LDP_POSTIDX_X(block, REG_X29, REG_X30, REG_XSP, 16); + host_arm64_RET(block, REG_X30); +} + +static void build_loadstore_routines(codeblock_t *block) +{ + codegen_mem_load_byte = &block_write_data[block_pos]; + build_load_routine(block, 1, 0); + codegen_mem_load_word = &block_write_data[block_pos]; + build_load_routine(block, 2, 0); + codegen_mem_load_long = &block_write_data[block_pos]; + build_load_routine(block, 4, 0); + codegen_mem_load_quad = &block_write_data[block_pos]; + build_load_routine(block, 8, 0); + codegen_mem_load_single = &block_write_data[block_pos]; + build_load_routine(block, 4, 1); + codegen_mem_load_double = &block_write_data[block_pos]; + build_load_routine(block, 8, 1); + + codegen_mem_store_byte = &block_write_data[block_pos]; + build_store_routine(block, 1, 0); + codegen_mem_store_word = &block_write_data[block_pos]; + build_store_routine(block, 2, 0); + codegen_mem_store_long = &block_write_data[block_pos]; + build_store_routine(block, 4, 0); + codegen_mem_store_quad = &block_write_data[block_pos]; + build_store_routine(block, 8, 0); + codegen_mem_store_single = &block_write_data[block_pos]; + build_store_routine(block, 4, 1); + codegen_mem_store_double = &block_write_data[block_pos]; + build_store_routine(block, 8, 1); +} + +static void build_fp_round_routine(codeblock_t *block, int is_quad) +{ + uint64_t *jump_table; + + codegen_alloc(block, 80); + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.new_fp_control - (uintptr_t)&cpu_state); + host_arm64_ADR(block, REG_TEMP2, 12); + host_arm64_LDR_REG_X(block, REG_TEMP2, REG_TEMP2, REG_TEMP); + host_arm64_BR(block, REG_TEMP2); + + jump_table = (uint64_t *)&block_write_data[block_pos]; + block_pos += 4*8; + + jump_table[X87_ROUNDING_NEAREST] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //tie even + if (is_quad) + host_arm64_FCVTNS_X_D(block, REG_TEMP, REG_V_TEMP); + else + host_arm64_FCVTNS_W_D(block, REG_TEMP, REG_V_TEMP); + host_arm64_RET(block, REG_X30); + + jump_table[X87_ROUNDING_UP] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //pos inf + if (is_quad) + host_arm64_FCVTPS_X_D(block, REG_TEMP, REG_V_TEMP); + else + host_arm64_FCVTPS_W_D(block, REG_TEMP, REG_V_TEMP); + host_arm64_RET(block, REG_X30); + + jump_table[X87_ROUNDING_DOWN] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //neg inf + if (is_quad) + host_arm64_FCVTMS_X_D(block, REG_TEMP, REG_V_TEMP); + else + host_arm64_FCVTMS_W_D(block, REG_TEMP, REG_V_TEMP); + host_arm64_RET(block, REG_X30); + + jump_table[X87_ROUNDING_CHOP] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //zero + if (is_quad) + host_arm64_FCVTZS_X_D(block, REG_TEMP, REG_V_TEMP); + else + host_arm64_FCVTZS_W_D(block, REG_TEMP, REG_V_TEMP); + host_arm64_RET(block, REG_X30); +} + +void codegen_backend_init() +{ + codeblock_t *block; + int c; +#if defined(__linux__) || defined(__APPLE__) + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); + codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); + + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + + for (c = 0; c < BLOCK_SIZE; c++) + { + codeblock[c].pc = BLOCK_PC_INVALID; + } + + block_current = 0; + block_pos = 0; + block = &codeblock[block_current]; + block->head_mem_block = codegen_allocator_allocate(NULL, block_current); + block->data = codeblock_allocator_get_ptr(block->head_mem_block); + block_write_data = block->data; + build_loadstore_routines(block); + + codegen_fp_round = &block_write_data[block_pos]; + build_fp_round_routine(block, 0); + codegen_fp_round_quad = &block_write_data[block_pos]; + build_fp_round_routine(block, 1); + + codegen_alloc(block, 80); + codegen_gpf_rout = &block_write_data[block_pos]; + host_arm64_mov_imm(block, REG_ARG0, 0); + host_arm64_mov_imm(block, REG_ARG1, 0); + host_arm64_call(block, (void *)x86gpf); + + codegen_exit_rout = &block_write_data[block_pos]; + host_arm64_LDP_POSTIDX_X(block, REG_X19, REG_X20, REG_XSP, 64); + host_arm64_LDP_POSTIDX_X(block, REG_X21, REG_X22, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X23, REG_X24, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X25, REG_X26, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X27, REG_X28, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X29, REG_X30, REG_XSP, 16); + host_arm64_RET(block, REG_X30); + + block_write_data = NULL; + + codegen_allocator_clean_blocks(block->head_mem_block); + + asm("mrs %0, fpcr\n" + : "=r" (cpu_state.old_fp_control) + ); +} + +void codegen_set_rounding_mode(int mode) +{ + if (mode < 0 || mode > 3) + fatal("codegen_set_rounding_mode - invalid mode\n"); + cpu_state.new_fp_control = mode << 3; +} + +/*R10 - cpu_state*/ +void codegen_backend_prologue(codeblock_t *block) +{ + block_pos = BLOCK_START; + + /*Entry code*/ + + host_arm64_STP_PREIDX_X(block, REG_X29, REG_X30, REG_XSP, -16); + host_arm64_STP_PREIDX_X(block, REG_X27, REG_X28, REG_XSP, -16); + host_arm64_STP_PREIDX_X(block, REG_X25, REG_X26, REG_XSP, -16); + host_arm64_STP_PREIDX_X(block, REG_X23, REG_X24, REG_XSP, -16); + host_arm64_STP_PREIDX_X(block, REG_X21, REG_X22, REG_XSP, -16); + host_arm64_STP_PREIDX_X(block, REG_X19, REG_X20, REG_XSP, -64); + + host_arm64_MOVX_IMM(block, REG_CPUSTATE, (uint64_t)&cpu_state); + + if (block->flags & CODEBLOCK_HAS_FPU) + { + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.TOP - (uintptr_t)&cpu_state); + host_arm64_SUB_IMM(block, REG_TEMP, REG_TEMP, block->TOP); + host_arm64_STR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + } +} + +void codegen_backend_epilogue(codeblock_t *block) +{ + host_arm64_LDP_POSTIDX_X(block, REG_X19, REG_X20, REG_XSP, 64); + host_arm64_LDP_POSTIDX_X(block, REG_X21, REG_X22, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X23, REG_X24, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X25, REG_X26, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X27, REG_X28, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X29, REG_X30, REG_XSP, 16); + host_arm64_RET(block, REG_X30); + + codegen_allocator_clean_blocks(block->head_mem_block); +} + +#endif diff --git a/src/cpu_new/codegen_backend_arm64.h b/src/cpu_new/codegen_backend_arm64.h new file mode 100644 index 000000000..b4888d38e --- /dev/null +++ b/src/cpu_new/codegen_backend_arm64.h @@ -0,0 +1,31 @@ +#include "codegen_backend_arm64_defs.h" + +#define BLOCK_SIZE 0x4000 +#define BLOCK_MASK 0x3fff +#define BLOCK_START 0 + +#define HASH_SIZE 0x20000 +#define HASH_MASK 0x1ffff + +#define HASH(l) ((l) & 0x1ffff) + +#define BLOCK_MAX 0x3c0 + + +void host_arm64_BLR(codeblock_t *block, int addr_reg); +void host_arm64_CBNZ(codeblock_t *block, int reg, uintptr_t dest); +void host_arm64_MOVK_IMM(codeblock_t *block, int reg, uint32_t imm_data); +void host_arm64_MOVZ_IMM(codeblock_t *block, int reg, uint32_t imm_data); +void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset); +void host_arm64_LDR_LITERAL_W(codeblock_t *block, int dest_reg, int literal_offset); +void host_arm64_LDR_LITERAL_X(codeblock_t *block, int dest_reg, int literal_offset); +void host_arm64_NOP(codeblock_t *block); +void host_arm64_RET(codeblock_t *block, int reg); +void host_arm64_STP_PREIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset); +void host_arm64_STR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STRB_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); + +void host_arm64_call(codeblock_t *block, void *dst_addr); +void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data); + +uint32_t host_arm64_find_imm(uint32_t data); \ No newline at end of file diff --git a/src/cpu_new/codegen_backend_arm64_defs.h b/src/cpu_new/codegen_backend_arm64_defs.h new file mode 100644 index 000000000..dabfe8ae8 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm64_defs.h @@ -0,0 +1,135 @@ +#define REG_W0 0 +#define REG_W1 1 +#define REG_W2 2 +#define REG_W3 3 +#define REG_W4 4 +#define REG_W5 5 +#define REG_W6 6 +#define REG_W7 7 +#define REG_W8 8 +#define REG_W9 9 +#define REG_W10 10 +#define REG_W11 11 +#define REG_W12 12 +#define REG_W13 13 +#define REG_W14 14 +#define REG_W15 15 +#define REG_W16 16 +#define REG_W17 17 +#define REG_W18 18 +#define REG_W19 19 +#define REG_W20 20 +#define REG_W21 21 +#define REG_W22 22 +#define REG_W23 23 +#define REG_W24 24 +#define REG_W25 25 +#define REG_W26 26 +#define REG_W27 27 +#define REG_W28 28 +#define REG_W29 29 +#define REG_W30 30 +#define REG_WZR 31 + +#define REG_X0 0 +#define REG_X1 1 +#define REG_X2 2 +#define REG_X3 3 +#define REG_X4 4 +#define REG_X5 5 +#define REG_X6 6 +#define REG_X7 7 +#define REG_X8 8 +#define REG_X9 9 +#define REG_X10 10 +#define REG_X11 11 +#define REG_X12 12 +#define REG_X13 13 +#define REG_X14 14 +#define REG_X15 15 +#define REG_X16 16 +#define REG_X17 17 +#define REG_X18 18 +#define REG_X19 19 +#define REG_X20 20 +#define REG_X21 21 +#define REG_X22 22 +#define REG_X23 23 +#define REG_X24 24 +#define REG_X25 25 +#define REG_X26 26 +#define REG_X27 27 +#define REG_X28 28 +#define REG_X29 29 +#define REG_X30 30 +#define REG_XZR 31 + +#define REG_V0 0 +#define REG_V1 1 +#define REG_V2 2 +#define REG_V3 3 +#define REG_V4 4 +#define REG_V5 5 +#define REG_V6 6 +#define REG_V7 7 +#define REG_V8 8 +#define REG_V9 9 +#define REG_V10 10 +#define REG_V11 11 +#define REG_V12 12 +#define REG_V13 13 +#define REG_V14 14 +#define REG_V15 15 +#define REG_V16 16 +#define REG_V17 17 +#define REG_V18 18 +#define REG_V19 19 +#define REG_V20 20 +#define REG_V21 21 +#define REG_V22 22 +#define REG_V23 23 +#define REG_V24 24 +#define REG_V25 25 +#define REG_V26 26 +#define REG_V27 27 +#define REG_V28 28 +#define REG_V29 29 +#define REG_V30 30 +#define REG_V31 31 + +#define REG_XSP 31 + +#define REG_ARG0 REG_X0 +#define REG_ARG1 REG_X1 +#define REG_ARG2 REG_X2 +#define REG_ARG3 REG_X3 + +#define REG_CPUSTATE REG_X29 + +#define REG_TEMP REG_X7 +#define REG_TEMP2 REG_X6 + +#define REG_V_TEMP REG_V0 + +#define CODEGEN_HOST_REGS 10 +#define CODEGEN_HOST_FP_REGS 8 + +extern void *codegen_mem_load_byte; +extern void *codegen_mem_load_word; +extern void *codegen_mem_load_long; +extern void *codegen_mem_load_quad; +extern void *codegen_mem_load_single; +extern void *codegen_mem_load_double; + +extern void *codegen_mem_store_byte; +extern void *codegen_mem_store_word; +extern void *codegen_mem_store_long; +extern void *codegen_mem_store_quad; +extern void *codegen_mem_store_single; +extern void *codegen_mem_store_double; + +extern void *codegen_fp_round; +extern void *codegen_fp_round_quad; + +extern void *codegen_gpf_rout; +extern void *codegen_exit_rout; \ No newline at end of file diff --git a/src/cpu_new/codegen_backend_arm64_imm.c b/src/cpu_new/codegen_backend_arm64_imm.c new file mode 100644 index 000000000..0362b71d6 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm64_imm.c @@ -0,0 +1,1330 @@ +#include +#include + +/*ARM64 logical instructions have an 'interesting' immediate encoding. + All valid values are in the table below, which we perform a binary + search over*/ +#define IMM_NR 1302 +static uint32_t imm_table[][2] = +{ + {0x800, 0x00000001}, + {0xfc0, 0x00000002}, + {0x801, 0x00000003}, + {0xf80, 0x00000004}, + {0xfc1, 0x00000006}, + {0x802, 0x00000007}, + {0xf40, 0x00000008}, + {0xf81, 0x0000000c}, + {0xfc2, 0x0000000e}, + {0x803, 0x0000000f}, + {0xf00, 0x00000010}, + {0xf41, 0x00000018}, + {0xf82, 0x0000001c}, + {0xfc3, 0x0000001e}, + {0x804, 0x0000001f}, + {0xec0, 0x00000020}, + {0xf01, 0x00000030}, + {0xf42, 0x00000038}, + {0xf83, 0x0000003c}, + {0xfc4, 0x0000003e}, + {0x805, 0x0000003f}, + {0xe80, 0x00000040}, + {0xec1, 0x00000060}, + {0xf02, 0x00000070}, + {0xf43, 0x00000078}, + {0xf84, 0x0000007c}, + {0xfc5, 0x0000007e}, + {0x806, 0x0000007f}, + {0xe40, 0x00000080}, + {0xe81, 0x000000c0}, + {0xec2, 0x000000e0}, + {0xf03, 0x000000f0}, + {0xf44, 0x000000f8}, + {0xf85, 0x000000fc}, + {0xfc6, 0x000000fe}, + {0x807, 0x000000ff}, + {0xe00, 0x00000100}, + {0xe41, 0x00000180}, + {0xe82, 0x000001c0}, + {0xec3, 0x000001e0}, + {0xf04, 0x000001f0}, + {0xf45, 0x000001f8}, + {0xf86, 0x000001fc}, + {0xfc7, 0x000001fe}, + {0x808, 0x000001ff}, + {0xdc0, 0x00000200}, + {0xe01, 0x00000300}, + {0xe42, 0x00000380}, + {0xe83, 0x000003c0}, + {0xec4, 0x000003e0}, + {0xf05, 0x000003f0}, + {0xf46, 0x000003f8}, + {0xf87, 0x000003fc}, + {0xfc8, 0x000003fe}, + {0x809, 0x000003ff}, + {0xd80, 0x00000400}, + {0xdc1, 0x00000600}, + {0xe02, 0x00000700}, + {0xe43, 0x00000780}, + {0xe84, 0x000007c0}, + {0xec5, 0x000007e0}, + {0xf06, 0x000007f0}, + {0xf47, 0x000007f8}, + {0xf88, 0x000007fc}, + {0xfc9, 0x000007fe}, + {0x80a, 0x000007ff}, + {0xd40, 0x00000800}, + {0xd81, 0x00000c00}, + {0xdc2, 0x00000e00}, + {0xe03, 0x00000f00}, + {0xe44, 0x00000f80}, + {0xe85, 0x00000fc0}, + {0xec6, 0x00000fe0}, + {0xf07, 0x00000ff0}, + {0xf48, 0x00000ff8}, + {0xf89, 0x00000ffc}, + {0xfca, 0x00000ffe}, + {0x80b, 0x00000fff}, + {0xd00, 0x00001000}, + {0xd41, 0x00001800}, + {0xd82, 0x00001c00}, + {0xdc3, 0x00001e00}, + {0xe04, 0x00001f00}, + {0xe45, 0x00001f80}, + {0xe86, 0x00001fc0}, + {0xec7, 0x00001fe0}, + {0xf08, 0x00001ff0}, + {0xf49, 0x00001ff8}, + {0xf8a, 0x00001ffc}, + {0xfcb, 0x00001ffe}, + {0x80c, 0x00001fff}, + {0xcc0, 0x00002000}, + {0xd01, 0x00003000}, + {0xd42, 0x00003800}, + {0xd83, 0x00003c00}, + {0xdc4, 0x00003e00}, + {0xe05, 0x00003f00}, + {0xe46, 0x00003f80}, + {0xe87, 0x00003fc0}, + {0xec8, 0x00003fe0}, + {0xf09, 0x00003ff0}, + {0xf4a, 0x00003ff8}, + {0xf8b, 0x00003ffc}, + {0xfcc, 0x00003ffe}, + {0x80d, 0x00003fff}, + {0xc80, 0x00004000}, + {0xcc1, 0x00006000}, + {0xd02, 0x00007000}, + {0xd43, 0x00007800}, + {0xd84, 0x00007c00}, + {0xdc5, 0x00007e00}, + {0xe06, 0x00007f00}, + {0xe47, 0x00007f80}, + {0xe88, 0x00007fc0}, + {0xec9, 0x00007fe0}, + {0xf0a, 0x00007ff0}, + {0xf4b, 0x00007ff8}, + {0xf8c, 0x00007ffc}, + {0xfcd, 0x00007ffe}, + {0x80e, 0x00007fff}, + {0xc40, 0x00008000}, + {0xc81, 0x0000c000}, + {0xcc2, 0x0000e000}, + {0xd03, 0x0000f000}, + {0xd44, 0x0000f800}, + {0xd85, 0x0000fc00}, + {0xdc6, 0x0000fe00}, + {0xe07, 0x0000ff00}, + {0xe48, 0x0000ff80}, + {0xe89, 0x0000ffc0}, + {0xeca, 0x0000ffe0}, + {0xf0b, 0x0000fff0}, + {0xf4c, 0x0000fff8}, + {0xf8d, 0x0000fffc}, + {0xfce, 0x0000fffe}, + {0x80f, 0x0000ffff}, + {0xc00, 0x00010000}, + {0xc20, 0x00010001}, + {0xc41, 0x00018000}, + {0xc82, 0x0001c000}, + {0xcc3, 0x0001e000}, + {0xd04, 0x0001f000}, + {0xd45, 0x0001f800}, + {0xd86, 0x0001fc00}, + {0xdc7, 0x0001fe00}, + {0xe08, 0x0001ff00}, + {0xe49, 0x0001ff80}, + {0xe8a, 0x0001ffc0}, + {0xecb, 0x0001ffe0}, + {0xf0c, 0x0001fff0}, + {0xf4d, 0x0001fff8}, + {0xf8e, 0x0001fffc}, + {0xfcf, 0x0001fffe}, + {0x810, 0x0001ffff}, + {0xbc0, 0x00020000}, + {0xfe0, 0x00020002}, + {0xc01, 0x00030000}, + {0xc21, 0x00030003}, + {0xc42, 0x00038000}, + {0xc83, 0x0003c000}, + {0xcc4, 0x0003e000}, + {0xd05, 0x0003f000}, + {0xd46, 0x0003f800}, + {0xd87, 0x0003fc00}, + {0xdc8, 0x0003fe00}, + {0xe09, 0x0003ff00}, + {0xe4a, 0x0003ff80}, + {0xe8b, 0x0003ffc0}, + {0xecc, 0x0003ffe0}, + {0xf0d, 0x0003fff0}, + {0xf4e, 0x0003fff8}, + {0xf8f, 0x0003fffc}, + {0xfd0, 0x0003fffe}, + {0x811, 0x0003ffff}, + {0xb80, 0x00040000}, + {0xfa0, 0x00040004}, + {0xbc1, 0x00060000}, + {0xfe1, 0x00060006}, + {0xc02, 0x00070000}, + {0xc22, 0x00070007}, + {0xc43, 0x00078000}, + {0xc84, 0x0007c000}, + {0xcc5, 0x0007e000}, + {0xd06, 0x0007f000}, + {0xd47, 0x0007f800}, + {0xd88, 0x0007fc00}, + {0xdc9, 0x0007fe00}, + {0xe0a, 0x0007ff00}, + {0xe4b, 0x0007ff80}, + {0xe8c, 0x0007ffc0}, + {0xecd, 0x0007ffe0}, + {0xf0e, 0x0007fff0}, + {0xf4f, 0x0007fff8}, + {0xf90, 0x0007fffc}, + {0xfd1, 0x0007fffe}, + {0x812, 0x0007ffff}, + {0xb40, 0x00080000}, + {0xf60, 0x00080008}, + {0xb81, 0x000c0000}, + {0xfa1, 0x000c000c}, + {0xbc2, 0x000e0000}, + {0xfe2, 0x000e000e}, + {0xc03, 0x000f0000}, + {0xc23, 0x000f000f}, + {0xc44, 0x000f8000}, + {0xc85, 0x000fc000}, + {0xcc6, 0x000fe000}, + {0xd07, 0x000ff000}, + {0xd48, 0x000ff800}, + {0xd89, 0x000ffc00}, + {0xdca, 0x000ffe00}, + {0xe0b, 0x000fff00}, + {0xe4c, 0x000fff80}, + {0xe8d, 0x000fffc0}, + {0xece, 0x000fffe0}, + {0xf0f, 0x000ffff0}, + {0xf50, 0x000ffff8}, + {0xf91, 0x000ffffc}, + {0xfd2, 0x000ffffe}, + {0x813, 0x000fffff}, + {0xb00, 0x00100000}, + {0xf20, 0x00100010}, + {0xb41, 0x00180000}, + {0xf61, 0x00180018}, + {0xb82, 0x001c0000}, + {0xfa2, 0x001c001c}, + {0xbc3, 0x001e0000}, + {0xfe3, 0x001e001e}, + {0xc04, 0x001f0000}, + {0xc24, 0x001f001f}, + {0xc45, 0x001f8000}, + {0xc86, 0x001fc000}, + {0xcc7, 0x001fe000}, + {0xd08, 0x001ff000}, + {0xd49, 0x001ff800}, + {0xd8a, 0x001ffc00}, + {0xdcb, 0x001ffe00}, + {0xe0c, 0x001fff00}, + {0xe4d, 0x001fff80}, + {0xe8e, 0x001fffc0}, + {0xecf, 0x001fffe0}, + {0xf10, 0x001ffff0}, + {0xf51, 0x001ffff8}, + {0xf92, 0x001ffffc}, + {0xfd3, 0x001ffffe}, + {0x814, 0x001fffff}, + {0xac0, 0x00200000}, + {0xee0, 0x00200020}, + {0xb01, 0x00300000}, + {0xf21, 0x00300030}, + {0xb42, 0x00380000}, + {0xf62, 0x00380038}, + {0xb83, 0x003c0000}, + {0xfa3, 0x003c003c}, + {0xbc4, 0x003e0000}, + {0xfe4, 0x003e003e}, + {0xc05, 0x003f0000}, + {0xc25, 0x003f003f}, + {0xc46, 0x003f8000}, + {0xc87, 0x003fc000}, + {0xcc8, 0x003fe000}, + {0xd09, 0x003ff000}, + {0xd4a, 0x003ff800}, + {0xd8b, 0x003ffc00}, + {0xdcc, 0x003ffe00}, + {0xe0d, 0x003fff00}, + {0xe4e, 0x003fff80}, + {0xe8f, 0x003fffc0}, + {0xed0, 0x003fffe0}, + {0xf11, 0x003ffff0}, + {0xf52, 0x003ffff8}, + {0xf93, 0x003ffffc}, + {0xfd4, 0x003ffffe}, + {0x815, 0x003fffff}, + {0xa80, 0x00400000}, + {0xea0, 0x00400040}, + {0xac1, 0x00600000}, + {0xee1, 0x00600060}, + {0xb02, 0x00700000}, + {0xf22, 0x00700070}, + {0xb43, 0x00780000}, + {0xf63, 0x00780078}, + {0xb84, 0x007c0000}, + {0xfa4, 0x007c007c}, + {0xbc5, 0x007e0000}, + {0xfe5, 0x007e007e}, + {0xc06, 0x007f0000}, + {0xc26, 0x007f007f}, + {0xc47, 0x007f8000}, + {0xc88, 0x007fc000}, + {0xcc9, 0x007fe000}, + {0xd0a, 0x007ff000}, + {0xd4b, 0x007ff800}, + {0xd8c, 0x007ffc00}, + {0xdcd, 0x007ffe00}, + {0xe0e, 0x007fff00}, + {0xe4f, 0x007fff80}, + {0xe90, 0x007fffc0}, + {0xed1, 0x007fffe0}, + {0xf12, 0x007ffff0}, + {0xf53, 0x007ffff8}, + {0xf94, 0x007ffffc}, + {0xfd5, 0x007ffffe}, + {0x816, 0x007fffff}, + {0xa40, 0x00800000}, + {0xe60, 0x00800080}, + {0xa81, 0x00c00000}, + {0xea1, 0x00c000c0}, + {0xac2, 0x00e00000}, + {0xee2, 0x00e000e0}, + {0xb03, 0x00f00000}, + {0xf23, 0x00f000f0}, + {0xb44, 0x00f80000}, + {0xf64, 0x00f800f8}, + {0xb85, 0x00fc0000}, + {0xfa5, 0x00fc00fc}, + {0xbc6, 0x00fe0000}, + {0xfe6, 0x00fe00fe}, + {0xc07, 0x00ff0000}, + {0xc27, 0x00ff00ff}, + {0xc48, 0x00ff8000}, + {0xc89, 0x00ffc000}, + {0xcca, 0x00ffe000}, + {0xd0b, 0x00fff000}, + {0xd4c, 0x00fff800}, + {0xd8d, 0x00fffc00}, + {0xdce, 0x00fffe00}, + {0xe0f, 0x00ffff00}, + {0xe50, 0x00ffff80}, + {0xe91, 0x00ffffc0}, + {0xed2, 0x00ffffe0}, + {0xf13, 0x00fffff0}, + {0xf54, 0x00fffff8}, + {0xf95, 0x00fffffc}, + {0xfd6, 0x00fffffe}, + {0x817, 0x00ffffff}, + {0xa00, 0x01000000}, + {0xe20, 0x01000100}, + {0xe30, 0x01010101}, + {0xa41, 0x01800000}, + {0xe61, 0x01800180}, + {0xa82, 0x01c00000}, + {0xea2, 0x01c001c0}, + {0xac3, 0x01e00000}, + {0xee3, 0x01e001e0}, + {0xb04, 0x01f00000}, + {0xf24, 0x01f001f0}, + {0xb45, 0x01f80000}, + {0xf65, 0x01f801f8}, + {0xb86, 0x01fc0000}, + {0xfa6, 0x01fc01fc}, + {0xbc7, 0x01fe0000}, + {0xfe7, 0x01fe01fe}, + {0xc08, 0x01ff0000}, + {0xc28, 0x01ff01ff}, + {0xc49, 0x01ff8000}, + {0xc8a, 0x01ffc000}, + {0xccb, 0x01ffe000}, + {0xd0c, 0x01fff000}, + {0xd4d, 0x01fff800}, + {0xd8e, 0x01fffc00}, + {0xdcf, 0x01fffe00}, + {0xe10, 0x01ffff00}, + {0xe51, 0x01ffff80}, + {0xe92, 0x01ffffc0}, + {0xed3, 0x01ffffe0}, + {0xf14, 0x01fffff0}, + {0xf55, 0x01fffff8}, + {0xf96, 0x01fffffc}, + {0xfd7, 0x01fffffe}, + {0x818, 0x01ffffff}, + {0x9c0, 0x02000000}, + {0xde0, 0x02000200}, + {0xff0, 0x02020202}, + {0xa01, 0x03000000}, + {0xe21, 0x03000300}, + {0xe31, 0x03030303}, + {0xa42, 0x03800000}, + {0xe62, 0x03800380}, + {0xa83, 0x03c00000}, + {0xea3, 0x03c003c0}, + {0xac4, 0x03e00000}, + {0xee4, 0x03e003e0}, + {0xb05, 0x03f00000}, + {0xf25, 0x03f003f0}, + {0xb46, 0x03f80000}, + {0xf66, 0x03f803f8}, + {0xb87, 0x03fc0000}, + {0xfa7, 0x03fc03fc}, + {0xbc8, 0x03fe0000}, + {0xfe8, 0x03fe03fe}, + {0xc09, 0x03ff0000}, + {0xc29, 0x03ff03ff}, + {0xc4a, 0x03ff8000}, + {0xc8b, 0x03ffc000}, + {0xccc, 0x03ffe000}, + {0xd0d, 0x03fff000}, + {0xd4e, 0x03fff800}, + {0xd8f, 0x03fffc00}, + {0xdd0, 0x03fffe00}, + {0xe11, 0x03ffff00}, + {0xe52, 0x03ffff80}, + {0xe93, 0x03ffffc0}, + {0xed4, 0x03ffffe0}, + {0xf15, 0x03fffff0}, + {0xf56, 0x03fffff8}, + {0xf97, 0x03fffffc}, + {0xfd8, 0x03fffffe}, + {0x819, 0x03ffffff}, + {0x980, 0x04000000}, + {0xda0, 0x04000400}, + {0xfb0, 0x04040404}, + {0x9c1, 0x06000000}, + {0xde1, 0x06000600}, + {0xff1, 0x06060606}, + {0xa02, 0x07000000}, + {0xe22, 0x07000700}, + {0xe32, 0x07070707}, + {0xa43, 0x07800000}, + {0xe63, 0x07800780}, + {0xa84, 0x07c00000}, + {0xea4, 0x07c007c0}, + {0xac5, 0x07e00000}, + {0xee5, 0x07e007e0}, + {0xb06, 0x07f00000}, + {0xf26, 0x07f007f0}, + {0xb47, 0x07f80000}, + {0xf67, 0x07f807f8}, + {0xb88, 0x07fc0000}, + {0xfa8, 0x07fc07fc}, + {0xbc9, 0x07fe0000}, + {0xfe9, 0x07fe07fe}, + {0xc0a, 0x07ff0000}, + {0xc2a, 0x07ff07ff}, + {0xc4b, 0x07ff8000}, + {0xc8c, 0x07ffc000}, + {0xccd, 0x07ffe000}, + {0xd0e, 0x07fff000}, + {0xd4f, 0x07fff800}, + {0xd90, 0x07fffc00}, + {0xdd1, 0x07fffe00}, + {0xe12, 0x07ffff00}, + {0xe53, 0x07ffff80}, + {0xe94, 0x07ffffc0}, + {0xed5, 0x07ffffe0}, + {0xf16, 0x07fffff0}, + {0xf57, 0x07fffff8}, + {0xf98, 0x07fffffc}, + {0xfd9, 0x07fffffe}, + {0x81a, 0x07ffffff}, + {0x940, 0x08000000}, + {0xd60, 0x08000800}, + {0xf70, 0x08080808}, + {0x981, 0x0c000000}, + {0xda1, 0x0c000c00}, + {0xfb1, 0x0c0c0c0c}, + {0x9c2, 0x0e000000}, + {0xde2, 0x0e000e00}, + {0xff2, 0x0e0e0e0e}, + {0xa03, 0x0f000000}, + {0xe23, 0x0f000f00}, + {0xe33, 0x0f0f0f0f}, + {0xa44, 0x0f800000}, + {0xe64, 0x0f800f80}, + {0xa85, 0x0fc00000}, + {0xea5, 0x0fc00fc0}, + {0xac6, 0x0fe00000}, + {0xee6, 0x0fe00fe0}, + {0xb07, 0x0ff00000}, + {0xf27, 0x0ff00ff0}, + {0xb48, 0x0ff80000}, + {0xf68, 0x0ff80ff8}, + {0xb89, 0x0ffc0000}, + {0xfa9, 0x0ffc0ffc}, + {0xbca, 0x0ffe0000}, + {0xfea, 0x0ffe0ffe}, + {0xc0b, 0x0fff0000}, + {0xc2b, 0x0fff0fff}, + {0xc4c, 0x0fff8000}, + {0xc8d, 0x0fffc000}, + {0xcce, 0x0fffe000}, + {0xd0f, 0x0ffff000}, + {0xd50, 0x0ffff800}, + {0xd91, 0x0ffffc00}, + {0xdd2, 0x0ffffe00}, + {0xe13, 0x0fffff00}, + {0xe54, 0x0fffff80}, + {0xe95, 0x0fffffc0}, + {0xed6, 0x0fffffe0}, + {0xf17, 0x0ffffff0}, + {0xf58, 0x0ffffff8}, + {0xf99, 0x0ffffffc}, + {0xfda, 0x0ffffffe}, + {0x81b, 0x0fffffff}, + {0x900, 0x10000000}, + {0xd20, 0x10001000}, + {0xf30, 0x10101010}, + {0xf38, 0x11111111}, + {0x941, 0x18000000}, + {0xd61, 0x18001800}, + {0xf71, 0x18181818}, + {0x982, 0x1c000000}, + {0xda2, 0x1c001c00}, + {0xfb2, 0x1c1c1c1c}, + {0x9c3, 0x1e000000}, + {0xde3, 0x1e001e00}, + {0xff3, 0x1e1e1e1e}, + {0xa04, 0x1f000000}, + {0xe24, 0x1f001f00}, + {0xe34, 0x1f1f1f1f}, + {0xa45, 0x1f800000}, + {0xe65, 0x1f801f80}, + {0xa86, 0x1fc00000}, + {0xea6, 0x1fc01fc0}, + {0xac7, 0x1fe00000}, + {0xee7, 0x1fe01fe0}, + {0xb08, 0x1ff00000}, + {0xf28, 0x1ff01ff0}, + {0xb49, 0x1ff80000}, + {0xf69, 0x1ff81ff8}, + {0xb8a, 0x1ffc0000}, + {0xfaa, 0x1ffc1ffc}, + {0xbcb, 0x1ffe0000}, + {0xfeb, 0x1ffe1ffe}, + {0xc0c, 0x1fff0000}, + {0xc2c, 0x1fff1fff}, + {0xc4d, 0x1fff8000}, + {0xc8e, 0x1fffc000}, + {0xccf, 0x1fffe000}, + {0xd10, 0x1ffff000}, + {0xd51, 0x1ffff800}, + {0xd92, 0x1ffffc00}, + {0xdd3, 0x1ffffe00}, + {0xe14, 0x1fffff00}, + {0xe55, 0x1fffff80}, + {0xe96, 0x1fffffc0}, + {0xed7, 0x1fffffe0}, + {0xf18, 0x1ffffff0}, + {0xf59, 0x1ffffff8}, + {0xf9a, 0x1ffffffc}, + {0xfdb, 0x1ffffffe}, + {0x81c, 0x1fffffff}, + {0x8c0, 0x20000000}, + {0xce0, 0x20002000}, + {0xef0, 0x20202020}, + {0xff8, 0x22222222}, + {0x901, 0x30000000}, + {0xd21, 0x30003000}, + {0xf31, 0x30303030}, + {0xf39, 0x33333333}, + {0x942, 0x38000000}, + {0xd62, 0x38003800}, + {0xf72, 0x38383838}, + {0x983, 0x3c000000}, + {0xda3, 0x3c003c00}, + {0xfb3, 0x3c3c3c3c}, + {0x9c4, 0x3e000000}, + {0xde4, 0x3e003e00}, + {0xff4, 0x3e3e3e3e}, + {0xa05, 0x3f000000}, + {0xe25, 0x3f003f00}, + {0xe35, 0x3f3f3f3f}, + {0xa46, 0x3f800000}, + {0xe66, 0x3f803f80}, + {0xa87, 0x3fc00000}, + {0xea7, 0x3fc03fc0}, + {0xac8, 0x3fe00000}, + {0xee8, 0x3fe03fe0}, + {0xb09, 0x3ff00000}, + {0xf29, 0x3ff03ff0}, + {0xb4a, 0x3ff80000}, + {0xf6a, 0x3ff83ff8}, + {0xb8b, 0x3ffc0000}, + {0xfab, 0x3ffc3ffc}, + {0xbcc, 0x3ffe0000}, + {0xfec, 0x3ffe3ffe}, + {0xc0d, 0x3fff0000}, + {0xc2d, 0x3fff3fff}, + {0xc4e, 0x3fff8000}, + {0xc8f, 0x3fffc000}, + {0xcd0, 0x3fffe000}, + {0xd11, 0x3ffff000}, + {0xd52, 0x3ffff800}, + {0xd93, 0x3ffffc00}, + {0xdd4, 0x3ffffe00}, + {0xe15, 0x3fffff00}, + {0xe56, 0x3fffff80}, + {0xe97, 0x3fffffc0}, + {0xed8, 0x3fffffe0}, + {0xf19, 0x3ffffff0}, + {0xf5a, 0x3ffffff8}, + {0xf9b, 0x3ffffffc}, + {0xfdc, 0x3ffffffe}, + {0x81d, 0x3fffffff}, + {0x880, 0x40000000}, + {0xca0, 0x40004000}, + {0xeb0, 0x40404040}, + {0xfb8, 0x44444444}, + {0xfbc, 0x55555555}, + {0x8c1, 0x60000000}, + {0xce1, 0x60006000}, + {0xef1, 0x60606060}, + {0xff9, 0x66666666}, + {0x902, 0x70000000}, + {0xd22, 0x70007000}, + {0xf32, 0x70707070}, + {0xf3a, 0x77777777}, + {0x943, 0x78000000}, + {0xd63, 0x78007800}, + {0xf73, 0x78787878}, + {0x984, 0x7c000000}, + {0xda4, 0x7c007c00}, + {0xfb4, 0x7c7c7c7c}, + {0x9c5, 0x7e000000}, + {0xde5, 0x7e007e00}, + {0xff5, 0x7e7e7e7e}, + {0xa06, 0x7f000000}, + {0xe26, 0x7f007f00}, + {0xe36, 0x7f7f7f7f}, + {0xa47, 0x7f800000}, + {0xe67, 0x7f807f80}, + {0xa88, 0x7fc00000}, + {0xea8, 0x7fc07fc0}, + {0xac9, 0x7fe00000}, + {0xee9, 0x7fe07fe0}, + {0xb0a, 0x7ff00000}, + {0xf2a, 0x7ff07ff0}, + {0xb4b, 0x7ff80000}, + {0xf6b, 0x7ff87ff8}, + {0xb8c, 0x7ffc0000}, + {0xfac, 0x7ffc7ffc}, + {0xbcd, 0x7ffe0000}, + {0xfed, 0x7ffe7ffe}, + {0xc0e, 0x7fff0000}, + {0xc2e, 0x7fff7fff}, + {0xc4f, 0x7fff8000}, + {0xc90, 0x7fffc000}, + {0xcd1, 0x7fffe000}, + {0xd12, 0x7ffff000}, + {0xd53, 0x7ffff800}, + {0xd94, 0x7ffffc00}, + {0xdd5, 0x7ffffe00}, + {0xe16, 0x7fffff00}, + {0xe57, 0x7fffff80}, + {0xe98, 0x7fffffc0}, + {0xed9, 0x7fffffe0}, + {0xf1a, 0x7ffffff0}, + {0xf5b, 0x7ffffff8}, + {0xf9c, 0x7ffffffc}, + {0xfdd, 0x7ffffffe}, + {0x81e, 0x7fffffff}, + {0x840, 0x80000000}, + {0x841, 0x80000001}, + {0x842, 0x80000003}, + {0x843, 0x80000007}, + {0x844, 0x8000000f}, + {0x845, 0x8000001f}, + {0x846, 0x8000003f}, + {0x847, 0x8000007f}, + {0x848, 0x800000ff}, + {0x849, 0x800001ff}, + {0x84a, 0x800003ff}, + {0x84b, 0x800007ff}, + {0x84c, 0x80000fff}, + {0x84d, 0x80001fff}, + {0x84e, 0x80003fff}, + {0x84f, 0x80007fff}, + {0xc60, 0x80008000}, + {0x850, 0x8000ffff}, + {0xc61, 0x80018001}, + {0x851, 0x8001ffff}, + {0xc62, 0x80038003}, + {0x852, 0x8003ffff}, + {0xc63, 0x80078007}, + {0x853, 0x8007ffff}, + {0xc64, 0x800f800f}, + {0x854, 0x800fffff}, + {0xc65, 0x801f801f}, + {0x855, 0x801fffff}, + {0xc66, 0x803f803f}, + {0x856, 0x803fffff}, + {0xc67, 0x807f807f}, + {0x857, 0x807fffff}, + {0xe70, 0x80808080}, + {0xc68, 0x80ff80ff}, + {0x858, 0x80ffffff}, + {0xe71, 0x81818181}, + {0xc69, 0x81ff81ff}, + {0x859, 0x81ffffff}, + {0xe72, 0x83838383}, + {0xc6a, 0x83ff83ff}, + {0x85a, 0x83ffffff}, + {0xe73, 0x87878787}, + {0xc6b, 0x87ff87ff}, + {0x85b, 0x87ffffff}, + {0xf78, 0x88888888}, + {0xe74, 0x8f8f8f8f}, + {0xc6c, 0x8fff8fff}, + {0x85c, 0x8fffffff}, + {0xf79, 0x99999999}, + {0xe75, 0x9f9f9f9f}, + {0xc6d, 0x9fff9fff}, + {0x85d, 0x9fffffff}, + {0xffc, 0xaaaaaaaa}, + {0xf7a, 0xbbbbbbbb}, + {0xe76, 0xbfbfbfbf}, + {0xc6e, 0xbfffbfff}, + {0x85e, 0xbfffffff}, + {0x881, 0xc0000000}, + {0x882, 0xc0000001}, + {0x883, 0xc0000003}, + {0x884, 0xc0000007}, + {0x885, 0xc000000f}, + {0x886, 0xc000001f}, + {0x887, 0xc000003f}, + {0x888, 0xc000007f}, + {0x889, 0xc00000ff}, + {0x88a, 0xc00001ff}, + {0x88b, 0xc00003ff}, + {0x88c, 0xc00007ff}, + {0x88d, 0xc0000fff}, + {0x88e, 0xc0001fff}, + {0x88f, 0xc0003fff}, + {0x890, 0xc0007fff}, + {0xca1, 0xc000c000}, + {0x891, 0xc000ffff}, + {0xca2, 0xc001c001}, + {0x892, 0xc001ffff}, + {0xca3, 0xc003c003}, + {0x893, 0xc003ffff}, + {0xca4, 0xc007c007}, + {0x894, 0xc007ffff}, + {0xca5, 0xc00fc00f}, + {0x895, 0xc00fffff}, + {0xca6, 0xc01fc01f}, + {0x896, 0xc01fffff}, + {0xca7, 0xc03fc03f}, + {0x897, 0xc03fffff}, + {0xca8, 0xc07fc07f}, + {0x898, 0xc07fffff}, + {0xeb1, 0xc0c0c0c0}, + {0xca9, 0xc0ffc0ff}, + {0x899, 0xc0ffffff}, + {0xeb2, 0xc1c1c1c1}, + {0xcaa, 0xc1ffc1ff}, + {0x89a, 0xc1ffffff}, + {0xeb3, 0xc3c3c3c3}, + {0xcab, 0xc3ffc3ff}, + {0x89b, 0xc3ffffff}, + {0xeb4, 0xc7c7c7c7}, + {0xcac, 0xc7ffc7ff}, + {0x89c, 0xc7ffffff}, + {0xfb9, 0xcccccccc}, + {0xeb5, 0xcfcfcfcf}, + {0xcad, 0xcfffcfff}, + {0x89d, 0xcfffffff}, + {0xfba, 0xdddddddd}, + {0xeb6, 0xdfdfdfdf}, + {0xcae, 0xdfffdfff}, + {0x89e, 0xdfffffff}, + {0x8c2, 0xe0000000}, + {0x8c3, 0xe0000001}, + {0x8c4, 0xe0000003}, + {0x8c5, 0xe0000007}, + {0x8c6, 0xe000000f}, + {0x8c7, 0xe000001f}, + {0x8c8, 0xe000003f}, + {0x8c9, 0xe000007f}, + {0x8ca, 0xe00000ff}, + {0x8cb, 0xe00001ff}, + {0x8cc, 0xe00003ff}, + {0x8cd, 0xe00007ff}, + {0x8ce, 0xe0000fff}, + {0x8cf, 0xe0001fff}, + {0x8d0, 0xe0003fff}, + {0x8d1, 0xe0007fff}, + {0xce2, 0xe000e000}, + {0x8d2, 0xe000ffff}, + {0xce3, 0xe001e001}, + {0x8d3, 0xe001ffff}, + {0xce4, 0xe003e003}, + {0x8d4, 0xe003ffff}, + {0xce5, 0xe007e007}, + {0x8d5, 0xe007ffff}, + {0xce6, 0xe00fe00f}, + {0x8d6, 0xe00fffff}, + {0xce7, 0xe01fe01f}, + {0x8d7, 0xe01fffff}, + {0xce8, 0xe03fe03f}, + {0x8d8, 0xe03fffff}, + {0xce9, 0xe07fe07f}, + {0x8d9, 0xe07fffff}, + {0xef2, 0xe0e0e0e0}, + {0xcea, 0xe0ffe0ff}, + {0x8da, 0xe0ffffff}, + {0xef3, 0xe1e1e1e1}, + {0xceb, 0xe1ffe1ff}, + {0x8db, 0xe1ffffff}, + {0xef4, 0xe3e3e3e3}, + {0xcec, 0xe3ffe3ff}, + {0x8dc, 0xe3ffffff}, + {0xef5, 0xe7e7e7e7}, + {0xced, 0xe7ffe7ff}, + {0x8dd, 0xe7ffffff}, + {0xffa, 0xeeeeeeee}, + {0xef6, 0xefefefef}, + {0xcee, 0xefffefff}, + {0x8de, 0xefffffff}, + {0x903, 0xf0000000}, + {0x904, 0xf0000001}, + {0x905, 0xf0000003}, + {0x906, 0xf0000007}, + {0x907, 0xf000000f}, + {0x908, 0xf000001f}, + {0x909, 0xf000003f}, + {0x90a, 0xf000007f}, + {0x90b, 0xf00000ff}, + {0x90c, 0xf00001ff}, + {0x90d, 0xf00003ff}, + {0x90e, 0xf00007ff}, + {0x90f, 0xf0000fff}, + {0x910, 0xf0001fff}, + {0x911, 0xf0003fff}, + {0x912, 0xf0007fff}, + {0xd23, 0xf000f000}, + {0x913, 0xf000ffff}, + {0xd24, 0xf001f001}, + {0x914, 0xf001ffff}, + {0xd25, 0xf003f003}, + {0x915, 0xf003ffff}, + {0xd26, 0xf007f007}, + {0x916, 0xf007ffff}, + {0xd27, 0xf00ff00f}, + {0x917, 0xf00fffff}, + {0xd28, 0xf01ff01f}, + {0x918, 0xf01fffff}, + {0xd29, 0xf03ff03f}, + {0x919, 0xf03fffff}, + {0xd2a, 0xf07ff07f}, + {0x91a, 0xf07fffff}, + {0xf33, 0xf0f0f0f0}, + {0xd2b, 0xf0fff0ff}, + {0x91b, 0xf0ffffff}, + {0xf34, 0xf1f1f1f1}, + {0xd2c, 0xf1fff1ff}, + {0x91c, 0xf1ffffff}, + {0xf35, 0xf3f3f3f3}, + {0xd2d, 0xf3fff3ff}, + {0x91d, 0xf3ffffff}, + {0xf36, 0xf7f7f7f7}, + {0xd2e, 0xf7fff7ff}, + {0x91e, 0xf7ffffff}, + {0x944, 0xf8000000}, + {0x945, 0xf8000001}, + {0x946, 0xf8000003}, + {0x947, 0xf8000007}, + {0x948, 0xf800000f}, + {0x949, 0xf800001f}, + {0x94a, 0xf800003f}, + {0x94b, 0xf800007f}, + {0x94c, 0xf80000ff}, + {0x94d, 0xf80001ff}, + {0x94e, 0xf80003ff}, + {0x94f, 0xf80007ff}, + {0x950, 0xf8000fff}, + {0x951, 0xf8001fff}, + {0x952, 0xf8003fff}, + {0x953, 0xf8007fff}, + {0xd64, 0xf800f800}, + {0x954, 0xf800ffff}, + {0xd65, 0xf801f801}, + {0x955, 0xf801ffff}, + {0xd66, 0xf803f803}, + {0x956, 0xf803ffff}, + {0xd67, 0xf807f807}, + {0x957, 0xf807ffff}, + {0xd68, 0xf80ff80f}, + {0x958, 0xf80fffff}, + {0xd69, 0xf81ff81f}, + {0x959, 0xf81fffff}, + {0xd6a, 0xf83ff83f}, + {0x95a, 0xf83fffff}, + {0xd6b, 0xf87ff87f}, + {0x95b, 0xf87fffff}, + {0xf74, 0xf8f8f8f8}, + {0xd6c, 0xf8fff8ff}, + {0x95c, 0xf8ffffff}, + {0xf75, 0xf9f9f9f9}, + {0xd6d, 0xf9fff9ff}, + {0x95d, 0xf9ffffff}, + {0xf76, 0xfbfbfbfb}, + {0xd6e, 0xfbfffbff}, + {0x95e, 0xfbffffff}, + {0x985, 0xfc000000}, + {0x986, 0xfc000001}, + {0x987, 0xfc000003}, + {0x988, 0xfc000007}, + {0x989, 0xfc00000f}, + {0x98a, 0xfc00001f}, + {0x98b, 0xfc00003f}, + {0x98c, 0xfc00007f}, + {0x98d, 0xfc0000ff}, + {0x98e, 0xfc0001ff}, + {0x98f, 0xfc0003ff}, + {0x990, 0xfc0007ff}, + {0x991, 0xfc000fff}, + {0x992, 0xfc001fff}, + {0x993, 0xfc003fff}, + {0x994, 0xfc007fff}, + {0xda5, 0xfc00fc00}, + {0x995, 0xfc00ffff}, + {0xda6, 0xfc01fc01}, + {0x996, 0xfc01ffff}, + {0xda7, 0xfc03fc03}, + {0x997, 0xfc03ffff}, + {0xda8, 0xfc07fc07}, + {0x998, 0xfc07ffff}, + {0xda9, 0xfc0ffc0f}, + {0x999, 0xfc0fffff}, + {0xdaa, 0xfc1ffc1f}, + {0x99a, 0xfc1fffff}, + {0xdab, 0xfc3ffc3f}, + {0x99b, 0xfc3fffff}, + {0xdac, 0xfc7ffc7f}, + {0x99c, 0xfc7fffff}, + {0xfb5, 0xfcfcfcfc}, + {0xdad, 0xfcfffcff}, + {0x99d, 0xfcffffff}, + {0xfb6, 0xfdfdfdfd}, + {0xdae, 0xfdfffdff}, + {0x99e, 0xfdffffff}, + {0x9c6, 0xfe000000}, + {0x9c7, 0xfe000001}, + {0x9c8, 0xfe000003}, + {0x9c9, 0xfe000007}, + {0x9ca, 0xfe00000f}, + {0x9cb, 0xfe00001f}, + {0x9cc, 0xfe00003f}, + {0x9cd, 0xfe00007f}, + {0x9ce, 0xfe0000ff}, + {0x9cf, 0xfe0001ff}, + {0x9d0, 0xfe0003ff}, + {0x9d1, 0xfe0007ff}, + {0x9d2, 0xfe000fff}, + {0x9d3, 0xfe001fff}, + {0x9d4, 0xfe003fff}, + {0x9d5, 0xfe007fff}, + {0xde6, 0xfe00fe00}, + {0x9d6, 0xfe00ffff}, + {0xde7, 0xfe01fe01}, + {0x9d7, 0xfe01ffff}, + {0xde8, 0xfe03fe03}, + {0x9d8, 0xfe03ffff}, + {0xde9, 0xfe07fe07}, + {0x9d9, 0xfe07ffff}, + {0xdea, 0xfe0ffe0f}, + {0x9da, 0xfe0fffff}, + {0xdeb, 0xfe1ffe1f}, + {0x9db, 0xfe1fffff}, + {0xdec, 0xfe3ffe3f}, + {0x9dc, 0xfe3fffff}, + {0xded, 0xfe7ffe7f}, + {0x9dd, 0xfe7fffff}, + {0xff6, 0xfefefefe}, + {0xdee, 0xfefffeff}, + {0x9de, 0xfeffffff}, + {0xa07, 0xff000000}, + {0xa08, 0xff000001}, + {0xa09, 0xff000003}, + {0xa0a, 0xff000007}, + {0xa0b, 0xff00000f}, + {0xa0c, 0xff00001f}, + {0xa0d, 0xff00003f}, + {0xa0e, 0xff00007f}, + {0xa0f, 0xff0000ff}, + {0xa10, 0xff0001ff}, + {0xa11, 0xff0003ff}, + {0xa12, 0xff0007ff}, + {0xa13, 0xff000fff}, + {0xa14, 0xff001fff}, + {0xa15, 0xff003fff}, + {0xa16, 0xff007fff}, + {0xe27, 0xff00ff00}, + {0xa17, 0xff00ffff}, + {0xe28, 0xff01ff01}, + {0xa18, 0xff01ffff}, + {0xe29, 0xff03ff03}, + {0xa19, 0xff03ffff}, + {0xe2a, 0xff07ff07}, + {0xa1a, 0xff07ffff}, + {0xe2b, 0xff0fff0f}, + {0xa1b, 0xff0fffff}, + {0xe2c, 0xff1fff1f}, + {0xa1c, 0xff1fffff}, + {0xe2d, 0xff3fff3f}, + {0xa1d, 0xff3fffff}, + {0xe2e, 0xff7fff7f}, + {0xa1e, 0xff7fffff}, + {0xa48, 0xff800000}, + {0xa49, 0xff800001}, + {0xa4a, 0xff800003}, + {0xa4b, 0xff800007}, + {0xa4c, 0xff80000f}, + {0xa4d, 0xff80001f}, + {0xa4e, 0xff80003f}, + {0xa4f, 0xff80007f}, + {0xa50, 0xff8000ff}, + {0xa51, 0xff8001ff}, + {0xa52, 0xff8003ff}, + {0xa53, 0xff8007ff}, + {0xa54, 0xff800fff}, + {0xa55, 0xff801fff}, + {0xa56, 0xff803fff}, + {0xa57, 0xff807fff}, + {0xe68, 0xff80ff80}, + {0xa58, 0xff80ffff}, + {0xe69, 0xff81ff81}, + {0xa59, 0xff81ffff}, + {0xe6a, 0xff83ff83}, + {0xa5a, 0xff83ffff}, + {0xe6b, 0xff87ff87}, + {0xa5b, 0xff87ffff}, + {0xe6c, 0xff8fff8f}, + {0xa5c, 0xff8fffff}, + {0xe6d, 0xff9fff9f}, + {0xa5d, 0xff9fffff}, + {0xe6e, 0xffbfffbf}, + {0xa5e, 0xffbfffff}, + {0xa89, 0xffc00000}, + {0xa8a, 0xffc00001}, + {0xa8b, 0xffc00003}, + {0xa8c, 0xffc00007}, + {0xa8d, 0xffc0000f}, + {0xa8e, 0xffc0001f}, + {0xa8f, 0xffc0003f}, + {0xa90, 0xffc0007f}, + {0xa91, 0xffc000ff}, + {0xa92, 0xffc001ff}, + {0xa93, 0xffc003ff}, + {0xa94, 0xffc007ff}, + {0xa95, 0xffc00fff}, + {0xa96, 0xffc01fff}, + {0xa97, 0xffc03fff}, + {0xa98, 0xffc07fff}, + {0xea9, 0xffc0ffc0}, + {0xa99, 0xffc0ffff}, + {0xeaa, 0xffc1ffc1}, + {0xa9a, 0xffc1ffff}, + {0xeab, 0xffc3ffc3}, + {0xa9b, 0xffc3ffff}, + {0xeac, 0xffc7ffc7}, + {0xa9c, 0xffc7ffff}, + {0xead, 0xffcfffcf}, + {0xa9d, 0xffcfffff}, + {0xeae, 0xffdfffdf}, + {0xa9e, 0xffdfffff}, + {0xaca, 0xffe00000}, + {0xacb, 0xffe00001}, + {0xacc, 0xffe00003}, + {0xacd, 0xffe00007}, + {0xace, 0xffe0000f}, + {0xacf, 0xffe0001f}, + {0xad0, 0xffe0003f}, + {0xad1, 0xffe0007f}, + {0xad2, 0xffe000ff}, + {0xad3, 0xffe001ff}, + {0xad4, 0xffe003ff}, + {0xad5, 0xffe007ff}, + {0xad6, 0xffe00fff}, + {0xad7, 0xffe01fff}, + {0xad8, 0xffe03fff}, + {0xad9, 0xffe07fff}, + {0xeea, 0xffe0ffe0}, + {0xada, 0xffe0ffff}, + {0xeeb, 0xffe1ffe1}, + {0xadb, 0xffe1ffff}, + {0xeec, 0xffe3ffe3}, + {0xadc, 0xffe3ffff}, + {0xeed, 0xffe7ffe7}, + {0xadd, 0xffe7ffff}, + {0xeee, 0xffefffef}, + {0xade, 0xffefffff}, + {0xb0b, 0xfff00000}, + {0xb0c, 0xfff00001}, + {0xb0d, 0xfff00003}, + {0xb0e, 0xfff00007}, + {0xb0f, 0xfff0000f}, + {0xb10, 0xfff0001f}, + {0xb11, 0xfff0003f}, + {0xb12, 0xfff0007f}, + {0xb13, 0xfff000ff}, + {0xb14, 0xfff001ff}, + {0xb15, 0xfff003ff}, + {0xb16, 0xfff007ff}, + {0xb17, 0xfff00fff}, + {0xb18, 0xfff01fff}, + {0xb19, 0xfff03fff}, + {0xb1a, 0xfff07fff}, + {0xf2b, 0xfff0fff0}, + {0xb1b, 0xfff0ffff}, + {0xf2c, 0xfff1fff1}, + {0xb1c, 0xfff1ffff}, + {0xf2d, 0xfff3fff3}, + {0xb1d, 0xfff3ffff}, + {0xf2e, 0xfff7fff7}, + {0xb1e, 0xfff7ffff}, + {0xb4c, 0xfff80000}, + {0xb4d, 0xfff80001}, + {0xb4e, 0xfff80003}, + {0xb4f, 0xfff80007}, + {0xb50, 0xfff8000f}, + {0xb51, 0xfff8001f}, + {0xb52, 0xfff8003f}, + {0xb53, 0xfff8007f}, + {0xb54, 0xfff800ff}, + {0xb55, 0xfff801ff}, + {0xb56, 0xfff803ff}, + {0xb57, 0xfff807ff}, + {0xb58, 0xfff80fff}, + {0xb59, 0xfff81fff}, + {0xb5a, 0xfff83fff}, + {0xb5b, 0xfff87fff}, + {0xf6c, 0xfff8fff8}, + {0xb5c, 0xfff8ffff}, + {0xf6d, 0xfff9fff9}, + {0xb5d, 0xfff9ffff}, + {0xf6e, 0xfffbfffb}, + {0xb5e, 0xfffbffff}, + {0xb8d, 0xfffc0000}, + {0xb8e, 0xfffc0001}, + {0xb8f, 0xfffc0003}, + {0xb90, 0xfffc0007}, + {0xb91, 0xfffc000f}, + {0xb92, 0xfffc001f}, + {0xb93, 0xfffc003f}, + {0xb94, 0xfffc007f}, + {0xb95, 0xfffc00ff}, + {0xb96, 0xfffc01ff}, + {0xb97, 0xfffc03ff}, + {0xb98, 0xfffc07ff}, + {0xb99, 0xfffc0fff}, + {0xb9a, 0xfffc1fff}, + {0xb9b, 0xfffc3fff}, + {0xb9c, 0xfffc7fff}, + {0xfad, 0xfffcfffc}, + {0xb9d, 0xfffcffff}, + {0xfae, 0xfffdfffd}, + {0xb9e, 0xfffdffff}, + {0xbce, 0xfffe0000}, + {0xbcf, 0xfffe0001}, + {0xbd0, 0xfffe0003}, + {0xbd1, 0xfffe0007}, + {0xbd2, 0xfffe000f}, + {0xbd3, 0xfffe001f}, + {0xbd4, 0xfffe003f}, + {0xbd5, 0xfffe007f}, + {0xbd6, 0xfffe00ff}, + {0xbd7, 0xfffe01ff}, + {0xbd8, 0xfffe03ff}, + {0xbd9, 0xfffe07ff}, + {0xbda, 0xfffe0fff}, + {0xbdb, 0xfffe1fff}, + {0xbdc, 0xfffe3fff}, + {0xbdd, 0xfffe7fff}, + {0xfee, 0xfffefffe}, + {0xbde, 0xfffeffff}, + {0xc0f, 0xffff0000}, + {0xc10, 0xffff0001}, + {0xc11, 0xffff0003}, + {0xc12, 0xffff0007}, + {0xc13, 0xffff000f}, + {0xc14, 0xffff001f}, + {0xc15, 0xffff003f}, + {0xc16, 0xffff007f}, + {0xc17, 0xffff00ff}, + {0xc18, 0xffff01ff}, + {0xc19, 0xffff03ff}, + {0xc1a, 0xffff07ff}, + {0xc1b, 0xffff0fff}, + {0xc1c, 0xffff1fff}, + {0xc1d, 0xffff3fff}, + {0xc1e, 0xffff7fff}, + {0xc50, 0xffff8000}, + {0xc51, 0xffff8001}, + {0xc52, 0xffff8003}, + {0xc53, 0xffff8007}, + {0xc54, 0xffff800f}, + {0xc55, 0xffff801f}, + {0xc56, 0xffff803f}, + {0xc57, 0xffff807f}, + {0xc58, 0xffff80ff}, + {0xc59, 0xffff81ff}, + {0xc5a, 0xffff83ff}, + {0xc5b, 0xffff87ff}, + {0xc5c, 0xffff8fff}, + {0xc5d, 0xffff9fff}, + {0xc5e, 0xffffbfff}, + {0xc91, 0xffffc000}, + {0xc92, 0xffffc001}, + {0xc93, 0xffffc003}, + {0xc94, 0xffffc007}, + {0xc95, 0xffffc00f}, + {0xc96, 0xffffc01f}, + {0xc97, 0xffffc03f}, + {0xc98, 0xffffc07f}, + {0xc99, 0xffffc0ff}, + {0xc9a, 0xffffc1ff}, + {0xc9b, 0xffffc3ff}, + {0xc9c, 0xffffc7ff}, + {0xc9d, 0xffffcfff}, + {0xc9e, 0xffffdfff}, + {0xcd2, 0xffffe000}, + {0xcd3, 0xffffe001}, + {0xcd4, 0xffffe003}, + {0xcd5, 0xffffe007}, + {0xcd6, 0xffffe00f}, + {0xcd7, 0xffffe01f}, + {0xcd8, 0xffffe03f}, + {0xcd9, 0xffffe07f}, + {0xcda, 0xffffe0ff}, + {0xcdb, 0xffffe1ff}, + {0xcdc, 0xffffe3ff}, + {0xcdd, 0xffffe7ff}, + {0xcde, 0xffffefff}, + {0xd13, 0xfffff000}, + {0xd14, 0xfffff001}, + {0xd15, 0xfffff003}, + {0xd16, 0xfffff007}, + {0xd17, 0xfffff00f}, + {0xd18, 0xfffff01f}, + {0xd19, 0xfffff03f}, + {0xd1a, 0xfffff07f}, + {0xd1b, 0xfffff0ff}, + {0xd1c, 0xfffff1ff}, + {0xd1d, 0xfffff3ff}, + {0xd1e, 0xfffff7ff}, + {0xd54, 0xfffff800}, + {0xd55, 0xfffff801}, + {0xd56, 0xfffff803}, + {0xd57, 0xfffff807}, + {0xd58, 0xfffff80f}, + {0xd59, 0xfffff81f}, + {0xd5a, 0xfffff83f}, + {0xd5b, 0xfffff87f}, + {0xd5c, 0xfffff8ff}, + {0xd5d, 0xfffff9ff}, + {0xd5e, 0xfffffbff}, + {0xd95, 0xfffffc00}, + {0xd96, 0xfffffc01}, + {0xd97, 0xfffffc03}, + {0xd98, 0xfffffc07}, + {0xd99, 0xfffffc0f}, + {0xd9a, 0xfffffc1f}, + {0xd9b, 0xfffffc3f}, + {0xd9c, 0xfffffc7f}, + {0xd9d, 0xfffffcff}, + {0xd9e, 0xfffffdff}, + {0xdd6, 0xfffffe00}, + {0xdd7, 0xfffffe01}, + {0xdd8, 0xfffffe03}, + {0xdd9, 0xfffffe07}, + {0xdda, 0xfffffe0f}, + {0xddb, 0xfffffe1f}, + {0xddc, 0xfffffe3f}, + {0xddd, 0xfffffe7f}, + {0xdde, 0xfffffeff}, + {0xe17, 0xffffff00}, + {0xe18, 0xffffff01}, + {0xe19, 0xffffff03}, + {0xe1a, 0xffffff07}, + {0xe1b, 0xffffff0f}, + {0xe1c, 0xffffff1f}, + {0xe1d, 0xffffff3f}, + {0xe1e, 0xffffff7f}, + {0xe58, 0xffffff80}, + {0xe59, 0xffffff81}, + {0xe5a, 0xffffff83}, + {0xe5b, 0xffffff87}, + {0xe5c, 0xffffff8f}, + {0xe5d, 0xffffff9f}, + {0xe5e, 0xffffffbf}, + {0xe99, 0xffffffc0}, + {0xe9a, 0xffffffc1}, + {0xe9b, 0xffffffc3}, + {0xe9c, 0xffffffc7}, + {0xe9d, 0xffffffcf}, + {0xe9e, 0xffffffdf}, + {0xeda, 0xffffffe0}, + {0xedb, 0xffffffe1}, + {0xedc, 0xffffffe3}, + {0xedd, 0xffffffe7}, + {0xede, 0xffffffef}, + {0xf1b, 0xfffffff0}, + {0xf1c, 0xfffffff1}, + {0xf1d, 0xfffffff3}, + {0xf1e, 0xfffffff7}, + {0xf5c, 0xfffffff8}, + {0xf5d, 0xfffffff9}, + {0xf5e, 0xfffffffb}, + {0xf9d, 0xfffffffc}, + {0xf9e, 0xfffffffd}, + {0xfde, 0xfffffffe}, +}; + +uint32_t host_arm64_find_imm(uint32_t data) +{ + int l = 0, r = IMM_NR - 1; + + while (l <= r) + { + int m = (l + r) >> 1; + + if (imm_table[m][1] < data) + l = m+1; + else if (imm_table[m][1] > data) + r = m-1; + else + return imm_table[m][0]; + } + return 0; +} diff --git a/src/cpu_new/codegen_backend_arm64_ops.c b/src/cpu_new/codegen_backend_arm64_ops.c new file mode 100644 index 000000000..44cf87647 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm64_ops.c @@ -0,0 +1,1386 @@ +#ifdef __aarch64__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_arm64_defs.h" +#include "codegen_backend_arm64_ops.h" + + +#define Rt(x) (x) +#define Rd(x) (x) +#define Rn(x) ((x) << 5) +#define Rt2(x) ((x) << 10) +#define Rm(x) ((x) << 16) + +#define shift_imm6(x) ((x) << 10) + +#define DATA_OFFSET_UP (1 << 23) +#define DATA_OFFSET_DOWN (0 << 23) + +#define COND_EQ (0x0) +#define COND_NE (0x1) +#define COND_CS (0x2) +#define COND_CC (0x3) +#define COND_MI (0x4) +#define COND_PL (0x5) +#define COND_VS (0x6) +#define COND_VC (0x7) +#define COND_HI (0x8) +#define COND_LS (0x9) +#define COND_GE (0xa) +#define COND_LT (0xb) +#define COND_GT (0xc) +#define COND_LE (0xd) + +#define CSEL_COND(cond) ((cond) << 12) + +#define OPCODE_SHIFT 24 +#define OPCODE_ADD_IMM (0x11 << OPCODE_SHIFT) +#define OPCODE_ADDX_IMM (0x91 << OPCODE_SHIFT) +#define OPCODE_ADR (0x10 << OPCODE_SHIFT) +#define OPCODE_B (0x14 << OPCODE_SHIFT) +#define OPCODE_BCOND (0x54 << OPCODE_SHIFT) +#define OPCODE_CBNZ (0xb5 << OPCODE_SHIFT) +#define OPCODE_CBZ (0xb4 << OPCODE_SHIFT) +#define OPCODE_CMN_IMM (0x31 << OPCODE_SHIFT) +#define OPCODE_CMNX_IMM (0xb1 << OPCODE_SHIFT) +#define OPCODE_CMP_IMM (0x71 << OPCODE_SHIFT) +#define OPCODE_CMPX_IMM (0xf1 << OPCODE_SHIFT) +#define OPCODE_SUB_IMM (0x51 << OPCODE_SHIFT) +#define OPCODE_SUBX_IMM (0xd1 << OPCODE_SHIFT) +#define OPCODE_TBNZ (0x37 << OPCODE_SHIFT) +#define OPCODE_TBZ (0x36 << OPCODE_SHIFT) + +#define OPCODE_AND_IMM (0x024 << 23) +#define OPCODE_ANDS_IMM (0x0e4 << 23) +#define OPCODE_EOR_IMM (0x0a4 << 23) +#define OPCODE_MOVK_W (0x0e5 << 23) +#define OPCODE_MOVK_X (0x1e5 << 23) +#define OPCODE_MOVZ_W (0x0a5 << 23) +#define OPCODE_MOVZ_X (0x1a5 << 23) +#define OPCODE_ORR_IMM (0x064 << 23) + +#define OPCODE_BFI (0x0cc << 22) +#define OPCODE_LDR_IMM_W (0x2e5 << 22) +#define OPCODE_LDR_IMM_X (0x3e5 << 22) +#define OPCODE_LDR_IMM_F64 (0x3f5 << 22) +#define OPCODE_LDRB_IMM_W (0x0e5 << 22) +#define OPCODE_LDRH_IMM (0x1e5 << 22) +#define OPCODE_LDP_POSTIDX_X (0x2a3 << 22) +#define OPCODE_SBFX (0x04c << 22) +#define OPCODE_STP_PREIDX_X (0x2a6 << 22) +#define OPCODE_STR_IMM_W (0x2e4 << 22) +#define OPCODE_STR_IMM_Q (0x3e4 << 22) +#define OPCODE_STR_IMM_F64 (0x3f4 << 22) +#define OPCODE_STRB_IMM (0x0e4 << 22) +#define OPCODE_STRH_IMM (0x1e4 << 22) +#define OPCODE_UBFX (0x14c << 22) + +#define OPCODE_ADD_LSL (0x058 << 21) +#define OPCODE_ADD_LSR (0x05a << 21) +#define OPCODE_ADDX_LSL (0x458 << 21) +#define OPCODE_AND_ASR (0x054 << 21) +#define OPCODE_AND_LSL (0x050 << 21) +#define OPCODE_AND_ROR (0x056 << 21) +#define OPCODE_ANDS_LSL (0x350 << 21) +#define OPCODE_CMP_LSL (0x358 << 21) +#define OPCODE_CSEL (0x0d4 << 21) +#define OPCODE_EOR_LSL (0x250 << 21) +#define OPCODE_ORR_ASR (0x154 << 21) +#define OPCODE_ORR_LSL (0x150 << 21) +#define OPCODE_ORR_LSR (0x152 << 21) +#define OPCODE_ORR_ROR (0x156 << 21) +#define OPCODE_ORRX_LSL (0x550 << 21) +#define OPCODE_SUB_LSL (0x258 << 21) +#define OPCODE_SUB_LSR (0x25a << 21) +#define OPCODE_SUBX_LSL (0x658 << 21) + +#define OPCODE_ADD_V8B (0x0e208400) +#define OPCODE_ADD_V4H (0x0e608400) +#define OPCODE_ADD_V2S (0x0ea08400) +#define OPCODE_ADDP_V4S (0x4ea0bc00) +#define OPCODE_AND_V (0x0e201c00) +#define OPCODE_ASR (0x1ac02800) +#define OPCODE_BIC_V (0x0e601c00) +#define OPCODE_BLR (0xd63f0000) +#define OPCODE_BR (0xd61f0000) +#define OPCODE_CMEQ_V8B (0x2e208c00) +#define OPCODE_CMEQ_V4H (0x2e608c00) +#define OPCODE_CMEQ_V2S (0x2ea08c00) +#define OPCODE_CMGT_V8B (0x0e203400) +#define OPCODE_CMGT_V4H (0x0e603400) +#define OPCODE_CMGT_V2S (0x0ea03400) +#define OPCODE_DUP_V2S (0x0e040400) +#define OPCODE_EOR_V (0x2e201c00) +#define OPCODE_FABS_D (0x1e60c000) +#define OPCODE_FADD_D (0x1e602800) +#define OPCODE_FADD_V2S (0x0e20d400) +#define OPCODE_FCMEQ_V2S (0x0e20e400) +#define OPCODE_FCMGE_V2S (0x2e20e400) +#define OPCODE_FCMGT_V2S (0x2ea0e400) +#define OPCODE_FCMP_D (0x1e602000) +#define OPCODE_FCVT_D_S (0x1e22c000) +#define OPCODE_FCVT_S_D (0x1e624000) +#define OPCODE_FCVTMS_W_D (0x1e700000) +#define OPCODE_FCVTMS_X_D (0x9e700000) +#define OPCODE_FCVTNS_W_D (0x1e600000) +#define OPCODE_FCVTNS_X_D (0x9e600000) +#define OPCODE_FCVTPS_W_D (0x1e680000) +#define OPCODE_FCVTPS_X_D (0x9e680000) +#define OPCODE_FCVTZS_W_D (0x1e780000) +#define OPCODE_FCVTZS_X_D (0x9e780000) +#define OPCODE_FCVTZS_V2S (0x0ea1b800) +#define OPCODE_FDIV_D (0x1e601800) +#define OPCODE_FDIV_S (0x1e201800) +#define OPCODE_FMAX_V2S (0x0e20f400) +#define OPCODE_FMIN_V2S (0x0ea0f400) +#define OPCODE_FMOV_D_D (0x1e604000) +#define OPCODE_FMOV_D_Q (0x9e670000) +#define OPCODE_FMOV_Q_D (0x9e660000) +#define OPCODE_FMOV_S_W (0x1e270000) +#define OPCODE_FMOV_W_S (0x1e260000) +#define OPCODE_FMOV_S_ONE (0x1e2e1000) +#define OPCODE_FMUL_D (0x1e600800) +#define OPCODE_FMUL_V2S (0x2e20dc00) +#define OPCODE_FNEG_D (0x1e614000) +#define OPCODE_FRINTX_D (0x1e674000) +#define OPCODE_FSQRT_D (0x1e61c000) +#define OPCODE_FSQRT_S (0x1e21c000) +#define OPCODE_FSUB_D (0x1e603800) +#define OPCODE_FSUB_V2S (0x0ea0d400) +#define OPCODE_LDR_REG (0xb8606800) +#define OPCODE_LDRX_REG (0xf8606800) +#define OPCODE_LDRB_REG (0x38606800) +#define OPCODE_LDRH_REG (0x78606800) +#define OPCODE_LDRX_REG_LSL3 (0xf8607800) +#define OPCODE_LDR_REG_F32 (0xbc606800) +#define OPCODE_LDR_REG_F64 (0xfc606800) +#define OPCODE_LDR_REG_F64_S (0xfc607800) +#define OPCODE_LSL (0x1ac02000) +#define OPCODE_LSR (0x1ac02400) +#define OPCODE_MSR_FPCR (0xd51b4400) +#define OPCODE_MUL_V4H (0x0e609c00) +#define OPCODE_NOP (0xd503201f) +#define OPCODE_ORR_V (0x0ea01c00) +#define OPCODE_RET (0xd65f0000) +#define OPCODE_ROR (0x1ac02c00) +#define OPCODE_SADDLP_V2S_4H (0x0e602800) +#define OPCODE_SCVTF_D_Q (0x9e620000) +#define OPCODE_SCVTF_D_W (0x1e620000) +#define OPCODE_SCVTF_V2S (0x0e21d800) +#define OPCODE_SQADD_V8B (0x0e200c00) +#define OPCODE_SQADD_V4H (0x0e600c00) +#define OPCODE_SQSUB_V8B (0x0e202c00) +#define OPCODE_SQSUB_V4H (0x0e602c00) +#define OPCODE_SQXTN_V8B_8H (0x0e214800) +#define OPCODE_SQXTN_V4H_4S (0x0e614800) +#define OPCODE_SHL_VD (0x0f005400) +#define OPCODE_SHL_VQ (0x4f005400) +#define OPCODE_SHRN (0x0f008400) +#define OPCODE_SMULL_V4S_4H (0x0e60c000) +#define OPCODE_SSHR_VD (0x0f000400) +#define OPCODE_SSHR_VQ (0x4f000400) +#define OPCODE_STR_REG (0xb8206800) +#define OPCODE_STRB_REG (0x38206800) +#define OPCODE_STRH_REG (0x78206800) +#define OPCODE_STR_REG_F32 (0xbc206800) +#define OPCODE_STR_REG_F64 (0xfc206800) +#define OPCODE_STR_REG_F64_S (0xfc207800) +#define OPCODE_SUB_V8B (0x2e208400) +#define OPCODE_SUB_V4H (0x2e608400) +#define OPCODE_SUB_V2S (0x2ea08400) +#define OPCODE_UQADD_V8B (0x2e200c00) +#define OPCODE_UQADD_V4H (0x2e600c00) +#define OPCODE_UQSUB_V8B (0x2e202c00) +#define OPCODE_UQSUB_V4H (0x2e602c00) +#define OPCODE_UQXTN_V8B_8H (0x2e214800) +#define OPCODE_UQXTN_V4H_4S (0x2e614800) +#define OPCODE_USHR_VD (0x2f000400) +#define OPCODE_USHR_VQ (0x6f000400) +#define OPCODE_ZIP1_V8B (0x0e003800) +#define OPCODE_ZIP1_V4H (0x0e403800) +#define OPCODE_ZIP1_V2S (0x0e803800) +#define OPCODE_ZIP2_V8B (0x0e007800) +#define OPCODE_ZIP2_V4H (0x0e407800) +#define OPCODE_ZIP2_V2S (0x0e807800) + +#define DATPROC_SHIFT(sh) (sh << 10) +#define DATPROC_IMM_SHIFT(sh) (sh << 22) +#define MOV_WIDE_HW(hw) (hw << 21) + +#define IMM7_X(imm_data) (((imm_data >> 3) & 0x7f) << 15) +#define IMM12(imm_data) ((imm_data) << 10) +#define IMM16(imm_data) ((imm_data) << 5) + +#define IMMN(immn) ((immn) << 22) +#define IMMR(immr) ((immr) << 16) +#define IMMS(imms) ((imms) << 10) + +#define IMM_LOGICAL(imm) ((imm) << 10) + +#define BIT_TBxZ(bit) ((((bit) & 0x1f) << 19) | (((bit) & 0x20) ? (1 << 31) : 0)) + +#define OFFSET14(offset) (((offset >> 2) << 5) & 0x0007ffe0) +#define OFFSET19(offset) (((offset >> 2) << 5) & 0x00ffffe0) +#define OFFSET20(offset) (((offset & 3) << 29) | ((((offset) & 0x1fffff) >> 2) << 5)) +#define OFFSET26(offset) ((offset >> 2) & 0x03ffffff) + +#define OFFSET12_B(offset) (offset << 10) +#define OFFSET12_H(offset) ((offset >> 1) << 10) +#define OFFSET12_W(offset) ((offset >> 2) << 10) +#define OFFSET12_Q(offset) ((offset >> 3) << 10) + +#define SHIFT_IMM_V4H(shift) (((shift) | 0x10) << 16) +#define SHIFT_IMM_V2S(shift) (((shift) | 0x20) << 16) +#define SHIFT_IMM_V2D(shift) (((shift) | 0x40) << 16) + +#define SHRN_SHIFT_IMM_V4S(shift) (((shift) | 0x10) << 16) + +#define DUP_ELEMENT(element) ((element) << 19) + +/*Returns true if offset fits into 19 bits*/ +static int offset_is_19bit(int offset) +{ + if (offset >= (1 << (18+2))) + return 0; + if (offset < -(1 << (18+2))) + return 0; + return 1; +} + +/*Returns true if offset fits into 26 bits*/ +static int offset_is_26bit(int offset) +{ + if (offset >= (1 << (25+2))) + return 0; + if (offset < -(1 << (25+2))) + return 0; + return 1; +} + +static inline int imm_is_imm16(uint32_t imm_data) +{ + if (!(imm_data & 0xffff0000) || !(imm_data & 0x0000ffff)) + return 1; + return 0; +} +static inline int imm_is_imm12(uint32_t imm_data) +{ + if (!(imm_data & 0xfffff000) || !(imm_data & 0xff000fff)) + return 1; + return 0; +} + +static void codegen_allocate_new_block(codeblock_t *block); + +static inline void codegen_addlong(codeblock_t *block, uint32_t val) +{ + if (block_pos >= (BLOCK_MAX-4)) + codegen_allocate_new_block(block); + *(uint32_t *)&block_write_data[block_pos] = val; + block_pos += 4; +} + +static void codegen_allocate_new_block(codeblock_t *block) +{ + /*Current block is full. Allocate a new block*/ + struct mem_block_t *new_block = codegen_allocator_allocate(block->head_mem_block, get_block_nr(block)); + uint8_t *new_ptr = codeblock_allocator_get_ptr(new_block); + uint32_t offset = (uintptr_t)new_ptr - (uintptr_t)&block_write_data[block_pos]; + + if (!offset_is_26bit(offset)) + fatal("codegen_allocate_new_block - offset out of range %x\n", offset); + /*Add a jump instruction to the new block*/ + *(uint32_t *)&block_write_data[block_pos] = OPCODE_B | OFFSET26(offset); + + /*Set write address to start of new block*/ + block_pos = 0; + block_write_data = new_ptr; +} + +void codegen_alloc(codeblock_t *block, int size) +{ + if (block_pos >= (BLOCK_MAX-size)) + codegen_allocate_new_block(block); +} + +void host_arm64_ADD_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + if (!imm_data) + host_arm64_MOV_REG(block, dst_reg, src_n_reg, 0); + else if ((int32_t)imm_data < 0 && imm_data != 0x80000000) + { + host_arm64_SUB_IMM(block, dst_reg, src_n_reg, -(int32_t)imm_data); + } + else if (!(imm_data & 0xff000000)) + { + if (imm_data & 0xfff) + { + codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(dst_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else + { + host_arm64_MOVZ_IMM(block, REG_W16, imm_data & 0xffff); + host_arm64_MOVK_IMM(block, REG_W16, imm_data & 0xffff0000); + codegen_addlong(block, OPCODE_ADD_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_ADDX_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint64_t imm_data) +{ + if (!(imm_data & ~0xffffffull)) + { + if (imm_data & 0xfff) + { + codegen_addlong(block, OPCODE_ADDX_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_ADDX_IMM | Rd(dst_reg) | Rn(dst_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_ADDX_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else + fatal("ADD_IMM_X %016llx\n", imm_data); +} +void host_arm64_ADD_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ADD_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_ADD_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ADD_LSR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_ADD_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ADD_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ADD_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ADD_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ADD_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ADD_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_ADDP_V4S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ADDP_V4S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_ADR(codeblock_t *block, int dst_reg, int offset) +{ + codegen_addlong(block, OPCODE_ADR | Rd(dst_reg) | OFFSET20(offset)); +} + +void host_arm64_AND_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + uint32_t imm_encoding = host_arm64_find_imm(imm_data); + + if (imm_encoding) + { + codegen_addlong(block, OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM_LOGICAL(imm_encoding)); + } + else + { + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_AND_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_AND_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_AND_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_AND_REG_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_AND_ASR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_AND_REG_ROR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_AND_ROR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_AND_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_AND_V | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_ANDS_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + uint32_t imm_encoding = host_arm64_find_imm(imm_data); + + if (imm_encoding) + { + codegen_addlong(block, OPCODE_ANDS_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM_LOGICAL(imm_encoding)); + } + else + { + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_ANDS_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} + +void host_arm64_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg) +{ + codegen_addlong(block, OPCODE_ASR | Rd(dst_reg) | Rn(src_n_reg) | Rm(shift_reg)); +} + +void host_arm64_B(codeblock_t *block, void *dest) +{ + int offset; + + codegen_alloc(block, 4); + offset = (uintptr_t)dest - (uintptr_t)&block_write_data[block_pos]; + + if (!offset_is_26bit(offset)) + fatal("host_arm64_B - offset out of range %x\n", offset); + codegen_addlong(block, OPCODE_B | OFFSET26(offset)); +} + +void host_arm64_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) +{ + codegen_addlong(block, OPCODE_BFI | Rd(dst_reg) | Rn(src_reg) | IMMN(0) | IMMR((32 - lsb) & 31) | IMMS((width-1) & 31)); +} + +void host_arm64_BLR(codeblock_t *block, int addr_reg) +{ + codegen_addlong(block, OPCODE_BLR | Rn(addr_reg)); +} + +uint32_t *host_arm64_BCC_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_CS | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BCS_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_CC | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BEQ_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_NE | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BGE_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_LT | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BGT_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_LE | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BHI_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_LS | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BLE_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_GT | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BLS_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_HI | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BLT_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_GE | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BMI_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_PL | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BNE_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_EQ | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BPL_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_MI | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BVC_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_VS | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BVS_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_VC | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} + +void host_arm64_branch_set_offset(uint32_t *opcode, void *dest) +{ + int offset = (uintptr_t)dest - (uintptr_t)opcode; + *opcode |= OFFSET26(offset); +} + +void host_arm64_BR(codeblock_t *block, int addr_reg) +{ + codegen_addlong(block, OPCODE_BR | Rn(addr_reg)); +} + +void host_arm64_BEQ(codeblock_t *block, void *dest) +{ + uint32_t *opcode = host_arm64_BEQ_(block); + host_arm64_branch_set_offset(opcode, dest); +} + +void host_arm64_BIC_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_BIC_V | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_CBNZ(codeblock_t *block, int reg, uintptr_t dest) +{ + int offset; + + codegen_alloc(block, 4); + offset = dest - (uintptr_t)&block_write_data[block_pos]; + if (offset_is_19bit(offset)) + { + codegen_addlong(block, OPCODE_CBNZ | OFFSET19(offset) | Rt(reg)); + } + else + { + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_CBZ | OFFSET19(8) | Rt(reg)); + offset = (uintptr_t)dest - (uintptr_t)&block_write_data[block_pos]; + codegen_addlong(block, OPCODE_B | OFFSET26(offset)); + } +} + +void host_arm64_CMEQ_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CMEQ_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CMEQ_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CMEQ_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CMEQ_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CMEQ_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CMGT_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CMGT_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CMGT_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CMGT_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CMGT_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CMGT_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_CMN_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data) +{ + if ((int32_t)imm_data < 0 && imm_data != (1ull << 31)) + { + host_arm64_CMP_IMM(block, src_n_reg, -(int32_t)imm_data); + } + else if (!(imm_data & 0xfffff000)) + { + codegen_addlong(block, OPCODE_CMN_IMM | Rd(REG_WZR) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + } + else + fatal("CMN_IMM %08x\n", imm_data); +} +void host_arm64_CMNX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data) +{ + if ((int64_t)imm_data < 0 && imm_data != (1ull << 63)) + { + host_arm64_CMPX_IMM(block, src_n_reg, -(int64_t)imm_data); + } + else if (!(imm_data & 0xfffffffffffff000ull)) + { + codegen_addlong(block, OPCODE_CMNX_IMM | Rd(REG_XZR) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + } + else + fatal("CMNX_IMM %08x\n", imm_data); +} + +void host_arm64_CMP_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data) +{ + if ((int32_t)imm_data < 0 && imm_data != (1ull << 31)) + { + host_arm64_CMN_IMM(block, src_n_reg, -(int32_t)imm_data); + } + else if (!(imm_data & 0xfffff000)) + { + codegen_addlong(block, OPCODE_CMP_IMM | Rd(REG_WZR) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + } + else + fatal("CMP_IMM %08x\n", imm_data); +} +void host_arm64_CMPX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data) +{ + if ((int64_t)imm_data < 0 && imm_data != (1ull << 63)) + { + host_arm64_CMNX_IMM(block, src_n_reg, -(int64_t)imm_data); + } + else if (!(imm_data & 0xfffffffffffff000ull)) + { + codegen_addlong(block, OPCODE_CMPX_IMM | Rd(REG_XZR) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + } + else + fatal("CMPX_IMM %08x\n", imm_data); +} + +void host_arm64_CMP_REG_LSL(codeblock_t *block, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_CMP_LSL | Rd(0x1f) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_CSEL_CC(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CSEL | CSEL_COND(COND_CC) | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CSEL_EQ(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CSEL | CSEL_COND(COND_EQ) | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CSEL_VS(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CSEL | CSEL_COND(COND_VS) | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_DUP_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int element) +{ + codegen_addlong(block, OPCODE_DUP_V2S | Rd(dst_reg) | Rn(src_n_reg) | DUP_ELEMENT(element)); +} + +void host_arm64_EOR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + uint32_t imm_encoding = host_arm64_find_imm(imm_data); + + if (imm_encoding) + { + codegen_addlong(block, OPCODE_EOR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM_LOGICAL(imm_encoding)); + } + else + { + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_EOR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_EOR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_EOR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_EOR_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_EOR_V | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FABS_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FABS_D | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_FADD_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FADD_D | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FADD_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FADD_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FCMEQ_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FCMEQ_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FCMGE_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FCMGE_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FCMGT_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FCMGT_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FCMP_D(codeblock_t *block, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FCMP_D | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FCVT_D_S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVT_D_S | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVT_S_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVT_S_D | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_FCVTMS_W_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTMS_W_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTMS_X_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTMS_X_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTNS_W_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTNS_W_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTNS_X_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTNS_X_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTPS_W_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTPS_W_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTPS_X_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTPS_X_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTZS_W_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTZS_W_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTZS_X_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTZS_X_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTZS_V2S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTZS_V2S | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_FDIV_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FDIV_D | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FDIV_S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FDIV_S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FMAX_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FMAX_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FMIN_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FMIN_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FMUL_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FMUL_D | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FMUL_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FMUL_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FSUB_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FSUB_D | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FSUB_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FSUB_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FMOV_D_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FMOV_D_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FMOV_D_Q(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FMOV_D_Q | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FMOV_Q_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FMOV_Q_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FMOV_S_W(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FMOV_S_W | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FMOV_W_S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FMOV_W_S | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FMOV_S_ONE(codeblock_t *block, int dst_reg) +{ + codegen_addlong(block, OPCODE_FMOV_S_ONE | Rd(dst_reg)); +} + +void host_arm64_FNEG_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FNEG_D | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_FRINTX_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FRINTX_D | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_FSQRT_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FSQRT_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FSQRT_S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FSQRT_S | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset) +{ + if (!in_range7_x(offset)) + fatal("host_arm64_LDP_POSTIDX out of range7 %i\n", offset); + codegen_addlong(block, OPCODE_LDP_POSTIDX_X | IMM7_X(offset) | Rn(base_reg) | Rt(src_reg1) | Rt2(src_reg2)); +} + +void host_arm64_LDR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_w(offset)) + fatal("host_arm64_LDR_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_LDR_IMM_W | OFFSET12_W(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_LDR_IMM_X(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_q(offset)) + fatal("host_arm64_LDR_IMM_X out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_LDR_IMM_X | OFFSET12_Q(offset) | Rn(base_reg) | Rt(dest_reg)); +} + +void host_arm64_LDR_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDR_REG | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} +void host_arm64_LDR_REG_X(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDRX_REG | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LDR_REG_F32(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDR_REG_F32 | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} +void host_arm64_LDR_IMM_F64(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + codegen_addlong(block, OPCODE_LDR_IMM_F64 | OFFSET12_Q(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_LDR_REG_F64(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDR_REG_F64 | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} +void host_arm64_LDR_REG_F64_S(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDR_REG_F64_S | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LDRB_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_b(offset)) + fatal("host_arm64_LDRB_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_LDRB_IMM_W | OFFSET12_B(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_LDRB_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDRB_REG | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LDRH_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_h(offset)) + fatal("host_arm64_LDRH_IMM out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_LDRH_IMM | OFFSET12_H(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_LDRH_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDRH_REG | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LDRX_REG_LSL3(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDRX_REG_LSL3 | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LSL(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg) +{ + codegen_addlong(block, OPCODE_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(shift_reg)); +} + +void host_arm64_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg) +{ + codegen_addlong(block, OPCODE_LSR | Rd(dst_reg) | Rn(src_n_reg) | Rm(shift_reg)); +} + +void host_arm64_MOV_REG_ASR(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ORR_ASR | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_MOV_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + if (dst_reg != src_m_reg || shift) + codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ORR_LSR | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_MOV_REG_ROR(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ORR_ROR | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_MOVX_IMM(codeblock_t *block, int reg, uint64_t imm_data) +{ + codegen_addlong(block, OPCODE_MOVZ_X | MOV_WIDE_HW(0) | IMM16(imm_data & 0xffff) | Rd(reg)); + if ((imm_data >> 16) & 0xffff) + codegen_addlong(block, OPCODE_MOVK_X | MOV_WIDE_HW(1) | IMM16((imm_data >> 16) & 0xffff) | Rd(reg)); + if ((imm_data >> 32) & 0xffff) + codegen_addlong(block, OPCODE_MOVK_X | MOV_WIDE_HW(2) | IMM16((imm_data >> 32) & 0xffff) | Rd(reg)); + if ((imm_data >> 48) & 0xffff) + codegen_addlong(block, OPCODE_MOVK_X | MOV_WIDE_HW(3) | IMM16((imm_data >> 48) & 0xffff) | Rd(reg)); +} +void host_arm64_MOVX_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + if (dst_reg != src_m_reg) + codegen_addlong(block, OPCODE_ORRX_LSL | Rd(dst_reg) | Rn(REG_XZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_MOVZ_IMM(codeblock_t *block, int reg, uint32_t imm_data) +{ + int hw; + + if (!imm_is_imm16(imm_data)) + fatal("MOVZ_IMM - imm not representable %08x\n", imm_data); + + hw = (imm_data & 0xffff0000) ? 1 : 0; + if (hw) + imm_data >>= 16; + + codegen_addlong(block, OPCODE_MOVZ_W | MOV_WIDE_HW(hw) | IMM16(imm_data) | Rd(reg)); +} + +void host_arm64_MOVK_IMM(codeblock_t *block, int reg, uint32_t imm_data) +{ + int hw; + + if (!imm_is_imm16(imm_data)) + fatal("MOVK_IMM - imm not representable %08x\n", imm_data); + + hw = (imm_data & 0xffff0000) ? 1 : 0; + if (hw) + imm_data >>= 16; + + codegen_addlong(block, OPCODE_MOVK_W | MOV_WIDE_HW(hw) | IMM16(imm_data) | Rd(reg)); +} + +void host_arm64_MSR_FPCR(codeblock_t *block, int src_reg) +{ + codegen_addlong(block, OPCODE_MSR_FPCR | Rd(src_reg)); +} + +void host_arm64_MUL_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_MUL_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_NOP(codeblock_t *block) +{ + codegen_addlong(block, OPCODE_NOP); +} + +void host_arm64_ORR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + uint32_t imm_encoding = host_arm64_find_imm(imm_data); + + if (imm_encoding) + { + codegen_addlong(block, OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM_LOGICAL(imm_encoding)); + } + else + { + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_ORR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_ORR_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ORR_V | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_RET(codeblock_t *block, int reg) +{ + codegen_addlong(block, OPCODE_RET | Rn(reg)); +} + +void host_arm64_ROR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg) +{ + codegen_addlong(block, OPCODE_ROR | Rd(dst_reg) | Rn(src_n_reg) | Rm(shift_reg)); +} + +void host_arm64_SADDLP_V2S_4H(codeblock_t *block, int dst_reg, int src_n_reg) +{ + codegen_addlong(block, OPCODE_SADDLP_V2S_4H | Rd(dst_reg) | Rn(src_n_reg)); +} + +void host_arm64_SBFX(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) +{ + codegen_addlong(block, OPCODE_SBFX | Rd(dst_reg) | Rn(src_reg) | IMMN(0) | IMMR(lsb) | IMMS((lsb+width-1) & 31)); +} + +void host_arm64_SCVTF_D_Q(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_SCVTF_D_Q | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_SCVTF_D_W(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_SCVTF_D_W | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_SCVTF_V2S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_SCVTF_V2S | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_SHRN_V4H_4S(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 16) + fatal("host_arm64_SHRN_V4H_4S : shift > 16\n"); + codegen_addlong(block, OPCODE_SHRN | Rd(dst_reg) | Rn(src_n_reg) | SHRN_SHIFT_IMM_V4S(16-shift)); +} + +void host_arm64_SMULL_V4S_4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SMULL_V4S_4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_SQADD_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SQADD_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_SQADD_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SQADD_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_SQSUB_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SQSUB_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_SQSUB_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SQSUB_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_SQXTN_V8B_8H(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_SQXTN_V8B_8H | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_SQXTN_V4H_4S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_SQXTN_V4H_4S | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_SHL_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + codegen_addlong(block, OPCODE_SHL_VD | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V4H(shift)); +} +void host_arm64_SHL_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + codegen_addlong(block, OPCODE_SHL_VD | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V2S(shift)); +} +void host_arm64_SHL_V2D(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + codegen_addlong(block, OPCODE_SHL_VQ | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V2D(shift)); +} + +void host_arm64_SSHR_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 16) + fatal("host_arm_USHR_V4H : shift > 16\n"); + codegen_addlong(block, OPCODE_SSHR_VD | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V4H(16-shift)); +} +void host_arm64_SSHR_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 32) + fatal("host_arm_SSHR_V2S : shift > 32\n"); + codegen_addlong(block, OPCODE_SSHR_VD | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V2S(32-shift)); +} +void host_arm64_SSHR_V2D(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 64) + fatal("host_arm_SSHR_V2D : shift > 64\n"); + codegen_addlong(block, OPCODE_SSHR_VQ | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V2D(64-shift)); +} + +void host_arm64_STP_PREIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset) +{ + if (!in_range7_x(offset)) + fatal("host_arm64_STP_PREIDX out of range7 %i\n", offset); + codegen_addlong(block, OPCODE_STP_PREIDX_X | IMM7_X(offset) | Rn(base_reg) | Rt(src_reg1) | Rt2(src_reg2)); +} + +void host_arm64_STR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_w(offset)) + fatal("host_arm64_STR_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_STR_IMM_W | OFFSET12_W(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_STR_IMM_Q(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_q(offset)) + fatal("host_arm64_STR_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_STR_IMM_Q | OFFSET12_Q(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_STR_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STR_REG | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} + +void host_arm64_STR_REG_F32(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STR_REG_F32 | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} +void host_arm64_STR_IMM_F64(codeblock_t *block, int src_reg, int base_reg, int offset) +{ + codegen_addlong(block, OPCODE_STR_IMM_F64 | OFFSET12_Q(offset) | Rn(base_reg) | Rt(src_reg)); +} +void host_arm64_STR_REG_F64(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STR_REG_F64 | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} +void host_arm64_STR_REG_F64_S(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STR_REG_F64_S | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} + +void host_arm64_STRB_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_b(offset)) + fatal("host_arm64_STRB_IMM out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_STRB_IMM | OFFSET12_B(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_STRB_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STRB_REG | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} + +void host_arm64_STRH_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_h(offset)) + fatal("host_arm64_STRH_IMM out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_STRH_IMM | OFFSET12_H(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_STRH_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STRH_REG | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} + +void host_arm64_SUB_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + if (!imm_data) + host_arm64_MOV_REG(block, dst_reg, src_n_reg, 0); + else if ((int32_t)imm_data < 0 && imm_data != 0x80000000) + { + host_arm64_ADD_IMM(block, dst_reg, src_n_reg, -(int32_t)imm_data); + } + else if (!(imm_data & 0xff000000)) + { + if (imm_data & 0xfff) + { + codegen_addlong(block, OPCODE_SUB_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_SUB_IMM | Rd(dst_reg) | Rn(dst_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_SUB_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else + { + host_arm64_MOVZ_IMM(block, REG_W16, imm_data & 0xffff); + host_arm64_MOVK_IMM(block, REG_W16, imm_data & 0xffff0000); + codegen_addlong(block, OPCODE_SUB_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_SUB_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_SUB_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_SUB_LSR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_SUB_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SUB_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_SUB_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SUB_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_SUB_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SUB_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +uint32_t *host_arm64_TBNZ(codeblock_t *block, int reg, int bit) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_TBZ | Rt(reg) | BIT_TBxZ(bit) | OFFSET14(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} + +void host_arm64_UBFX(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) +{ + codegen_addlong(block, OPCODE_UBFX | Rd(dst_reg) | Rn(src_reg) | IMMN(0) | IMMR(lsb) | IMMS((lsb+width-1) & 31)); +} + +void host_arm64_UQADD_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_UQADD_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_UQADD_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_UQADD_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_UQSUB_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_UQSUB_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_UQSUB_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_UQSUB_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_UQXTN_V8B_8H(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_UQXTN_V8B_8H | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_UQXTN_V4H_4S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_UQXTN_V4H_4S | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_USHR_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 16) + fatal("host_arm_USHR_V4H : shift > 16\n"); + codegen_addlong(block, OPCODE_USHR_VD | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V4H(16-shift)); +} +void host_arm64_USHR_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 32) + fatal("host_arm_USHR_V4S : shift > 32\n"); + codegen_addlong(block, OPCODE_USHR_VD | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V2S(32-shift)); +} +void host_arm64_USHR_V2D(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 64) + fatal("host_arm_USHR_V2D : shift > 64\n"); + codegen_addlong(block, OPCODE_USHR_VQ | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V2D(64-shift)); +} + +void host_arm64_ZIP1_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ZIP1_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ZIP1_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ZIP1_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ZIP1_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ZIP1_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ZIP2_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ZIP2_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ZIP2_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ZIP2_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ZIP2_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ZIP2_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_call(codeblock_t *block, void *dst_addr) +{ + host_arm64_MOVX_IMM(block, REG_X16, (uint64_t)dst_addr); + host_arm64_BLR(block, REG_X16); +} + +void host_arm64_jump(codeblock_t *block, uintptr_t dst_addr) +{ + host_arm64_MOVX_IMM(block, REG_X16, (uint64_t)dst_addr); + host_arm64_BR(block, REG_X16); +} + +void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data) +{ + if (imm_is_imm16(imm_data)) + host_arm64_MOVZ_IMM(block, reg, imm_data); + else + { + host_arm64_MOVZ_IMM(block, reg, imm_data & 0xffff); + host_arm64_MOVK_IMM(block, reg, imm_data & 0xffff0000); + } +} + +#endif diff --git a/src/cpu_new/codegen_backend_arm64_ops.h b/src/cpu_new/codegen_backend_arm64_ops.h new file mode 100644 index 000000000..2a514edbe --- /dev/null +++ b/src/cpu_new/codegen_backend_arm64_ops.h @@ -0,0 +1,264 @@ +void host_arm64_ADD_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_ADD_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_ADD_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_ADD_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ADD_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ADD_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ADDX_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint64_t imm_data); + +void host_arm64_ADDP_V4S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_ADR(codeblock_t *block, int dst_reg, int offset); + +void host_arm64_AND_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_AND_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_AND_REG_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_AND_REG_ROR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_AND_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_ANDS_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); + +void host_arm64_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg); + +void host_arm64_B(codeblock_t *block, void *dest); + +void host_arm64_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width); + +void host_arm64_BLR(codeblock_t *block, int addr_reg); + +void host_arm64_BEQ(codeblock_t *block, void *dest); + +uint32_t *host_arm64_BCC_(codeblock_t *block); +uint32_t *host_arm64_BCS_(codeblock_t *block); +uint32_t *host_arm64_BEQ_(codeblock_t *block); +uint32_t *host_arm64_BGE_(codeblock_t *block); +uint32_t *host_arm64_BGT_(codeblock_t *block); +uint32_t *host_arm64_BHI_(codeblock_t *block); +uint32_t *host_arm64_BLE_(codeblock_t *block); +uint32_t *host_arm64_BLS_(codeblock_t *block); +uint32_t *host_arm64_BLT_(codeblock_t *block); +uint32_t *host_arm64_BMI_(codeblock_t *block); +uint32_t *host_arm64_BNE_(codeblock_t *block); +uint32_t *host_arm64_BPL_(codeblock_t *block); +uint32_t *host_arm64_BVC_(codeblock_t *block); +uint32_t *host_arm64_BVS_(codeblock_t *block); + +void host_arm64_branch_set_offset(uint32_t *opcode, void *dest); + +void host_arm64_BR(codeblock_t *block, int addr_reg); + +void host_arm64_BIC_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_CBNZ(codeblock_t *block, int reg, uintptr_t dest); + +void host_arm64_CMEQ_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CMEQ_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CMEQ_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CMGT_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CMGT_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CMGT_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_CMN_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data); +void host_arm64_CMNX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data); + +void host_arm64_CMP_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data); +void host_arm64_CMPX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data); + +#define host_arm64_CMP_REG(block, src_n_reg, src_m_reg) host_arm64_CMP_REG_LSL(block, src_n_reg, src_m_reg, 0) +void host_arm64_CMP_REG_LSL(codeblock_t *block, int src_n_reg, int src_m_reg, int shift); + +void host_arm64_CSEL_CC(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CSEL_EQ(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CSEL_VS(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_DUP_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int element); + +void host_arm64_EOR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_EOR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_EOR_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_FABS_D(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_FADD_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FADD_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FCMEQ_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FCMGE_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FCMGT_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FCMP_D(codeblock_t *block, int src_n_reg, int src_m_reg); +void host_arm64_FDIV_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FDIV_S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FMAX_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FMIN_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FMUL_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FMUL_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FSUB_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FSUB_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_FCVT_D_S(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVT_S_D(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_FCVTMS_W_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTMS_X_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTNS_W_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTNS_X_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTPS_W_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTPS_X_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTZS_W_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTZS_X_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTZS_V2S(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_FMOV_D_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FMOV_D_Q(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FMOV_Q_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FMOV_S_W(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FMOV_W_S(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FMOV_S_ONE(codeblock_t *block, int dst_reg); + +void host_arm64_FNEG_D(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_FRINTX_D(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_FSQRT_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FSQRT_S(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset); + +void host_arm64_LDR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDR_IMM_X(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDR_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); +void host_arm64_LDR_REG_X(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LDR_REG_F32(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); +void host_arm64_LDR_IMM_F64(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDR_REG_F64(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); +void host_arm64_LDR_REG_F64_S(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LDRB_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDRB_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LDRH_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDRH_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LDRX_REG_LSL3(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LSL(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg); +void host_arm64_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg); + +void host_arm64_MOV_REG_ASR(codeblock_t *block, int dst_reg, int src_m_reg, int shift); +void host_arm64_MOV_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift); +void host_arm64_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_m_reg, int shift); +void host_arm64_MOV_REG_ROR(codeblock_t *block, int dst_reg, int src_m_reg, int shift); + +void host_arm64_MOVX_IMM(codeblock_t *block, int reg, uint64_t imm_data); +void host_arm64_MOVX_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift); + +void host_arm64_MOVZ_IMM(codeblock_t *block, int reg, uint32_t imm_data); +void host_arm64_MOVK_IMM(codeblock_t *block, int reg, uint32_t imm_data); + +void host_arm64_MSR_FPCR(codeblock_t *block, int src_reg); + +void host_arm64_MUL_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_NOP(codeblock_t *block); + +void host_arm64_ORR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_ORR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_ORR_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_RET(codeblock_t *block, int reg); + +void host_arm64_ROR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg); + +void host_arm64_SADDLP_V2S_4H(codeblock_t *block, int dst_reg, int src_n_reg); + +void host_arm64_SBFX(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width); + +void host_arm64_SCVTF_D_Q(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_SCVTF_D_W(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_SCVTF_V2S(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_SQADD_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_SQADD_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_SQSUB_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_SQSUB_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_SQXTN_V8B_8H(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_SQXTN_V4H_4S(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_SHL_V4H(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm64_SHL_V2S(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm64_SHL_V2D(codeblock_t *block, int dst_reg, int src_reg, int shift); + +void host_arm64_SHRN_V4H_4S(codeblock_t *block, int dst_reg, int src_n_reg, int shift); + +void host_arm64_SMULL_V4S_4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_SSHR_V4H(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm64_SSHR_V2S(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm64_SSHR_V2D(codeblock_t *block, int dst_reg, int src_reg, int shift); + +void host_arm64_STP_PREIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset); + +void host_arm64_STR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STR_IMM_Q(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STR_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg); + +void host_arm64_STR_REG_F32(codeblock_t *block, int src_reg, int base_reg, int offset_reg); +void host_arm64_STR_IMM_F64(codeblock_t *block, int src_reg, int base_reg, int offset); +void host_arm64_STR_REG_F64(codeblock_t *block, int src_reg, int base_reg, int offset_reg); +void host_arm64_STR_REG_F64_S(codeblock_t *block, int src_reg, int base_reg, int offset_reg); + +void host_arm64_STRB_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STRB_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg); + +void host_arm64_STRH_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STRH_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg); + +void host_arm64_SUB_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_SUB_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_SUB_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_SUB_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_SUB_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +uint32_t *host_arm64_TBNZ(codeblock_t *block, int reg, int bit); + +#define host_arm64_TST_IMM(block, src_n_reg, imm_data) host_arm64_ANDS_IMM(block, REG_XZR, src_n_reg, imm_data) + +void host_arm64_UBFX(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width); + +void host_arm64_UQADD_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_UQADD_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_UQSUB_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_UQSUB_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_UQXTN_V8B_8H(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_UQXTN_V4H_4S(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_USHR_V4H(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm64_USHR_V2S(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm64_USHR_V2D(codeblock_t *block, int dst_reg, int src_reg, int shift); + +void host_arm64_ZIP1_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ZIP1_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ZIP1_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ZIP2_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ZIP2_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ZIP2_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_call(codeblock_t *block, void *dst_addr); +void host_arm64_jump(codeblock_t *block, uintptr_t dst_addr); +void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data); + + +#define in_range7_x(offset) (((offset) >= -0x200) && ((offset) < (0x200)) && !((offset) & 7)) +#define in_range12_b(offset) (((offset) >= 0) && ((offset) < 0x1000)) +#define in_range12_h(offset) (((offset) >= 0) && ((offset) < 0x2000) && !((offset) & 1)) +#define in_range12_w(offset) (((offset) >= 0) && ((offset) < 0x4000) && !((offset) & 3)) +#define in_range12_q(offset) (((offset) >= 0) && ((offset) < 0x8000) && !((offset) & 7)) + + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p); + +void codegen_alloc(codeblock_t *block, int size); \ No newline at end of file diff --git a/src/cpu_new/codegen_backend_arm64_uops.c b/src/cpu_new/codegen_backend_arm64_uops.c new file mode 100644 index 000000000..e9cf28684 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm64_uops.c @@ -0,0 +1,3372 @@ +#ifdef __aarch64__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x87.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_backend_arm64_defs.h" +#include "codegen_backend_arm64_ops.h" +#include "codegen_ir_defs.h" + +#define OFFSET19(offset) (((offset >> 2) << 5) & 0x00ffffe0) + +#define HOST_REG_GET(reg) (IREG_GET_REG(reg) & 0x1f) + +#define REG_IS_L(size) (size == IREG_SIZE_L) +#define REG_IS_W(size) (size == IREG_SIZE_W) +#define REG_IS_B(size) (size == IREG_SIZE_B) +#define REG_IS_BH(size) (size == IREG_SIZE_BH) +#define REG_IS_D(size) (size == IREG_SIZE_D) +#define REG_IS_Q(size) (size == IREG_SIZE_Q) + +static int codegen_ADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_ADD_REG(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_ADD_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_ADD_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_ADD_REG_LSR(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_ADD_REG_LSR(block, REG_TEMP, src_reg_b, src_reg_a, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg_a, 0x0000ff00); + host_arm64_ADD_REG(block, REG_TEMP, REG_TEMP, src_reg_b, 0); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("ADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_ADD_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_ADD_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_ADD_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_ADD_IMM(block, REG_TEMP, src_reg, uop->imm_data << 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("ADD_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop) +{ + host_arm64_ADD_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data); + return 0; +} + +static int codegen_AND(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_AND_REG_V(block, dest_reg, src_reg_a, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_AND_REG(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_b, 0xffff0000); + host_arm64_AND_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_b, 0xffffff00); + host_arm64_AND_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_b, 0xffff00ff); + host_arm64_AND_REG_ASR(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_b, 0xffffff00); + host_arm64_AND_REG_ROR(block, dest_reg, src_reg_a, REG_TEMP, 24); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_b, 0xffff00ff); + host_arm64_AND_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_AND_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_AND_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_b, 0xffff00ff); + host_arm64_AND_REG_ROR(block, REG_TEMP, src_reg_a, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_a, 0xffff00ff); + host_arm64_AND_REG_ROR(block, REG_TEMP, src_reg_b, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_AND_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else + fatal("AND %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_AND_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, dest_reg, src_reg, uop->imm_data | 0xffff0000); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, dest_reg, src_reg, uop->imm_data | 0xffffff00); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_AND_IMM(block, dest_reg, src_reg, (uop->imm_data << 8) | 0xffff00ff); + } + else + fatal("AND_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_ANDN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_BIC_REG_V(block, dest_reg, src_reg_b, src_reg_a); + } + else + fatal("ANDN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_CALL_FUNC(codeblock_t *block, uop_t *uop) +{ + host_arm64_call(block, uop->p); + + return 0; +} + +static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_L(dest_size)) + fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real); + host_arm64_call(block, uop->p); + host_arm64_MOV_REG(block, dest_reg, REG_W0, 0); + + return 0; +} + +static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) +{ + host_arm64_call(block, uop->p); + host_arm64_CBNZ(block, REG_X0, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm64_CMP_IMM(block, src_reg, uop->imm_data); + } + else + fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real); + host_arm64_BEQ(block, uop->p); + + return 0; +} + +static int codegen_CMP_IMM_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm64_CMP_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xffff); + host_arm64_CMP_IMM(block, REG_TEMP, uop->imm_data); + } + else + fatal("CMP_IMM_JNZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BNE_(block); + + return 0; +} +static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm64_CMP_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xffff); + host_arm64_CMP_IMM(block, REG_TEMP, uop->imm_data); + } + else + fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BEQ_(block); + + return 0; +} + +static int codegen_CMP_JB(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else + fatal("CMP_JB %02x\n", uop->src_reg_a_real); + + jump_p = host_arm64_BCC_(block); + host_arm64_branch_set_offset(jump_p, uop->p); + + return 0; +} +static int codegen_CMP_JNBE(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else + fatal("CMP_JNBE %02x\n", uop->src_reg_a_real); + + jump_p = host_arm64_BHI_(block); + host_arm64_branch_set_offset(jump_p, uop->p); + + return 0; +} + +static int codegen_CMP_JNB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNB_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BCS_(block); + + return 0; +} +static int codegen_CMP_JNBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNBE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BHI_(block); + + return 0; +} +static int codegen_CMP_JNL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNL_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BGE_(block); + + return 0; +} +static int codegen_CMP_JNLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNLE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BGT_(block); + + return 0; +} +static int codegen_CMP_JNO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNO_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BVC_(block); + + return 0; +} +static int codegen_CMP_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BNE_(block); + + return 0; +} +static int codegen_CMP_JB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JB_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BCC_(block); + + return 0; +} +static int codegen_CMP_JBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JBE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BLS_(block); + + return 0; +} +static int codegen_CMP_JL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JL_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BLT_(block); + + return 0; +} +static int codegen_CMP_JLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JLE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BLE_(block); + + return 0; +} +static int codegen_CMP_JO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JO_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BVS_(block); + + return 0; +} +static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BEQ_(block); + + return 0; +} + +static int codegen_FABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm64_FABS_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FABS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FCHS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm64_FNEG_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FCHS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm64_FSQRT_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FSQRT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FTST(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a)) + { + host_arm64_FSUB_D(block, REG_V_TEMP, REG_V_TEMP, REG_V_TEMP); + host_arm64_MOVZ_IMM(block, dest_reg, 0); + host_arm64_FCMP_D(block, src_reg_a, REG_V_TEMP); + host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C3); + host_arm64_ORR_IMM(block, REG_TEMP2, dest_reg, C0); + host_arm64_CSEL_EQ(block, dest_reg, REG_TEMP, dest_reg); + host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C0|C2|C3); + host_arm64_CSEL_CC(block, dest_reg, REG_TEMP2, dest_reg); + host_arm64_CSEL_VS(block, dest_reg, REG_TEMP, dest_reg); + } + else + fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_FADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_FADD_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FCOM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_MOVZ_IMM(block, dest_reg, 0); + host_arm64_FCMP_D(block, src_reg_a, src_reg_b); + host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C3); + host_arm64_ORR_IMM(block, REG_TEMP2, dest_reg, C0); + host_arm64_CSEL_EQ(block, dest_reg, REG_TEMP, dest_reg); + host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C0|C2|C3); + host_arm64_CSEL_CC(block, dest_reg, REG_TEMP2, dest_reg); + host_arm64_CSEL_VS(block, dest_reg, REG_TEMP, dest_reg); + } + else + fatal("codegen_FCOM %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FDIV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_FDIV_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FDIV %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_FMUL_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_FSUB_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_ptr; + + if (!in_range12_w((uintptr_t)&cr0 - (uintptr_t)&cpu_state)) + fatal("codegen_FP_ENTER - out of range\n"); + + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cr0 - (uintptr_t)&cpu_state); + host_arm64_TST_IMM(block, REG_TEMP, 0xc); + branch_ptr = host_arm64_BEQ_(block); + + host_arm64_mov_imm(block, REG_TEMP, uop->imm_data); + host_arm64_STR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.oldpc - (uintptr_t)&cpu_state); + host_arm64_mov_imm(block, REG_ARG0, 7); + host_arm64_call(block, x86_int); + host_arm64_B(block, codegen_exit_rout); + + host_arm64_branch_set_offset(branch_ptr, &block_write_data[block_pos]); + + return 0; +} +static int codegen_MMX_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_ptr; + + if (!in_range12_w((uintptr_t)&cr0 - (uintptr_t)&cpu_state)) + fatal("codegen_MMX_ENTER - out of range\n"); + + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cr0 - (uintptr_t)&cpu_state); + host_arm64_TST_IMM(block, REG_TEMP, 0xc); + branch_ptr = host_arm64_BEQ_(block); + + host_arm64_mov_imm(block, REG_TEMP, uop->imm_data); + host_arm64_STR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.oldpc - (uintptr_t)&cpu_state); + host_arm64_mov_imm(block, REG_ARG0, 7); + host_arm64_call(block, x86_int); + host_arm64_B(block, codegen_exit_rout); + + host_arm64_branch_set_offset(branch_ptr, &block->data[block_pos]); + + host_arm64_mov_imm(block, REG_TEMP, 0x01010101); + host_arm64_STR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.tag[0] - (uintptr_t)&cpu_state); + host_arm64_STR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.tag[4] - (uintptr_t)&cpu_state); + host_arm64_STR_IMM_W(block, REG_WZR, REG_CPUSTATE, (uintptr_t)&cpu_state.TOP - (uintptr_t)&cpu_state); + host_arm64_STRB_IMM(block, REG_WZR, REG_CPUSTATE, (uintptr_t)&cpu_state.ismmx - (uintptr_t)&cpu_state); + + return 0; +} + +static int codegen_JMP(codeblock_t *block, uop_t *uop) +{ + host_arm64_jump(block, (uintptr_t)uop->p); + + return 0; +} + +static int codegen_LOAD_FUNC_ARG0(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_ARG0, src_reg, 0xffff); + } + else + fatal("codegen_LOAD_FUNC_ARG0 %02x\n", uop->src_reg_a_real); + + return 0; +} +static int codegen_LOAD_FUNC_ARG1(codeblock_t *block, uop_t *uop) +{ + fatal("codegen_LOAD_FUNC_ARG1 %02x\n", uop->src_reg_a_real); + return 0; +} +static int codegen_LOAD_FUNC_ARG2(codeblock_t *block, uop_t *uop) +{ + fatal("codegen_LOAD_FUNC_ARG2 %02x\n", uop->src_reg_a_real); + return 0; +} +static int codegen_LOAD_FUNC_ARG3(codeblock_t *block, uop_t *uop) +{ + fatal("codegen_LOAD_FUNC_ARG3 %02x\n", uop->src_reg_a_real); + return 0; +} + +static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, REG_ARG0, uop->imm_data); + + return 0; +} +static int codegen_LOAD_FUNC_ARG1_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, REG_ARG1, uop->imm_data); + + return 0; +} +static int codegen_LOAD_FUNC_ARG2_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, REG_ARG2, uop->imm_data); + + return 0; +} +static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, REG_ARG3, uop->imm_data); + + return 0; +} + +static int codegen_LOAD_SEG(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (!REG_IS_W(src_size)) + fatal("LOAD_SEG %02x %p\n", uop->src_reg_a_real, uop->p); + + host_arm64_MOVX_IMM(block, REG_ARG1, (uint64_t)uop->p); + host_arm64_AND_IMM(block, REG_ARG0, src_reg, 0xffff); + host_arm64_call(block, (void *)loadseg); + host_arm64_CBNZ(block, REG_X0, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_LOAD_ABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm64_ADD_IMM(block, REG_X0, seg_reg, uop->imm_data); + if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) + { + host_arm64_call(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_call(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_arm64_call(block, codegen_mem_load_long); + } + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 8, 8); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 0, 16); + } + else if (REG_IS_L(dest_size)) + { + host_arm64_MOV_REG(block, dest_reg, REG_X0, 0); + } + + return 0; +} +static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm64_ADD_REG(block, REG_X0, seg_reg, addr_reg, 0); + if (uop->imm_data) + host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) + { + host_arm64_call(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_call(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_arm64_call(block, codegen_mem_load_long); + } + else if (REG_IS_Q(dest_size)) + { + host_arm64_call(block, codegen_mem_load_quad); + } + else + fatal("MEM_LOAD_REG - %02x\n", uop->dest_reg_a_real); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 8, 8); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 0, 16); + } + else if (REG_IS_L(dest_size)) + { + host_arm64_MOV_REG(block, dest_reg, REG_X0, 0); + } + else if (REG_IS_Q(dest_size)) + { + host_arm64_FMOV_D_D(block, dest_reg, REG_V_TEMP); + } + + return 0; +} +static int codegen_MEM_LOAD_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_DOUBLE - %02x\n", uop->dest_reg_a_real); + + host_arm64_ADD_REG(block, REG_X0, seg_reg, addr_reg, 0); + if (uop->imm_data) + host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + host_arm64_call(block, codegen_mem_load_double); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + host_arm64_FMOV_D_D(block, dest_reg, REG_V_TEMP); + + return 0; +} +static int codegen_MEM_LOAD_SINGLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_DOUBLE - %02x\n", uop->dest_reg_a_real); + + host_arm64_ADD_REG(block, REG_X0, seg_reg, addr_reg, 0); + if (uop->imm_data) + host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + host_arm64_call(block, codegen_mem_load_single); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + host_arm64_FCVT_D_S(block, dest_reg, REG_V_TEMP); + + return 0; +} + +static int codegen_MEM_STORE_ABS(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_b_real); + int src_size = IREG_GET_SIZE(uop->src_reg_b_real); + + host_arm64_ADD_IMM(block, REG_W0, seg_reg, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, REG_W1, src_reg, 0xff); + host_arm64_call(block, codegen_mem_store_byte); + } + else if (REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_W1, src_reg, 8, 8); + host_arm64_call(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_W1, src_reg, 0xffff); + host_arm64_call(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_arm64_MOV_REG(block, REG_W1, src_reg, 0); + host_arm64_call(block, codegen_mem_store_long); + } + else + fatal("MEM_STORE_ABS - %02x\n", uop->dest_reg_a_real); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + if (uop->imm_data) + host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, REG_W1, src_reg, 0xff); + host_arm64_call(block, codegen_mem_store_byte); + } + else if (REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_W1, src_reg, 8, 8); + host_arm64_call(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_W1, src_reg, 0xffff); + host_arm64_call(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_arm64_MOV_REG(block, REG_W1, src_reg, 0); + host_arm64_call(block, codegen_mem_store_long); + } + else if (REG_IS_Q(src_size)) + { + host_arm64_FMOV_D_D(block, REG_V_TEMP, src_reg); + host_arm64_call(block, codegen_mem_store_quad); + } + else + fatal("MEM_STORE_REG - %02x\n", uop->src_reg_c_real); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_IMM_8(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + host_arm64_mov_imm(block, REG_W1, uop->imm_data); + host_arm64_call(block, codegen_mem_store_byte); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_16(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + host_arm64_mov_imm(block, REG_W1, uop->imm_data); + host_arm64_call(block, codegen_mem_store_word); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_32(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + host_arm64_mov_imm(block, REG_W1, uop->imm_data); + host_arm64_call(block, codegen_mem_store_long); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_SINGLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_REG - %02x\n", uop->dest_reg_a_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + if (uop->imm_data) + host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + host_arm64_FCVT_S_D(block, REG_V_TEMP, src_reg); + host_arm64_call(block, codegen_mem_store_single); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_REG - %02x\n", uop->dest_reg_a_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + if (uop->imm_data) + host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + host_arm64_FMOV_D_D(block, REG_V_TEMP, src_reg); + host_arm64_call(block, codegen_mem_store_double); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MOV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_MOV_REG(block, dest_reg, src_reg, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_BFI(block, dest_reg, src_reg, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_BFI(block, dest_reg, src_reg, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_B(src_size)) + { + host_arm64_BFI(block, dest_reg, src_reg, 8, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size)) + { + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + } + else if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + } + else + fatal("MOV %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_arm64_mov_imm(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_MOVK_IMM(block, dest_reg, uop->imm_data & 0xffff); + } + else if (REG_IS_B(dest_size)) + { + host_arm64_MOVZ_IMM(block, REG_TEMP, uop->imm_data & 0xff); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm64_MOVZ_IMM(block, REG_TEMP, uop->imm_data & 0xff); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("MOV_IMM %x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOV_PTR(codeblock_t *block, uop_t *uop) +{ + host_arm64_MOVX_IMM(block, uop->dest_reg_a_real, (uint64_t)uop->p); + + return 0; +} + +static int codegen_MOVSX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_arm64_SBFX(block, dest_reg, src_reg, 0, 8); + } + else if (REG_IS_L(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_SBFX(block, dest_reg, src_reg, 8, 8); + } + else if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_arm64_SBFX(block, dest_reg, src_reg, 0, 16); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_arm64_SBFX(block, REG_TEMP, src_reg, 0, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_W(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_SBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOVSX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOVZX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_L(src_size)) + { + host_arm64_FMOV_D_Q(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_Q(src_size)) + { + host_arm64_FMOV_W_S(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, dest_reg, src_reg, 0xff); + } + else if (REG_IS_L(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, dest_reg, src_reg, 8, 8); + } + else if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, dest_reg, src_reg, 0xffff); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xff); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_W(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOVZX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_MOV_DOUBLE_INT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_L(src_size)) + { + host_arm64_SCVTF_D_W(block, dest_reg, src_reg); + } + else if (REG_IS_D(dest_size) && REG_IS_W(src_size)) + { + host_arm64_SBFX(block, REG_TEMP, src_reg, 0, 16); + host_arm64_SCVTF_D_W(block, dest_reg, REG_TEMP); + } + else if (REG_IS_D(dest_size) && REG_IS_Q(src_size)) + { + host_arm64_FMOV_Q_D(block, REG_TEMP, src_reg); + host_arm64_SCVTF_D_Q(block, dest_reg, REG_TEMP); + } + else + fatal("MOV_DOUBLE_INT %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOV_INT_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_D(src_size)) + { + host_arm64_FMOV_D_D(block, REG_V_TEMP, src_reg); + host_arm64_call(block, codegen_fp_round); + host_arm64_MOV_REG(block, dest_reg, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_D(src_size)) + { + host_arm64_FMOV_D_D(block, REG_V_TEMP, src_reg); + host_arm64_call(block, codegen_fp_round); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOV_INT_DOUBLE %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOV_INT_DOUBLE_64(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), src_64_reg = HOST_REG_GET(uop->src_reg_b_real), tag_reg = HOST_REG_GET(uop->src_reg_c_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real), src_64_size = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_D(src_size) && REG_IS_Q(src_64_size)) + { + uint32_t *branch_offset; + + /*If TAG_UINT64 is set then the source is MM[]. Otherwise it is a double in ST()*/ + host_arm64_FMOV_D_D(block, dest_reg, src_64_reg); + branch_offset = host_arm64_TBNZ(block, tag_reg, 7); + + host_arm64_FMOV_D_D(block, REG_V_TEMP, src_reg); + host_arm64_call(block, codegen_fp_round_quad); + host_arm64_FMOV_D_Q(block, dest_reg, REG_TEMP); + + host_arm64_branch_set_offset(branch_offset, &block_write_data[block_pos]); + } + else + fatal("MOV_INT_DOUBLE_64 %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOV_REG_PTR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm64_MOVX_IMM(block, REG_TEMP, (uint64_t)uop->p); + if (REG_IS_L(dest_size)) + { + host_arm64_LDR_IMM_W(block, dest_reg, REG_TEMP, 0); + } + else + fatal("MOV_REG_PTR %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_8(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm64_MOVX_IMM(block, REG_TEMP, (uint64_t)uop->p); + if (REG_IS_L(dest_size)) + { + host_arm64_LDRB_IMM_W(block, dest_reg, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_LDRB_IMM_W(block, REG_TEMP, REG_TEMP, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size)) + { + host_arm64_LDRB_IMM_W(block, REG_TEMP, REG_TEMP, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else + fatal("MOVZX_REG_PTR_8 %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_16(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm64_MOVX_IMM(block, REG_TEMP, (uint64_t)uop->p); + if (REG_IS_L(dest_size)) + { + host_arm64_LDRH_IMM(block, dest_reg, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_LDRH_IMM(block, REG_TEMP, REG_TEMP, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOVZX_REG_PTR_16 %02x\n", uop->dest_reg_a_real); + + return 0; +} + +static int codegen_NOP(codeblock_t *block, uop_t *uop) +{ + return 0; +} + +static int codegen_OR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ORR_REG_V(block, dest_reg, src_reg_a, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_ORR_REG(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_ORR_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg_b, 0xff); + host_arm64_ORR_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_UBFX(block, REG_TEMP, src_reg_b, 8, 8); + host_arm64_ORR_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg_b, 0xff); + host_arm64_ORR_REG(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_UBFX(block, REG_TEMP, src_reg_b, 8, 8); + host_arm64_ORR_REG(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else + fatal("OR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_OR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_ORR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size) && dest_reg == src_reg) + { + host_arm64_ORR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size) && dest_reg == src_reg) + { + host_arm64_ORR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size) && dest_reg == src_reg) + { + host_arm64_ORR_IMM(block, dest_reg, src_reg, uop->imm_data << 8); + } + else + fatal("OR_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_PACKSSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_arm64_SQXTN_V8B_8H(block, REG_V_TEMP, src_reg_b); + host_arm64_SQXTN_V8B_8H(block, dest_reg, dest_reg); + host_arm64_ZIP1_V2S(block, dest_reg, dest_reg, REG_V_TEMP); + } + else + fatal("PACKSSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PACKSSDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_arm64_SQXTN_V4H_4S(block, REG_V_TEMP, src_reg_b); + host_arm64_SQXTN_V4H_4S(block, dest_reg, dest_reg); + host_arm64_ZIP1_V2S(block, dest_reg, dest_reg, REG_V_TEMP); + } + else + fatal("PACKSSDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PACKUSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_arm64_UQXTN_V8B_8H(block, REG_V_TEMP, src_reg_b); + host_arm64_UQXTN_V8B_8H(block, dest_reg, dest_reg); + host_arm64_ZIP1_V2S(block, dest_reg, dest_reg, REG_V_TEMP); + } + else + fatal("PACKUSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PADDB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ADD_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ADD_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ADD_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SQADD_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SQADD_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_UQADD_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_UQADD_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PCMPEQB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_CMEQ_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPEQB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPEQW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_CMEQ_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPEQW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPEQD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_CMEQ_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPEQD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPGTB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_CMGT_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPGTB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPGTW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_CMGT_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPGTW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPGTD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_CMGT_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPGTD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PF2ID(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_arm64_FCVTZS_V2S(block, dest_reg, src_reg_a); + } + else + fatal("PF2ID %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_PFADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FADD_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFCMPEQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FCMEQ_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFCMPEQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFCMPGE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FCMGE_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFCMPGE %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFCMPGT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FCMGT_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFCMPGT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFMAX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FMAX_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFMAX %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFMIN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FMIN_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFMIN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FMUL_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFRCP(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use VRECPE/VRECPS)*/ + host_arm64_FMOV_S_ONE(block, REG_V_TEMP); + host_arm64_FDIV_S(block, dest_reg, REG_V_TEMP, src_reg_a); + host_arm64_DUP_V2S(block, dest_reg, dest_reg, 0); + } + else + fatal("PFRCP %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_PFRSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use VRSQRTE/VRSQRTS)*/ + host_arm64_FSQRT_S(block, REG_V_TEMP, src_reg_a); + host_arm64_FMOV_S_ONE(block, REG_V_TEMP); + host_arm64_FDIV_S(block, dest_reg, dest_reg, REG_V_TEMP); + host_arm64_DUP_V2S(block, dest_reg, dest_reg, 0); + } + else + fatal("PFRSQRT %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_PFSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FSUB_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PI2FD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_arm64_SCVTF_V2S(block, dest_reg, src_reg_a); + } + else + fatal("PI2FD %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} + +static int codegen_PMADDWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SMULL_V4S_4H(block, REG_V_TEMP, src_reg_a, src_reg_b); + host_arm64_ADDP_V4S(block, dest_reg, REG_V_TEMP, REG_V_TEMP); + } + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PMULHW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SMULL_V4S_4H(block, dest_reg, src_reg_a, src_reg_b); + host_arm64_SHRN_V4H_4S(block, dest_reg, dest_reg, 16); + } + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PMULLW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_MUL_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PMULLW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PSLLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 15) + host_arm64_EOR_REG_V(block, dest_reg, dest_reg, dest_reg); + else + host_arm64_SHL_V4H(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSLLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSLLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 31) + host_arm64_EOR_REG_V(block, dest_reg, dest_reg, dest_reg); + else + host_arm64_SHL_V2S(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSLLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSLLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 63) + host_arm64_EOR_REG_V(block, dest_reg, dest_reg, dest_reg); + else + host_arm64_SHL_V2D(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSLLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRAW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 15) + host_arm64_SSHR_V4H(block, dest_reg, src_reg, 15); + else + host_arm64_SSHR_V4H(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRAW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRAD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 31) + host_arm64_SSHR_V2S(block, dest_reg, src_reg, 31); + else + host_arm64_SSHR_V2S(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRAD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRAQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 63) + host_arm64_SSHR_V2D(block, dest_reg, src_reg, 63); + else + host_arm64_SSHR_V2D(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRAQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 15) + host_arm64_EOR_REG_V(block, dest_reg, dest_reg, dest_reg); + else + host_arm64_USHR_V4H(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 31) + host_arm64_EOR_REG_V(block, dest_reg, dest_reg, dest_reg); + else + host_arm64_USHR_V2S(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 63) + host_arm64_EOR_REG_V(block, dest_reg, dest_reg, dest_reg); + else + host_arm64_USHR_V2D(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_PSUBB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SUB_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SUB_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SUB_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SQSUB_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SQSUB_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_UQSUB_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_UQSUB_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PUNPCKHBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ZIP2_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PUNPCKHBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKHWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ZIP2_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PUNPCKHWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKHDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ZIP2_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PUNPCKHDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKLBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ZIP1_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PUNPCKLBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKLWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ZIP1_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PUNPCKLWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKLDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ZIP1_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PUNPCKLDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_ROL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_mov_imm(block, REG_TEMP2, 32); + host_arm64_SUB_REG(block, REG_TEMP2, REG_TEMP2, shift_reg, 0); + host_arm64_ROR(block, dest_reg, src_reg, REG_TEMP2); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_mov_imm(block, REG_TEMP2, 16); + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 16); + host_arm64_SUB_REG(block, REG_TEMP2, REG_TEMP2, shift_reg, 0); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm64_ROR(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + cs = cs; + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_mov_imm(block, REG_TEMP2, 8); + host_arm64_SUB_REG(block, REG_TEMP2, REG_TEMP2, shift_reg, 0); + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 8); + host_arm64_AND_IMM(block, REG_TEMP2, REG_TEMP2, 7); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_mov_imm(block, REG_TEMP2, 8); + host_arm64_SUB_REG(block, REG_TEMP2, REG_TEMP2, shift_reg, 0); + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_AND_IMM(block, REG_TEMP2, REG_TEMP2, 7); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("ROL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ROL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (!(uop->imm_data & 31)) + { + if (src_reg != dest_reg) + host_arm64_MOV_REG(block, dest_reg, src_reg, 0); + } + else + { + host_arm64_MOV_REG_ROR(block, dest_reg, src_reg, 32 - (uop->imm_data & 31)); + } + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if ((uop->imm_data & 15) == 0) + { + if (src_reg != dest_reg) + host_arm64_BFI(block, dest_reg, src_reg, 0, 16); + } + else + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 16); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 16-(uop->imm_data & 15)); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + host_arm64_BFI(block, dest_reg, src_reg, 0, 8); + } + else + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 8); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8-(uop->imm_data & 7)); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + fatal("ROL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8-(uop->imm_data & 7)); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + } + else + fatal("ROL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ROR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_ROR(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 16); + host_arm64_AND_IMM(block, REG_TEMP2, shift_reg, 15); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 8); + host_arm64_AND_IMM(block, REG_TEMP2, shift_reg, 7); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_AND_IMM(block, REG_TEMP2, shift_reg, 7); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("ROR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ROR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (!(uop->imm_data & 31)) + { + if (src_reg != dest_reg) + host_arm64_MOV_REG(block, dest_reg, src_reg, 0); + } + else + { + host_arm64_MOV_REG_ROR(block, dest_reg, src_reg, uop->imm_data & 31); + } + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if ((uop->imm_data & 15) == 0) + { + if (src_reg != dest_reg) + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 16); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data & 15); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 8); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data & 7); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data & 7); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + } + else + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_SAR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_ASR(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, 16); + host_arm64_ASR(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_UBFX(block, REG_TEMP, REG_TEMP, 16, 16); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, 24); + host_arm64_ASR(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_UBFX(block, REG_TEMP, REG_TEMP, 24, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, 16); + host_arm64_ASR(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_UBFX(block, REG_TEMP, REG_TEMP, 24, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SAR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SAR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_MOV_REG_ASR(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, 16); + host_arm64_MOV_REG_ASR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_UBFX(block, REG_TEMP, REG_TEMP, 16, 16); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, 24); + host_arm64_MOV_REG_ASR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_UBFX(block, REG_TEMP, REG_TEMP, 24, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, 16); + host_arm64_MOV_REG_ASR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_UBFX(block, REG_TEMP, REG_TEMP, 24, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SAR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_LSL(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_LSL(block, REG_TEMP, src_reg, shift_reg); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_LSL(block, REG_TEMP, src_reg, shift_reg); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_LSL(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_MOV_REG(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_MOV_REG(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_LSR(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xffff); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xff); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_MOV_REG_LSR(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xffff); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xff); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_STORE_PTR_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, REG_W16, uop->imm_data); + + if (in_range12_w((uintptr_t)uop->p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_W(block, REG_W16, REG_CPUSTATE, (uintptr_t)uop->p - (uintptr_t)&cpu_state); + else + fatal("codegen_STORE_PTR_IMM - not in range\n"); + + return 0; +} +static int codegen_STORE_PTR_IMM_8(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, REG_W16, uop->imm_data); + + if (in_range12_b((uintptr_t)uop->p - (uintptr_t)&cpu_state)) + host_arm64_STRB_IMM(block, REG_W16, REG_CPUSTATE, (uintptr_t)uop->p - (uintptr_t)&cpu_state); + else + fatal("codegen_STORE_PTR_IMM - not in range\n"); + + return 0; +} + +static int codegen_SUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_SUB_REG(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_SUB_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_SUB_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_SUB_REG_LSR(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_SUB_REG(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_MOV_REG_LSR(block, REG_TEMP, src_reg_a, 8); + host_arm64_SUB_REG_LSR(block, REG_TEMP, REG_TEMP, src_reg_b, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_SUB_REG(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_MOV_REG_LSR(block, REG_TEMP, src_reg_a, 8); + host_arm64_SUB_REG_LSR(block, REG_TEMP, REG_TEMP, src_reg_b, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_SUB_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_SUB_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data << 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data << 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SUB_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_TEST_JNS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm64_TST_IMM(block, src_reg, 1 << 31); + } + else if (REG_IS_W(src_size)) + { + host_arm64_TST_IMM(block, src_reg, 1 << 15); + } + else if (REG_IS_B(src_size)) + { + host_arm64_TST_IMM(block, src_reg, 1 << 7); + } + else + fatal("TEST_JNS_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BEQ_(block); + + return 0; +} +static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm64_TST_IMM(block, src_reg, 1 << 31); + } + else if (REG_IS_W(src_size)) + { + host_arm64_TST_IMM(block, src_reg, 1 << 15); + } + else if (REG_IS_B(src_size)) + { + host_arm64_TST_IMM(block, src_reg, 1 << 7); + } + else + fatal("TEST_JS_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BNE_(block); + + return 0; +} + +static int codegen_XOR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_EOR_REG_V(block, dest_reg, src_reg_a, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_EOR_REG(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg_b, 0xffff); + host_arm64_EOR_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg_b, 0xff); + host_arm64_EOR_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_UBFX(block, REG_TEMP, src_reg_b, 8, 8); + host_arm64_EOR_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg_b, 0xff); + host_arm64_EOR_REG(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_UBFX(block, REG_TEMP, src_reg_b, 8, 8); + host_arm64_EOR_REG(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else + fatal("XOR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_EOR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size) && dest_reg == src_reg) + { + host_arm64_EOR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size) && dest_reg == src_reg) + { + host_arm64_EOR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size) && dest_reg == src_reg) + { + host_arm64_EOR_IMM(block, dest_reg, src_reg, uop->imm_data << 8); + } + else + fatal("XOR_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +const uOpFn uop_handlers[UOP_MAX] = +{ + [UOP_CALL_FUNC & UOP_MASK] = codegen_CALL_FUNC, + [UOP_CALL_FUNC_RESULT & UOP_MASK] = codegen_CALL_FUNC_RESULT, + [UOP_CALL_INSTRUCTION_FUNC & UOP_MASK] = codegen_CALL_INSTRUCTION_FUNC, + + [UOP_JMP & UOP_MASK] = codegen_JMP, + + [UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG, + + [UOP_LOAD_FUNC_ARG_0 & UOP_MASK] = codegen_LOAD_FUNC_ARG0, + [UOP_LOAD_FUNC_ARG_1 & UOP_MASK] = codegen_LOAD_FUNC_ARG1, + [UOP_LOAD_FUNC_ARG_2 & UOP_MASK] = codegen_LOAD_FUNC_ARG2, + [UOP_LOAD_FUNC_ARG_3 & UOP_MASK] = codegen_LOAD_FUNC_ARG3, + + [UOP_LOAD_FUNC_ARG_0_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG0_IMM, + [UOP_LOAD_FUNC_ARG_1_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG1_IMM, + [UOP_LOAD_FUNC_ARG_2_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG2_IMM, + [UOP_LOAD_FUNC_ARG_3_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG3_IMM, + + [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, + [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, + [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, + [UOP_MEM_LOAD_SINGLE & UOP_MASK] = codegen_MEM_LOAD_SINGLE, + [UOP_MEM_LOAD_DOUBLE & UOP_MASK] = codegen_MEM_LOAD_DOUBLE, + + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, + [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, + [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, + [UOP_MEM_STORE_IMM_16 & UOP_MASK] = codegen_MEM_STORE_IMM_16, + [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, + [UOP_MEM_STORE_SINGLE & UOP_MASK] = codegen_MEM_STORE_SINGLE, + [UOP_MEM_STORE_DOUBLE & UOP_MASK] = codegen_MEM_STORE_DOUBLE, + + [UOP_MOV & UOP_MASK] = codegen_MOV, + [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, + [UOP_MOVSX & UOP_MASK] = codegen_MOVSX, + [UOP_MOVZX & UOP_MASK] = codegen_MOVZX, + [UOP_MOV_DOUBLE_INT & UOP_MASK] = codegen_MOV_DOUBLE_INT, + [UOP_MOV_INT_DOUBLE & UOP_MASK] = codegen_MOV_INT_DOUBLE, + [UOP_MOV_INT_DOUBLE_64 & UOP_MASK] = codegen_MOV_INT_DOUBLE_64, + [UOP_MOV_REG_PTR & UOP_MASK] = codegen_MOV_REG_PTR, + [UOP_MOVZX_REG_PTR_8 & UOP_MASK] = codegen_MOVZX_REG_PTR_8, + [UOP_MOVZX_REG_PTR_16 & UOP_MASK] = codegen_MOVZX_REG_PTR_16, + + [UOP_ADD & UOP_MASK] = codegen_ADD, + [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, + [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, + [UOP_AND & UOP_MASK] = codegen_AND, + [UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM, + [UOP_ANDN & UOP_MASK] = codegen_ANDN, + [UOP_OR & UOP_MASK] = codegen_OR, + [UOP_OR_IMM & UOP_MASK] = codegen_OR_IMM, + [UOP_SUB & UOP_MASK] = codegen_SUB, + [UOP_SUB_IMM & UOP_MASK] = codegen_SUB_IMM, + [UOP_XOR & UOP_MASK] = codegen_XOR, + [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM, + + [UOP_SAR & UOP_MASK] = codegen_SAR, + [UOP_SAR_IMM & UOP_MASK] = codegen_SAR_IMM, + [UOP_SHL & UOP_MASK] = codegen_SHL, + [UOP_SHL_IMM & UOP_MASK] = codegen_SHL_IMM, + [UOP_SHR & UOP_MASK] = codegen_SHR, + [UOP_SHR_IMM & UOP_MASK] = codegen_SHR_IMM, + [UOP_ROL & UOP_MASK] = codegen_ROL, + [UOP_ROL_IMM & UOP_MASK] = codegen_ROL_IMM, + [UOP_ROR & UOP_MASK] = codegen_ROR, + [UOP_ROR_IMM & UOP_MASK] = codegen_ROR_IMM, + + [UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ, + + [UOP_CMP_JB & UOP_MASK] = codegen_CMP_JB, + [UOP_CMP_JNBE & UOP_MASK] = codegen_CMP_JNBE, + + [UOP_CMP_JNB_DEST & UOP_MASK] = codegen_CMP_JNB_DEST, + [UOP_CMP_JNBE_DEST & UOP_MASK] = codegen_CMP_JNBE_DEST, + [UOP_CMP_JNL_DEST & UOP_MASK] = codegen_CMP_JNL_DEST, + [UOP_CMP_JNLE_DEST & UOP_MASK] = codegen_CMP_JNLE_DEST, + [UOP_CMP_JNO_DEST & UOP_MASK] = codegen_CMP_JNO_DEST, + [UOP_CMP_JNZ_DEST & UOP_MASK] = codegen_CMP_JNZ_DEST, + [UOP_CMP_JB_DEST & UOP_MASK] = codegen_CMP_JB_DEST, + [UOP_CMP_JBE_DEST & UOP_MASK] = codegen_CMP_JBE_DEST, + [UOP_CMP_JL_DEST & UOP_MASK] = codegen_CMP_JL_DEST, + [UOP_CMP_JLE_DEST & UOP_MASK] = codegen_CMP_JLE_DEST, + [UOP_CMP_JO_DEST & UOP_MASK] = codegen_CMP_JO_DEST, + [UOP_CMP_JZ_DEST & UOP_MASK] = codegen_CMP_JZ_DEST, + + [UOP_CMP_IMM_JNZ_DEST & UOP_MASK] = codegen_CMP_IMM_JNZ_DEST, + [UOP_CMP_IMM_JZ_DEST & UOP_MASK] = codegen_CMP_IMM_JZ_DEST, + + [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, + [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, + + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, + [UOP_MMX_ENTER & UOP_MASK] = codegen_MMX_ENTER, + + [UOP_FADD & UOP_MASK] = codegen_FADD, + [UOP_FCOM & UOP_MASK] = codegen_FCOM, + [UOP_FDIV & UOP_MASK] = codegen_FDIV, + [UOP_FMUL & UOP_MASK] = codegen_FMUL, + [UOP_FSUB & UOP_MASK] = codegen_FSUB, + + [UOP_FABS & UOP_MASK] = codegen_FABS, + [UOP_FCHS & UOP_MASK] = codegen_FCHS, + [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, + [UOP_FTST & UOP_MASK] = codegen_FTST, + + [UOP_PACKSSWB & UOP_MASK] = codegen_PACKSSWB, + [UOP_PACKSSDW & UOP_MASK] = codegen_PACKSSDW, + [UOP_PACKUSWB & UOP_MASK] = codegen_PACKUSWB, + + [UOP_PADDB & UOP_MASK] = codegen_PADDB, + [UOP_PADDW & UOP_MASK] = codegen_PADDW, + [UOP_PADDD & UOP_MASK] = codegen_PADDD, + [UOP_PADDSB & UOP_MASK] = codegen_PADDSB, + [UOP_PADDSW & UOP_MASK] = codegen_PADDSW, + [UOP_PADDUSB & UOP_MASK] = codegen_PADDUSB, + [UOP_PADDUSW & UOP_MASK] = codegen_PADDUSW, + + [UOP_PCMPEQB & UOP_MASK] = codegen_PCMPEQB, + [UOP_PCMPEQW & UOP_MASK] = codegen_PCMPEQW, + [UOP_PCMPEQD & UOP_MASK] = codegen_PCMPEQD, + [UOP_PCMPGTB & UOP_MASK] = codegen_PCMPGTB, + [UOP_PCMPGTW & UOP_MASK] = codegen_PCMPGTW, + [UOP_PCMPGTD & UOP_MASK] = codegen_PCMPGTD, + + [UOP_PF2ID & UOP_MASK] = codegen_PF2ID, + [UOP_PFADD & UOP_MASK] = codegen_PFADD, + [UOP_PFCMPEQ & UOP_MASK] = codegen_PFCMPEQ, + [UOP_PFCMPGE & UOP_MASK] = codegen_PFCMPGE, + [UOP_PFCMPGT & UOP_MASK] = codegen_PFCMPGT, + [UOP_PFMAX & UOP_MASK] = codegen_PFMAX, + [UOP_PFMIN & UOP_MASK] = codegen_PFMIN, + [UOP_PFMUL & UOP_MASK] = codegen_PFMUL, + [UOP_PFRCP & UOP_MASK] = codegen_PFRCP, + [UOP_PFRSQRT & UOP_MASK] = codegen_PFRSQRT, + [UOP_PFSUB & UOP_MASK] = codegen_PFSUB, + [UOP_PI2FD & UOP_MASK] = codegen_PI2FD, + + [UOP_PMADDWD & UOP_MASK] = codegen_PMADDWD, + [UOP_PMULHW & UOP_MASK] = codegen_PMULHW, + [UOP_PMULLW & UOP_MASK] = codegen_PMULLW, + + [UOP_PSLLW_IMM & UOP_MASK] = codegen_PSLLW_IMM, + [UOP_PSLLD_IMM & UOP_MASK] = codegen_PSLLD_IMM, + [UOP_PSLLQ_IMM & UOP_MASK] = codegen_PSLLQ_IMM, + [UOP_PSRAW_IMM & UOP_MASK] = codegen_PSRAW_IMM, + [UOP_PSRAD_IMM & UOP_MASK] = codegen_PSRAD_IMM, + [UOP_PSRAQ_IMM & UOP_MASK] = codegen_PSRAQ_IMM, + [UOP_PSRLW_IMM & UOP_MASK] = codegen_PSRLW_IMM, + [UOP_PSRLD_IMM & UOP_MASK] = codegen_PSRLD_IMM, + [UOP_PSRLQ_IMM & UOP_MASK] = codegen_PSRLQ_IMM, + + [UOP_PSUBB & UOP_MASK] = codegen_PSUBB, + [UOP_PSUBW & UOP_MASK] = codegen_PSUBW, + [UOP_PSUBD & UOP_MASK] = codegen_PSUBD, + [UOP_PSUBSB & UOP_MASK] = codegen_PSUBSB, + [UOP_PSUBSW & UOP_MASK] = codegen_PSUBSW, + [UOP_PSUBUSB & UOP_MASK] = codegen_PSUBUSB, + [UOP_PSUBUSW & UOP_MASK] = codegen_PSUBUSW, + + [UOP_PUNPCKHBW & UOP_MASK] = codegen_PUNPCKHBW, + [UOP_PUNPCKHWD & UOP_MASK] = codegen_PUNPCKHWD, + [UOP_PUNPCKHDQ & UOP_MASK] = codegen_PUNPCKHDQ, + [UOP_PUNPCKLBW & UOP_MASK] = codegen_PUNPCKLBW, + [UOP_PUNPCKLWD & UOP_MASK] = codegen_PUNPCKLWD, + [UOP_PUNPCKLDQ & UOP_MASK] = codegen_PUNPCKLDQ, + + [UOP_NOP_BARRIER & UOP_MASK] = codegen_NOP +}; + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_b((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDRB_IMM_W(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_8 - not in range\n"); +} +void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_h((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDRH_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_16 - not in range\n"); +} +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_w((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDR_IMM_W(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_32 - not in range\n"); +} +void codegen_direct_read_64(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDR_IMM_F64(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_double - not in range\n"); +} +void codegen_direct_read_pointer(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDR_IMM_X(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_pointer - not in range\n"); +} +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDR_IMM_F64(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_double - not in range\n"); +} +void codegen_direct_read_st_8(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADDX_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_LDRB_REG(block, host_reg, REG_TEMP2, REG_TEMP); +} +void codegen_direct_read_st_64(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADDX_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_LDR_REG_F64_S(block, host_reg, REG_TEMP2, REG_TEMP); +} +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADDX_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_LDR_REG_F64_S(block, host_reg, REG_TEMP2, REG_TEMP); +} + +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_b((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STRB_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_8 - not in range\n"); +} +void codegen_direct_write_16(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_h((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STRH_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_16 - not in range\n"); +} +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_w((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_W(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_32 - not in range\n"); +} +void codegen_direct_write_64(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_F64(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_double - not in range\n"); +} +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_F64(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_double - not in range\n"); +} +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADDX_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_STRB_REG(block, host_reg, REG_TEMP2, REG_TEMP); +} +void codegen_direct_write_st_64(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADDX_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_STR_REG_F64_S(block, host_reg, REG_TEMP2, REG_TEMP); +} +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADDX_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_STR_REG_F64_S(block, host_reg, REG_TEMP2, REG_TEMP); +} + +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_Q(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_ptr - not in range\n"); +} + +void codegen_direct_read_16_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + if (in_range12_h(stack_offset)) + host_arm64_LDRH_IMM(block, host_reg, REG_XSP, stack_offset); + else + fatal("codegen_direct_read_32_stack - not in range\n"); +} +void codegen_direct_read_32_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + if (in_range12_w(stack_offset)) + host_arm64_LDR_IMM_W(block, host_reg, REG_XSP, stack_offset); + else + fatal("codegen_direct_read_32_stack - not in range\n"); +} +void codegen_direct_read_pointer_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + if (in_range12_q(stack_offset)) + host_arm64_LDR_IMM_X(block, host_reg, REG_XSP, stack_offset); + else + fatal("codegen_direct_read_pointer_stack - not in range\n"); +} +void codegen_direct_read_64_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_arm64_LDR_IMM_F64(block, host_reg, REG_XSP, stack_offset); +} +void codegen_direct_read_double_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_arm64_LDR_IMM_F64(block, host_reg, REG_XSP, stack_offset); +} + +void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + if (in_range12_w(stack_offset)) + host_arm64_STR_IMM_W(block, host_reg, REG_XSP, stack_offset); + else + fatal("codegen_direct_write_32_stack - not in range\n"); +} +void codegen_direct_write_64_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_arm64_STR_IMM_F64(block, host_reg, REG_XSP, stack_offset); +} +void codegen_direct_write_double_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_arm64_STR_IMM_F64(block, host_reg, REG_XSP, stack_offset); +} + +void codegen_set_jump_dest(codeblock_t *block, void *p) +{ + host_arm64_branch_set_offset(p, &block_write_data[block_pos]); +} +#endif diff --git a/src/cpu_new/codegen_backend_arm_defs.h b/src/cpu_new/codegen_backend_arm_defs.h new file mode 100644 index 000000000..74567998a --- /dev/null +++ b/src/cpu_new/codegen_backend_arm_defs.h @@ -0,0 +1,89 @@ +#define REG_R0 0 +#define REG_R1 1 +#define REG_R2 2 +#define REG_R3 3 +#define REG_R4 4 +#define REG_R5 5 +#define REG_R6 6 +#define REG_R7 7 +#define REG_R8 8 +#define REG_R9 9 +#define REG_R10 10 +#define REG_R11 11 +#define REG_R12 12 +#define REG_HOST_SP 13 +#define REG_LR 14 +#define REG_PC 15 + +#define REG_ARG0 REG_R0 +#define REG_ARG1 REG_R1 +#define REG_ARG2 REG_R2 +#define REG_ARG3 REG_R3 + +#define REG_CPUSTATE REG_R10 + +#define REG_TEMP REG_R3 +#define REG_TEMP2 REG_R2 + +#define REG_D0 0 +#define REG_D1 1 +#define REG_D2 2 +#define REG_D3 3 +#define REG_D4 4 +#define REG_D5 5 +#define REG_D6 6 +#define REG_D7 7 +#define REG_D8 8 +#define REG_D9 9 +#define REG_D10 10 +#define REG_D11 11 +#define REG_D12 12 +#define REG_D13 13 +#define REG_D14 14 +#define REG_D15 15 + +#define REG_D_TEMP REG_D0 +#define REG_Q_TEMP REG_D0 +#define REG_Q_TEMP_2 REG_D2 + +#define REG_MASK_R0 (1 << REG_R0) +#define REG_MASK_R1 (1 << REG_R1) +#define REG_MASK_R2 (1 << REG_R2) +#define REG_MASK_R3 (1 << REG_R3) +#define REG_MASK_R4 (1 << REG_R4) +#define REG_MASK_R5 (1 << REG_R5) +#define REG_MASK_R6 (1 << REG_R6) +#define REG_MASK_R7 (1 << REG_R7) +#define REG_MASK_R8 (1 << REG_R8) +#define REG_MASK_R9 (1 << REG_R9) +#define REG_MASK_R10 (1 << REG_R10) +#define REG_MASK_R11 (1 << REG_R11) +#define REG_MASK_R12 (1 << REG_R12) +#define REG_MASK_SP (1 << REG_HOST_SP) +#define REG_MASK_LR (1 << REG_LR) +#define REG_MASK_PC (1 << REG_PC) + +#define REG_MASK_LOCAL (REG_MASK_R4 | REG_MASK_R5 | REG_MASK_R6 | REG_MASK_R7 | \ + REG_MASK_R8 | REG_MASK_R9 | REG_MASK_R10 | REG_MASK_R11) + +#define CODEGEN_HOST_REGS 7 +#define CODEGEN_HOST_FP_REGS 8 + +extern void *codegen_mem_load_byte; +extern void *codegen_mem_load_word; +extern void *codegen_mem_load_long; +extern void *codegen_mem_load_quad; +extern void *codegen_mem_load_single; +extern void *codegen_mem_load_double; + +extern void *codegen_mem_store_byte; +extern void *codegen_mem_store_word; +extern void *codegen_mem_store_long; +extern void *codegen_mem_store_quad; +extern void *codegen_mem_store_single; +extern void *codegen_mem_store_double; + +extern void *codegen_fp_round; + +extern void *codegen_gpf_rout; +extern void *codegen_exit_rout; diff --git a/src/cpu_new/codegen_backend_arm_ops.c b/src/cpu_new/codegen_backend_arm_ops.c new file mode 100644 index 000000000..1b2ef28f3 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm_ops.c @@ -0,0 +1,1274 @@ +#ifdef __ARM_EABI__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_arm_defs.h" +#include "codegen_backend_arm_ops.h" + +#define Rm(x) (x) +#define Rs(x) ((x) << 8) +#define Rd(x) ((x) << 12) +#define Rt(x) ((x) << 12) +#define Rn(x) ((x) << 16) +#define Rt2(x) ((x) << 16) + +#define Vm(x) (x) +#define Vd(x) ((x) << 12) +#define Vn(x) ((x) << 16) + +#define DATA_OFFSET_UP (1 << 23) +#define DATA_OFFSET_DOWN (0 << 23) + +#define OPCODE_SHIFT 20 +#define OPCODE_ADD_IMM (0x28 << OPCODE_SHIFT) +#define OPCODE_ADD_REG (0x08 << OPCODE_SHIFT) +#define OPCODE_AND_IMM (0x20 << OPCODE_SHIFT) +#define OPCODE_AND_REG (0x00 << OPCODE_SHIFT) +#define OPCODE_B (0xa0 << OPCODE_SHIFT) +#define OPCODE_BIC_IMM (0x3c << OPCODE_SHIFT) +#define OPCODE_BIC_REG (0x1c << OPCODE_SHIFT) +#define OPCODE_BL (0xb0 << OPCODE_SHIFT) +#define OPCODE_CMN_IMM (0x37 << OPCODE_SHIFT) +#define OPCODE_CMN_REG (0x17 << OPCODE_SHIFT) +#define OPCODE_CMP_IMM (0x35 << OPCODE_SHIFT) +#define OPCODE_CMP_REG (0x15 << OPCODE_SHIFT) +#define OPCODE_EOR_IMM (0x22 << OPCODE_SHIFT) +#define OPCODE_EOR_REG (0x02 << OPCODE_SHIFT) +#define OPCODE_LDMIA_WB (0x8b << OPCODE_SHIFT) +#define OPCODE_LDR_IMM (0x51 << OPCODE_SHIFT) +#define OPCODE_LDR_IMM_POST (0x41 << OPCODE_SHIFT) +#define OPCODE_LDR_REG (0x79 << OPCODE_SHIFT) +#define OPCODE_LDRB_IMM (0x55 << OPCODE_SHIFT) +#define OPCODE_LDRB_REG (0x7d << OPCODE_SHIFT) +#define OPCODE_MOV_IMM (0x3a << OPCODE_SHIFT) +#define OPCODE_MOVT_IMM (0x34 << OPCODE_SHIFT) +#define OPCODE_MOVW_IMM (0x30 << OPCODE_SHIFT) +#define OPCODE_MOV_REG (0x1a << OPCODE_SHIFT) +#define OPCODE_MVN_REG (0x1e << OPCODE_SHIFT) +#define OPCODE_ORR_IMM (0x38 << OPCODE_SHIFT) +#define OPCODE_ORR_REG (0x18 << OPCODE_SHIFT) +#define OPCODE_RSB_IMM (0x26 << OPCODE_SHIFT) +#define OPCODE_RSB_REG (0x06 << OPCODE_SHIFT) +#define OPCODE_STMDB_WB (0x92 << OPCODE_SHIFT) +#define OPCODE_STR_IMM (0x50 << OPCODE_SHIFT) +#define OPCODE_STR_IMM_WB (0x52 << OPCODE_SHIFT) +#define OPCODE_STR_REG (0x78 << OPCODE_SHIFT) +#define OPCODE_STRB_IMM (0x54 << OPCODE_SHIFT) +#define OPCODE_STRB_REG (0x7c << OPCODE_SHIFT) +#define OPCODE_SUB_IMM (0x24 << OPCODE_SHIFT) +#define OPCODE_SUB_REG (0x04 << OPCODE_SHIFT) +#define OPCODE_TST_IMM (0x31 << OPCODE_SHIFT) +#define OPCODE_TST_REG (0x11 << OPCODE_SHIFT) + +#define OPCODE_BFI 0xe7c00010 +#define OPCODE_BLX 0xe12fff30 +#define OPCODE_BX 0xe12fff10 +#define OPCODE_LDRH_IMM 0xe1d000b0 +#define OPCODE_LDRH_REG 0xe19000b0 +#define OPCODE_STRH_IMM 0xe1c000b0 +#define OPCODE_STRH_REG 0xe18000b0 +#define OPCODE_SXTB 0xe6af0070 +#define OPCODE_SXTH 0xe6bf0070 +#define OPCODE_UADD8 0xe6500f90 +#define OPCODE_UADD16 0xe6500f10 +#define OPCODE_USUB8 0xe6500ff0 +#define OPCODE_USUB16 0xe6500f70 +#define OPCODE_UXTB 0xe6ef0070 +#define OPCODE_UXTH 0xe6ff0070 +#define OPCODE_VABS_D 0xeeb00bc0 +#define OPCODE_VADD 0xee300b00 +#define OPCODE_VADD_I8 0xf2000800 +#define OPCODE_VADD_I16 0xf2100800 +#define OPCODE_VADD_I32 0xf2200800 +#define OPCODE_VADD_F32 0xf2000d00 +#define OPCODE_VAND_D 0xf2000110 +#define OPCODE_VBIC_D 0xf2100110 +#define OPCODE_VCEQ_F32 0xf2000e00 +#define OPCODE_VCEQ_I8 0xf3000810 +#define OPCODE_VCEQ_I16 0xf3100810 +#define OPCODE_VCEQ_I32 0xf3200810 +#define OPCODE_VCGE_F32 0xf3000e00 +#define OPCODE_VCGT_F32 0xf3200e00 +#define OPCODE_VCGT_S8 0xf2000300 +#define OPCODE_VCGT_S16 0xf2100300 +#define OPCODE_VCGT_S32 0xf2200300 +#define OPCODE_VCMP_D 0xeeb40b40 +#define OPCODE_VCVT_D_IS 0xeeb80bc0 +#define OPCODE_VCVT_D_S 0xeeb70ac0 +#define OPCODE_VCVT_F32_S32 0xf3bb0700 +#define OPCODE_VCVT_IS_D 0xeebd0bc0 +#define OPCODE_VCVT_S32_F32 0xf3bb0600 +#define OPCODE_VCVT_S_D 0xeeb70bc0 +#define OPCODE_VCVTR_IS_D 0xeebd0b40 +#define OPCODE_VDIV 0xee800b00 +#define OPCODE_VDIV_S 0xee800a00 +#define OPCODE_VDUP_32 0xf3b40c00 +#define OPCODE_VEOR_D 0xf3000110 +#define OPCODE_VLDR_D 0xed900b00 +#define OPCODE_VLDR_S 0xed900a00 +#define OPCODE_VMAX_F32 0xf200f00 +#define OPCODE_VMIN_F32 0xf220f00 +#define OPCODE_VMOV_32_S 0xee100a10 +#define OPCODE_VMOV_64_D 0xec500b10 +#define OPCODE_VMOV_D_64 0xec400b10 +#define OPCODE_VMOV_S_32 0xee000a10 +#define OPCODE_VMOV_D_D 0xeeb00b40 +#define OPCODE_VMOVN_I32 0xf3b60200 +#define OPCODE_VMOVN_I64 0xf3ba0200 +#define OPCODE_VMOV_F32_ONE 0xf2870f10 +#define OPCODE_VMRS_APSR 0xeef1fa10 +#define OPCODE_VMSR_FPSCR 0xeee10a10 +#define OPCODE_VMUL 0xee200b00 +#define OPCODE_VMUL_F32 0xf3000d10 +#define OPCODE_VMUL_S16 0xf2100910 +#define OPCODE_VMULL_S16 0xf2900c00 +#define OPCODE_VNEG_D 0xeeb10b40 +#define OPCODE_VORR_D 0xf2200110 +#define OPCODE_VPADDL_S16 0xf3b40200 +#define OPCODE_VPADDL_S32 0xf3b80200 +#define OPCODE_VPADDL_Q_S32 0xf3b80240 +#define OPCODE_VQADD_S8 0xf2000010 +#define OPCODE_VQADD_S16 0xf2100010 +#define OPCODE_VQADD_U8 0xf3000010 +#define OPCODE_VQADD_U16 0xf3100010 +#define OPCODE_VQMOVN_S16 0xf3b20280 +#define OPCODE_VQMOVN_S32 0xf3b60280 +#define OPCODE_VQMOVN_U16 0xf3b202c0 +#define OPCODE_VQSUB_S8 0xf2000210 +#define OPCODE_VQSUB_S16 0xf2100210 +#define OPCODE_VQSUB_U8 0xf3000210 +#define OPCODE_VQSUB_U16 0xf3100210 +#define OPCODE_VSHL_D_IMM_16 0xf2900510 +#define OPCODE_VSHL_D_IMM_32 0xf2a00510 +#define OPCODE_VSHL_D_IMM_64 0xf2800590 +#define OPCODE_VSHR_D_S16 0xf2900010 +#define OPCODE_VSHR_D_S32 0xf2a00010 +#define OPCODE_VSHR_D_S64 0xf2800090 +#define OPCODE_VSHR_D_U16 0xf3900010 +#define OPCODE_VSHR_D_U32 0xf3a00010 +#define OPCODE_VSHR_D_U64 0xf3800090 +#define OPCODE_VSHRN 0xf2800810 +#define OPCODE_VSQRT_D 0xeeb10bc0 +#define OPCODE_VSQRT_S 0xeeb10ac0 +#define OPCODE_VSTR_D 0xed800b00 +#define OPCODE_VSTR_S 0xed800a00 +#define OPCODE_VSUB 0xee300b40 +#define OPCODE_VSUB_I8 0xf3000800 +#define OPCODE_VSUB_I16 0xf3100800 +#define OPCODE_VSUB_I32 0xf3200800 +#define OPCODE_VSUB_F32 0xf3000d00 +#define OPCODE_VZIP_D8 0xf3b20180 +#define OPCODE_VZIP_D16 0xf3b60180 +#define OPCODE_VZIP_D32 0xf3ba0080 + +#define B_OFFSET(x) (((x) >> 2) & 0xffffff) + +#define SHIFT_TYPE_SHIFT 5 +#define SHIFT_TYPE_LSL (0 << SHIFT_TYPE_SHIFT) +#define SHIFT_TYPE_LSR (1 << SHIFT_TYPE_SHIFT) +#define SHIFT_TYPE_ASR (2 << SHIFT_TYPE_SHIFT) +#define SHIFT_TYPE_ROR (3 << SHIFT_TYPE_SHIFT) + +#define SHIFT_TYPE_IMM (0 << 4) +#define SHIFT_TYPE_REG (1 << 4) + +#define SHIFT_IMM_SHIFT 7 +#define SHIFT_ASR_IMM(x) (SHIFT_TYPE_ASR | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) +#define SHIFT_LSL_IMM(x) (SHIFT_TYPE_LSL | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) +#define SHIFT_LSR_IMM(x) (SHIFT_TYPE_LSR | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) +#define SHIFT_ROR_IMM(x) (SHIFT_TYPE_ROR | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) + +#define SHIFT_ASR_REG(x) (SHIFT_TYPE_ASR | SHIFT_TYPE_REG | Rs(x)) +#define SHIFT_LSL_REG(x) (SHIFT_TYPE_LSL | SHIFT_TYPE_REG | Rs(x)) +#define SHIFT_LSR_REG(x) (SHIFT_TYPE_LSR | SHIFT_TYPE_REG | Rs(x)) +#define SHIFT_ROR_REG(x) (SHIFT_TYPE_ROR | SHIFT_TYPE_REG | Rs(x)) + +#define BFI_lsb(lsb) ((lsb) << 7) +#define BFI_msb(msb) ((msb) << 16) + +#define UXTB_ROTATE(rotate) (((rotate) >> 3) << 10) + +#define MOVT_IMM(imm) (((imm) & 0xfff) | (((imm) & 0xf000) << 4)) +#define MOVW_IMM(imm) (((imm) & 0xfff) | (((imm) & 0xf000) << 4)) + +#define LDRH_IMM(imm) (((imm) & 0xf) | (((imm) & 0xf0) << 4)) +#define STRH_IMM(imm) LDRH_IMM(imm) + +#define VSHIFT_IMM(shift) ((shift) << 16) + +#define VSHIFT_IMM_32(shift) (((16 - (shift)) | 0x10) << 16) + +#define VDUP_32_IMM(imm) ((imm) << 19) + +static void codegen_allocate_new_block(codeblock_t *block); + +static inline void codegen_addlong(codeblock_t *block, uint32_t val) +{ + if (block_pos >= (BLOCK_MAX-4)) + codegen_allocate_new_block(block); + *(uint32_t *)&block_write_data[block_pos] = val; + block_pos += 4; +} + +static void codegen_allocate_new_block(codeblock_t *block) +{ + /*Current block is full. Allocate a new block*/ + struct mem_block_t *new_block = codegen_allocator_allocate(block->head_mem_block, get_block_nr(block)); + uint8_t *new_ptr = codeblock_allocator_get_ptr(new_block); + uint32_t offset = ((uintptr_t)new_ptr - (uintptr_t)&block_write_data[block_pos]) - 8; + + /*Add a jump instruction to the new block*/ + *(uint32_t *)&block_write_data[block_pos] = COND_AL | OPCODE_B | B_OFFSET(offset); + + /*Set write address to start of new block*/ + block_pos = 0; + block_write_data = new_ptr; +} + +static inline void codegen_alloc_4(codeblock_t *block) +{ + if (block_pos >= (BLOCK_MAX-4)) + codegen_allocate_new_block(block); +} + +void codegen_alloc(codeblock_t *block, int size) +{ + if (block_pos >= (BLOCK_MAX-size)) + codegen_allocate_new_block(block); +} + +static inline uint32_t arm_data_offset(int offset) +{ + if (offset < -0xffc || offset > 0xffc) + fatal("arm_data_offset out of range - %i\n", offset); + + if (offset >= 0) + return offset | DATA_OFFSET_UP; + return (-offset) | DATA_OFFSET_DOWN; +} + +static inline int get_arm_imm(uint32_t imm_data, uint32_t *arm_imm) +{ + int shift = 0; + if (!(imm_data & 0xffff)) + { + shift += 16; + imm_data >>= 16; + } + if (!(imm_data & 0xff)) + { + shift += 8; + imm_data >>= 8; + } + if (!(imm_data & 0xf)) + { + shift += 4; + imm_data >>= 4; + } + if (!(imm_data & 0x3)) + { + shift += 2; + imm_data >>= 2; + } + if (imm_data > 0xff) /*Note - should handle rotation round the word*/ + return 0; + *arm_imm = imm_data | ((((32 - shift) >> 1) & 15) << 8); + return 1; +} + +static inline int in_range(void *addr, void *base) +{ + int diff = (uintptr_t)addr - (uintptr_t)base; + + if (diff < -4095 || diff > 4095) + return 0; + return 1; +} + +void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_EOR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +//void host_arm_ORR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_SUB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_ADD_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if ((int32_t)imm < 0 && imm != 0x80000000) + { + host_arm_SUB_IMM(block, dst_reg, src_reg, -(int32_t)imm); + } + else if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_ADD_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_ADD_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} +void host_arm_ADD_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_ADD_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_AND_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else if (get_arm_imm(~imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_BIC_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_AND_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_AND_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} +void host_arm_AND_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_AND_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_B(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset; + + codegen_alloc_4(block); + offset = (dest_addr - (uintptr_t)&block_write_data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + { + host_arm_MOV_IMM(block, REG_R3, dest_addr); + host_arm_BX(block, REG_R3); + } + else + codegen_addlong(block, COND_AL | OPCODE_B | B_OFFSET(offset)); +} + +void host_arm_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) +{ + codegen_addlong(block, OPCODE_BFI | Rd(dst_reg) | Rm(src_reg) | BFI_lsb(lsb) | BFI_msb((lsb + width) - 1)); +} + +void host_arm_BIC_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_BIC_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else if (get_arm_imm(~imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_BIC_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} +void host_arm_BIC_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_BIC_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} +void host_arm_BIC_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_BIC_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_BL(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset; + + codegen_alloc_4(block); + offset = (dest_addr - (uintptr_t)&block_write_data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + { + host_arm_MOV_IMM(block, REG_R3, dest_addr); + host_arm_BLX(block, REG_R3); + } + else + codegen_addlong(block, COND_AL | OPCODE_BL | B_OFFSET(offset)); +} +void host_arm_BL_r1(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset; + + codegen_alloc_4(block); + offset = (dest_addr - (uintptr_t)&block_write_data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + { + host_arm_MOV_IMM(block, REG_R1, dest_addr); + host_arm_BLX(block, REG_R1); + } + else + codegen_addlong(block, COND_AL | OPCODE_BL | B_OFFSET(offset)); +} +void host_arm_BLX(codeblock_t *block, int addr_reg) +{ + codegen_addlong(block, OPCODE_BLX | Rm(addr_reg)); +} + +uint32_t *host_arm_BCC_(codeblock_t *block) +{ + codegen_addlong(block, COND_CC | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BCS_(codeblock_t *block) +{ + codegen_addlong(block, COND_CS | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BEQ_(codeblock_t *block) +{ + codegen_addlong(block, COND_EQ | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BGE_(codeblock_t *block) +{ + codegen_addlong(block, COND_GE | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BGT_(codeblock_t *block) +{ + codegen_addlong(block, COND_GT | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BHI_(codeblock_t *block) +{ + codegen_addlong(block, COND_HI | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BLE_(codeblock_t *block) +{ + codegen_addlong(block, COND_LE | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BLS_(codeblock_t *block) +{ + codegen_addlong(block, COND_LS | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BLT_(codeblock_t *block) +{ + codegen_addlong(block, COND_LT | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BMI_(codeblock_t *block) +{ + codegen_addlong(block, COND_MI | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BNE_(codeblock_t *block) +{ + codegen_addlong(block, COND_NE | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BPL_(codeblock_t *block) +{ + codegen_addlong(block, COND_PL | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BVC_(codeblock_t *block) +{ + codegen_addlong(block, COND_VC | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BVS_(codeblock_t *block) +{ + codegen_addlong(block, COND_VS | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} + +void host_arm_BEQ(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset; + + codegen_alloc_4(block); + offset = (dest_addr - (uintptr_t)&block_write_data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + fatal("host_arm_BEQ - out of range %08x %i\n", offset, offset); + + codegen_addlong(block, COND_EQ | OPCODE_B | B_OFFSET(offset)); +} +void host_arm_BNE(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset; + + codegen_alloc_4(block); + offset = (dest_addr - (uintptr_t)&block_write_data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + fatal("host_arm_BNE - out of range %08x %i\n", offset, offset); + + codegen_addlong(block, COND_NE | OPCODE_B | B_OFFSET(offset)); +} + +void host_arm_BX(codeblock_t *block, int addr_reg) +{ + codegen_addlong(block, OPCODE_BLX | Rm(addr_reg)); +} + +void host_arm_CMN_IMM(codeblock_t *block, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if ((int32_t)imm < 0 && imm != 0x80000000) + { + host_arm_CMP_IMM(block, src_reg, -(int32_t)imm); + } + else if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_CMN_IMM | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_CMN_REG_LSL(block, src_reg, REG_TEMP, 0); + } +} +void host_arm_CMN_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_CMN_REG | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_CMP_IMM(codeblock_t *block, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if ((int32_t)imm < 0 && imm != 0x80000000) + { + host_arm_CMN_IMM(block, src_reg, -(int32_t)imm); + } + else if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_CMP_IMM | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_CMP_REG_LSL(block, src_reg, REG_TEMP, 0); + } +} +void host_arm_CMP_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_CMP_REG | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_EOR_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_EOR_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_EOR_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_EOR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_EOR_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_LDMIA_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask) +{ + codegen_addlong(block, COND_AL | OPCODE_LDMIA_WB | Rn(addr_reg) | reg_mask); +} + +void host_arm_LDR_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_LDR_IMM | Rn(addr_reg) | Rd(dst_reg) | arm_data_offset(offset)); +} +void host_arm_LDR_IMM_POST(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_LDR_IMM_POST | Rn(addr_reg) | Rd(dst_reg) | arm_data_offset(offset)); +} +void host_arm_LDR_REG_LSL(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_LDR_REG | Rn(addr_reg) | Rd(dst_reg) | Rm(offset_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_LDRB_ABS(codeblock_t *block, int dst_reg, void *p) +{ + if (in_range(p, &cpu_state)) + host_arm_LDRB_IMM(block, dst_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("LDRB_ABS - not in range\n"); +} +void host_arm_LDRB_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_LDRB_IMM | Rn(addr_reg) | Rd(dst_reg) | arm_data_offset(offset)); +} +void host_arm_LDRB_REG_LSL(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_LDRB_REG | Rn(addr_reg) | Rd(dst_reg) | Rm(offset_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_LDRH_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_LDRH_IMM | Rn(addr_reg) | Rd(dst_reg) | LDRH_IMM(offset)); +} +void host_arm_LDRH_REG(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_LDRH_REG | Rn(addr_reg) | Rd(dst_reg) | Rm(offset_reg)); +} + +void host_arm_MOV_IMM(codeblock_t *block, int dst_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_MOV_IMM | Rd(dst_reg) | arm_imm); + } + else + { + host_arm_MOVW_IMM(block, dst_reg, imm & 0xffff); + if (imm >> 16) + host_arm_MOVT_IMM(block, dst_reg, imm >> 16); + } +} + +void host_arm_MOV_REG_ASR(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_ASR_IMM(shift)); +} +void host_arm_MOV_REG_ASR_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_ASR_REG(shift_reg)); +} +void host_arm_MOV_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSL_IMM(shift)); +} +void host_arm_MOV_REG_LSL_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSL_REG(shift_reg)); +} +void host_arm_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSR_IMM(shift)); +} +void host_arm_MOV_REG_LSR_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSR_REG(shift_reg)); +} +void host_arm_MOV_REG_ROR(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_ROR_IMM(shift)); +} +void host_arm_MOV_REG_ROR_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_ROR_REG(shift_reg)); +} + +void host_arm_MOVT_IMM(codeblock_t *block, int dst_reg, uint16_t imm) +{ + codegen_addlong(block, COND_AL | OPCODE_MOVT_IMM | Rd(dst_reg) | MOVT_IMM(imm)); +} +void host_arm_MOVW_IMM(codeblock_t *block, int dst_reg, uint16_t imm) +{ + codegen_addlong(block, COND_AL | OPCODE_MOVW_IMM | Rd(dst_reg) | MOVW_IMM(imm)); +} + +void host_arm_MVN_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MVN_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_ORR_IMM_cond(codeblock_t *block, uint32_t cond, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, cond | OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_ORR_REG_LSL_cond(block, cond, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_ORR_REG_LSL_cond(codeblock_t *block, uint32_t cond, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, cond | OPCODE_ORR_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_RSB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_RSB_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_RSB_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} +void host_arm_RSB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_RSB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} +void host_arm_RSB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_RSB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_STMDB_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask) +{ + codegen_addlong(block, COND_AL | OPCODE_STMDB_WB | Rn(addr_reg) | reg_mask); +} + +void host_arm_STR_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_STR_IMM | Rn(addr_reg) | Rd(src_reg) | arm_data_offset(offset)); +} +void host_arm_STR_IMM_WB(codeblock_t *block, int src_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_STR_IMM_WB | Rn(addr_reg) | Rd(src_reg) | arm_data_offset(offset)); +} +void host_arm_STR_REG_LSL(codeblock_t *block, int src_reg, int addr_reg, int offset_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_STR_REG | Rn(addr_reg) | Rd(src_reg) | Rm(offset_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_STRB_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_STRB_IMM | Rn(addr_reg) | Rd(src_reg) | arm_data_offset(offset)); +} +void host_arm_STRB_REG_LSL(codeblock_t *block, int src_reg, int addr_reg, int offset_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_STRB_REG | Rn(addr_reg) | Rd(src_reg) | Rm(offset_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_STRH_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_STRH_IMM | Rn(addr_reg) | Rd(dst_reg) | STRH_IMM(offset)); +} +void host_arm_STRH_REG(codeblock_t *block, int src_reg, int addr_reg, int offset_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_STRH_REG | Rn(addr_reg) | Rd(src_reg) | Rm(offset_reg)); +} + +void host_arm_SUB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if ((int32_t)imm < 0 && imm != 0x80000000) + { + host_arm_ADD_IMM(block, dst_reg, src_reg, -(int32_t)imm); + } + else if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_SUB_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_SUB_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_SUB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_SUB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} +void host_arm_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_SUB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_SXTB(codeblock_t *block, int dst_reg, int src_reg, int rotate) +{ + codegen_addlong(block, OPCODE_SXTB | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); +} +void host_arm_SXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate) +{ + codegen_addlong(block, OPCODE_SXTH | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); +} + +void host_arm_TST_IMM(codeblock_t *block, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_TST_IMM | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_TST_REG(block, src_reg, REG_TEMP); + } +} +void host_arm_TST_REG(codeblock_t *block, int src_reg1, int src_reg2) +{ + codegen_addlong(block, COND_AL | OPCODE_TST_REG | Rn(src_reg1) | Rm(src_reg2)); +} + +void host_arm_UADD8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addlong(block, COND_AL | OPCODE_UADD8 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); +} + +void host_arm_UADD16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addlong(block, COND_AL | OPCODE_UADD16 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); +} + +void host_arm_USUB8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addlong(block, COND_AL | OPCODE_USUB8 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); +} + +void host_arm_USUB16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addlong(block, COND_AL | OPCODE_USUB16 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); +} + +void host_arm_UXTB(codeblock_t *block, int dst_reg, int src_reg, int rotate) +{ + codegen_addlong(block, OPCODE_UXTB | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); +} + +void host_arm_UXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate) +{ + codegen_addlong(block, OPCODE_UXTH | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); +} + +void host_arm_VABS_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VABS_D | Vd(dest_reg) | Vm(src_reg)); +} + +void host_arm_VADD_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VADD | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VADD_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VADD_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VADD_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VADD_I8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VADD_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VADD_I16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VADD_I32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VADD_I32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VAND_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VAND_D | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VBIC_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VBIC_D | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCMP_D(codeblock_t *block, int src_reg_d, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VCMP_D | Rd(src_reg_d) | Rm(src_reg_m)); +} + +void host_arm_VCEQ_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCEQ_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCEQ_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCEQ_I8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCEQ_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCEQ_I16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCEQ_I32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCEQ_I32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCGE_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCGE_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCGT_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCGT_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCGT_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCGT_S8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCGT_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCGT_S16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCGT_S32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCGT_S32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + +void host_arm_VCVT_D_IS(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVT_D_IS | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VCVT_D_S(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVT_D_S | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VCVT_F32_S32(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVT_F32_S32 | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VCVT_IS_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVT_IS_D | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VCVT_S32_F32(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVT_S32_F32 | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VCVT_S_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVT_S_D | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VCVTR_IS_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVTR_IS_D | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VDIV_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VDIV | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VDIV_S(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VDIV_S | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VDUP_32(codeblock_t *block, int dst_reg, int src_reg_m, int imm) +{ + codegen_addlong(block, COND_AL | OPCODE_VDUP_32 | Rd(dst_reg) | Rm(src_reg_m) | VDUP_32_IMM(imm)); +} +void host_arm_VEOR_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VEOR_D | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VLDR_D(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if ((offset > 1020) || (offset & 3)) + fatal("VLDR_D bad offset %i\n", offset); + codegen_addlong(block, COND_AL | OPCODE_VLDR_D | Rd(dest_reg) | Rn(base_reg) | (offset >> 2)); +} +void host_arm_VLDR_S(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if ((offset > 1020) || (offset & 3)) + fatal("VLDR_S bad offset %i\n", offset); + codegen_addlong(block, COND_AL | OPCODE_VLDR_S | Rd(dest_reg) | Rn(base_reg) | (offset >> 2)); +} +void host_arm_VMOV_32_S(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VMOV_32_S | Rt(dest_reg) | Vn(src_reg)); +} +void host_arm_VMOV_64_D(codeblock_t *block, int dest_reg_low, int dest_reg_high, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VMOV_64_D | Rt(dest_reg_low) | Rt2(dest_reg_high) | Vm(src_reg)); +} +void host_arm_VMOV_D_64(codeblock_t *block, int dest_reg, int src_reg_low, int src_reg_high) +{ + codegen_addlong(block, COND_AL | OPCODE_VMOV_D_64 | Vm(dest_reg) | Rt(src_reg_low) | Rt2(src_reg_high)); +} +void host_arm_VMOV_S_32(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VMOV_S_32 | Vn(dest_reg) | Rt(src_reg)); +} +void host_arm_VMOV_D_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VMOV_D_D | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VMOVN_I32(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VMOVN_I32 | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VMOVN_I64(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VMOVN_I64 | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VMOV_F32_ONE(codeblock_t *block, int dst_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VMOV_F32_ONE | Rd(dst_reg)); +} +void host_arm_VMSR_FPSCR(codeblock_t *block, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VMSR_FPSCR | Rd(src_reg)); +} +void host_arm_VMRS_APSR(codeblock_t *block) +{ + codegen_addlong(block, COND_AL | OPCODE_VMRS_APSR); +} + +void host_arm_VMAX_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VMAX_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VMIN_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VMIN_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + +void host_arm_VMUL_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VMUL | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VMUL_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VMUL_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VMUL_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VMUL_S16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VMULL_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VMULL_S16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + +void host_arm_VNEG_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VNEG_D | Vd(dest_reg) | Vm(src_reg)); +} + +void host_arm_VORR_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VORR_D | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + +void host_arm_VPADDL_S16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VPADDL_S16 | Vd(dst_reg) | Vm(src_reg)); +} +void host_arm_VPADDL_S32(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VPADDL_S32 | Vd(dst_reg) | Vm(src_reg)); +} +void host_arm_VPADDL_Q_S32(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VPADDL_Q_S32 | Vd(dst_reg) | Vm(src_reg)); +} + +void host_arm_VQADD_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQADD_S8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQADD_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQADD_S16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQADD_U8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQADD_U8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQADD_U16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQADD_U16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQSUB_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQSUB_S8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQSUB_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQSUB_S16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQSUB_U8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQSUB_U8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQSUB_U16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQSUB_U16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + +void host_arm_VQMOVN_S16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VQMOVN_S16 | Vd(dst_reg) | Vm(src_reg)); +} +void host_arm_VQMOVN_S32(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VQMOVN_S32 | Vd(dst_reg) | Vm(src_reg)); +} +void host_arm_VQMOVN_U16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VQMOVN_U16 | Vd(dst_reg) | Vm(src_reg)); +} + +void host_arm_VSHL_D_IMM_16(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 15) + fatal("host_arm_VSHL_D_IMM_16 : shift > 15\n"); + codegen_addlong(block, OPCODE_VSHL_D_IMM_16 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(shift)); +} +void host_arm_VSHL_D_IMM_32(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 31) + fatal("host_arm_VSHL_D_IMM_32 : shift > 31\n"); + codegen_addlong(block, OPCODE_VSHL_D_IMM_32 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(shift)); +} +void host_arm_VSHL_D_IMM_64(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 63) + fatal("host_arm_VSHL_D_IMM_64 : shift > 63\n"); + codegen_addlong(block, OPCODE_VSHL_D_IMM_64 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(shift)); +} +void host_arm_VSHR_D_S16(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 15) + fatal("host_arm_VSHR_SD_IMM_16 : shift > 15\n"); + codegen_addlong(block, OPCODE_VSHR_D_S16 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(16-shift)); +} +void host_arm_VSHR_D_S32(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 31) + fatal("host_arm_VSHR_SD_IMM_32 : shift > 31\n"); + codegen_addlong(block, OPCODE_VSHR_D_S32 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(32-shift)); +} +void host_arm_VSHR_D_S64(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 63) + fatal("host_arm_VSHR_SD_IMM_64 : shift > 63\n"); + codegen_addlong(block, OPCODE_VSHR_D_S64 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(64-shift)); +} +void host_arm_VSHR_D_U16(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 15) + fatal("host_arm_VSHR_UD_IMM_16 : shift > 15\n"); + codegen_addlong(block, OPCODE_VSHR_D_U16 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(16-shift)); +} +void host_arm_VSHR_D_U32(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 31) + fatal("host_arm_VSHR_UD_IMM_32 : shift > 31\n"); + codegen_addlong(block, OPCODE_VSHR_D_U32 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(32-shift)); +} +void host_arm_VSHR_D_U64(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 63) + fatal("host_arm_VSHR_UD_IMM_64 : shift > 63\n"); + codegen_addlong(block, OPCODE_VSHR_D_U64 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(64-shift)); +} +void host_arm_VSHRN_32(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 16) + fatal("host_arm_VSHRN_32 : shift > 16\n"); + codegen_addlong(block, OPCODE_VSHRN | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM_32(16-shift)); +} + +void host_arm_VSQRT_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VSQRT_D | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VSQRT_S(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VSQRT_S | Vd(dest_reg) | Vm(src_reg)); +} + +void host_arm_VSTR_D(codeblock_t *block, int src_reg, int base_reg, int offset) +{ + if ((offset > 1020) || (offset & 3)) + fatal("VSTR_D bad offset %i\n", offset); + codegen_addlong(block, COND_AL | OPCODE_VSTR_D | Rd(src_reg) | Rn(base_reg) | (offset >> 2)); +} +void host_arm_VSTR_S(codeblock_t *block, int src_reg, int base_reg, int offset) +{ + if ((offset > 1020) || (offset & 3)) + fatal("VSTR_S bad offset %i\n", offset); + codegen_addlong(block, COND_AL | OPCODE_VSTR_S | Rd(src_reg) | Rn(base_reg) | (offset >> 2)); +} +void host_arm_VSUB_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VSUB | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VSUB_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VSUB_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VSUB_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VSUB_I8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VSUB_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VSUB_I16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VSUB_I32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VSUB_I32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + +void host_arm_VZIP_D8(codeblock_t *block, int d_reg, int m_reg) +{ + codegen_addlong(block, OPCODE_VZIP_D8 | Vd(d_reg) | Vm(m_reg)); +} +void host_arm_VZIP_D16(codeblock_t *block, int d_reg, int m_reg) +{ + codegen_addlong(block, OPCODE_VZIP_D16 | Vd(d_reg) | Vm(m_reg)); +} +void host_arm_VZIP_D32(codeblock_t *block, int d_reg, int m_reg) +{ + codegen_addlong(block, OPCODE_VZIP_D32 | Vd(d_reg) | Vm(m_reg)); +} + +#endif diff --git a/src/cpu_new/codegen_backend_arm_ops.h b/src/cpu_new/codegen_backend_arm_ops.h new file mode 100644 index 000000000..7627f51a7 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm_ops.h @@ -0,0 +1,252 @@ +#define COND_SHIFT 28 +#define COND_EQ (0x0 << COND_SHIFT) +#define COND_NE (0x1 << COND_SHIFT) +#define COND_CS (0x2 << COND_SHIFT) +#define COND_CC (0x3 << COND_SHIFT) +#define COND_MI (0x4 << COND_SHIFT) +#define COND_PL (0x5 << COND_SHIFT) +#define COND_VS (0x6 << COND_SHIFT) +#define COND_VC (0x7 << COND_SHIFT) +#define COND_HI (0x8 << COND_SHIFT) +#define COND_LS (0x9 << COND_SHIFT) +#define COND_GE (0xa << COND_SHIFT) +#define COND_LT (0xb << COND_SHIFT) +#define COND_GT (0xc << COND_SHIFT) +#define COND_LE (0xd << COND_SHIFT) +#define COND_AL (0xe << COND_SHIFT) + +void host_arm_ADD_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +#define host_arm_ADD_REG(block, dst_reg, src_reg_n, src_reg_m) host_arm_ADD_REG_LSL(block, dst_reg, src_reg_n, src_reg_m, 0) +void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_ADD_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_AND_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_AND_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_B(codeblock_t *block, uintptr_t dest_addr); + +void host_arm_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width); + +void host_arm_BIC_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_BIC_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_BIC_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_BL(codeblock_t *block, uintptr_t dest_addr); +void host_arm_BL_r1(codeblock_t *block, uintptr_t dest_addr); +void host_arm_BLX(codeblock_t *block, int addr_reg); + +uint32_t *host_arm_BCC_(codeblock_t *block); +uint32_t *host_arm_BCS_(codeblock_t *block); +uint32_t *host_arm_BEQ_(codeblock_t *block); +uint32_t *host_arm_BGE_(codeblock_t *block); +uint32_t *host_arm_BGT_(codeblock_t *block); +uint32_t *host_arm_BHI_(codeblock_t *block); +uint32_t *host_arm_BLE_(codeblock_t *block); +uint32_t *host_arm_BLS_(codeblock_t *block); +uint32_t *host_arm_BLT_(codeblock_t *block); +uint32_t *host_arm_BMI_(codeblock_t *block); +uint32_t *host_arm_BNE_(codeblock_t *block); +uint32_t *host_arm_BPL_(codeblock_t *block); +uint32_t *host_arm_BVC_(codeblock_t *block); +uint32_t *host_arm_BVS_(codeblock_t *block); + +void host_arm_BEQ(codeblock_t *block, uintptr_t dest_addr); +void host_arm_BNE(codeblock_t *block, uintptr_t dest_addr); + +void host_arm_BX(codeblock_t *block, int addr_reg); + +void host_arm_CMN_IMM(codeblock_t *block, int src_reg, uint32_t imm); +void host_arm_CMN_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift); + +void host_arm_CMP_IMM(codeblock_t *block, int src_reg, uint32_t imm); +#define host_arm_CMP_REG(block, src_reg_n, src_reg_m) host_arm_CMP_REG_LSL(block, src_reg_n, src_reg_m, 0) +void host_arm_CMP_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift); + +void host_arm_EOR_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_EOR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_LDMIA_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask); + +void host_arm_LDR_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset); +void host_arm_LDR_IMM_POST(codeblock_t *block, int dst_reg, int addr_reg, int offset); +#define host_arm_LDR_REG(block, dst_reg, addr_reg, offset_reg) host_arm_LDR_REG_LSL(block, dst_reg, addr_reg, offset_reg, 0) +void host_arm_LDR_REG_LSL(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg, int shift); + +void host_arm_LDRB_ABS(codeblock_t *block, int dst, void *p); +void host_arm_LDRB_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset); +#define host_arm_LDRB_REG(block, dst_reg, addr_reg, offset_reg) host_arm_LDRB_REG_LSL(block, dst_reg, addr_reg, offset_reg, 0) +void host_arm_LDRB_REG_LSL(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg, int shift); + +void host_arm_LDRH_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset); +void host_arm_LDRH_REG(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg); + +void host_arm_MOV_IMM(codeblock_t *block, int dst_reg, uint32_t imm); +#define host_arm_MOV_REG(block, dst_reg, src_reg) host_arm_MOV_REG_LSL(block, dst_reg, src_reg, 0) +void host_arm_MOV_REG_ASR(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm_MOV_REG_ASR_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg); +void host_arm_MOV_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm_MOV_REG_LSL_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg); +void host_arm_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm_MOV_REG_LSR_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg); +void host_arm_MOV_REG_ROR(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm_MOV_REG_ROR_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg); +void host_arm_MOVT_IMM(codeblock_t *block, int dst_reg, uint16_t imm); +void host_arm_MOVW_IMM(codeblock_t *block, int dst_reg, uint16_t imm); + +void host_arm_MVN_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift); + +#define host_arm_NOP(block) host_arm_MOV_REG(block, REG_R0, REG_R0) + +void host_arm_ORR_IMM_cond(codeblock_t *block, uint32_t cond, int dst_reg, int src_reg, uint32_t imm); +void host_arm_ORR_REG_LSL_cond(codeblock_t *block, uint32_t cond, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +#define host_arm_ORR_IMM(block, dst_reg, src_reg, imm) host_arm_ORR_IMM_cond(block, COND_AL, dst_reg, src_reg, imm) +#define host_arm_ORR_REG_LSL(block, dst_reg, src_reg_a, src_reg_b, shift) host_arm_ORR_REG_LSL_cond(block, COND_AL, dst_reg, src_reg_a, src_reg_b, shift) + +#define host_arm_ORRCC_IMM(block, dst_reg, src_reg, imm) host_arm_ORR_IMM_cond(block, COND_CC, dst_reg, src_reg, imm) +#define host_arm_ORREQ_IMM(block, dst_reg, src_reg, imm) host_arm_ORR_IMM_cond(block, COND_EQ, dst_reg, src_reg, imm) +#define host_arm_ORRVS_IMM(block, dst_reg, src_reg, imm) host_arm_ORR_IMM_cond(block, COND_VS, dst_reg, src_reg, imm) + +void host_arm_RSB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_RSB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_RSB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_STMDB_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask); + +void host_arm_STR_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset); +void host_arm_STR_IMM_WB(codeblock_t *block, int src_reg, int addr_reg, int offset); +#define host_arm_STR_REG(block, src_reg, addr_reg, offset_reg) host_arm_STR_REG_LSL(block, src_reg, addr_reg, offset_reg, 0) +void host_arm_STR_REG_LSL(codeblock_t *block, int src_reg, int addr_reg, int offset_reg, int shift); + +void host_arm_STRB_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset); +#define host_arm_STRB_REG(block, src_reg, addr_reg, offset_reg) host_arm_STRB_REG_LSL(block, src_reg, addr_reg, offset_reg, 0) +void host_arm_STRB_REG_LSL(codeblock_t *block, int src_reg, int addr_reg, int offset_reg, int shift); + +void host_arm_STRH_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset); +void host_arm_STRH_REG(codeblock_t *block, int src_reg, int addr_reg, int offset_reg); + +void host_arm_SUB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_SUB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_SXTB(codeblock_t *block, int dst_reg, int src_reg, int rotate); +void host_arm_SXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate); + +void host_arm_TST_IMM(codeblock_t *block, int src_reg1, uint32_t imm); +void host_arm_TST_REG(codeblock_t *block, int src_reg1, int src_reg2); + +void host_arm_UADD8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_arm_UADD16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_arm_USUB8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_arm_USUB16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_arm_UXTB(codeblock_t *block, int dst_reg, int src_reg, int rotate); +void host_arm_UXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate); + +void host_arm_VABS_D(codeblock_t *block, int dest_reg, int src_reg); + +void host_arm_VADD_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VADD_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VADD_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VADD_I32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VADD_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VAND_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VBIC_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCMP_D(codeblock_t *block, int src_reg_d, int src_reg_m); + +void host_arm_VCEQ_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCEQ_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCEQ_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCEQ_I32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCGE_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCGT_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCGT_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCGT_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCGT_S32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); + +void host_arm_VCHS_D(codeblock_t *block, int dest_reg, int src_reg); + +void host_arm_VCVT_D_IS(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VCVT_D_S(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VCVT_F32_S32(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VCVT_IS_D(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VCVT_S32_F32(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VCVT_S_D(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VCVTR_IS_D(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VDIV_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VDIV_S(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VDUP_32(codeblock_t *block, int dst_reg, int src_reg_m, int imm); +void host_arm_VEOR_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VLDR_D(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm_VLDR_S(codeblock_t *block, int dest_reg, int base_reg, int offset); + +void host_arm_VMOV_32_S(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VMOV_64_D(codeblock_t *block, int dest_reg_low, int dest_reg_high, int src_reg); +void host_arm_VMOV_D_64(codeblock_t *block, int dest_reg, int src_reg_low, int src_reg_high); +void host_arm_VMOV_S_32(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VMOV_D_D(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VMOVN_I32(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VMOVN_I64(codeblock_t *block, int dest_reg, int src_reg); + +void host_arm_VMRS_APSR(codeblock_t *block); +void host_arm_VMSR_FPSCR(codeblock_t *block, int src_reg); + +void host_arm_VMAX_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VMIN_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); + +void host_arm_VMOV_F32_ONE(codeblock_t *block, int dst_reg); + +void host_arm_VMUL_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VMUL_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VMUL_S16(codeblock_t *block, int dest_reg, int src_reg_n, int src_reg_m); +void host_arm_VMULL_S16(codeblock_t *block, int dest_reg, int src_reg_n, int src_reg_m); + +void host_arm_VNEG_D(codeblock_t *block, int dest_reg, int src_reg); + +void host_arm_VORR_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); + +void host_arm_VPADDL_S16(codeblock_t *block, int dst_reg, int src_reg); +void host_arm_VPADDL_S32(codeblock_t *block, int dst_reg, int src_reg); +void host_arm_VPADDL_Q_S32(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm_VQADD_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQADD_U8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQADD_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQADD_U16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQSUB_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQSUB_U8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQSUB_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQSUB_U16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); + +void host_arm_VQMOVN_S16(codeblock_t *block, int dst_reg, int src_reg); +void host_arm_VQMOVN_S32(codeblock_t *block, int dst_reg, int src_reg); +void host_arm_VQMOVN_U16(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm_VSHL_D_IMM_16(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHL_D_IMM_32(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHL_D_IMM_64(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHR_D_S16(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHR_D_S32(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHR_D_S64(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHR_D_U16(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHR_D_U32(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHR_D_U64(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHRN_32(codeblock_t *block, int dest_reg, int src_reg, int shift); + +void host_arm_VSQRT_D(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VSQRT_S(codeblock_t *block, int dest_reg, int src_reg); + +void host_arm_VSTR_D(codeblock_t *block, int src_reg, int base_reg, int offset); +void host_arm_VSTR_S(codeblock_t *block, int src_reg, int base_reg, int offset); +void host_arm_VSUB_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VSUB_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VSUB_S(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VSUB_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VSUB_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VSUB_I32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); + +void host_arm_VZIP_D8(codeblock_t *block, int d_reg, int m_reg); +void host_arm_VZIP_D16(codeblock_t *block, int d_reg, int m_reg); +void host_arm_VZIP_D32(codeblock_t *block, int d_reg, int m_reg); diff --git a/src/cpu_new/codegen_backend_arm_uops.c b/src/cpu_new/codegen_backend_arm_uops.c new file mode 100644 index 000000000..1dbaab407 --- /dev/null +++ b/src/cpu_new/codegen_backend_arm_uops.c @@ -0,0 +1,3502 @@ +#ifdef __ARM_EABI__ + +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x87.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_arm_defs.h" +#include "codegen_backend_arm_ops.h" +#include "codegen_ir_defs.h" + +static inline int get_arm_imm(uint32_t imm_data, uint32_t *arm_imm) +{ + int shift = 0; + if (!(imm_data & 0xffff)) + { + shift += 16; + imm_data >>= 16; + } + if (!(imm_data & 0xff)) + { + shift += 8; + imm_data >>= 8; + } + if (!(imm_data & 0xf)) + { + shift += 4; + imm_data >>= 4; + } + if (!(imm_data & 0x3)) + { + shift += 2; + imm_data >>= 2; + } + if (imm_data > 0xff) /*Note - should handle rotation round the word*/ + return 0; + *arm_imm = imm_data | ((((32 - shift) >> 1) & 15) << 8); + return 1; +} + +static inline int in_range(void *addr, void *base) +{ + int diff = (uintptr_t)addr - (uintptr_t)base; + + if (diff < -4095 || diff > 4095) + return 0; + return 1; +} + +static inline int in_range_h(void *addr, void *base) +{ + int diff = (uintptr_t)addr - (uintptr_t)base; + + if (diff < 0 || diff > 255) + return 0; + return 1; +} + +void host_arm_call(codeblock_t *block, void *dst_addr) +{ + host_arm_MOV_IMM(block, REG_R3, (uintptr_t)dst_addr); + host_arm_BLX(block, REG_R3); +} + +void host_arm_nop(codeblock_t *block) +{ + host_arm_MOV_REG_LSL(block, REG_R0, REG_R0, 0); +} + +#define HOST_REG_GET(reg) (IREG_GET_REG(reg) & 0xf) + +#define REG_IS_L(size) (size == IREG_SIZE_L) +#define REG_IS_W(size) (size == IREG_SIZE_W) +#define REG_IS_B(size) (size == IREG_SIZE_B) +#define REG_IS_BH(size) (size == IREG_SIZE_BH) +#define REG_IS_D(size) (size == IREG_SIZE_D) +#define REG_IS_Q(size) (size == IREG_SIZE_Q) + +static int codegen_ADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_ADD_REG_LSL(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_ADD_REG(block, REG_TEMP, src_reg_a, src_reg_b); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_ADD_REG(block, REG_TEMP, src_reg_a, src_reg_b); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 8); + host_arm_UADD8(block, dest_reg, src_reg_a, REG_TEMP); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm_ADD_REG_LSR(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 0); + host_arm_MOV_REG_LSL(block, REG_TEMP, REG_TEMP, 8); + host_arm_UADD8(block, dest_reg, src_reg_a, REG_TEMP); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_AND_IMM(block, REG_TEMP, src_reg_b, 0x0000ff00); + host_arm_UADD8(block, dest_reg, src_reg_a, REG_TEMP); + } + else + fatal("ADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) +{ +// host_arm_ADD_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data); +// return 0; + + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_ADD_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_ADD_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_ADD_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size) && src_reg == dest_reg) + { + host_arm_MOV_IMM(block, REG_TEMP, uop->imm_data << 8); + host_arm_UADD8(block, dest_reg, src_reg, REG_TEMP); + } + else + fatal("ADD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; + +} +static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop) +{ + host_arm_ADD_REG_LSL(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data); + return 0; +} + +static int codegen_AND(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VAND_D(block, dest_reg, src_reg_a, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_AND_REG_LSL(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b) && dest_reg == src_reg_a) + { + host_arm_MVN_REG_LSL(block, REG_TEMP, src_reg_b, 16); + host_arm_BIC_REG_LSR(block, dest_reg, src_reg_a, REG_TEMP, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_MVN_REG_LSL(block, REG_TEMP, src_reg_b, 24); + host_arm_BIC_REG_LSR(block, dest_reg, src_reg_a, REG_TEMP, 24); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_MVN_REG_LSL(block, REG_TEMP, src_reg_b, 16); + host_arm_BIC_REG_LSR(block, dest_reg, src_reg_a, REG_TEMP, 24); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_MVN_REG_LSL(block, REG_TEMP, src_reg_b, 8); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 0x0000ff00); + host_arm_BIC_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_MVN_REG_LSL(block, REG_TEMP, src_reg_b, 0); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 0x0000ff00); + host_arm_BIC_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_AND_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_AND_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm_AND_REG_LSR(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_AND_REG_LSR(block, REG_TEMP, src_reg_b, src_reg_a, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm_AND_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else + fatal("AND %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_AND_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size) && dest_reg == src_reg) + { + host_arm_AND_IMM(block, dest_reg, src_reg, uop->imm_data | 0xffff0000); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size) && dest_reg == src_reg) + { + host_arm_AND_IMM(block, dest_reg, src_reg, uop->imm_data | 0xffffff00); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size) && dest_reg == src_reg) + { + host_arm_AND_IMM(block, dest_reg, src_reg, (uop->imm_data << 8) | 0xffff00ff); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_AND_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_AND_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else + fatal("AND_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ANDN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VBIC_D(block, dest_reg, src_reg_b, src_reg_a); + } + else + fatal("ANDN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_CALL_FUNC(codeblock_t *block, uop_t *uop) +{ + host_arm_call(block, uop->p); + + return 0; +} + +static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_L(dest_size)) + fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real); + host_arm_call(block, uop->p); + host_arm_MOV_REG(block, dest_reg, REG_R0); + + return 0; +} + +static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) +{ + host_arm_call(block, uop->p); + host_arm_TST_REG(block, REG_R0, REG_R0); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm_CMP_IMM(block, src_reg, uop->imm_data); + } + else + fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real); + host_arm_BEQ(block, (uintptr_t)uop->p); + + return 0; +} + +static int codegen_CMP_IMM_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm_CMP_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_CMP_IMM(block, REG_TEMP, uop->imm_data); + } + else + fatal("CMP_IMM_JNZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BNE_(block); + + return 0; +} +static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm_CMP_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_CMP_IMM(block, REG_TEMP, uop->imm_data); + } + else + fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BEQ_(block); + + return 0; +} + +static int codegen_CMP_JB(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else + fatal("CMP_JB %02x\n", uop->src_reg_a_real); + + jump_p = host_arm_BCC_(block); + *jump_p |= ((((uintptr_t)uop->p - (uintptr_t)jump_p) - 8) & 0x3fffffc) >> 2; + + return 0; +} +static int codegen_CMP_JNBE(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else + fatal("CMP_JNBE %02x\n", uop->src_reg_a_real); + + jump_p = host_arm_BHI_(block); + *jump_p |= ((((uintptr_t)uop->p - (uintptr_t)jump_p) - 8) & 0x3fffffc) >> 2; + + return 0; +} + +static int codegen_CMP_JNB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNB_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BCS_(block); + + return 0; +} +static int codegen_CMP_JNBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNBE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BHI_(block); + + return 0; +} +static int codegen_CMP_JNL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNL_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BGE_(block); + + return 0; +} +static int codegen_CMP_JNLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNLE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BGT_(block); + + return 0; +} +static int codegen_CMP_JNO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNO_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BVC_(block); + + return 0; +} +static int codegen_CMP_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BNE_(block); + + return 0; +} +static int codegen_CMP_JB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JB_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BCC_(block); + + return 0; +} +static int codegen_CMP_JBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JBE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BLS_(block); + + return 0; +} +static int codegen_CMP_JL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JL_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BLT_(block); + + return 0; +} +static int codegen_CMP_JLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JLE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BLE_(block); + + return 0; +} +static int codegen_CMP_JO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JO_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BVS_(block); + + return 0; +} +static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BEQ_(block); + + return 0; +} + +static int codegen_FABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm_VABS_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FABS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FCHS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm_VNEG_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FCHS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm_VSQRT_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FSQRT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FTST(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a)) + { + host_arm_VSUB_D(block, REG_D_TEMP, REG_D_TEMP, REG_D_TEMP); + host_arm_VCMP_D(block, src_reg_a, REG_D_TEMP); + host_arm_MOV_IMM(block, dest_reg, 0); + host_arm_VMRS_APSR(block); + host_arm_ORREQ_IMM(block, dest_reg, dest_reg, C3); + host_arm_ORRCC_IMM(block, dest_reg, dest_reg, C0); + host_arm_ORRVS_IMM(block, dest_reg, dest_reg, C0|C2|C3); + } + else + fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_FADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VADD_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FCOM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VCMP_D(block, src_reg_a, src_reg_b); + host_arm_MOV_IMM(block, dest_reg, 0); + host_arm_VMRS_APSR(block); + host_arm_ORREQ_IMM(block, dest_reg, dest_reg, C3); + host_arm_ORRCC_IMM(block, dest_reg, dest_reg, C0); + host_arm_ORRVS_IMM(block, dest_reg, dest_reg, C0|C2|C3); + } + else + fatal("codegen_FCOM %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FDIV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VDIV_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FDIV %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VMUL_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VSUB_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_ptr; + + if (!in_range(&cr0, &cpu_state)) + fatal("codegen_FP_ENTER - out of range\n"); + + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cr0 - (uintptr_t)&cpu_state); + host_arm_TST_IMM(block, REG_TEMP, 0xc); + branch_ptr = host_arm_BEQ_(block); + + host_arm_MOV_IMM(block, REG_TEMP, uop->imm_data); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.oldpc - (uintptr_t)&cpu_state); + host_arm_MOV_IMM(block, REG_ARG0, 7); + host_arm_call(block, x86_int); + host_arm_B(block, (uintptr_t)codegen_exit_rout); + + *branch_ptr |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_ptr) - 8) & 0x3fffffc) >> 2; + + return 0; +} +static int codegen_MMX_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_ptr; + + if (!in_range(&cr0, &cpu_state)) + fatal("codegen_MMX_ENTER - out of range\n"); + + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cr0 - (uintptr_t)&cpu_state); + host_arm_TST_IMM(block, REG_TEMP, 0xc); + branch_ptr = host_arm_BEQ_(block); + + host_arm_MOV_IMM(block, REG_TEMP, uop->imm_data); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.oldpc - (uintptr_t)&cpu_state); + host_arm_MOV_IMM(block, REG_ARG0, 7); + host_arm_call(block, x86_int); + host_arm_B(block, (uintptr_t)codegen_exit_rout); + + *branch_ptr |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_ptr) - 8) & 0x3fffffc) >> 2; + + host_arm_MOV_IMM(block, REG_TEMP, 0x01010101); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.tag[0] - (uintptr_t)&cpu_state); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.tag[4] - (uintptr_t)&cpu_state); + host_arm_MOV_IMM(block, REG_TEMP, 0); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.TOP - (uintptr_t)&cpu_state); + host_arm_STRB_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.ismmx - (uintptr_t)&cpu_state); + + return 0; +} + +static int codegen_JMP(codeblock_t *block, uop_t *uop) +{ + host_arm_B(block, (uintptr_t)uop->p); + + return 0; +} + +static int codegen_LOAD_FUNC_ARG0(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_ARG0, src_reg, 0); + } + else + fatal("codegen_LOAD_FUNC_ARG0 %02x\n", uop->src_reg_a_real); + + return 0; +} +static int codegen_LOAD_FUNC_ARG1(codeblock_t *block, uop_t *uop) +{ + fatal("codegen_LOAD_FUNC_ARG1 %02x\n", uop->src_reg_a_real); + return 0; +} +static int codegen_LOAD_FUNC_ARG2(codeblock_t *block, uop_t *uop) +{ + fatal("codegen_LOAD_FUNC_ARG2 %02x\n", uop->src_reg_a_real); + return 0; +} +static int codegen_LOAD_FUNC_ARG3(codeblock_t *block, uop_t *uop) +{ + fatal("codegen_LOAD_FUNC_ARG3 %02x\n", uop->src_reg_a_real); + return 0; +} + +static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, REG_ARG0, uop->imm_data); + return 0; +} +static int codegen_LOAD_FUNC_ARG1_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, REG_ARG1, uop->imm_data); + return 0; +} +static int codegen_LOAD_FUNC_ARG2_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, REG_ARG2, uop->imm_data); + return 0; +} +static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, REG_ARG3, uop->imm_data); + return 0; +} + +static int codegen_LOAD_SEG(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (!REG_IS_W(src_size)) + fatal("LOAD_SEG %02x %p\n", uop->src_reg_a_real, uop->p); + host_arm_UXTH(block, REG_ARG0, src_reg, 0); + host_arm_MOV_IMM(block, REG_ARG1, (uint32_t)uop->p); + host_arm_call(block, loadseg); + host_arm_TST_REG(block, REG_R0, REG_R0); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_LOAD_ABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm_ADD_IMM(block, REG_R0, seg_reg, uop->imm_data); + if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_long); + } + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 8, 8); + } + else if (REG_IS_W(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 0, 16); + } + else if (REG_IS_L(dest_size)) + { + host_arm_MOV_REG(block, dest_reg, REG_R0); + } + + return 0; +} + +static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (uop->imm_data) + host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_long); + } + else if (REG_IS_Q(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_quad); + } + else + fatal("MEM_LOAD_REG - %02x\n", uop->dest_reg_a_real); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 8, 8); + } + else if (REG_IS_W(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 0, 16); + } + else if (REG_IS_L(dest_size)) + { + host_arm_MOV_REG(block, dest_reg, REG_R0); + } + else if (REG_IS_Q(dest_size)) + { + host_arm_VMOV_D_D(block, dest_reg, REG_D_TEMP); + } + + return 0; +} +static int codegen_MEM_LOAD_SINGLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_SINGLE - %02x\n", uop->dest_reg_a_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (uop->imm_data) + host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + host_arm_BL(block, (uintptr_t)codegen_mem_load_single); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + host_arm_VCVT_D_S(block, dest_reg, REG_D_TEMP); + + return 0; +} +static int codegen_MEM_LOAD_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_DOUBLE - %02x\n", uop->dest_reg_a_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (uop->imm_data) + host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + host_arm_BL(block, (uintptr_t)codegen_mem_load_double); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + host_arm_VMOV_D_D(block, dest_reg, REG_D_TEMP); + + return 0; +} + +static int codegen_MEM_STORE_ABS(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_b_real); + int src_size = IREG_GET_SIZE(uop->src_reg_b_real); + + host_arm_ADD_IMM(block, REG_R0, seg_reg, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_long); + } + else + fatal("MEM_STORE_ABS - %02x\n", uop->src_reg_b_real); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (uop->imm_data) + host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_byte); + } + else if (REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSR(block, REG_R1, src_reg, 8); + host_arm_BL(block, (uintptr_t)codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_long); + } + else if (REG_IS_Q(src_size)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_quad); + } + else + fatal("MEM_STORE_REG - %02x\n", uop->src_reg_c_real); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_IMM_8(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + host_arm_MOV_IMM(block, REG_R1, uop->imm_data); + host_arm_BL(block, (uintptr_t)codegen_mem_store_byte); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_16(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + host_arm_MOV_IMM(block, REG_R1, uop->imm_data); + host_arm_BL(block, (uintptr_t)codegen_mem_store_word); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_32(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + host_arm_MOV_IMM(block, REG_R1, uop->imm_data); + host_arm_BL(block, (uintptr_t)codegen_mem_store_long); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_SINGLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_REG - %02x\n", uop->dest_reg_a_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (uop->imm_data) + host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + host_arm_VCVT_S_D(block, REG_D_TEMP, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_single); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_REG - %02x\n", uop->dest_reg_a_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (uop->imm_data) + host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_double); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MOV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_LSL(block, dest_reg, src_reg, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_BFI(block, dest_reg, src_reg, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_BFI(block, dest_reg, src_reg, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_B(src_size)) + { + host_arm_BFI(block, dest_reg, src_reg, 8, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size)) + { + host_arm_VMOV_D_D(block, dest_reg, src_reg); + } + else if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + host_arm_VMOV_D_D(block, dest_reg, src_reg); + } + else + fatal("MOV %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_arm_MOV_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size)) + { + host_arm_MOVW_IMM(block, REG_TEMP, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size)) + { + host_arm_AND_IMM(block, dest_reg, dest_reg, ~0x000000ff); + host_arm_ORR_IMM(block, dest_reg, dest_reg, uop->imm_data); + } + else if (REG_IS_BH(dest_size)) + { + host_arm_AND_IMM(block, dest_reg, dest_reg, ~0x0000ff00); + host_arm_ORR_IMM(block, dest_reg, dest_reg, uop->imm_data << 8); + } + else + fatal("MOV_IMM %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOV_PTR(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, uop->dest_reg_a_real, (uintptr_t)uop->p); + + return 0; +} + +static int codegen_MOVSX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_arm_SXTB(block, dest_reg, src_reg, 0); + } + else if (REG_IS_L(dest_size) && REG_IS_BH(src_size)) + { + host_arm_SXTB(block, dest_reg, src_reg, 8); + } + else if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_arm_SXTH(block, dest_reg, src_reg, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_arm_SXTB(block, REG_TEMP, src_reg, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_W(dest_size) && REG_IS_BH(src_size)) + { + host_arm_SXTB(block, REG_TEMP, src_reg, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOVSX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOVZX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_IMM(block, REG_TEMP, 0); + host_arm_VMOV_D_64(block, dest_reg, src_reg, REG_TEMP); + } + else if (REG_IS_L(dest_size) && REG_IS_Q(src_size)) + { + host_arm_VMOV_32_S(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_arm_UXTB(block, dest_reg, src_reg, 0); + } + else if (REG_IS_L(dest_size) && REG_IS_BH(src_size)) + { + host_arm_UXTB(block, dest_reg, src_reg, 8); + } + else if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_arm_UXTH(block, dest_reg, src_reg, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + if (src_reg == dest_reg) + host_arm_BIC_IMM(block, dest_reg, dest_reg, 0xff00); + else + { + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + } + else if (REG_IS_W(dest_size) && REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm_BIC_IMM(block, dest_reg, dest_reg, 0xff00); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else + fatal("MOVZX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static double int64_to_double(int64_t a) +{ + return (double)a; +} +static int codegen_MOV_DOUBLE_INT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_L(src_size)) + { + host_arm_VMOV_S_32(block, REG_D_TEMP, src_reg); + host_arm_VCVT_D_IS(block, dest_reg, REG_D_TEMP); + } + else if (REG_IS_D(dest_size) && REG_IS_W(src_size)) + { + host_arm_SXTH(block, REG_TEMP, src_reg, 0); + host_arm_VMOV_S_32(block, REG_D_TEMP, REG_TEMP); + host_arm_VCVT_D_IS(block, dest_reg, REG_D_TEMP); + } + else if (REG_IS_D(dest_size) && REG_IS_Q(src_size)) + { + /*ARMv7 has no instructions to convert a 64-bit integer to a double. + For simplicity, call a C function and let the compiler do it.*/ + host_arm_VMOV_64_D(block, REG_R0, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)int64_to_double); /*Input - R0/R1, Output - D0*/ + host_arm_VMOV_D_D(block, dest_reg, REG_D0); + } + else + fatal("MOV_DOUBLE_INT %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOV_INT_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_D(src_size)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg); + host_arm_BL(block, (uintptr_t)codegen_fp_round); + host_arm_VMOV_32_S(block, dest_reg, REG_D_TEMP); + } + else if (REG_IS_W(dest_size) && REG_IS_D(src_size)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg); + host_arm_BL(block, (uintptr_t)codegen_fp_round); + host_arm_VMOV_32_S(block, REG_TEMP, REG_D_TEMP); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOV_INT_DOUBLE %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int64_t x87_fround64(double b) +{ + int64_t a, c; + + switch ((cpu_state.npxc >> 10) & 3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)floor(b); + case 2: /*Up*/ + return (int64_t)ceil(b); + case 3: /*Chop*/ + return (int64_t)b; + } + + return 0; +} +static int codegen_MOV_INT_DOUBLE_64(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), src_64_reg = HOST_REG_GET(uop->src_reg_b_real), tag_reg = HOST_REG_GET(uop->src_reg_c_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real), src_64_size = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_D(src_size) && REG_IS_Q(src_64_size)) + { + uint32_t *branch_offset; + + /*If TAG_UINT64 is set then the source is MM[]. Otherwise it is a double in ST()*/ + host_arm_VMOV_D_D(block, dest_reg, src_64_reg); + host_arm_TST_IMM(block, tag_reg, TAG_UINT64); + branch_offset = host_arm_BNE_(block); + + /*VFP/NEON has no instructions to convert a float to 64-bit integer, + so call out to C.*/ + host_arm_VMOV_D_D(block, REG_D0, src_reg); + host_arm_call(block, x87_fround64); + host_arm_VMOV_D_64(block, REG_D_TEMP, REG_R0, REG_R1); + + *branch_offset |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 8) & 0x3fffffc) >> 2; + } + else + fatal("MOV_INT_DOUBLE_64 %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOV_REG_PTR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm_MOV_IMM(block, REG_TEMP, (uintptr_t)uop->p); + if (REG_IS_L(dest_size)) + { + host_arm_LDR_IMM(block, dest_reg, REG_TEMP, 0); + } + else + fatal("MOV_REG_PTR %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_8(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm_MOV_IMM(block, REG_TEMP, (uintptr_t)uop->p); + if (REG_IS_L(dest_size)) + { + host_arm_LDRB_IMM(block, dest_reg, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size)) + { + host_arm_LDRB_IMM(block, REG_TEMP, REG_TEMP, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size)) + { + host_arm_LDRB_IMM(block, REG_TEMP, REG_TEMP, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else + fatal("MOVZX_REG_PTR_8 %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_16(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm_MOV_IMM(block, REG_TEMP, (uintptr_t)uop->p); + if (REG_IS_L(dest_size)) + { + host_arm_LDRH_IMM(block, dest_reg, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size)) + { + host_arm_LDRH_IMM(block, REG_TEMP, REG_TEMP, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOVZX_REG_PTR_16 %02x\n", uop->dest_reg_a_real); + + return 0; +} + +static int codegen_NOP(codeblock_t *block, uop_t *uop) +{ + return 0; +} + +static int codegen_OR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VORR_D(block, dest_reg, src_reg_a, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_ORR_REG_LSL(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_ORR_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 0); + host_arm_ORR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 8); + host_arm_ORR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 0); + host_arm_ORR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 8); + host_arm_ORR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else + fatal("OR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_OR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_ORR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size) && dest_reg == src_reg) + { + host_arm_ORR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size) && dest_reg == src_reg) + { + host_arm_ORR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size) && dest_reg == src_reg) + { + host_arm_ORR_IMM(block, dest_reg, src_reg, uop->imm_data << 8); + } + else + fatal("OR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_PACKSSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_Q_TEMP, src_reg_a); + host_arm_VMOV_D_D(block, REG_Q_TEMP_2, src_reg_b); + host_arm_VQMOVN_S16(block, dest_reg, REG_Q_TEMP); + host_arm_VQMOVN_S16(block, REG_D_TEMP, REG_Q_TEMP_2); + host_arm_VZIP_D32(block, dest_reg, REG_D_TEMP); + } + else + fatal("PACKSSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PACKSSDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_Q_TEMP, src_reg_a); + host_arm_VMOV_D_D(block, REG_Q_TEMP_2, src_reg_b); + host_arm_VQMOVN_S32(block, dest_reg, REG_Q_TEMP); + host_arm_VQMOVN_S32(block, REG_D_TEMP, REG_Q_TEMP_2); + host_arm_VZIP_D32(block, dest_reg, REG_D_TEMP); + } + else + fatal("PACKSSDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PACKUSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_Q_TEMP, src_reg_a); + host_arm_VMOV_D_D(block, REG_Q_TEMP_2, src_reg_b); + host_arm_VQMOVN_U16(block, dest_reg, REG_Q_TEMP); + host_arm_VQMOVN_U16(block, REG_D_TEMP, REG_Q_TEMP_2); + host_arm_VZIP_D32(block, dest_reg, REG_D_TEMP); + } + else + fatal("PACKUSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PADDB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VADD_I8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VADD_I16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VADD_I32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQADD_S8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQADD_S16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQADD_U8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQADD_U16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PCMPEQB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCEQ_I8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPEQB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPEQW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCEQ_I16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPEQW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPEQD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCEQ_I32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPEQD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPGTB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCGT_S8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPGTB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPGTW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCGT_S16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPGTW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPGTD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCGT_S32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPGTD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PF2ID(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_arm_VCVT_S32_F32(block, dest_reg, src_reg_a); + } + else + fatal("PF2ID %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_PFADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VADD_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFCMPEQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCEQ_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFCMPEQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFCMPGE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCGE_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFCMPGE %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFCMPGT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCGT_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFCMPGT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFMAX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMAX_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFMAX %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFMIN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMIN_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFMIN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMUL_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFRCP(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use VRECPE/VRECPS)*/ + host_arm_VMOV_F32_ONE(block, REG_D_TEMP); + host_arm_VDIV_S(block, dest_reg, REG_D_TEMP, src_reg_a); + host_arm_VDUP_32(block, dest_reg, dest_reg, 0); + } + else + fatal("PFRCP %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_PFRSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use VRSQRTE/VRSQRTS)*/ + host_arm_VSQRT_S(block, REG_D_TEMP, src_reg_a); + host_arm_VMOV_F32_ONE(block, REG_D_TEMP); + host_arm_VDIV_S(block, dest_reg, dest_reg, REG_D_TEMP); + host_arm_VDUP_32(block, dest_reg, dest_reg, 0); + } + else + fatal("PFRSQRT %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_PFSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VSUB_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PI2FD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_arm_VCVT_F32_S32(block, dest_reg, src_reg_a); + } + else + fatal("PI2FD %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} + +static int codegen_PMADDWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMULL_S16(block, REG_Q_TEMP, src_reg_a, src_reg_b); + host_arm_VPADDL_Q_S32(block, REG_Q_TEMP, REG_Q_TEMP); + host_arm_VMOVN_I64(block, dest_reg, REG_Q_TEMP); + } + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PMULHW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMULL_S16(block, REG_Q_TEMP, src_reg_a, src_reg_b); + host_arm_VSHRN_32(block, dest_reg, REG_Q_TEMP, 16); + } + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PMULLW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMUL_S16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PMULLW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PSLLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 15) + host_arm_VEOR_D(block, dest_reg, dest_reg, dest_reg); + else + host_arm_VSHL_D_IMM_16(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSLLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSLLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 31) + host_arm_VEOR_D(block, dest_reg, dest_reg, dest_reg); + else + host_arm_VSHL_D_IMM_32(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSLLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSLLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 63) + host_arm_VEOR_D(block, dest_reg, dest_reg, dest_reg); + else + host_arm_VSHL_D_IMM_64(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSLLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRAW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 15) + host_arm_VSHR_D_S16(block, dest_reg, src_reg, 15); + else + host_arm_VSHR_D_S16(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRAW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRAD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 31) + host_arm_VSHR_D_S32(block, dest_reg, src_reg, 31); + else + host_arm_VSHR_D_S32(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRAD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRAQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 63) + host_arm_VSHR_D_S64(block, dest_reg, src_reg, 63); + else + host_arm_VSHR_D_S64(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRAQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 15) + host_arm_VEOR_D(block, dest_reg, dest_reg, dest_reg); + else + host_arm_VSHR_D_U16(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 31) + host_arm_VEOR_D(block, dest_reg, dest_reg, dest_reg); + else + host_arm_VSHR_D_U32(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 63) + host_arm_VEOR_D(block, dest_reg, dest_reg, dest_reg); + else + host_arm_VSHR_D_U64(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_PSUBB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VSUB_I8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VSUB_I16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VSUB_I32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQSUB_S8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQSUB_S16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQSUB_U8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQSUB_U16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PUNPCKHBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg_b); + if (dest_reg != src_reg_a) + host_arm_VMOV_D_D(block, dest_reg, src_reg_a); + host_arm_VZIP_D8(block, dest_reg, REG_D_TEMP); + host_arm_VMOV_D_D(block, dest_reg, REG_D_TEMP); + } + else + fatal("PUNPCKHBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKHWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg_b); + if (dest_reg != src_reg_a) + host_arm_VMOV_D_D(block, dest_reg, src_reg_a); + host_arm_VZIP_D16(block, dest_reg, REG_D_TEMP); + host_arm_VMOV_D_D(block, dest_reg, REG_D_TEMP); + } + else + fatal("PUNPCKHWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKHDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg_b); + if (dest_reg != src_reg_a) + host_arm_VMOV_D_D(block, dest_reg, src_reg_a); + host_arm_VZIP_D32(block, dest_reg, REG_D_TEMP); + host_arm_VMOV_D_D(block, dest_reg, REG_D_TEMP); + } + else + fatal("PUNPCKHDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKLBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg_b); + if (dest_reg != src_reg_a) + host_arm_VMOV_D_D(block, dest_reg, src_reg_a); + host_arm_VZIP_D8(block, dest_reg, REG_D_TEMP); + } + else + fatal("PUNPCKLBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKLWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg_b); + if (dest_reg != src_reg_a) + host_arm_VMOV_D_D(block, dest_reg, src_reg_a); + host_arm_VZIP_D16(block, dest_reg, REG_D_TEMP); + } + else + fatal("PUNPCKLWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKLDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg_b); + if (dest_reg != src_reg_a) + host_arm_VMOV_D_D(block, dest_reg, src_reg_a); + host_arm_VZIP_D32(block, dest_reg, REG_D_TEMP); + } + else + fatal("PUNPCKLDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_ROL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_RSB_IMM(block, REG_TEMP2, shift_reg, 32); + host_arm_MOV_REG_ROR_REG(block, dest_reg, src_reg, REG_TEMP2); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_RSB_IMM(block, REG_TEMP2, shift_reg, 16); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm_MOV_REG_ROR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_RSB_IMM(block, REG_TEMP2, shift_reg, 8); + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_AND_IMM(block, REG_TEMP2, REG_TEMP2, 7); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_RSB_IMM(block, REG_TEMP2, shift_reg, 8); + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_AND_IMM(block, REG_TEMP2, REG_TEMP2, 7); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("ROL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ROL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (!(uop->imm_data & 31)) + { + if (src_reg != dest_reg) + host_arm_MOV_REG(block, dest_reg, src_reg); + } + else + { + host_arm_MOV_REG_ROR(block, dest_reg, src_reg, 32 - (uop->imm_data & 31)); + } + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if ((uop->imm_data & 15) == 0) + { + if (src_reg != dest_reg) + host_arm_BFI(block, dest_reg, src_reg, 0, 16); + } + else + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 16-(uop->imm_data & 15)); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + host_arm_BFI(block, dest_reg, src_reg, 0, 8); + } + else + { + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8-(uop->imm_data & 7)); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + fatal("ROL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8-(uop->imm_data & 7)); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + } + else + fatal("ROL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ROR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_ROR_REG(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_AND_IMM(block, REG_TEMP2, shift_reg, 15); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_AND_IMM(block, REG_TEMP2, shift_reg, 7); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_AND_IMM(block, REG_TEMP2, shift_reg, 7); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("ROR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ROR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (!(uop->imm_data & 31)) + { + if (src_reg != dest_reg) + host_arm_MOV_REG(block, dest_reg, src_reg); + } + else + { + host_arm_MOV_REG_ROR(block, dest_reg, src_reg, uop->imm_data & 31); + } + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if ((uop->imm_data & 15) == 0) + { + if (src_reg != dest_reg) + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data & 15); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data & 7); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data & 7); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + } + else + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_SAR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_ASR_REG(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, 16); + host_arm_MOV_REG_ASR_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_UXTH(block, REG_TEMP, REG_TEMP, 16); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, 24); + host_arm_MOV_REG_ASR_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_UXTB(block, REG_TEMP, REG_TEMP, 24); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, 16); + host_arm_MOV_REG_ASR_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_UXTB(block, REG_TEMP, REG_TEMP, 24); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SAR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SAR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_ASR(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, 16); + host_arm_MOV_REG_ASR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_UXTH(block, REG_TEMP, REG_TEMP, 16); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, 24); + host_arm_MOV_REG_ASR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_UXTB(block, REG_TEMP, REG_TEMP, 24); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, 16); + host_arm_MOV_REG_ASR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_UXTB(block, REG_TEMP, REG_TEMP, 24); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SAR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_LSL_REG(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_MOV_REG_LSL_REG(block, REG_TEMP, src_reg, shift_reg); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_MOV_REG_LSL_REG(block, REG_TEMP, src_reg, shift_reg); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_MOV_REG_LSL_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_LSL(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_MOV_REG_LSL(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_LSR_REG(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_LSR(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_STORE_PTR_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, REG_R0, uop->imm_data); + + if (in_range(uop->p, &cpu_state)) + host_arm_STR_IMM(block, REG_R0, REG_CPUSTATE, (uintptr_t)uop->p - (uintptr_t)&cpu_state); + else + fatal("codegen_STORE_PTR_IMM - not in range\n"); + + return 0; +} +static int codegen_STORE_PTR_IMM_8(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, REG_R0, uop->imm_data); + if (in_range(uop->p, &cpu_state)) + host_arm_STRB_IMM(block, REG_R0, REG_CPUSTATE, (uintptr_t)uop->p - (uintptr_t)&cpu_state); + else + fatal("codegen_STORE_PTR_IMM - not in range\n"); + + return 0; +} + +static int codegen_SUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_SUB_REG_LSL(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_SUB_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_SUB_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm_SUB_REG_LSR(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_RSB_REG_LSR(block, REG_TEMP, src_reg_b, src_reg_a, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm_SUB_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_RSB_REG_LSR(block, REG_TEMP, src_reg_b, src_reg_a, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm_MOV_REG_LSR(block, REG_TEMP, src_reg_a, 8); + host_arm_SUB_REG_LSR(block, REG_TEMP, REG_TEMP, src_reg_b, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; + +// host_arm_SUB_REG_LSL(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, 0); +// return 0; +} +static int codegen_SUB_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_SUB_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size)) + { + host_arm_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data << 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data << 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SUB_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_TEST_JNS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm_TST_IMM(block, src_reg, 1 << 31); + } + else if (REG_IS_W(src_size)) + { + host_arm_TST_IMM(block, src_reg, 1 << 15); + } + else if (REG_IS_B(src_size)) + { + host_arm_TST_IMM(block, src_reg, 1 << 7); + } + else + fatal("TEST_JNS_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BEQ_(block); + + return 0; +} +static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm_TST_IMM(block, src_reg, 1 << 31); + } + else if (REG_IS_W(src_size)) + { + host_arm_TST_IMM(block, src_reg, 1 << 15); + } + else if (REG_IS_B(src_size)) + { + host_arm_TST_IMM(block, src_reg, 1 << 7); + } + else + fatal("TEST_JS_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BNE_(block); + + return 0; +} + +static int codegen_XOR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VEOR_D(block, dest_reg, src_reg_a, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_EOR_REG_LSL(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTH(block, REG_TEMP, src_reg_b, 0); + host_arm_EOR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 0); + host_arm_EOR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 8); + host_arm_EOR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 0); + host_arm_EOR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 8); + host_arm_EOR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else + fatal("XOR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_EOR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size) && dest_reg == src_reg) + { + host_arm_EOR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size) && dest_reg == src_reg) + { + host_arm_EOR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size) && dest_reg == src_reg) + { + host_arm_EOR_IMM(block, dest_reg, src_reg, uop->imm_data << 8); + } + else + fatal("XOR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +const uOpFn uop_handlers[UOP_MAX] = +{ + [UOP_CALL_FUNC & UOP_MASK] = codegen_CALL_FUNC, + [UOP_CALL_FUNC_RESULT & UOP_MASK] = codegen_CALL_FUNC_RESULT, + [UOP_CALL_INSTRUCTION_FUNC & UOP_MASK] = codegen_CALL_INSTRUCTION_FUNC, + + [UOP_JMP & UOP_MASK] = codegen_JMP, + + [UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG, + + [UOP_LOAD_FUNC_ARG_0 & UOP_MASK] = codegen_LOAD_FUNC_ARG0, + [UOP_LOAD_FUNC_ARG_1 & UOP_MASK] = codegen_LOAD_FUNC_ARG1, + [UOP_LOAD_FUNC_ARG_2 & UOP_MASK] = codegen_LOAD_FUNC_ARG2, + [UOP_LOAD_FUNC_ARG_3 & UOP_MASK] = codegen_LOAD_FUNC_ARG3, + + [UOP_LOAD_FUNC_ARG_0_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG0_IMM, + [UOP_LOAD_FUNC_ARG_1_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG1_IMM, + [UOP_LOAD_FUNC_ARG_2_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG2_IMM, + [UOP_LOAD_FUNC_ARG_3_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG3_IMM, + + [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, + [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, + [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, + [UOP_MEM_LOAD_SINGLE & UOP_MASK] = codegen_MEM_LOAD_SINGLE, + [UOP_MEM_LOAD_DOUBLE & UOP_MASK] = codegen_MEM_LOAD_DOUBLE, + + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, + [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, + [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, + [UOP_MEM_STORE_IMM_16 & UOP_MASK] = codegen_MEM_STORE_IMM_16, + [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, + [UOP_MEM_STORE_SINGLE & UOP_MASK] = codegen_MEM_STORE_SINGLE, + [UOP_MEM_STORE_DOUBLE & UOP_MASK] = codegen_MEM_STORE_DOUBLE, + + [UOP_MOV & UOP_MASK] = codegen_MOV, + [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, + [UOP_MOVSX & UOP_MASK] = codegen_MOVSX, + [UOP_MOVZX & UOP_MASK] = codegen_MOVZX, + [UOP_MOV_DOUBLE_INT & UOP_MASK] = codegen_MOV_DOUBLE_INT, + [UOP_MOV_INT_DOUBLE & UOP_MASK] = codegen_MOV_INT_DOUBLE, + [UOP_MOV_INT_DOUBLE_64 & UOP_MASK] = codegen_MOV_INT_DOUBLE_64, + [UOP_MOV_REG_PTR & UOP_MASK] = codegen_MOV_REG_PTR, + [UOP_MOVZX_REG_PTR_8 & UOP_MASK] = codegen_MOVZX_REG_PTR_8, + [UOP_MOVZX_REG_PTR_16 & UOP_MASK] = codegen_MOVZX_REG_PTR_16, + + [UOP_ADD & UOP_MASK] = codegen_ADD, + [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, + [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, + [UOP_AND & UOP_MASK] = codegen_AND, + [UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM, + [UOP_ANDN & UOP_MASK] = codegen_ANDN, + [UOP_OR & UOP_MASK] = codegen_OR, + [UOP_OR_IMM & UOP_MASK] = codegen_OR_IMM, + [UOP_SUB & UOP_MASK] = codegen_SUB, + [UOP_SUB_IMM & UOP_MASK] = codegen_SUB_IMM, + [UOP_XOR & UOP_MASK] = codegen_XOR, + [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM, + + [UOP_SAR & UOP_MASK] = codegen_SAR, + [UOP_SAR_IMM & UOP_MASK] = codegen_SAR_IMM, + [UOP_SHL & UOP_MASK] = codegen_SHL, + [UOP_SHL_IMM & UOP_MASK] = codegen_SHL_IMM, + [UOP_SHR & UOP_MASK] = codegen_SHR, + [UOP_SHR_IMM & UOP_MASK] = codegen_SHR_IMM, + [UOP_ROL & UOP_MASK] = codegen_ROL, + [UOP_ROL_IMM & UOP_MASK] = codegen_ROL_IMM, + [UOP_ROR & UOP_MASK] = codegen_ROR, + [UOP_ROR_IMM & UOP_MASK] = codegen_ROR_IMM, + + [UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ, + + [UOP_CMP_JB & UOP_MASK] = codegen_CMP_JB, + [UOP_CMP_JNBE & UOP_MASK] = codegen_CMP_JNBE, + + [UOP_CMP_JNB_DEST & UOP_MASK] = codegen_CMP_JNB_DEST, + [UOP_CMP_JNBE_DEST & UOP_MASK] = codegen_CMP_JNBE_DEST, + [UOP_CMP_JNL_DEST & UOP_MASK] = codegen_CMP_JNL_DEST, + [UOP_CMP_JNLE_DEST & UOP_MASK] = codegen_CMP_JNLE_DEST, + [UOP_CMP_JNO_DEST & UOP_MASK] = codegen_CMP_JNO_DEST, + [UOP_CMP_JNZ_DEST & UOP_MASK] = codegen_CMP_JNZ_DEST, + [UOP_CMP_JB_DEST & UOP_MASK] = codegen_CMP_JB_DEST, + [UOP_CMP_JBE_DEST & UOP_MASK] = codegen_CMP_JBE_DEST, + [UOP_CMP_JL_DEST & UOP_MASK] = codegen_CMP_JL_DEST, + [UOP_CMP_JLE_DEST & UOP_MASK] = codegen_CMP_JLE_DEST, + [UOP_CMP_JO_DEST & UOP_MASK] = codegen_CMP_JO_DEST, + [UOP_CMP_JZ_DEST & UOP_MASK] = codegen_CMP_JZ_DEST, + + [UOP_CMP_IMM_JNZ_DEST & UOP_MASK] = codegen_CMP_IMM_JNZ_DEST, + [UOP_CMP_IMM_JZ_DEST & UOP_MASK] = codegen_CMP_IMM_JZ_DEST, + + [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, + [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, + + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, + [UOP_MMX_ENTER & UOP_MASK] = codegen_MMX_ENTER, + + [UOP_FADD & UOP_MASK] = codegen_FADD, + [UOP_FCOM & UOP_MASK] = codegen_FCOM, + [UOP_FDIV & UOP_MASK] = codegen_FDIV, + [UOP_FMUL & UOP_MASK] = codegen_FMUL, + [UOP_FSUB & UOP_MASK] = codegen_FSUB, + + [UOP_FABS & UOP_MASK] = codegen_FABS, + [UOP_FCHS & UOP_MASK] = codegen_FCHS, + [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, + [UOP_FTST & UOP_MASK] = codegen_FTST, + + [UOP_PACKSSWB & UOP_MASK] = codegen_PACKSSWB, + [UOP_PACKSSDW & UOP_MASK] = codegen_PACKSSDW, + [UOP_PACKUSWB & UOP_MASK] = codegen_PACKUSWB, + + [UOP_PADDB & UOP_MASK] = codegen_PADDB, + [UOP_PADDW & UOP_MASK] = codegen_PADDW, + [UOP_PADDD & UOP_MASK] = codegen_PADDD, + [UOP_PADDSB & UOP_MASK] = codegen_PADDSB, + [UOP_PADDSW & UOP_MASK] = codegen_PADDSW, + [UOP_PADDUSB & UOP_MASK] = codegen_PADDUSB, + [UOP_PADDUSW & UOP_MASK] = codegen_PADDUSW, + + [UOP_PCMPEQB & UOP_MASK] = codegen_PCMPEQB, + [UOP_PCMPEQW & UOP_MASK] = codegen_PCMPEQW, + [UOP_PCMPEQD & UOP_MASK] = codegen_PCMPEQD, + [UOP_PCMPGTB & UOP_MASK] = codegen_PCMPGTB, + [UOP_PCMPGTW & UOP_MASK] = codegen_PCMPGTW, + [UOP_PCMPGTD & UOP_MASK] = codegen_PCMPGTD, + + [UOP_PF2ID & UOP_MASK] = codegen_PF2ID, + [UOP_PFADD & UOP_MASK] = codegen_PFADD, + [UOP_PFCMPEQ & UOP_MASK] = codegen_PFCMPEQ, + [UOP_PFCMPGE & UOP_MASK] = codegen_PFCMPGE, + [UOP_PFCMPGT & UOP_MASK] = codegen_PFCMPGT, + [UOP_PFMAX & UOP_MASK] = codegen_PFMAX, + [UOP_PFMIN & UOP_MASK] = codegen_PFMIN, + [UOP_PFMUL & UOP_MASK] = codegen_PFMUL, + [UOP_PFRCP & UOP_MASK] = codegen_PFRCP, + [UOP_PFRSQRT & UOP_MASK] = codegen_PFRSQRT, + [UOP_PFSUB & UOP_MASK] = codegen_PFSUB, + [UOP_PI2FD & UOP_MASK] = codegen_PI2FD, + + [UOP_PMADDWD & UOP_MASK] = codegen_PMADDWD, + [UOP_PMULHW & UOP_MASK] = codegen_PMULHW, + [UOP_PMULLW & UOP_MASK] = codegen_PMULLW, + + [UOP_PSLLW_IMM & UOP_MASK] = codegen_PSLLW_IMM, + [UOP_PSLLD_IMM & UOP_MASK] = codegen_PSLLD_IMM, + [UOP_PSLLQ_IMM & UOP_MASK] = codegen_PSLLQ_IMM, + [UOP_PSRAW_IMM & UOP_MASK] = codegen_PSRAW_IMM, + [UOP_PSRAD_IMM & UOP_MASK] = codegen_PSRAD_IMM, + [UOP_PSRAQ_IMM & UOP_MASK] = codegen_PSRAQ_IMM, + [UOP_PSRLW_IMM & UOP_MASK] = codegen_PSRLW_IMM, + [UOP_PSRLD_IMM & UOP_MASK] = codegen_PSRLD_IMM, + [UOP_PSRLQ_IMM & UOP_MASK] = codegen_PSRLQ_IMM, + + [UOP_PSUBB & UOP_MASK] = codegen_PSUBB, + [UOP_PSUBW & UOP_MASK] = codegen_PSUBW, + [UOP_PSUBD & UOP_MASK] = codegen_PSUBD, + [UOP_PSUBSB & UOP_MASK] = codegen_PSUBSB, + [UOP_PSUBSW & UOP_MASK] = codegen_PSUBSW, + [UOP_PSUBUSB & UOP_MASK] = codegen_PSUBUSB, + [UOP_PSUBUSW & UOP_MASK] = codegen_PSUBUSW, + + [UOP_PUNPCKHBW & UOP_MASK] = codegen_PUNPCKHBW, + [UOP_PUNPCKHWD & UOP_MASK] = codegen_PUNPCKHWD, + [UOP_PUNPCKHDQ & UOP_MASK] = codegen_PUNPCKHDQ, + [UOP_PUNPCKLBW & UOP_MASK] = codegen_PUNPCKLBW, + [UOP_PUNPCKLWD & UOP_MASK] = codegen_PUNPCKLWD, + [UOP_PUNPCKLDQ & UOP_MASK] = codegen_PUNPCKLDQ, + + [UOP_NOP_BARRIER & UOP_MASK] = codegen_NOP +}; + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p) +{ + if (in_range_h(p, &cpu_state)) + host_arm_LDRB_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_8 - not in range\n"); +} +void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p) +{ + if (in_range_h(p, &cpu_state)) + host_arm_LDRH_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + { + host_arm_MOV_IMM(block, REG_R3, (uintptr_t)p - (uintptr_t)&cpu_state); + host_arm_LDRH_REG(block, host_reg, REG_CPUSTATE, REG_R3); + } +} +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) +{ + if (in_range(p, &cpu_state)) + host_arm_LDR_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_32 - not in range\n"); +} +void codegen_direct_read_pointer(codeblock_t *block, int host_reg, void *p) +{ + codegen_direct_read_32(block, host_reg, p); +} +void codegen_direct_read_64(codeblock_t *block, int host_reg, void *p) +{ + host_arm_VLDR_D(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); +} +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p) +{ + host_arm_VLDR_D(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); +} +void codegen_direct_read_st_8(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_LDRB_IMM(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} +void codegen_direct_read_st_64(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_VLDR_D(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_VLDR_D(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} + +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) +{ + if (in_range(p, &cpu_state)) + host_arm_STRB_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_8 - not in range\n"); +} +void codegen_direct_write_16(codeblock_t *block, void *p, int host_reg) +{ + if (in_range_h(p, &cpu_state)) + host_arm_STRH_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + { + host_arm_MOV_IMM(block, REG_R3, (uintptr_t)p - (uintptr_t)&cpu_state); + host_arm_STRH_REG(block, host_reg, REG_CPUSTATE, REG_R3); + } +} +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) +{ + if (in_range(p, &cpu_state)) + host_arm_STR_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_32 - not in range\n"); +} +void codegen_direct_write_64(codeblock_t *block, void *p, int host_reg) +{ + host_arm_VSTR_D(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); +} +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg) +{ + host_arm_VSTR_D(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); +} +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_STRB_IMM(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} +void codegen_direct_write_st_64(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_VSTR_D(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_VSTR_D(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} + +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) +{ + if (in_range(p, &cpu_state)) + host_arm_STR_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_ptr - not in range\n"); +} + +void codegen_direct_read_16_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + if (stack_offset >= 0 && stack_offset < 256) + host_arm_LDRH_IMM(block, host_reg, REG_HOST_SP, stack_offset); + else + fatal("codegen_direct_read_32 - not in range\n"); +} +void codegen_direct_read_32_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + if (stack_offset >= 0 && stack_offset < 4096) + host_arm_LDR_IMM(block, host_reg, REG_HOST_SP, stack_offset); + else + fatal("codegen_direct_read_32 - not in range\n"); +} +void codegen_direct_read_pointer_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + codegen_direct_read_32_stack(block, host_reg, stack_offset); +} +void codegen_direct_read_64_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_arm_VLDR_D(block, host_reg, REG_HOST_SP, stack_offset); +} +void codegen_direct_read_double_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_arm_VLDR_D(block, host_reg, REG_HOST_SP, stack_offset); +} + +void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + if (stack_offset >= 0 && stack_offset < 4096) + host_arm_STR_IMM(block, host_reg, REG_HOST_SP, stack_offset); + else + fatal("codegen_direct_write_32 - not in range\n"); +} +void codegen_direct_write_64_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_arm_VSTR_D(block, host_reg, REG_HOST_SP, stack_offset); +} +void codegen_direct_write_double_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_arm_VSTR_D(block, host_reg, REG_HOST_SP, stack_offset); +} + +void codegen_set_jump_dest(codeblock_t *block, void *p) +{ + *(uint32_t *)p |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)p) - 8) & 0x3fffffc) >> 2; +} +#endif diff --git a/src/cpu_new/codegen_backend_x86-64.c b/src/cpu_new/codegen_backend_x86-64.c new file mode 100644 index 000000000..4615aa381 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64.c @@ -0,0 +1,391 @@ +#ifdef __amd64__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86-64_defs.h" +#include "codegen_backend_x86-64_ops.h" +#include "codegen_backend_x86-64_ops_sse.h" +#include "codegen_reg.h" +#include "x86.h" + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +void *codegen_mem_load_byte; +void *codegen_mem_load_word; +void *codegen_mem_load_long; +void *codegen_mem_load_quad; +void *codegen_mem_load_single; +void *codegen_mem_load_double; + +void *codegen_mem_store_byte; +void *codegen_mem_store_word; +void *codegen_mem_store_long; +void *codegen_mem_store_quad; +void *codegen_mem_store_single; +void *codegen_mem_store_double; + +void *codegen_gpf_rout; +void *codegen_exit_rout; + +host_reg_def_t codegen_host_reg_list[CODEGEN_HOST_REGS] = +{ + /*Note: while EAX and EDX are normally volatile registers under x86 + calling conventions, the recompiler will explicitly save and restore + them across funcion calls*/ + {REG_EAX, 0}, + {REG_EBX, 0}, + {REG_EDX, 0} +}; + +host_reg_def_t codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = +{ +#if WIN64 + /*Windows x86-64 calling convention preserves XMM6-XMM15*/ + {REG_XMM6, 0}, + {REG_XMM7, 0}, +#else + /*System V AMD64 calling convention does not preserve any XMM registers*/ + {REG_XMM6, HOST_REG_FLAG_VOLATILE}, + {REG_XMM7, HOST_REG_FLAG_VOLATILE}, +#endif + {REG_XMM1, HOST_REG_FLAG_VOLATILE}, + {REG_XMM2, HOST_REG_FLAG_VOLATILE}, + {REG_XMM3, HOST_REG_FLAG_VOLATILE}, + {REG_XMM4, HOST_REG_FLAG_VOLATILE}, + {REG_XMM5, HOST_REG_FLAG_VOLATILE} +}; + +static void build_load_routine(codeblock_t *block, int size, int is_float) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset; + + /*In - ESI = address + Out - ECX = data, ESI = abrt*/ + /*MOV ECX, ESI + SHR ESI, 12 + MOV RSI, [readlookup2+ESI*4] + CMP ESI, -1 + JNZ + + MOVZX ECX, B[RSI+RCX] + XOR ESI,ESI + RET + * PUSH EAX + PUSH EDX + PUSH ECX + CALL readmembl + POP ECX + POP EDX + POP EAX + MOVZX ECX, AL + RET + */ + host_x86_MOV32_REG_REG(block, REG_ECX, REG_ESI); + host_x86_SHR32_IMM(block, REG_ESI, 12); + host_x86_MOV64_REG_IMM(block, REG_RDI, (uint64_t)(uintptr_t)readlookup2); + host_x86_MOV64_REG_BASE_INDEX_SHIFT(block, REG_RSI, REG_RDI, REG_RSI, 3); + if (size != 1) + { + host_x86_TEST32_REG_IMM(block, REG_ECX, size-1); + misaligned_offset = host_x86_JNZ_short(block); + } + host_x86_CMP64_REG_IMM(block, REG_RSI, (uint32_t)-1); + branch_offset = host_x86_JZ_short(block); + if (size == 1 && !is_float) + host_x86_MOVZX_BASE_INDEX_32_8(block, REG_ECX, REG_RSI, REG_RCX); + else if (size == 2 && !is_float) + host_x86_MOVZX_BASE_INDEX_32_16(block, REG_ECX, REG_RSI, REG_RCX); + else if (size == 4 && !is_float) + host_x86_MOV32_REG_BASE_INDEX(block, REG_ECX, REG_RSI, REG_RCX); + else if (size == 4 && is_float) + host_x86_CVTSS2SD_XREG_BASE_INDEX(block, REG_XMM_TEMP, REG_RSI, REG_RCX); + else if (size == 8) + host_x86_MOVQ_XREG_BASE_INDEX(block, REG_XMM_TEMP, REG_RSI, REG_RCX); + else + fatal("build_load_routine: size=%i\n", size); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI); + host_x86_RET(block); + + *branch_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 1; + if (size != 1) + *misaligned_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 1; + host_x86_PUSH(block, REG_RAX); + host_x86_PUSH(block, REG_RDX); +#if WIN64 + host_x86_SUB64_REG_IMM(block, REG_RSP, 0x20); + //host_x86_MOV32_REG_REG(block, REG_ECX, uop->imm_data); +#else + host_x86_MOV32_REG_REG(block, REG_EDI, REG_ECX); +#endif + if (size == 1 && !is_float) + { + host_x86_CALL(block, (void *)readmembl); + host_x86_MOVZX_REG_32_8(block, REG_ECX, REG_EAX); + } + else if (size == 2 && !is_float) + { + host_x86_CALL(block, (void *)readmemwl); + host_x86_MOVZX_REG_32_16(block, REG_ECX, REG_EAX); + } + else if (size == 4 && !is_float) + { + host_x86_CALL(block, (void *)readmemll); + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + } + else if (size == 4 && is_float) + { + host_x86_CALL(block, (void *)readmemll); + host_x86_MOVD_XREG_REG(block, REG_XMM_TEMP, REG_EAX); + host_x86_CVTSS2SD_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + } + else if (size == 8) + { + host_x86_CALL(block, (void *)readmemql); + host_x86_MOVQ_XREG_REG(block, REG_XMM_TEMP, REG_RAX); + } +#if WIN64 + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x20); +#endif + host_x86_POP(block, REG_RDX); + host_x86_POP(block, REG_RAX); + host_x86_MOVZX_REG_ABS_32_8(block, REG_ESI, &cpu_state.abrt); + host_x86_RET(block); +} + +static void build_store_routine(codeblock_t *block, int size, int is_float) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset; + + /*In - ECX = data, ESI = address + Out - ESI = abrt + Corrupts EDI*/ + /*MOV EDI, ESI + SHR ESI, 12 + MOV ESI, [writelookup2+ESI*4] + CMP ESI, -1 + JNZ + + MOV [RSI+RDI], ECX + XOR ESI,ESI + RET + * PUSH EAX + PUSH EDX + PUSH ECX + CALL writemembl + POP ECX + POP EDX + POP EAX + MOVZX ECX, AL + RET + */ + host_x86_MOV32_REG_REG(block, REG_EDI, REG_ESI); + host_x86_SHR32_IMM(block, REG_ESI, 12); + host_x86_MOV64_REG_IMM(block, REG_R8, (uint64_t)(uintptr_t)writelookup2); + host_x86_MOV64_REG_BASE_INDEX_SHIFT(block, REG_RSI, REG_R8, REG_RSI, 3); + if (size != 1) + { + host_x86_TEST32_REG_IMM(block, REG_EDI, size-1); + misaligned_offset = host_x86_JNZ_short(block); + } + host_x86_CMP64_REG_IMM(block, REG_RSI, (uint32_t)-1); + branch_offset = host_x86_JZ_short(block); + if (size == 1 && !is_float) + host_x86_MOV8_BASE_INDEX_REG(block, REG_RSI, REG_RDI, REG_ECX); + else if (size == 2 && !is_float) + host_x86_MOV16_BASE_INDEX_REG(block, REG_RSI, REG_RDI, REG_ECX); + else if (size == 4 && !is_float) + host_x86_MOV32_BASE_INDEX_REG(block, REG_RSI, REG_RDI, REG_ECX); + else if (size == 4 && is_float) + host_x86_MOVD_BASE_INDEX_XREG(block, REG_RSI, REG_RDI, REG_XMM_TEMP); + else if (size == 8) + host_x86_MOVQ_BASE_INDEX_XREG(block, REG_RSI, REG_RDI, REG_XMM_TEMP); + else + fatal("build_store_routine: size=%i\n", size); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI); + host_x86_RET(block); + + *branch_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 1; + if (size != 1) + *misaligned_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 1; + host_x86_PUSH(block, REG_RAX); + host_x86_PUSH(block, REG_RDX); +#if WIN64 + host_x86_SUB64_REG_IMM(block, REG_RSP, 0x28); + if (size == 4 && is_float) + host_x86_MOVD_REG_XREG(block, REG_EDX, REG_XMM_TEMP); //data + else if (size == 8) + host_x86_MOVQ_REG_XREG(block, REG_RDX, REG_XMM_TEMP); //data + else + host_x86_MOV32_REG_REG(block, REG_EDX, REG_ECX); //data + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EDI); //address +#else + host_x86_SUB64_REG_IMM(block, REG_RSP, 0x8); + //host_x86_MOV32_REG_REG(block, REG_EDI, REG_ECX); //address + if (size == 4 && is_float) + host_x86_MOVD_REG_XREG(block, REG_ESI, REG_XMM_TEMP); //data + else if (size == 8) + host_x86_MOVQ_REG_XREG(block, REG_RSI, REG_XMM_TEMP); //data + else + host_x86_MOV32_REG_REG(block, REG_ESI, REG_ECX); //data +#endif + if (size == 1) + host_x86_CALL(block, (void *)writemembl); + else if (size == 2) + host_x86_CALL(block, (void *)writememwl); + else if (size == 4) + host_x86_CALL(block, (void *)writememll); + else if (size == 8) + host_x86_CALL(block, (void *)writememql); +#if WIN64 + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x28); +#else + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x8); +#endif + host_x86_POP(block, REG_RDX); + host_x86_POP(block, REG_RAX); + host_x86_MOVZX_REG_ABS_32_8(block, REG_ESI, &cpu_state.abrt); + host_x86_RET(block); +} + +static void build_loadstore_routines(codeblock_t *block) +{ + codegen_mem_load_byte = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 1, 0); + codegen_mem_load_word = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 2, 0); + codegen_mem_load_long = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 4, 0); + codegen_mem_load_quad = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 8, 0); + codegen_mem_load_single = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 4, 1); + codegen_mem_load_double = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 8, 1); + + codegen_mem_store_byte = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 1, 0); + codegen_mem_store_word = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 2, 0); + codegen_mem_store_long = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 4, 0); + codegen_mem_store_quad = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 8, 0); + codegen_mem_store_single = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 4, 1); + codegen_mem_store_double = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 8, 1); +} + +void codegen_backend_init() +{ + codeblock_t *block; + int c; +#if defined(__linux__) || defined(__APPLE__) + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); + codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); + + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + + for (c = 0; c < BLOCK_SIZE; c++) + codeblock[c].pc = BLOCK_PC_INVALID; + + block_current = 0; + block_pos = 0; + block = &codeblock[block_current]; + codeblock[block_current].head_mem_block = codegen_allocator_allocate(NULL, block_current); + codeblock[block_current].data = codeblock_allocator_get_ptr(codeblock[block_current].head_mem_block); + block_write_data = codeblock[block_current].data; + build_loadstore_routines(&codeblock[block_current]); + + codegen_gpf_rout = &codeblock[block_current].data[block_pos]; +#if WIN64 + host_x86_XOR32_REG_REG(block, REG_ECX, REG_ECX); + host_x86_XOR32_REG_REG(block, REG_EDX, REG_EDX); +#else + host_x86_XOR32_REG_REG(block, REG_EDI, REG_EDI); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI); +#endif + /* host_x86_CALL(block, (uintptr_t)x86gpf); */ + host_x86_CALL(block, (void *)x86gpf); + codegen_exit_rout = &codeblock[block_current].data[block_pos]; + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x38); + host_x86_POP(block, REG_R15); + host_x86_POP(block, REG_R14); + host_x86_POP(block, REG_R13); + host_x86_POP(block, REG_R12); + host_x86_POP(block, REG_RDI); + host_x86_POP(block, REG_RSI); + host_x86_POP(block, REG_RBP); + host_x86_POP(block, REG_RDX); + host_x86_RET(block); + + block_write_data = NULL; + + asm( + "stmxcsr %0\n" + : "=m" (cpu_state.old_fp_control) + ); + cpu_state.trunc_fp_control = cpu_state.old_fp_control | 0x6000; +} + +void codegen_set_rounding_mode(int mode) +{ + cpu_state.new_fp_control = (cpu_state.old_fp_control & ~0x6000) | (mode << 13); +} + +void codegen_backend_prologue(codeblock_t *block) +{ + block_pos = BLOCK_START; /*Entry code*/ + host_x86_PUSH(block, REG_RBX); + host_x86_PUSH(block, REG_RBP); + host_x86_PUSH(block, REG_RSI); + host_x86_PUSH(block, REG_RDI); + host_x86_PUSH(block, REG_R12); + host_x86_PUSH(block, REG_R13); + host_x86_PUSH(block, REG_R14); + host_x86_PUSH(block, REG_R15); + host_x86_SUB64_REG_IMM(block, REG_RSP, 0x38); + host_x86_MOV64_REG_IMM(block, REG_RBP, ((uintptr_t)&cpu_state) + 128); + if (block->flags & CODEBLOCK_HAS_FPU) + { + host_x86_MOV32_REG_ABS(block, REG_EAX, &cpu_state.TOP); + host_x86_SUB32_REG_IMM(block, REG_EAX, block->TOP); + host_x86_MOV32_BASE_OFFSET_REG(block, REG_RSP, IREG_TOP_diff_stack_offset, REG_EAX); + } + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + host_x86_MOV64_REG_IMM(block, REG_R12, (uintptr_t)ram); +} + +void codegen_backend_epilogue(codeblock_t *block) +{ + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x38); + host_x86_POP(block, REG_R15); + host_x86_POP(block, REG_R14); + host_x86_POP(block, REG_R13); + host_x86_POP(block, REG_R12); + host_x86_POP(block, REG_RDI); + host_x86_POP(block, REG_RSI); + host_x86_POP(block, REG_RBP); + host_x86_POP(block, REG_RDX); + host_x86_RET(block); +} +#endif diff --git a/src/cpu_new/codegen_backend_x86-64.h b/src/cpu_new/codegen_backend_x86-64.h new file mode 100644 index 000000000..70e953a6b --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64.h @@ -0,0 +1,12 @@ +#include "codegen_backend_x86-64_defs.h" + +#define BLOCK_SIZE 0x4000 +#define BLOCK_MASK 0x3fff +#define BLOCK_START 0 + +#define HASH_SIZE 0x20000 +#define HASH_MASK 0x1ffff + +#define HASH(l) ((l) & 0x1ffff) + +#define BLOCK_MAX 0x3c0 diff --git a/src/cpu_new/codegen_backend_x86-64_defs.h b/src/cpu_new/codegen_backend_x86-64_defs.h new file mode 100644 index 000000000..a21f62902 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64_defs.h @@ -0,0 +1,67 @@ +/*RBP = cpu_state + 128 + R12 = ram (if block->flags & CODEBLOCK_NO_IMMEDIATES)*/ +#define REG_AX 0 +#define REG_CX 1 +#define REG_DX 2 +#define REG_BX 3 +#define REG_SP 4 +#define REG_BP 5 +#define REG_SI 6 +#define REG_DI 7 + +#define REG_EAX 0 +#define REG_ECX 1 +#define REG_EDX 2 +#define REG_EBX 3 +#define REG_ESP 4 +#define REG_EBP 5 +#define REG_ESI 6 +#define REG_EDI 7 + +#define REG_RAX 0 +#define REG_RCX 1 +#define REG_RDX 2 +#define REG_RBX 3 +#define REG_RSP 4 +#define REG_RBP 5 +#define REG_RSI 6 +#define REG_RDI 7 +#define REG_R8 8 +#define REG_R9 9 +#define REG_R10 10 +#define REG_R11 11 +#define REG_R12 12 +#define REG_R13 13 +#define REG_R14 14 +#define REG_R15 15 + +#define REG_XMM0 0 +#define REG_XMM1 1 +#define REG_XMM2 2 +#define REG_XMM3 3 +#define REG_XMM4 4 +#define REG_XMM5 5 +#define REG_XMM6 6 +#define REG_XMM7 7 + +#define REG_XMM_TEMP REG_XMM7 + +#define CODEGEN_HOST_REGS 3 +#define CODEGEN_HOST_FP_REGS 7 + +extern void *codegen_mem_load_byte; +extern void *codegen_mem_load_word; +extern void *codegen_mem_load_long; +extern void *codegen_mem_load_quad; +extern void *codegen_mem_load_single; +extern void *codegen_mem_load_double; + +extern void *codegen_mem_store_byte; +extern void *codegen_mem_store_word; +extern void *codegen_mem_store_long; +extern void *codegen_mem_store_quad; +extern void *codegen_mem_store_single; +extern void *codegen_mem_store_double; + +extern void *codegen_gpf_rout; +extern void *codegen_exit_rout; diff --git a/src/cpu_new/codegen_backend_x86-64_ops.c b/src/cpu_new/codegen_backend_x86-64_ops.c new file mode 100644 index 000000000..74173e626 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64_ops.c @@ -0,0 +1,1787 @@ +#ifdef __amd64__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86-64_defs.h" +#include "codegen_backend_x86-64_ops.h" +#include "codegen_backend_x86-64_ops_helpers.h" + +#define RM_OP_ADD 0x00 +#define RM_OP_OR 0x08 +#define RM_OP_AND 0x20 +#define RM_OP_SUB 0x28 +#define RM_OP_XOR 0x30 +#define RM_OP_CMP 0x38 + +#define RM_OP_ROL 0x00 +#define RM_OP_ROR 0x08 +#define RM_OP_SHL 0x20 +#define RM_OP_SHR 0x28 +#define RM_OP_SAR 0x38 + +static inline void call(codeblock_t *block, uintptr_t func) +{ + uintptr_t diff; + + codegen_alloc_bytes(block, 5); + diff = func - (uintptr_t)&block_write_data[block_pos + 5]; + + if (diff >= -0x80000000 && diff < 0x7fffffff) + { + codegen_addbyte(block, 0xE8); /*CALL*/ + codegen_addlong(block, (uint32_t)diff); + } + else + { + codegen_alloc_bytes(block, 13); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, func*/ + codegen_addquad(block, func); + codegen_addbyte3(block, 0x41, 0xff, 0xd1); /*CALL R9*/ + } +} + +static inline void jmp(codeblock_t *block, uintptr_t func) +{ + uintptr_t diff; + + codegen_alloc_bytes(block, 5); + diff = func - (uintptr_t)&block_write_data[block_pos + 5]; + + if (diff >= -0x80000000 && diff < 0x7fffffff) + { + codegen_addbyte(block, 0xe9); /*JMP*/ + codegen_addlong(block, (uint32_t)diff); + } + else + { + codegen_alloc_bytes(block, 13); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, func*/ + codegen_addquad(block, func); + codegen_addbyte3(block, 0x41, 0xff, 0xe1); /*JMP R9*/ + } +} + +void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_ADD8_REG_IMM - dst_reg & 8\n"); + + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x04, imm_data); /*ADD EAX, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data); /*ADD dst_reg, imm_data*/ + } +} +void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_ADD16_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x05); /*AND AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_ADD | (dst_reg & 7)); /*ADD dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_ADD32_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x05); /*ADD EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_ADD | (dst_reg & 7)); /*ADD dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_ADD64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_ADD64_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x83, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/ + } + else + fatal("ADD64_REG_IMM !is_imm8 %016llx\n", imm_data); +} +void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_ADD8_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x00, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*ADD dst_reg, src_reg*/ +} +void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_ADD16_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x01, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*ADD dst_reg, src_reg*/ +} +void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_ADD32_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x01, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*ADD dst_reg, src_reg*/ +} + +void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_AND8_REG_IMM - dst_reg & 8\n"); + + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x24, imm_data); /*AND EAX, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_AND | (dst_reg & 7), imm_data); /*AND dst_reg, imm_data*/ + } +} +void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_AND16_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_AND | (dst_reg & 7), imm_data & 0xff); /*AND dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x25); /*AND AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_AND | (dst_reg & 7)); /*AND dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_AND32_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_AND | (dst_reg & 7), imm_data & 0xff); /*AND dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x25); /*AND EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_AND | (dst_reg & 7)); /*AND dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_AND8_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x20, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*AND dst_reg, src_reg*/ +} +void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_AND16_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x21, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*AND dst_reg, src_reg*/ +} +void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_AND32_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x21, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*AND dst_reg, src_reg*/ +} + +void host_x86_CALL(codeblock_t *block, void *p) +{ + call(block, (uintptr_t)p); +} + +void host_x86_CMP16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x3d); /*CMP AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_CMP | dst_reg); /*CMP dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x3d); /*CMP EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_CMP | dst_reg); /*CMP dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_CMP64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + } + else + fatal("CMP64_REG_IMM not 8-bit imm\n"); +} + +void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x38, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ +} +void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ +} +void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ +} + +void host_x86_JMP(codeblock_t *block, void *p) +{ + jmp(block, (uintptr_t)p); +} + +void host_x86_JNZ(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block_write_data[block_pos + 4]); +} +void host_x86_JZ(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x84); /*JZ*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block_write_data[block_pos + 4]); +} + +uint8_t *host_x86_JNZ_short(codeblock_t *block) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x75, 0); /*JNZ*/ + return &block_write_data[block_pos-1]; +} +uint8_t *host_x86_JS_short(codeblock_t *block) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x78, 0); /*JS*/ + return &block_write_data[block_pos-1]; +} +uint8_t *host_x86_JZ_short(codeblock_t *block) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x74, 0); /*JZ*/ + return &block_write_data[block_pos-1]; +} + +uint32_t *host_x86_JNB_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x83); /*JNB*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNBE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x87); /*JNBE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNL_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8d); /*JNL*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNLE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8f); /*JNLE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNO_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x81); /*JNO*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNS_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x89); /*JNS*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNZ_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JB_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x82); /*JB*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JBE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x86); /*JBE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JL_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8c); /*JL*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JLE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8e); /*JLE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JO_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x80); /*JO*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JS_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x88); /*JS*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JZ_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x84); /*JZ*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} + +void host_x86_LAHF(codeblock_t *block) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x9f); /*LAHF*/ +} + +void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t offset) +{ + if (offset) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x8d, 0x80 | (dst_reg << 3) | src_reg); /*LEA dst_reg, [offset+src_reg]*/ + codegen_addlong(block, offset); + } + else + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x8d, 0x00 | (dst_reg << 3) | src_reg); /*LEA dst_reg, [src_reg]*/ + } +} +void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if ((dst_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) + fatal("host_x86_LEA_REG_REG - bad reg\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8d, 0x04 | ((dst_reg & 7) << 3), /*LEA dst_reg, [Rsrc_reg_a + Rsrc_reg_b]*/ + ((src_reg_b & 7) << 3) | (src_reg_a & 7)); +} +void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift) +{ + if ((dst_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) + fatal("host_x86_LEA_REG_REG_SHIFT - bad reg\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8d, 0x04 | ((dst_reg & 7) << 3), /*LEA dst_reg, [Rsrc_reg_a + Rsrc_reg_b * (1 << shift)]*/ + (shift << 6) | ((src_reg_b & 7) << 3) | (src_reg_a & 7)); +} + +void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[RBP], imm_data*/ + codegen_addbyte(block, imm_data); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV8_ABS_IMM - out of range %p\n", p); + codegen_alloc_bytes(block, 8); + codegen_addbyte3(block, 0xc6, 0x04, 0x25); /*MOVB p, imm_data*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + codegen_addbyte(block, imm_data); + } +} +void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV32_ABS_IMM - out of range %p\n", p); + codegen_alloc_bytes(block, 11); + codegen_addbyte3(block, 0xc7, 0x04, 0x25); /*MOV p, imm_data*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOV8_ABS_REG - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x88, 0x45 | ((src_reg & 7) << 3), offset); /*MOVB offset[RBP], src_reg*/ + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV8_ABS_REG - out of range %p\n", p); + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x88); /*MOVB [p], src_reg*/ + codegen_addbyte(block, 0x05 | ((src_reg & 7) << 3)); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOV16_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOV16_ABS_REG - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x66, 0x89, 0x85 | ((src_reg & 7) << 3)); /*MOV offset[RBP], src_reg*/ + codegen_addlong(block, offset); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV32_ABS_REG - out of range %p\n", p); + } +} +void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOV32_ABS_REG - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x89, 0x85 | ((src_reg & 7) << 3)); /*MOV offset[RBP], src_reg*/ + codegen_addlong(block, offset); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV32_ABS_REG - out of range %p\n", p); + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x89); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | ((src_reg & 7) << 3)); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOV64_ABS_REG - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV64_ABS_REG - out of range %p\n", p); + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0x48, 0x89, 0x04 | ((src_reg & 7) << 3), 0x25); /*MOV [p], src_reg*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} + +void host_x86_MOV8_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int base_reg, int index_reg, int shift, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_BASE_INDEX_REG reg & 8\n"); + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x88, 0x44 | (src_reg << 3), base_reg | (index_reg << 3) | (shift << 6), addr & 0xff); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x88, 0x84 | (src_reg << 3), base_reg | (index_reg << 3) | (shift << 6)); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + codegen_addlong(block, addr); + } +} + +void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int base_reg, int index_reg, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_BASE_INDEX_REG reg & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x88, 0x04 | (src_reg << 3), (index_reg << 3) | base_reg); /*MOV B[base_reg + index_reg], src_reg*/ +} +void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int base_reg, int index_reg, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_BASE_INDEX_REG reg & 8\n"); + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x89, 0x04 | (src_reg << 3), (index_reg << 3) | base_reg); /*MOV W[base_reg + index_reg], src_reg*/ +} +void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int base_reg, int index_reg, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_BASE_INDEX_REG reg & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x89, 0x04 | (src_reg << 3), (index_reg << 3) | base_reg); /*MOV L[base_reg + index_reg], src_reg*/ +} + +void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; + + if (dst_reg & 8) + fatal("host_x86_MOV8_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8a, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x8a, 0x85 | ((dst_reg & 7) << 3)); /*MOV dst_reg, offset[RBP]*/ + codegen_addlong(block, offset); + } + else if ((ram_offset < (1ull << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0x41, 0x8a, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, ram_offset[R12]*/ + codegen_addlong(block, ram_offset); + } + else + { + fatal("host_x86_MOV8_REG_ABS - out of range\n"); + } +} +void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; + + if (dst_reg & 8) + fatal("host_x86_MOV16_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x66, 0x8b, 0x85 | ((dst_reg & 7) << 3)); /*MOV dst_reg, offset[RBP]*/ + codegen_addlong(block, offset); + } + else if ((ram_offset < (1ull << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) + { + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x41, 0x8b, 0x84 | ((dst_reg & 7) << 3)); /*MOV dst_reg, ram_offset[R12]*/ + codegen_addbyte(block, 0x24); + codegen_addlong(block, ram_offset); + } + else + { + fatal("host_x86_MOV16_REG_ABS - out of range\n"); + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, p*/ + codegen_addquad(block, (uintptr_t)p); + codegen_alloc_bytes(block, 1); + codegen_addbyte4(block, 0x66, 0x41, 0x8b, 0x01 | ((dst_reg & 7) << 3)); /*MOV dst_reg, [r9]*/ + } +} +void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; + + if (dst_reg & 8) + fatal("host_x86_MOV32_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x8b, 0x85 | ((dst_reg & 7) << 3)); /*MOV dst_reg, offset[RBP]*/ + codegen_addlong(block, offset); + } + else if ((ram_offset < (1ull << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0x41, 0x8b, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, ram_offset[R12]*/ + codegen_addlong(block, ram_offset); + } + else + { + fatal("host_x86_MOV32_REG_ABS - out of range\n"); + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | ((dst_reg & 7) << 3)); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOV64_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (dst_reg & 8) + fatal("host_x86_MOV64_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x48, 0x8b, 0x85 | ((dst_reg & 7) << 3)); /*MOV dst_reg, offset[RBP]*/ + codegen_addlong(block, offset); + } + else + fatal("host_x86_MOV64_REG_ABS - out of range\n"); +} + +void host_x86_MOV8_REG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int base_reg, int index_reg, int shift) +{ + if ((dst_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_REG_ABS_REG_REG_SHIFT reg & 8\n"); + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x8a, 0x44 | (dst_reg << 3), base_reg | (index_reg << 3) | (shift << 6), addr & 0xff); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x8a, 0x84 | (dst_reg << 3), base_reg | (index_reg << 3) | (shift << 6)); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + codegen_addlong(block, addr); + } +} + +void host_x86_MOV32_REG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int index_reg) +{ + if ((dst_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV32_REG_BASE_INDEX reg & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8b, 0x04 | (dst_reg << 3), (index_reg << 3) | base_reg); /*MOV dst_reg, Q[base_reg + index_reg]*/ +} + +void host_x86_MOV64_REG_BASE_INDEX_SHIFT(codeblock_t *block, int dst_reg, int base_reg, int index_reg, int scale) +{ + if ((dst_reg & 8) || (index_reg & 8)) + fatal("host_x86_MOV64_REG_BASE_INDEX_SHIFT reg & 8\n"); + codegen_alloc_bytes(block, 4); + if (base_reg & 8) + codegen_addbyte4(block, 0x49, 0x8b, 0x04 | ((dst_reg & 7) << 3), (scale << 6) | ((index_reg & 7) << 3) | (base_reg & 7)); /*MOV dst_reg, Q[base_reg + index_reg << scale]*/ + else + codegen_addbyte4(block, 0x48, 0x8b, 0x04 | ((dst_reg & 7) << 3), (scale << 6) | ((index_reg & 7) << 3) | (base_reg & 7)); /*MOV dst_reg, Q[base_reg + index_reg << scale]*/ +} + +void host_x86_MOV16_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if ((dst_reg & 8) || (base_reg & 8)) + fatal("host_x86_MOV16_REG_BASE_OFFSET reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x66); + codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + } + } + else + fatal("MOV16_REG_BASE_OFFSET - offset %i\n", offset); +} +void host_x86_MOV32_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if ((dst_reg & 8) || (base_reg & 8)) + fatal("host_x86_MOV32_REG_BASE_OFFSET reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + } + } + else + fatal("MOV32_REG_BASE_OFFSET - offset %i\n", offset); +} +void host_x86_MOV64_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if ((dst_reg & 8) || (base_reg & 8)) + fatal("host_x86_MOV64_REG_BASE_OFFSET reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x48); + codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + } + } + else + fatal("MOV32_REG_BASE_OFFSET - offset %i\n", offset); +} + +void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8)) + fatal("host_x86_MOV32_BASE_OFFSET_REG reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x89, 0x40 | base_reg | (src_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x89, 0x40 | base_reg | (src_reg << 3), offset); + } + } + else + fatal("MOV32_BASE_OFFSET_REG - offset %i\n", offset); +} +void host_x86_MOV64_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8)) + fatal("host_x86_MOV64_BASE_OFFSET_REG reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x48); + codegen_addbyte4(block, 0x89, 0x40 | base_reg | (src_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x89, 0x40 | base_reg | (src_reg << 3), offset); + } + } + else + fatal("MOV64_BASE_OFFSET_REG - offset %i\n", offset); +} + +void host_x86_MOV8_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data) +{ + if (reg >= 8) + fatal("host_x86_MOV8_REG_IMM reg >= 4\n"); + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xb0 | reg, imm_data); /*MOV reg, imm_data*/ +} +void host_x86_MOV16_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data) +{ + if (reg & 8) + fatal("host_x86_MOV16_REG_IMM reg & 8\n"); + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x66, 0xb8 | (reg & 7)); /*MOV reg, imm_data*/ + codegen_addword(block, imm_data); +} +void host_x86_MOV32_REG_IMM(codeblock_t *block, int reg, uint32_t imm_data) +{ + if (reg & 8) + fatal("host_x86_MOV32_REG_IMM reg & 8\n"); + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xb8 | (reg & 7)); /*MOV reg, imm_data*/ + codegen_addlong(block, imm_data); +} + +void host_x86_MOV64_REG_IMM(codeblock_t *block, int reg, uint64_t imm_data) +{ + if (reg & 8) + { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x49, 0xb8 | (reg & 7)); /*MOVQ reg, imm_data*/ + codegen_addquad(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x48, 0xb8 | (reg & 7)); /*MOVQ reg, imm_data*/ + codegen_addquad(block, imm_data); + } +} + +void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOV8_REG_REG - bad reg\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x88, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); +} +void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOV16_REG_REG - bad reg\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x89, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); +} +void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOV32_REG_REG - bad reg\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x89, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); +} + +void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data) +{ + if (!offset) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0xc7, 0x04, 0x24); /*MOV [ESP], imm_data*/ + codegen_addlong(block, imm_data); + } + else if (offset >= -80 || offset < 0x80) + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0xc7, 0x44, 0x24, offset & 0xff); /*MOV offset[ESP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 11); + codegen_addbyte3(block, 0xc7, 0x84, 0x24); /*MOV offset[ESP], imm_data*/ + codegen_addlong(block, offset); + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOVSX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xbe, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ +} +void host_x86_MOVSX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xbe, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ +} +void host_x86_MOVSX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xbf, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ +} + +void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int index_reg) +{ + if ((dst_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOVZX_BASE_INDEX_32_8 reg & 8\n"); + + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb6, 0x04 | (dst_reg << 3), (index_reg << 3) | base_reg); +} +void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int index_reg) +{ + if ((dst_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOVZX_BASE_INDEX_32_16 reg & 8\n"); + + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb7, 0x04 | (dst_reg << 3), (index_reg << 3) | base_reg); +} + +void host_x86_MOVZX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOVZX_REG_16_8 - bad reg\n"); + + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xb6, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} +void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOVZX_REG_32_8 - bad reg\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xb6, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} +void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOVZX_REG_16_8 - bad reg\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xb7, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} + +void host_x86_MOVZX_REG_ABS_16_8(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; + + if (dst_reg & 8) + fatal("host_x86_MOVZX_REG_ABS_16_8 - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x66); + codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | ((dst_reg & 7) << 3), offset); /*MOVZX dst_reg, offset[RBP]*/ + } + else if ((ram_offset < (1ull << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) + { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x66, 0x41); + codegen_addbyte4(block, 0x0f, 0xb6, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOVZX dst_reg, ram_offset[R12]*/ + codegen_addlong(block, ram_offset); + } + else + { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, p*/ + codegen_addquad(block, (uintptr_t)p); + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x66); + codegen_addbyte4(block, 0x41, 0x0f, 0xb6, 0x01 | ((dst_reg & 7) << 3)); /*MOVZX dst_reg, [r9]*/ + } +} +void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; + +// if (dst_reg & 8) +// fatal("host_x86_MOVZX_REG_ABS_32_8 - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + if (dst_reg & 8) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x44); + codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | ((dst_reg & 7) << 3), offset); /*MOVZX dst_reg, offset[RBP]*/ + } + else + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | ((dst_reg & 7) << 3), offset); /*MOVZX dst_reg, offset[RBP]*/ + } + } + else if ((ram_offset < (1ull << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) + { + if (dst_reg & 8) + fatal("host_x86_MOVZX_REG_ABS_32_8 - bad reg\n"); + + codegen_alloc_bytes(block, 9); + codegen_addbyte(block, 0x41); + codegen_addbyte4(block, 0x0f, 0xb6, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOVZX dst_reg, ram_offset[R12]*/ + codegen_addlong(block, ram_offset); + } + else + { + if (dst_reg & 8) + fatal("host_x86_MOVZX_REG_ABS_32_8 - bad reg\n"); + + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, p*/ + codegen_addquad(block, (uintptr_t)p); + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x41, 0x0f, 0xb6, 0x01 | ((dst_reg & 7) << 3)); /*MOVZX dst_reg, [r9]*/ + } +} +void host_x86_MOVZX_REG_ABS_32_16(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; + + if (dst_reg & 8) + fatal("host_x86_MOVZX_REG_ABS_32_16 - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb7, 0x45 | ((dst_reg & 7) << 3), offset); /*MOVZX dst_reg, offset[RBP]*/ + } + else if ((ram_offset < (1ull << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) + { + codegen_alloc_bytes(block, 9); + codegen_addbyte(block, 0x41); + codegen_addbyte4(block, 0x0f, 0xb7, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOVZX dst_reg, ram_offset[R12]*/ + codegen_addlong(block, ram_offset); + } + else + { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, p*/ + codegen_addquad(block, (uintptr_t)p); + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x41, 0x0f, 0xb7, 0x01 | ((dst_reg & 7) << 3)); /*MOVZX dst_reg, [r9]*/ + } +} + +void host_x86_NOP(codeblock_t *block) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x90); /*NOP*/ +} + +void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_OR8_REG_IMM - dst_reg & 8\n"); + + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x0c, imm_data); /*OR EAX, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_OR | (dst_reg & 7), imm_data); /*OR dst_reg, imm_data*/ + } +} +void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_OR16_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_OR | (dst_reg & 7), imm_data & 0xff); /*OR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x0d); /*OR AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_OR | (dst_reg & 7)); /*OR dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_OR32_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_OR | (dst_reg & 7), imm_data & 0xff); /*OR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x0d); /*OR EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_OR | (dst_reg & 7)); /*OR dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_OR8_REG_IMM - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x08, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*OR dst_reg, src_reg*/ +} +void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_OR16_REG_IMM - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x09, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*OR dst_reg, src_reg*/ +} +void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_OR32_REG_IMM - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x09, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*OR dst_reg, src_reg*/ +} + +void host_x86_POP(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x41, 0x58 | (dst_reg & 7)); /*POP reg*/ + } + else + { + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x58 | dst_reg); /*POP reg*/ + } +} + +void host_x86_PUSH(codeblock_t *block, int src_reg) +{ + if (src_reg & 8) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x41, 0x50 | (src_reg & 7)); /*PUSH reg*/ + } + else + { + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x50 | src_reg); /*PUSH reg*/ + } +} + +void host_x86_RET(codeblock_t *block) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0xc3); /*RET*/ +} + +void host_x86_ROL8_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("ROL8 CL & 8\n"); + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_ROL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_ROL16_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("ROL16 CL & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_ROL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_ROL32_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("ROL32 CL & 8\n"); + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_ROL | dst_reg); /*SHL dst_reg, CL*/ +} + +void host_x86_ROL8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("ROL8 imm & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_ROL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_ROL16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("ROL16 imm & 8\n"); + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_ROL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_ROL32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("ROL32 imm & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_ROL | dst_reg, shift); /*SHL dst_reg, shift*/ +} + +void host_x86_ROR8_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("ROR8 CL & 8\n"); + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_ROR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_ROR16_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("ROR16 CL & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_ROR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_ROR32_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("ROR32 CL & 8\n"); + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_ROR | dst_reg); /*SHR dst_reg, CL*/ +} + +void host_x86_ROR8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("ROR8 imm & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_ROR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_ROR16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("ROR16 imm & 8\n"); + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_ROR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_ROR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("ROR32 im & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_ROR | dst_reg, shift); /*SHR dst_reg, shift*/ +} + +void host_x86_SAR8_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SAR8 CL & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_SAR | dst_reg); /*SAR dst_reg, CL*/ +} +void host_x86_SAR16_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SAR16 CL & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_SAR | dst_reg); /*SAR dst_reg, CL*/ +} +void host_x86_SAR32_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SAR32 CL & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_SAR | dst_reg); /*SAR dst_reg, CL*/ +} + +void host_x86_SAR8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SAR8 imm & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_SAR | dst_reg, shift); /*SAR dst_reg, shift*/ +} +void host_x86_SAR16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SAR16 imm & 8\n"); + + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_SAR | dst_reg, shift); /*SAR dst_reg, shift*/ +} +void host_x86_SAR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SAR32 imm & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SAR | dst_reg, shift); /*SAR dst_reg, shift*/ +} + +void host_x86_SHL8_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SHL8 CL & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_SHL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_SHL16_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SHL16 CL & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_SHL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_SHL32_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SHL32 CL & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_SHL | dst_reg); /*SHL dst_reg, CL*/ +} + +void host_x86_SHL8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHL8 imm & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_SHL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_SHL16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHL16 imm & 8\n"); + + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_SHL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_SHL32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHL32 imm & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SHL | dst_reg, shift); /*SHL dst_reg, shift*/ +} + +void host_x86_SHR8_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SHR8 CL & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_SHR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_SHR16_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SHR16 CL & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_SHR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_SHR32_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SHR32 CL & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_SHR | dst_reg); /*SHR dst_reg, CL*/ +} + +void host_x86_SHR8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHR8 imm & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_SHR16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHR16 imm & 8\n"); + + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHR32 imm & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} + +void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_SUB8_REG_IMM - dst_reg & 8\n"); + + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x2c, imm_data); /*SUB EAX, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data); /*SUB dst_reg, imm_data*/ + } +} +void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_SUB16_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data & 0xff); /*SUB dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x2d); /*SUB AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_SUB | (dst_reg & 7)); /*SUB dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_SUB32_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data & 0xff); /*SUB dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x2d); /*SUB EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_SUB | (dst_reg & 7)); /*SUB dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_SUB64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_SUB64_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x83, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data & 0xff); /*SUB dst_reg, imm_data*/ + } + else + fatal("SUB64_REG_IMM !is_imm8 %016llx\n", imm_data); +} +void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_SUB8_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x28, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*SUB dst_reg, src_reg*/ +} +void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_SUB16_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x29, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*SUB dst_reg, src_reg*/ +} +void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_SUB32_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x29, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*SUB dst_reg, src_reg*/ +} + +#define MODRM_MOD_REG(rm, reg) (0xc0 | reg | (rm << 3)) + +void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x84, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST32_REG(codeblock_t *block, int src_reg, int dst_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_TEST32_REG - bad reg\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_reg, src_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("TEST32_REG_IMM reg & 8\n"); + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xa9); /*TEST EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0xf7, 0xc0 | dst_reg); /*TEST dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_XOR8_REG_IMM - dst_reg & 8\n"); + + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x34, imm_data); /*XOR EAX, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_XOR | (dst_reg & 7), imm_data); /*XOR dst_reg, imm_data*/ + } +} +void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_XOR16_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_XOR | (dst_reg & 7), imm_data & 0xff); /*XOR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x35); /*XOR AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_XOR | (dst_reg & 7)); /*XOR dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_XOR32_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_XOR | (dst_reg & 7), imm_data & 0xff); /*XOR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x35); /*XOR EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_XOR | (dst_reg & 7)); /*XOR dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_XOR8_REG_IMM - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x30, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*XOR dst_reg, src_reg*/ +} +void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_XOR16_REG_IMM - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x31, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*XOR dst_reg, src_reg*/ +} +void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_XOR32_REG_IMM - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x31, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*XOR dst_reg, src_reg*/ +} + +#endif diff --git a/src/cpu_new/codegen_backend_x86-64_ops.h b/src/cpu_new/codegen_backend_x86-64_ops.h new file mode 100644 index 000000000..62a9ba203 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64_ops.h @@ -0,0 +1,193 @@ +void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); +void host_x86_ADD64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data); + +void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_CALL(codeblock_t *block, void *p); + +void host_x86_CMP16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); +void host_x86_CMP64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data); + +void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); +void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); +void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); + +void host_x86_JMP(codeblock_t *block, void *p); + +void host_x86_JNZ(codeblock_t *block, void *p); +void host_x86_JZ(codeblock_t *block, void *p); + +uint8_t *host_x86_JNZ_short(codeblock_t *block); +uint8_t *host_x86_JS_short(codeblock_t *block); +uint8_t *host_x86_JZ_short(codeblock_t *block); + +uint32_t *host_x86_JNB_long(codeblock_t *block); +uint32_t *host_x86_JNBE_long(codeblock_t *block); +uint32_t *host_x86_JNL_long(codeblock_t *block); +uint32_t *host_x86_JNLE_long(codeblock_t *block); +uint32_t *host_x86_JNO_long(codeblock_t *block); +uint32_t *host_x86_JNS_long(codeblock_t *block); +uint32_t *host_x86_JNZ_long(codeblock_t *block); +uint32_t *host_x86_JB_long(codeblock_t *block); +uint32_t *host_x86_JBE_long(codeblock_t *block); +uint32_t *host_x86_JL_long(codeblock_t *block); +uint32_t *host_x86_JLE_long(codeblock_t *block); +uint32_t *host_x86_JO_long(codeblock_t *block); +uint32_t *host_x86_JS_long(codeblock_t *block); +uint32_t *host_x86_JZ_long(codeblock_t *block); + +void host_x86_LAHF(codeblock_t *block); + +void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t offset); +void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift); + +void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); +void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); + +void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV16_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg); + +void host_x86_MOV8_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int base_reg, int index_reg, int shift, int src_reg); + +void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg, int index_reg); +void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg, int index_reg); +void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg, int index_reg); + +void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg); +void host_x86_MOV64_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg); + +void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOV64_REG_ABS(codeblock_t *block, int dst_reg, void *p); + +void host_x86_MOV8_REG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int base_reg, int index_reg, int shift); + +void host_x86_MOV32_REG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int index_reg); + +void host_x86_MOV64_REG_BASE_INDEX_SHIFT(codeblock_t *block, int dst_reg, int base_reg, int index_reg, int scale); + +void host_x86_MOV16_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); +void host_x86_MOV32_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); +void host_x86_MOV64_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); + +void host_x86_MOV8_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data); +void host_x86_MOV16_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data); +void host_x86_MOV32_REG_IMM(codeblock_t *block, int reg, uint32_t imm_data); + +void host_x86_MOV64_REG_IMM(codeblock_t *block, int reg, uint64_t imm_data); + +void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data); + +void host_x86_MOVSX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVSX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVSX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int index_reg); +void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int index_reg); + +void host_x86_MOVZX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVZX_REG_ABS_16_8(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVZX_REG_ABS_32_16(codeblock_t *block, int dst_reg, void *p); + +void host_x86_NOP(codeblock_t *block); + +void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_POP(codeblock_t *block, int src_reg); + +void host_x86_PUSH(codeblock_t *block, int src_reg); + +void host_x86_RET(codeblock_t *block); + +void host_x86_ROL8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROL16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROL32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_ROL8_CL(codeblock_t *block, int dst_reg); +void host_x86_ROL16_CL(codeblock_t *block, int dst_reg); +void host_x86_ROL32_CL(codeblock_t *block, int dst_reg); + +void host_x86_ROR8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROR16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_ROR8_CL(codeblock_t *block, int dst_reg); +void host_x86_ROR16_CL(codeblock_t *block, int dst_reg); +void host_x86_ROR32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SAR8_CL(codeblock_t *block, int dst_reg); +void host_x86_SAR16_CL(codeblock_t *block, int dst_reg); +void host_x86_SAR32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SAR8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SAR16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SAR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SHL8_CL(codeblock_t *block, int dst_reg); +void host_x86_SHL16_CL(codeblock_t *block, int dst_reg); +void host_x86_SHL32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SHL8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHL16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHL32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SHR8_CL(codeblock_t *block, int dst_reg); +void host_x86_SHR16_CL(codeblock_t *block, int dst_reg); +void host_x86_SHR32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SHR8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHR16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); +void host_x86_SUB64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data); + +void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); +void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); +void host_x86_TEST32_REG(codeblock_t *block, int src_reg, int dst_reg); +void host_x86_TEST32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); diff --git a/src/cpu_new/codegen_backend_x86-64_ops_helpers.h b/src/cpu_new/codegen_backend_x86-64_ops_helpers.h new file mode 100644 index 000000000..a7755d1a8 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64_ops_helpers.h @@ -0,0 +1,102 @@ +#define JMP_LEN_BYTES 5 + +static inline void codegen_addbyte(codeblock_t *block, uint8_t val) +{ + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addbyte over! %i\n", block_pos); +// CPU_BLOCK_END(); + } + block_write_data[block_pos++] = val; +} +static inline void codegen_addbyte2(codeblock_t *block, uint8_t vala, uint8_t valb) +{ + if (block_pos > (BLOCK_MAX-2)) + { + fatal("codegen_addbyte2 over! %i\n", block_pos); + CPU_BLOCK_END(); + } + block_write_data[block_pos++] = vala; + block_write_data[block_pos++] = valb; +} +static inline void codegen_addbyte3(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc) +{ + if (block_pos > (BLOCK_MAX-3)) + { + fatal("codegen_addbyte3 over! %i\n", block_pos); + CPU_BLOCK_END(); + } + block_write_data[block_pos++] = vala; + block_write_data[block_pos++] = valb; + block_write_data[block_pos++] = valc; +} +static inline void codegen_addbyte4(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc, uint8_t vald) +{ + if (block_pos > (BLOCK_MAX-4)) + { + fatal("codegen_addbyte4 over! %i\n", block_pos); + CPU_BLOCK_END(); + } + block_write_data[block_pos++] = vala; + block_write_data[block_pos++] = valb; + block_write_data[block_pos++] = valc; + block_write_data[block_pos++] = vald; +} + +static inline void codegen_addword(codeblock_t *block, uint16_t val) +{ + if (block_pos > (BLOCK_MAX-2)) + { + fatal("codegen_addword over! %i\n", block_pos); + CPU_BLOCK_END(); + } + *(uint16_t *)&block_write_data[block_pos] = val; + block_pos += 2; +} + +static inline void codegen_addlong(codeblock_t *block, uint32_t val) +{ + if (block_pos > (BLOCK_MAX-4)) + { + fatal("codegen_addlong over! %i\n", block_pos); + CPU_BLOCK_END(); + } + *(uint32_t *)&block_write_data[block_pos] = val; + block_pos += 4; +} + +static inline void codegen_addquad(codeblock_t *block, uint64_t val) +{ + if (block_pos > (BLOCK_MAX-8)) + { + fatal("codegen_addquad over! %i\n", block_pos); + CPU_BLOCK_END(); + } + *(uint64_t *)&block_write_data[block_pos] = val; + block_pos += 8; +} + +static inline void codegen_alloc_bytes(codeblock_t *block, int size) +{ + if (block_pos > ((BLOCK_MAX - size) - JMP_LEN_BYTES)) + { + /*Current block is full. Allocate a new block*/ + struct mem_block_t *new_block = codegen_allocator_allocate(block->head_mem_block, get_block_nr(block)); + uint8_t *new_ptr = codeblock_allocator_get_ptr(new_block); + + /*Add a jump instruction to the new block*/ + codegen_addbyte(block, 0xe9); /*JMP*/ + codegen_addlong(block, (uintptr_t)new_ptr - (uintptr_t)&block_write_data[block_pos + 4]); + + /*Set write address to start of new block*/ + block_pos = 0; + block_write_data = new_ptr; + } +} + +static inline int is_imm8(uint32_t imm_data) +{ + if (imm_data <= 0x7f || imm_data >= 0xffffff80) + return 1; + return 0; +} diff --git a/src/cpu_new/codegen_backend_x86-64_ops_sse.c b/src/cpu_new/codegen_backend_x86-64_ops_sse.c new file mode 100644 index 000000000..b8177648e --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64_ops_sse.c @@ -0,0 +1,618 @@ +#ifdef __amd64__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86-64_defs.h" +#include "codegen_backend_x86-64_ops_sse.h" +#include "codegen_backend_x86-64_ops_helpers.h" + +void host_x86_ADDPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x58, 0xc0 | src_reg | (dst_reg << 3)); /*ADDPS dst_reg, src_reg*/ +} +void host_x86_ADDSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x58, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_CMPPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg, int type) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xc2, 0xc0 | src_reg | (dst_reg << 3), type); /*CMPPS dst_reg, src_reg, type*/ +} + +void host_x86_COMISD_XREG_XREG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x2e, 0xc0 | src_reg_b | (src_reg_a << 3)); +} + +void host_x86_CVTDQ2PS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5b, 0xc0 | src_reg | (dst_reg << 3)); /*CVTDQ2PS dst_reg, src_reg*/ +} +void host_x86_CVTPS2DQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x5b, 0xc0 | src_reg | (dst_reg << 3)); /*CVTPS2DQ dst_reg, src_reg*/ +} + +void host_x86_CVTSD2SI_REG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x2d, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSD2SI dst_reg, src_reg*/ +} +void host_x86_CVTSD2SI_REG64_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf2, 0x48, 0x0f, 0x2d); /*CVTSD2SI dst_reg, src_reg*/ + codegen_addbyte(block, 0xc0 | src_reg | (dst_reg << 3)); +} +void host_x86_CVTSD2SS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5a, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_CVTSI2SD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x2a, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSI2SD dst_reg, src_reg*/ +} +void host_x86_CVTSI2SS_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x2a, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSI2SD dst_reg, src_reg*/ +} +void host_x86_CVTSI2SD_XREG_REG64(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf2, 0x48, 0x0f, 0x2a); /*CVTSI2SD dst_reg, src_reg*/ + codegen_addbyte(block, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_CVTSS2SD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x5a, 0xc0 | src_reg | (dst_reg << 3)); +} +void host_x86_CVTSS2SD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x5a, 0x04 | (dst_reg << 3)); /*CVTSS2SD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} + +void host_x86_DIVSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5e, 0xc0 | src_reg | (dst_reg << 3)); +} +void host_x86_DIVSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x5e, 0xc0 | src_reg | (dst_reg << 3)); /*DIVSS dst_reg, src_reg*/ +} + +void host_x86_LDMXCSR(codeblock_t *block, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xae, 0x50 | REG_EBP, offset); /*LDMXCSR offset[EBP]*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x0f, 0xae, 0x90 | REG_EBP); /*LDMXCSR offset[EBP]*/ + codegen_addlong(block, offset); + } + else + { + fatal("host_x86_LDMXCSR - out of range %p\n", p); + } +} + +void host_x86_MAXSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5f, 0xc0 | src_reg | (dst_reg << 3)); /*MAXSD dst_reg, src_reg*/ +} + +void host_x86_MOVD_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x7e, 0x04 | (src_reg << 3)); /*MOVD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVD_REG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x7e, 0xc0 | dst_reg | (src_reg << 3)); +} +void host_x86_MOVD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x6e, 0x04 | (dst_reg << 3)); /*MOVD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x6e, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_MOVQ_ABS_XREG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOVQ_ABS_REG reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x45 | (src_reg << 3)); /*MOVQ offset[EBP], src_reg*/ + codegen_addbyte(block, offset); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOVQ_ABS_REG - out of range %p\n", p); + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x04 | (src_reg << 3)); /*MOVQ [p], src_reg*/ + codegen_addbyte(block, 0x25); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(codeblock_t *block, uint32_t addr, int src_reg_a, int src_reg_b, int shift, int src_reg) +{ + if ((src_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) + fatal("host_x86_MOVQ_ABS_REG_REG_SHIFT_REG - bad reg\n"); + + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte3(block, 0x66, 0x0f, 0xd6); /*MOVQ addr[src_reg_a + src_reg_b << shift], XMMx*/ + codegen_addbyte3(block, 0x44 | (src_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6), addr & 0xff); + } + else + { + codegen_alloc_bytes(block, 9); + codegen_addbyte3(block, 0x66, 0x0f, 0xd6); /*MOVQ addr[src_reg_a + src_reg_b << shift], XMMx*/ + codegen_addbyte2(block, 0x84 | (src_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6)); + codegen_addlong(block, addr); + } +} + +void host_x86_MOVQ_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x04 | (src_reg << 3)); /*MOVD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVQ_BASE_OFFSET_XREG(codeblock_t *block, int base_reg, int offset, int src_reg) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x44 | (src_reg << 3)); /*MOVQ [RSP + offset], XMMx*/ + codegen_addbyte2(block, 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x40 | base_reg | (src_reg << 3)); /*MOVQ [base_reg + offset], XMMx*/ + codegen_addbyte(block, offset); + } + } + else + fatal("MOVQ_BASE_OFFSET_XREG - offset %i\n", offset); +} + +void host_x86_MOVQ_XREG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (dst_reg & 8) + fatal("host_x86_MOVQ_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x45 | (dst_reg << 3)); /*MOVQ offset[EBP], src_reg*/ + codegen_addbyte(block, offset); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOVQ_REG_ABS - out of range %p\n", p); + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x04 | (dst_reg << 3)); /*MOVQ [p], src_reg*/ + codegen_addbyte(block, 0x25); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int src_reg_a, int src_reg_b, int shift) +{ + if ((dst_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) + fatal("host_x86_MOVQ_REG_ABS_REG_REG_SHIFT - bad reg\n"); + + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte3(block, 0xf3, 0x0f, 0x7e); /*MOVQ XMMx, addr[src_reg_a + src_reg_b << shift]*/ + codegen_addbyte3(block, 0x44 | (dst_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6), addr & 0xff); + } + else + { + codegen_alloc_bytes(block, 9); + codegen_addbyte3(block, 0xf3, 0x0f, 0x7e); /*MOVQ XMMx, addr[src_reg_a + src_reg_b << shift]*/ + codegen_addbyte2(block, 0x84 | (dst_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6)); + codegen_addlong(block, addr); + } +} +void host_x86_MOVQ_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x04 | (dst_reg << 3)); /*MOVQ XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVQ_XREG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x44 | (dst_reg << 3)); /*MOVQ XMMx, [ESP + offset]*/ + codegen_addbyte2(block, 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x40 | base_reg | (dst_reg << 3)); /*MOVQ XMMx, [base_reg + offset]*/ + codegen_addbyte(block, offset); + } + } + else + fatal("MOVQ_REG_BASE_OFFSET - offset %i\n", offset); +} + +void host_x86_MOVQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0xc0 | src_reg | (dst_reg << 3)); /*MOVQ dst_reg, src_reg*/ +} + +void host_x86_MOVQ_REG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x48, 0x0f, 0x7e); /*MOVQ dst_reg, src_reg*/ + codegen_addbyte(block, 0xc0 | dst_reg | (src_reg << 3)); +} +void host_x86_MOVQ_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x48, 0x0f, 0x6e); /*MOVQ dst_reg, src_reg*/ + codegen_addbyte(block, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_MAXPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5f, 0xc0 | src_reg | (dst_reg << 3)); /*MAXPS dst_reg, src_reg*/ +} +void host_x86_MINPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5d, 0xc0 | src_reg | (dst_reg << 3)); /*MINPS dst_reg, src_reg*/ +} + +void host_x86_MULPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x59, 0xc0 | src_reg | (dst_reg << 3)); /*MULPS dst_reg, src_reg*/ +} +void host_x86_MULSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x59, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_PACKSSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x63, 0xc0 | src_reg | (dst_reg << 3)); /*PACKSSWB dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0x88 (move bits 64-95 to 32-63)*/ + codegen_addbyte(block, 0x88); +} +void host_x86_PACKSSDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x6b, 0xc0 | src_reg | (dst_reg << 3)); /*PACKSSDW dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0x88 (move bits 64-95 to 32-63)*/ + codegen_addbyte(block, 0x88); +} +void host_x86_PACKUSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x67, 0xc0 | src_reg | (dst_reg << 3)); /*PACKUSWB dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0x88 (move bits 64-95 to 32-63)*/ + codegen_addbyte(block, 0x88); +} + +void host_x86_PADDB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfc, 0xc0 | src_reg | (dst_reg << 3)); /*PADDB dst_reg, src_reg*/ +} +void host_x86_PADDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfd, 0xc0 | src_reg | (dst_reg << 3)); /*PADDW dst_reg, src_reg*/ +} +void host_x86_PADDD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfe, 0xc0 | src_reg | (dst_reg << 3)); /*PADDD dst_reg, src_reg*/ +} +void host_x86_PADDSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xec, 0xc0 | src_reg | (dst_reg << 3)); /*PADDSB dst_reg, src_reg*/ +} +void host_x86_PADDSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xed, 0xc0 | src_reg | (dst_reg << 3)); /*PADDSW dst_reg, src_reg*/ +} +void host_x86_PADDUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdc, 0xc0 | src_reg | (dst_reg << 3)); /*PADDUSB dst_reg, src_reg*/ +} +void host_x86_PADDUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdd, 0xc0 | src_reg | (dst_reg << 3)); /*PADDUSW dst_reg, src_reg*/ +} + +void host_x86_PAND_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdb, 0xc0 | src_reg | (dst_reg << 3)); /*PAND dst_reg, src_reg*/ +} +void host_x86_PANDN_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdf, 0xc0 | src_reg | (dst_reg << 3)); /*PANDN dst_reg, src_reg*/ +} +void host_x86_POR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xeb, 0xc0 | src_reg | (dst_reg << 3)); /*POR dst_reg, src_reg*/ +} +void host_x86_PXOR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xef, 0xc0 | src_reg | (dst_reg << 3)); /*PXOR dst_reg, src_reg*/ +} + +void host_x86_PCMPEQB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x74, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPEQB dst_reg, src_reg*/ +} +void host_x86_PCMPEQW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x75, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPEQW dst_reg, src_reg*/ +} +void host_x86_PCMPEQD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x76, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPEQD dst_reg, src_reg*/ +} +void host_x86_PCMPGTB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x64, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPGTB dst_reg, src_reg*/ +} +void host_x86_PCMPGTW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x65, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPGTW dst_reg, src_reg*/ +} +void host_x86_PCMPGTD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x66, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPGTD dst_reg, src_reg*/ +} + +void host_x86_PMADDWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xf5, 0xc0 | src_reg | (dst_reg << 3)); /*PMULLW dst_reg, src_reg*/ +} +void host_x86_PMULHW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xe5, 0xc0 | src_reg | (dst_reg << 3)); /*PMULLW dst_reg, src_reg*/ +} +void host_x86_PMULLW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xd5, 0xc0 | src_reg | (dst_reg << 3)); /*PMULLW dst_reg, src_reg*/ +} + +void host_x86_PSLLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x71, 0xc0 | 0x30 | dst_reg); /*PSLLW dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSLLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x72, 0xc0 | 0x30 | dst_reg); /*PSLLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSLLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x73, 0xc0 | 0x30 | dst_reg); /*PSLLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRAW_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x71, 0xc0 | 0x20 | dst_reg); /*PSRAW dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRAD_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x72, 0xc0 | 0x20 | dst_reg); /*PSRAD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRAQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x73, 0xc0 | 0x20 | dst_reg); /*PSRAD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x71, 0xc0 | 0x10 | dst_reg); /*PSRLW dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x72, 0xc0 | 0x10 | dst_reg); /*PSRLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x73, 0xc0 | 0x10 | dst_reg); /*PSRLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} + +void host_x86_PSUBB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xf8, 0xc0 | src_reg | (dst_reg << 3)); /*PADDB dst_reg, src_reg*/ +} +void host_x86_PSUBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xf9, 0xc0 | src_reg | (dst_reg << 3)); /*PADDW dst_reg, src_reg*/ +} +void host_x86_PSUBD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfa, 0xc0 | src_reg | (dst_reg << 3)); /*PADDD dst_reg, src_reg*/ +} +void host_x86_PSUBSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xe8, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBSB dst_reg, src_reg*/ +} +void host_x86_PSUBSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xe9, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBSW dst_reg, src_reg*/ +} +void host_x86_PSUBUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xd8, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBUSB dst_reg, src_reg*/ +} +void host_x86_PSUBUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xd9, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBUSW dst_reg, src_reg*/ +} + +void host_x86_PUNPCKHBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x60, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLBW dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0xee (move top 64-bits to low 64-bits)*/ + codegen_addbyte(block, 0xee); +} +void host_x86_PUNPCKHWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x61, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLWD dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0xee (move top 64-bits to low 64-bits)*/ + codegen_addbyte(block, 0xee); +} +void host_x86_PUNPCKHDQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x62, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLDQ dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0xee (move top 64-bits to low 64-bits)*/ + codegen_addbyte(block, 0xee); +} +void host_x86_PUNPCKLBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x60, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLBW dst_reg, src_reg*/ +} +void host_x86_PUNPCKLWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x61, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLWD dst_reg, src_reg*/ +} +void host_x86_PUNPCKLDQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x62, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLDQ dst_reg, src_reg*/ +} + +void host_x86_SQRTSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x51, 0xc0 | src_reg | (dst_reg << 3)); /*SQRTSD dst_reg, src_reg*/ +} +void host_x86_SQRTSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x51, 0xc0 | src_reg | (dst_reg << 3)); /*SQRTSS dst_reg, src_reg*/ +} + +void host_x86_SUBPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5c, 0xc0 | src_reg | (dst_reg << 3)); /*SUBPS dst_reg, src_reg*/ +} +void host_x86_SUBSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5c, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_UNPCKLPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x14, 0xc0 | src_reg | (dst_reg << 3)); +} + +#endif diff --git a/src/cpu_new/codegen_backend_x86-64_ops_sse.h b/src/cpu_new/codegen_backend_x86-64_ops_sse.h new file mode 100644 index 000000000..76bb5ae7f --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64_ops_sse.h @@ -0,0 +1,114 @@ +void host_x86_ADDPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_ADDSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +#define CMPPS_EQ 0 +#define CMPPS_NLT 5 +#define CMPPS_NLE 6 +void host_x86_CMPPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg, int type); + +void host_x86_COMISD_XREG_XREG(codeblock_t *block, int src_reg_a, int src_reg_b); + +void host_x86_CVTDQ2PS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTPS2DQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_CVTSD2SI_REG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSD2SI_REG64_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSD2SS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSI2SD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSI2SD_XREG_REG64(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSI2SS_XREG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSS2SD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSS2SD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); + +void host_x86_DIVSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_DIVSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_LDMXCSR(codeblock_t *block, void *p); + +void host_x86_MAXSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVD_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOVD_REG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); +void host_x86_MOVD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVQ_ABS_XREG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(codeblock_t *block, uint32_t addr, int src_reg_a, int src_reg_b, int shift, int src_reg); +void host_x86_MOVQ_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOVQ_BASE_OFFSET_XREG(codeblock_t *block, int base_reg, int offset, int src_reg); +void host_x86_MOVQ_XREG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int src_reg_a, int src_reg_b, int shift); +void host_x86_MOVQ_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); +void host_x86_MOVQ_XREG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); + +void host_x86_MOVQ_REG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVQ_XREG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MAXPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MINPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MULPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MULSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MULSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PACKSSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PACKSSDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PACKUSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PADDB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PAND_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PANDN_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_POR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PXOR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PCMPEQB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPEQW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPEQD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPGTB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPGTW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPGTD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PMADDWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PMULHW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PMULLW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PSLLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSLLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSLLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRAW_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRAD_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRAQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_PSUBB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PUNPCKHBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKHWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKHDQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKLBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKLWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKLDQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_SQRTSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SQRTSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_SUBPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SUBSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_UNPCKLPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); diff --git a/src/cpu_new/codegen_backend_x86-64_uops.c b/src/cpu_new/codegen_backend_x86-64_uops.c new file mode 100644 index 000000000..bff4e3775 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86-64_uops.c @@ -0,0 +1,3148 @@ +#ifdef __amd64__ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x87.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_backend_x86-64_defs.h" +#include "codegen_backend_x86-64_ops.h" +#include "codegen_backend_x86-64_ops_sse.h" +#include "codegen_ir_defs.h" + +#define STACK_ARG0 (0) +#define STACK_ARG1 (4) +#define STACK_ARG2 (8) +#define STACK_ARG3 (12) + +#define HOST_REG_GET(reg) ((IREG_GET_SIZE(reg) == IREG_SIZE_BH) ? (IREG_GET_REG((reg) & 3) | 4) : (IREG_GET_REG(reg) & 7)) + +#define REG_IS_L(size) (size == IREG_SIZE_L) +#define REG_IS_W(size) (size == IREG_SIZE_W) +#define REG_IS_B(size) (size == IREG_SIZE_B || size == IREG_SIZE_BH) +#define REG_IS_BH(size) (size == IREG_SIZE_BH) +#define REG_IS_D(size) (size == IREG_SIZE_D) +#define REG_IS_Q(size) (size == IREG_SIZE_Q) + +static int codegen_ADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_LEA_REG_REG(block, dest_reg, src_reg_a, src_reg_b); + else + host_x86_ADD32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_ADD16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_ADD8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (dest_reg != src_reg) + host_x86_LEA_REG_IMM(block, dest_reg, src_reg, uop->imm_data); + else + host_x86_ADD32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ADD16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ADD8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ADD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop) +{ + if (!uop->imm_data) + { + if (uop->dest_reg_a_real == uop->src_reg_a_real) + host_x86_ADD32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_b_real); + else + host_x86_LEA_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + } + else if (uop->imm_data < 4) + host_x86_LEA_REG_REG_SHIFT(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data); +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_ADD_LSHIFT - shift out of range %i\n", uop->imm_data); +#endif + return 0; +} + +static int codegen_AND(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PAND_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg_a); + host_x86_AND32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_AND16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_AND8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("AND %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_AND32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_AND16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_AND8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("AND_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_ANDN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), /*src_reg_a = HOST_REG_GET(uop->src_reg_a_real), */src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PANDN_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ANDN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_CALL_FUNC(codeblock_t *block, uop_t *uop) +{ + host_x86_CALL(block, uop->p); + + return 0; +} + +static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + /* int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); */ + +#ifdef RECOMPILER_DEBUG + if (!REG_IS_L(dest_size)) + fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real); +#endif + host_x86_CALL(block, uop->p); + host_x86_MOV32_REG_REG(block, dest_reg, REG_EAX); + + return 0; +} + +static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) +{ + host_x86_CALL(block, uop->p); + host_x86_TEST32_REG(block, REG_EAX, REG_EAX); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real); +#endif + host_x86_JZ(block, uop->p); + + return 0; +} + +static int codegen_CMP_IMM_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_x86_CMP16_REG_IMM(block, src_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_IMM_JNZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNZ_long(block); + + return 0; +} +static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_x86_CMP16_REG_IMM(block, src_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JZ_long(block); + + return 0; +} + +static int codegen_CMP_JB(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JB %02x\n", uop->src_reg_a_real); +#endif + jump_p = host_x86_JB_long(block); + *jump_p = (uintptr_t)uop->p - ((uintptr_t)jump_p + 4); + + return 0; +} +static int codegen_CMP_JNBE(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNBE %02x\n", uop->src_reg_a_real); +#endif + jump_p = host_x86_JNBE_long(block); + *jump_p = (uintptr_t)uop->p - ((uintptr_t)jump_p + 4); + + return 0; +} + +static int codegen_CMP_JNB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNB_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNB_long(block); + + return 0; +} +static int codegen_CMP_JNBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNBE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNBE_long(block); + + return 0; +} +static int codegen_CMP_JNL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNL_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNL_long(block); + + return 0; +} +static int codegen_CMP_JNLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNLE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNLE_long(block); + + return 0; +} +static int codegen_CMP_JNO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNO_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNO_long(block); + + return 0; +} +static int codegen_CMP_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNZ_long(block); + + return 0; +} +static int codegen_CMP_JB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JB_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JB_long(block); + + return 0; +} +static int codegen_CMP_JBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JBE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JBE_long(block); + + return 0; +} +static int codegen_CMP_JL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JL_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JL_long(block); + + return 0; +} +static int codegen_CMP_JLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JLE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JLE_long(block); + + return 0; +} +static int codegen_CMP_JO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JO_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JO_long(block); + + return 0; +} +static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JZ_long(block); + + return 0; +} + +static int codegen_FABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && dest_reg == src_reg_a) + { + host_x86_PXOR_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + host_x86_SUBSD_XREG_XREG(block, REG_XMM_TEMP, dest_reg); + host_x86_MAXSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FABS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_FCHS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_PXOR_XREG_XREG(block, dest_reg, dest_reg); + host_x86_SUBSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FCHS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_FSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_SQRTSD_XREG_XREG(block, dest_reg, src_reg_a); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FSQRT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_FTST(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_PXOR_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + if (dest_reg != REG_EAX) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX); + host_x86_COMISD_XREG_XREG(block, src_reg_a, REG_XMM_TEMP); + host_x86_LAHF(block); + host_x86_AND16_REG_IMM(block, REG_EAX, C0|C2|C3); + if (dest_reg != REG_EAX) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX); + host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX); + } + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_FADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_ADDSD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FCOM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + if (dest_reg != REG_EAX) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX); + host_x86_COMISD_XREG_XREG(block, src_reg_a, src_reg_b); + host_x86_LAHF(block); + host_x86_AND16_REG_IMM(block, REG_EAX, C0|C2|C3); + if (dest_reg != REG_EAX) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX); + host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX); + } + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FCOM %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FDIV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_DIVSD_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_DIVSD_XREG_XREG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FDIV %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_MULSD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_SUBSD_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_SUBSD_XREG_XREG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_offset; + + host_x86_MOV32_REG_ABS(block, REG_ECX, &cr0); + host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); + branch_offset = host_x86_JZ_long(block); + host_x86_MOV32_ABS_IMM(block, &cpu_state.oldpc, uop->imm_data); +#if WIN64 + host_x86_MOV32_REG_IMM(block, REG_ECX, 7); +#else + host_x86_MOV32_REG_IMM(block, REG_EDI, 7); +#endif + host_x86_CALL(block, x86_int); + host_x86_JMP(block, codegen_exit_rout); + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; + + return 0; +} +static int codegen_MMX_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_offset; + + host_x86_MOV32_REG_ABS(block, REG_ECX, &cr0); + host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); + branch_offset = host_x86_JZ_long(block); + host_x86_MOV32_ABS_IMM(block, &cpu_state.oldpc, uop->imm_data); +#if WIN64 + host_x86_MOV32_REG_IMM(block, REG_ECX, 7); +#else + host_x86_MOV32_REG_IMM(block, REG_EDI, 7); +#endif + host_x86_CALL(block, x86_int); + host_x86_JMP(block, codegen_exit_rout); + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; + host_x86_MOV32_ABS_IMM(block, &cpu_state.tag[0], 0x01010101); + host_x86_MOV32_ABS_IMM(block, &cpu_state.tag[4], 0x01010101); + host_x86_MOV32_ABS_IMM(block, &cpu_state.TOP, 0); + host_x86_MOV8_ABS_IMM(block, &cpu_state.ismmx, 1); + + return 0; +} + +static int codegen_JMP(codeblock_t *block, uop_t *uop) +{ + host_x86_JMP(block, uop->p); + + return 0; +} + +static int codegen_LOAD_FUNC_ARG0(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(src_size)) + { +#if WIN64 + host_x86_MOVZX_REG_32_16(block, REG_ECX, src_reg); +#else + host_x86_MOVZX_REG_32_16(block, REG_EDI, src_reg); +#endif + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_LOAD_FUNC_ARG0 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG1(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG1 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG2(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG2 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG3(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG3 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) +{ +#if WIN64 + host_x86_MOV32_REG_IMM(block, REG_ECX, uop->imm_data); +#else + host_x86_MOV32_REG_IMM(block, REG_EDI, uop->imm_data); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG1_IMM(codeblock_t *block, uop_t *uop) +{ +#if WIN64 + host_x86_MOV32_REG_IMM(block, REG_EDX, uop->imm_data); +#else + host_x86_MOV32_REG_IMM(block, REG_ESI, uop->imm_data); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG2_IMM(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG2_IMM\n"); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG3_IMM\n"); +#endif + return 0; +} + +static int codegen_LOAD_SEG(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + /* int src_size = IREG_GET_SIZE(uop->src_reg_a_real); */ + +#ifdef RECOMPILER_DEBUG + if (!REG_IS_W(src_size)) + fatal("LOAD_SEG %02x %p\n", uop->src_reg_a_real, uop->p); +#endif +#if WIN64 + host_x86_MOV16_REG_REG(block, REG_CX, src_reg); + host_x86_MOV64_REG_IMM(block, REG_EDX, (uint64_t)uop->p); +#else + host_x86_MOV16_REG_REG(block, REG_DI, src_reg); + host_x86_MOV64_REG_IMM(block, REG_ESI, (uint64_t)uop->p); +#endif + host_x86_CALL(block, (void *)loadseg); + host_x86_TEST32_REG(block, REG_EAX, REG_EAX); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_LOAD_ABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_x86_LEA_REG_IMM(block, REG_ESI, seg_reg, uop->imm_data); + if (REG_IS_B(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_long); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, REG_ECX); + } + + return 0; +} +static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + if (REG_IS_B(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_long); + } + else if (REG_IS_Q(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_quad); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_LOAD_REG - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_Q(dest_size)) + { + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } + + return 0; +} +static int codegen_MEM_LOAD_SINGLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + /* int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); */ + +#ifdef RECOMPILER_DEBUG + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_SINGLE - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_CALL(block, codegen_mem_load_single); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + + return 0; +} +static int codegen_MEM_LOAD_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + /* int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); */ + +#ifdef RECOMPILER_DEBUG + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_DOUBLE - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_CALL(block, codegen_mem_load_double); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + + return 0; +} + +static int codegen_MEM_STORE_ABS(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_b_real); + int src_size = IREG_GET_SIZE(uop->src_reg_b_real); + + host_x86_LEA_REG_IMM(block, REG_ESI, seg_reg, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_long); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_STORE_ABS - %02x\n", uop->src_reg_b_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_IMM_8(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV8_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_byte); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_16(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV16_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_word); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_32(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV32_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_long); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_long); + } + else if (REG_IS_Q(src_size)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg); + host_x86_CALL(block, codegen_mem_store_quad); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_STORE_REG - %02x\n", uop->src_reg_b_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_SINGLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + /* int src_size = IREG_GET_SIZE(uop->src_reg_c_real); */ + +#ifdef RECOMPILER_DEBUG + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_SINGLE - %02x\n", uop->src_reg_b_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_CVTSD2SS_XREG_XREG(block, REG_XMM_TEMP, src_reg); + host_x86_CALL(block, codegen_mem_store_single); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + /* int src_size = IREG_GET_SIZE(uop->src_reg_c_real); */ + +#ifdef RECOMPILER_DEBUG + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_DOUBLE - %02x\n", uop->src_reg_b_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg); + host_x86_CALL(block, codegen_mem_store_double); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MOV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size)) + { + host_x86_MOVQ_XREG_XREG(block, dest_reg, src_reg); + } + else if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + host_x86_MOVQ_XREG_XREG(block, dest_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_IMM %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_PTR(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV64_REG_IMM(block, uop->dest_reg_a_real, (uint64_t)uop->p); + return 0; +} +static int codegen_MOV_REG_PTR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_ABS(block, dest_reg, uop->p); + } + else + fatal("MOV_REG_PTR %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_8(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOVZX_REG_ABS_32_8(block, dest_reg, uop->p); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOVZX_REG_ABS_16_8(block, dest_reg, uop->p); + } + else if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_ABS(block, dest_reg, uop->p); + } + else + fatal("MOVZX_REG_PTR_8 %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_16(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOVZX_REG_ABS_32_16(block, dest_reg, uop->p); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_ABS(block, dest_reg, uop->p); + } + else + fatal("MOVZX_REG_PTR_16 %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVSX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOVSX_REG_32_16(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVSX_REG_32_8(block, dest_reg, src_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVSX_REG_16_8(block, dest_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOVSX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOVZX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_L(src_size)) + { + host_x86_MOVD_XREG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_Q(src_size)) + { + host_x86_MOVD_REG_XREG(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOVZX_REG_32_16(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVZX_REG_32_8(block, dest_reg, src_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVZX_REG_16_8(block, dest_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOVZX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_MOV_DOUBLE_INT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_L(src_size)) + { + host_x86_CVTSI2SD_XREG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_D(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOVSX_REG_32_16(block, REG_ECX, src_reg); + host_x86_CVTSI2SD_XREG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_D(dest_size) && REG_IS_Q(src_size)) + { + host_x86_MOVQ_REG_XREG(block, REG_RCX, src_reg); + host_x86_CVTSI2SD_XREG_REG64(block, dest_reg, REG_RCX); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_DOUBLE_INT %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_INT_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_D(src_size)) + { + host_x86_LDMXCSR(block, &cpu_state.new_fp_control); + host_x86_CVTSD2SI_REG_XREG(block, dest_reg, src_reg); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + } + else if (REG_IS_W(dest_size) && REG_IS_D(src_size)) + { + host_x86_LDMXCSR(block, &cpu_state.new_fp_control); + host_x86_CVTSD2SI_REG_XREG(block, REG_ECX, src_reg); + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_INT_DOUBLE %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_INT_DOUBLE_64(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), src_64_reg = HOST_REG_GET(uop->src_reg_b_real), tag_reg = HOST_REG_GET(uop->src_reg_c_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real), src_64_size = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_D(src_size) && REG_IS_Q(src_64_size)) + { + uint32_t *branch_offset; + + /*If TAG_UINT64 is set then the source is MM[]. Otherwise it is a double in ST()*/ + host_x86_MOVQ_XREG_XREG(block, dest_reg, src_64_reg); + host_x86_TEST8_REG(block, tag_reg, tag_reg); + branch_offset = host_x86_JS_long(block); + + host_x86_LDMXCSR(block, &cpu_state.new_fp_control); + host_x86_CVTSD2SI_REG64_XREG(block, REG_RCX, src_reg); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + host_x86_MOVQ_XREG_REG(block, dest_reg, REG_RCX); + + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_INT_DOUBLE_64 %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_NOP(codeblock_t *block, uop_t *uop) +{ + return 0; +} + +static int codegen_OR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_POR_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg_a); + host_x86_OR32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_OR16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_OR8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("OR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_OR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real)/*, src_reg = HOST_REG_GET(uop->src_reg_a_real)*/; + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_x86_OR32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_x86_OR16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_x86_OR8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("OR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_PACKSSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PACKSSWB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PACKSSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PACKSSDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PACKSSDW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PACKSSDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PACKUSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PACKUSWB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PACKUSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PADDB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDUSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDUSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PCMPEQB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPEQB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPEQB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPEQW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPEQW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPEQW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPEQD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPEQD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPEQD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPGTB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPGTB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPGTB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPGTW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPGTW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPGTW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPGTD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPGTD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPGTD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PF2ID(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_x86_LDMXCSR(block, &cpu_state.trunc_fp_control); + host_x86_CVTPS2DQ_XREG_XREG(block, dest_reg, src_reg_a); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PF2ID %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_PFADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_ADDPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFCMPEQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_CMPPS_XREG_XREG(block, dest_reg, src_reg_b, CMPPS_EQ); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFCMPEQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFCMPGE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_CMPPS_XREG_XREG(block, dest_reg, src_reg_b, CMPPS_NLT); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFCMPGE %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFCMPGT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_CMPPS_XREG_XREG(block, dest_reg, src_reg_b, CMPPS_NLE); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFCMPGT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFMAX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_MAXPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFMAX %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFMIN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_MINPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFMIN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_MULPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFRCP(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use RCPSS + iteration)*/ + host_x86_MOV32_REG_IMM(block, REG_ECX, 1); + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_CVTSI2SS_XREG_REG(block, dest_reg, REG_ECX); + host_x86_DIVSS_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + host_x86_UNPCKLPS_XREG_XREG(block, dest_reg, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFRCP %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_PFRSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use RSQRTSS + iteration)*/ + host_x86_SQRTSS_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_MOV32_REG_IMM(block, REG_ECX, 1); + host_x86_CVTSI2SS_XREG_REG(block, dest_reg, REG_ECX); + host_x86_DIVSS_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + host_x86_UNPCKLPS_XREG_XREG(block, dest_reg, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFRSQRT %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_PFSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_SUBPS_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_SUBPS_XREG_XREG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PI2FD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_x86_CVTDQ2PS_XREG_XREG(block, dest_reg, src_reg_a); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PI2FD %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} + +static int codegen_PMADDWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PMADDWD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PMULHW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PMULHW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PMULLW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PMULLW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PMULLW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PSLLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSLLW_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSLLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSLLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSLLD_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSLLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSLLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSLLQ_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSLLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRAW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRAW_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRAW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRAD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRAD_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRAD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRAQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRAQ_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRAQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRLW_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRLD_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRLQ_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_PSUBB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBUSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBUSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PUNPCKHBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKHBW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKHBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKHWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKHWD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKHWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKHDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKHDQ_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKHDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKLBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLBW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKLBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKLWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLWD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKLWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKLDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLDQ_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKLDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_ROL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROL32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROL16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROL8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_ROL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROL32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROL16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROL8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_ROR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROR32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROR16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROR8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_ROR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROR32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROR16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROR8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_SAR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SAR32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SAR16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SAR8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SAR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SAR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SAR32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SAR16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SAR8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SAR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHL32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHL16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHL8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHL32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHL16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHL8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHR32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHR16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHR8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHR32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHR16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHR8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_STORE_PTR_IMM(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + if (((uintptr_t)uop->p) >> 32) + fatal("STORE_PTR_IMM 64-bit addr\n"); +#endif + host_x86_MOV32_ABS_IMM(block, uop->p, uop->imm_data); + return 0; +} +static int codegen_STORE_PTR_IMM_8(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + if (((uintptr_t)uop->p) >> 32) + fatal("STORE_PTR_IMM_8 64-bit addr\n"); +#endif + host_x86_MOV8_ABS_IMM(block, uop->p, uop->imm_data); + return 0; +} + +static int codegen_SUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg_a); + host_x86_SUB32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_SUB16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_SUB8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_SUB_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SUB32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SUB16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SUB8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SUB_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_TEST_JNS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_TEST32_REG(block, src_reg, src_reg); + } + else if (REG_IS_W(src_size)) + { + host_x86_TEST16_REG(block, src_reg, src_reg); + } + else if (REG_IS_B(src_size)) + { + host_x86_TEST8_REG(block, src_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("TEST_JNS_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNS_long(block); + + return 0; +} +static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_TEST32_REG(block, src_reg, src_reg); + } + else if (REG_IS_W(src_size)) + { + host_x86_TEST16_REG(block, src_reg, src_reg); + } + else if (REG_IS_B(src_size)) + { + host_x86_TEST8_REG(block, src_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("TEST_JS_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JS_long(block); + + return 0; +} + +static int codegen_XOR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real)/*, src_reg_a = HOST_REG_GET(uop->src_reg_a_real)*/, src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PXOR_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("XOR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real)/*, src_reg = HOST_REG_GET(uop->src_reg_a_real)*/; + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_x86_XOR32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_x86_XOR16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_x86_XOR8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("XOR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +const uOpFn uop_handlers[UOP_MAX] = +{ + [UOP_CALL_FUNC & UOP_MASK] = codegen_CALL_FUNC, + [UOP_CALL_FUNC_RESULT & UOP_MASK] = codegen_CALL_FUNC_RESULT, + [UOP_CALL_INSTRUCTION_FUNC & UOP_MASK] = codegen_CALL_INSTRUCTION_FUNC, + + [UOP_JMP & UOP_MASK] = codegen_JMP, + + [UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG, + + [UOP_LOAD_FUNC_ARG_0 & UOP_MASK] = codegen_LOAD_FUNC_ARG0, + [UOP_LOAD_FUNC_ARG_1 & UOP_MASK] = codegen_LOAD_FUNC_ARG1, + [UOP_LOAD_FUNC_ARG_2 & UOP_MASK] = codegen_LOAD_FUNC_ARG2, + [UOP_LOAD_FUNC_ARG_3 & UOP_MASK] = codegen_LOAD_FUNC_ARG3, + + [UOP_LOAD_FUNC_ARG_0_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG0_IMM, + [UOP_LOAD_FUNC_ARG_1_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG1_IMM, + [UOP_LOAD_FUNC_ARG_2_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG2_IMM, + [UOP_LOAD_FUNC_ARG_3_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG3_IMM, + + [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, + [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, + [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, + [UOP_MEM_LOAD_SINGLE & UOP_MASK] = codegen_MEM_LOAD_SINGLE, + [UOP_MEM_LOAD_DOUBLE & UOP_MASK] = codegen_MEM_LOAD_DOUBLE, + + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, + [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, + [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, + [UOP_MEM_STORE_IMM_16 & UOP_MASK] = codegen_MEM_STORE_IMM_16, + [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, + [UOP_MEM_STORE_SINGLE & UOP_MASK] = codegen_MEM_STORE_SINGLE, + [UOP_MEM_STORE_DOUBLE & UOP_MASK] = codegen_MEM_STORE_DOUBLE, + + [UOP_MOV & UOP_MASK] = codegen_MOV, + [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, + [UOP_MOVSX & UOP_MASK] = codegen_MOVSX, + [UOP_MOVZX & UOP_MASK] = codegen_MOVZX, + [UOP_MOV_DOUBLE_INT & UOP_MASK] = codegen_MOV_DOUBLE_INT, + [UOP_MOV_INT_DOUBLE & UOP_MASK] = codegen_MOV_INT_DOUBLE, + [UOP_MOV_INT_DOUBLE_64 & UOP_MASK] = codegen_MOV_INT_DOUBLE_64, + [UOP_MOV_REG_PTR & UOP_MASK] = codegen_MOV_REG_PTR, + [UOP_MOVZX_REG_PTR_8 & UOP_MASK] = codegen_MOVZX_REG_PTR_8, + [UOP_MOVZX_REG_PTR_16 & UOP_MASK] = codegen_MOVZX_REG_PTR_16, + + [UOP_ADD & UOP_MASK] = codegen_ADD, + [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, + [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, + [UOP_AND & UOP_MASK] = codegen_AND, + [UOP_ANDN & UOP_MASK] = codegen_ANDN, + [UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM, + [UOP_OR & UOP_MASK] = codegen_OR, + [UOP_OR_IMM & UOP_MASK] = codegen_OR_IMM, + [UOP_SUB & UOP_MASK] = codegen_SUB, + [UOP_SUB_IMM & UOP_MASK] = codegen_SUB_IMM, + [UOP_XOR & UOP_MASK] = codegen_XOR, + [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM, + + [UOP_SAR & UOP_MASK] = codegen_SAR, + [UOP_SAR_IMM & UOP_MASK] = codegen_SAR_IMM, + [UOP_SHL & UOP_MASK] = codegen_SHL, + [UOP_SHL_IMM & UOP_MASK] = codegen_SHL_IMM, + [UOP_SHR & UOP_MASK] = codegen_SHR, + [UOP_SHR_IMM & UOP_MASK] = codegen_SHR_IMM, + [UOP_ROL & UOP_MASK] = codegen_ROL, + [UOP_ROL_IMM & UOP_MASK] = codegen_ROL_IMM, + [UOP_ROR & UOP_MASK] = codegen_ROR, + [UOP_ROR_IMM & UOP_MASK] = codegen_ROR_IMM, + + [UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ, + + [UOP_CMP_JB & UOP_MASK] = codegen_CMP_JB, + [UOP_CMP_JNBE & UOP_MASK] = codegen_CMP_JNBE, + + [UOP_CMP_JNB_DEST & UOP_MASK] = codegen_CMP_JNB_DEST, + [UOP_CMP_JNBE_DEST & UOP_MASK] = codegen_CMP_JNBE_DEST, + [UOP_CMP_JNL_DEST & UOP_MASK] = codegen_CMP_JNL_DEST, + [UOP_CMP_JNLE_DEST & UOP_MASK] = codegen_CMP_JNLE_DEST, + [UOP_CMP_JNO_DEST & UOP_MASK] = codegen_CMP_JNO_DEST, + [UOP_CMP_JNZ_DEST & UOP_MASK] = codegen_CMP_JNZ_DEST, + [UOP_CMP_JB_DEST & UOP_MASK] = codegen_CMP_JB_DEST, + [UOP_CMP_JBE_DEST & UOP_MASK] = codegen_CMP_JBE_DEST, + [UOP_CMP_JL_DEST & UOP_MASK] = codegen_CMP_JL_DEST, + [UOP_CMP_JLE_DEST & UOP_MASK] = codegen_CMP_JLE_DEST, + [UOP_CMP_JO_DEST & UOP_MASK] = codegen_CMP_JO_DEST, + [UOP_CMP_JZ_DEST & UOP_MASK] = codegen_CMP_JZ_DEST, + + [UOP_CMP_IMM_JNZ_DEST & UOP_MASK] = codegen_CMP_IMM_JNZ_DEST, + [UOP_CMP_IMM_JZ_DEST & UOP_MASK] = codegen_CMP_IMM_JZ_DEST, + + [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, + [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, + + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, + [UOP_MMX_ENTER & UOP_MASK] = codegen_MMX_ENTER, + + [UOP_FADD & UOP_MASK] = codegen_FADD, + [UOP_FCOM & UOP_MASK] = codegen_FCOM, + [UOP_FDIV & UOP_MASK] = codegen_FDIV, + [UOP_FMUL & UOP_MASK] = codegen_FMUL, + [UOP_FSUB & UOP_MASK] = codegen_FSUB, + + [UOP_FABS & UOP_MASK] = codegen_FABS, + [UOP_FCHS & UOP_MASK] = codegen_FCHS, + [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, + [UOP_FTST & UOP_MASK] = codegen_FTST, + + [UOP_PACKSSWB & UOP_MASK] = codegen_PACKSSWB, + [UOP_PACKSSDW & UOP_MASK] = codegen_PACKSSDW, + [UOP_PACKUSWB & UOP_MASK] = codegen_PACKUSWB, + + [UOP_PADDB & UOP_MASK] = codegen_PADDB, + [UOP_PADDW & UOP_MASK] = codegen_PADDW, + [UOP_PADDD & UOP_MASK] = codegen_PADDD, + [UOP_PADDSB & UOP_MASK] = codegen_PADDSB, + [UOP_PADDSW & UOP_MASK] = codegen_PADDSW, + [UOP_PADDUSB & UOP_MASK] = codegen_PADDUSB, + [UOP_PADDUSW & UOP_MASK] = codegen_PADDUSW, + + [UOP_PCMPEQB & UOP_MASK] = codegen_PCMPEQB, + [UOP_PCMPEQW & UOP_MASK] = codegen_PCMPEQW, + [UOP_PCMPEQD & UOP_MASK] = codegen_PCMPEQD, + [UOP_PCMPGTB & UOP_MASK] = codegen_PCMPGTB, + [UOP_PCMPGTW & UOP_MASK] = codegen_PCMPGTW, + [UOP_PCMPGTD & UOP_MASK] = codegen_PCMPGTD, + + [UOP_PF2ID & UOP_MASK] = codegen_PF2ID, + [UOP_PFADD & UOP_MASK] = codegen_PFADD, + [UOP_PFCMPEQ & UOP_MASK] = codegen_PFCMPEQ, + [UOP_PFCMPGE & UOP_MASK] = codegen_PFCMPGE, + [UOP_PFCMPGT & UOP_MASK] = codegen_PFCMPGT, + [UOP_PFMAX & UOP_MASK] = codegen_PFMAX, + [UOP_PFMIN & UOP_MASK] = codegen_PFMIN, + [UOP_PFMUL & UOP_MASK] = codegen_PFMUL, + [UOP_PFRCP & UOP_MASK] = codegen_PFRCP, + [UOP_PFRSQRT & UOP_MASK] = codegen_PFRSQRT, + [UOP_PFSUB & UOP_MASK] = codegen_PFSUB, + [UOP_PI2FD & UOP_MASK] = codegen_PI2FD, + + [UOP_PMADDWD & UOP_MASK] = codegen_PMADDWD, + [UOP_PMULHW & UOP_MASK] = codegen_PMULHW, + [UOP_PMULLW & UOP_MASK] = codegen_PMULLW, + + [UOP_PSLLW_IMM & UOP_MASK] = codegen_PSLLW_IMM, + [UOP_PSLLD_IMM & UOP_MASK] = codegen_PSLLD_IMM, + [UOP_PSLLQ_IMM & UOP_MASK] = codegen_PSLLQ_IMM, + [UOP_PSRAW_IMM & UOP_MASK] = codegen_PSRAW_IMM, + [UOP_PSRAD_IMM & UOP_MASK] = codegen_PSRAD_IMM, + [UOP_PSRAQ_IMM & UOP_MASK] = codegen_PSRAQ_IMM, + [UOP_PSRLW_IMM & UOP_MASK] = codegen_PSRLW_IMM, + [UOP_PSRLD_IMM & UOP_MASK] = codegen_PSRLD_IMM, + [UOP_PSRLQ_IMM & UOP_MASK] = codegen_PSRLQ_IMM, + + [UOP_PSUBB & UOP_MASK] = codegen_PSUBB, + [UOP_PSUBW & UOP_MASK] = codegen_PSUBW, + [UOP_PSUBD & UOP_MASK] = codegen_PSUBD, + [UOP_PSUBSB & UOP_MASK] = codegen_PSUBSB, + [UOP_PSUBSW & UOP_MASK] = codegen_PSUBSW, + [UOP_PSUBUSB & UOP_MASK] = codegen_PSUBUSB, + [UOP_PSUBUSW & UOP_MASK] = codegen_PSUBUSW, + + [UOP_PUNPCKHBW & UOP_MASK] = codegen_PUNPCKHBW, + [UOP_PUNPCKHWD & UOP_MASK] = codegen_PUNPCKHWD, + [UOP_PUNPCKHDQ & UOP_MASK] = codegen_PUNPCKHDQ, + [UOP_PUNPCKLBW & UOP_MASK] = codegen_PUNPCKLBW, + [UOP_PUNPCKLWD & UOP_MASK] = codegen_PUNPCKLWD, + [UOP_PUNPCKLDQ & UOP_MASK] = codegen_PUNPCKLDQ, + + [UOP_NOP_BARRIER & UOP_MASK] = codegen_NOP +}; + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV8_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV16_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV32_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_64(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOVQ_XREG_ABS(block, host_reg, p); +} +void codegen_direct_read_pointer(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV64_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOVQ_XREG_ABS(block, host_reg, p); +} +void codegen_direct_read_st_8(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOV8_REG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_RBP, REG_ECX, 0); +} +void codegen_direct_read_st_64(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_RBP, REG_ECX, 3); +} +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_RBP, REG_ECX, 3); +} + +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV8_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_16(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV16_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV32_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_64(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOVQ_ABS_XREG(block, p, host_reg); +} +void codegen_direct_write_pointer(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV64_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOVQ_ABS_XREG(block, p, host_reg); +} +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOV8_ABS_REG_REG_SHIFT_REG(block, offset, REG_RBP, REG_ECX, 0, host_reg); +} +void codegen_direct_write_st_64(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(block, offset, REG_RBP, REG_ECX, 3, host_reg); +} +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(block, offset, REG_RBP, REG_ECX, 3, host_reg); +} + +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV64_ABS_REG(block, p, host_reg); +} + +void codegen_direct_read_16_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOV16_REG_BASE_OFFSET(block, host_reg, REG_ESP, stack_offset); +} +void codegen_direct_read_32_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOV32_REG_BASE_OFFSET(block, host_reg, REG_RSP, stack_offset); +} +void codegen_direct_read_64_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOVQ_XREG_BASE_OFFSET(block, host_reg, REG_RSP, stack_offset); +} +void codegen_direct_read_pointer_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOV64_REG_BASE_OFFSET(block, host_reg, REG_RSP, stack_offset); +} +void codegen_direct_read_double_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOVQ_XREG_BASE_OFFSET(block, host_reg, REG_RSP, stack_offset); +} + +void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOV32_BASE_OFFSET_REG(block, REG_RSP, stack_offset, host_reg); +} +void codegen_direct_write_64_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOVQ_BASE_OFFSET_XREG(block, REG_RSP, stack_offset, host_reg); +} +void codegen_direct_write_pointer_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOV64_BASE_OFFSET_REG(block, REG_RSP, stack_offset, host_reg); +} +void codegen_direct_write_double_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOVQ_BASE_OFFSET_XREG(block, REG_RSP, stack_offset, host_reg); +} + +void codegen_set_jump_dest(codeblock_t *block, void *p) +{ + *(uint32_t *)p = (uintptr_t)&block_write_data[block_pos] - ((uintptr_t)p + 4); +} + +#endif diff --git a/src/cpu_new/codegen_backend_x86.c b/src/cpu_new/codegen_backend_x86.c new file mode 100644 index 000000000..d83d99af0 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86.c @@ -0,0 +1,351 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops.h" +#include "codegen_backend_x86_ops_sse.h" +#include "codegen_reg.h" +#include "x86.h" + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +void *codegen_mem_load_byte; +void *codegen_mem_load_word; +void *codegen_mem_load_long; +void *codegen_mem_load_quad; +void *codegen_mem_load_single; +void *codegen_mem_load_double; + +void *codegen_mem_store_byte; +void *codegen_mem_store_word; +void *codegen_mem_store_long; +void *codegen_mem_store_quad; +void *codegen_mem_store_single; +void *codegen_mem_store_double; + +void *codegen_gpf_rout; +void *codegen_exit_rout; + +host_reg_def_t codegen_host_reg_list[CODEGEN_HOST_REGS] = +{ + /*Note: while EAX and EDX are normally volatile registers under x86 + calling conventions, the recompiler will explicitly save and restore + them across funcion calls*/ + {REG_EAX, 0}, + {REG_EBX, 0}, + {REG_EDX, 0} +}; + +host_reg_def_t codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = +{ + {REG_XMM0, HOST_REG_FLAG_VOLATILE}, + {REG_XMM1, HOST_REG_FLAG_VOLATILE}, + {REG_XMM2, HOST_REG_FLAG_VOLATILE}, + {REG_XMM3, HOST_REG_FLAG_VOLATILE}, + {REG_XMM4, HOST_REG_FLAG_VOLATILE}, + {REG_XMM5, HOST_REG_FLAG_VOLATILE} +}; + +static void build_load_routine(codeblock_t *block, int size, int is_float) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset = NULL; + + /*In - ESI = address + Out - ECX = data, ESI = abrt*/ + /*MOV ECX, ESI + SHR ESI, 12 + MOV ESI, [readlookup2+ESI*4] + CMP ESI, -1 + JNZ + + MOVZX ECX, B[ESI+ECX] + XOR ESI,ESI + RET + * PUSH EAX + PUSH EDX + PUSH ECX + CALL readmembl + POP ECX + POP EDX + POP EAX + MOVZX ECX, AL + RET + */ + host_x86_MOV32_REG_REG(block, REG_ECX, REG_ESI); + host_x86_SHR32_IMM(block, REG_ESI, 12); + host_x86_MOV32_REG_ABS_INDEX_SHIFT(block, REG_ESI, readlookup2, REG_ESI, 2); + if (size != 1) + { + host_x86_TEST32_REG_IMM(block, REG_ECX, size-1); + misaligned_offset = host_x86_JNZ_short(block); + } + host_x86_CMP32_REG_IMM(block, REG_ESI, (uint32_t)-1); + branch_offset = host_x86_JZ_short(block); + if (size == 1 && !is_float) + host_x86_MOVZX_BASE_INDEX_32_8(block, REG_ECX, REG_ESI, REG_ECX); + else if (size == 2 && !is_float) + host_x86_MOVZX_BASE_INDEX_32_16(block, REG_ECX, REG_ESI, REG_ECX); + else if (size == 4 && !is_float) + host_x86_MOV32_REG_BASE_INDEX(block, REG_ECX, REG_ESI, REG_ECX); + else if (size == 4 && is_float) + host_x86_CVTSS2SD_XREG_BASE_INDEX(block, REG_XMM_TEMP, REG_ESI, REG_ECX); + else if (size == 8) + host_x86_MOVQ_XREG_BASE_INDEX(block, REG_XMM_TEMP, REG_ESI, REG_ECX); + else + fatal("build_load_routine: size=%i\n", size); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI); + host_x86_RET(block); + + *branch_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 1; + if (size != 1) + *misaligned_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 1; + host_x86_PUSH(block, REG_EAX); + host_x86_PUSH(block, REG_EDX); + host_x86_PUSH(block, REG_ECX); + if (size == 1) + host_x86_CALL(block, (void *)readmembl); + else if (size == 2) + host_x86_CALL(block, (void *)readmemwl); + else if (size == 4) + host_x86_CALL(block, (void *)readmemll); + else if (size == 8) + host_x86_CALL(block, (void *)readmemql); + host_x86_POP(block, REG_ECX); + if (size == 1 && !is_float) + host_x86_MOVZX_REG_32_8(block, REG_ECX, REG_EAX); + else if (size == 2 && !is_float) + host_x86_MOVZX_REG_32_16(block, REG_ECX, REG_EAX); + else if (size == 4 && !is_float) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + else if (size == 4 && is_float) + { + host_x86_MOVD_XREG_REG(block, REG_XMM_TEMP, REG_EAX); + host_x86_CVTSS2SD_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + } + else if (size == 8) + { + host_x86_MOVD_XREG_REG(block, REG_XMM_TEMP, REG_EAX); + host_x86_MOVD_XREG_REG(block, REG_XMM_TEMP2, REG_EDX); + host_x86_UNPCKLPS_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP2); + } + host_x86_POP(block, REG_EDX); + host_x86_POP(block, REG_EAX); + host_x86_MOVZX_REG_ABS_32_8(block, REG_ESI, &cpu_state.abrt); + host_x86_RET(block); + block_pos = (block_pos + 63) & ~63; +} + +static void build_store_routine(codeblock_t *block, int size, int is_float) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset = NULL; + + /*In - ECX = data, ESI = address + Out - ESI = abrt + Corrupts EDI*/ + /*MOV EDI, ESI + SHR ESI, 12 + MOV ESI, [writelookup2+ESI*4] + CMP ESI, -1 + JNZ + + MOV [ESI+EDI], ECX + XOR ESI,ESI + RET + * PUSH EAX + PUSH EDX + PUSH ECX + CALL writemembl + POP ECX + POP EDX + POP EAX + MOVZX ECX, AL + RET + */ + host_x86_MOV32_REG_REG(block, REG_EDI, REG_ESI); + host_x86_SHR32_IMM(block, REG_ESI, 12); + host_x86_MOV32_REG_ABS_INDEX_SHIFT(block, REG_ESI, writelookup2, REG_ESI, 2); + if (size != 1) + { + host_x86_TEST32_REG_IMM(block, REG_EDI, size-1); + misaligned_offset = host_x86_JNZ_short(block); + } + host_x86_CMP32_REG_IMM(block, REG_ESI, (uint32_t)-1); + branch_offset = host_x86_JZ_short(block); + if (size == 1 && !is_float) + host_x86_MOV8_BASE_INDEX_REG(block, REG_ESI, REG_EDI, REG_ECX); + else if (size == 2 && !is_float) + host_x86_MOV16_BASE_INDEX_REG(block, REG_ESI, REG_EDI, REG_ECX); + else if (size == 4 && !is_float) + host_x86_MOV32_BASE_INDEX_REG(block, REG_ESI, REG_EDI, REG_ECX); + else if (size == 4 && is_float) + host_x86_MOVD_BASE_INDEX_XREG(block, REG_ESI, REG_EDI, REG_XMM_TEMP); + else if (size == 8) + host_x86_MOVQ_BASE_INDEX_XREG(block, REG_ESI, REG_EDI, REG_XMM_TEMP); + else + fatal("build_store_routine: size=%i is_float=%i\n", size, is_float); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI); + host_x86_RET(block); + + *branch_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 1; + if (size != 1) + *misaligned_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 1; + if (size == 4 && is_float) + host_x86_MOVD_REG_XREG(block, REG_ECX, REG_XMM_TEMP); + host_x86_PUSH(block, REG_EAX); + host_x86_PUSH(block, REG_EDX); + host_x86_PUSH(block, REG_ECX); + if (size == 8) + { + host_x86_MOVQ_STACK_OFFSET_XREG(block, -8, REG_XMM_TEMP); + host_x86_SUB32_REG_IMM(block, REG_ESP, 8); + } + host_x86_PUSH(block, REG_EDI); + if (size == 1) + host_x86_CALL(block, (void *)writemembl); + else if (size == 2) + host_x86_CALL(block, (void *)writememwl); + else if (size == 4) + host_x86_CALL(block, (void *)writememll); + else if (size == 8) + host_x86_CALL(block, (void *)writememql); + host_x86_POP(block, REG_EDI); + if (size == 8) + host_x86_ADD32_REG_IMM(block, REG_ESP, 8); + host_x86_POP(block, REG_ECX); + host_x86_POP(block, REG_EDX); + host_x86_POP(block, REG_EAX); + host_x86_MOVZX_REG_ABS_32_8(block, REG_ESI, &cpu_state.abrt); + host_x86_RET(block); + block_pos = (block_pos + 63) & ~63; +} + +static void build_loadstore_routines(codeblock_t *block) +{ + codegen_mem_load_byte = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 1, 0); + codegen_mem_load_word = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 2, 0); + codegen_mem_load_long = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 4, 0); + codegen_mem_load_quad = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 8, 0); + codegen_mem_load_single = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 4, 1); + codegen_mem_load_double = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 8, 1); + + codegen_mem_store_byte = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 1, 0); + codegen_mem_store_word = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 2, 0); + codegen_mem_store_long = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 4, 0); + codegen_mem_store_quad = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 8, 0); + codegen_mem_store_single = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 4, 1); + codegen_mem_store_double = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 8, 1); +} + +void codegen_backend_init() +{ + codeblock_t *block; + int c; +#if defined(__linux__) || defined(__APPLE__) + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); + codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); + + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + + for (c = 0; c < BLOCK_SIZE; c++) + codeblock[c].pc = BLOCK_PC_INVALID; + + block_current = 0; + block_pos = 0; + block = &codeblock[block_current]; + block->head_mem_block = codegen_allocator_allocate(NULL, block_current); + block->data = codeblock_allocator_get_ptr(block->head_mem_block); + block_write_data = block->data; + build_loadstore_routines(block); + + codegen_gpf_rout = &codeblock[block_current].data[block_pos]; + host_x86_MOV32_STACK_IMM(block, STACK_ARG0, 0); + host_x86_MOV32_STACK_IMM(block, STACK_ARG1, 0); + host_x86_CALL(block, (void *)x86gpf); + codegen_exit_rout = &codeblock[block_current].data[block_pos]; + host_x86_ADD32_REG_IMM(block, REG_ESP, 64); + host_x86_POP(block, REG_EDI); + host_x86_POP(block, REG_ESI); + host_x86_POP(block, REG_EBP); + host_x86_POP(block, REG_EDX); + host_x86_RET(block); + block_write_data = NULL; + + cpu_state.old_fp_control = 0; + asm( + "fstcw %0\n" + "stmxcsr %1\n" + : "=m" (cpu_state.old_fp_control2), + "=m" (cpu_state.old_fp_control) + ); + cpu_state.trunc_fp_control = cpu_state.old_fp_control | 0x6000; +} + +void codegen_set_rounding_mode(int mode) +{ + /*SSE*/ + cpu_state.new_fp_control = (cpu_state.old_fp_control & ~0x6000) | (mode << 13); + /*x87 - used for double -> i64 conversions*/ + cpu_state.new_fp_control2 = (cpu_state.old_fp_control2 & ~0x0c00) | (mode << 10); +} + +void codegen_backend_prologue(codeblock_t *block) +{ + block_pos = BLOCK_START; /*Entry code*/ + host_x86_PUSH(block, REG_EBX); + host_x86_PUSH(block, REG_EBP); + host_x86_PUSH(block, REG_ESI); + host_x86_PUSH(block, REG_EDI); + host_x86_SUB32_REG_IMM(block, REG_ESP, 64); + host_x86_MOV32_REG_IMM(block, REG_EBP, ((uintptr_t)&cpu_state) + 128); + if (block->flags & CODEBLOCK_HAS_FPU) + { + host_x86_MOV32_REG_ABS(block, REG_EAX, &cpu_state.TOP); + host_x86_SUB32_REG_IMM(block, REG_EAX, block->TOP); + host_x86_MOV32_BASE_OFFSET_REG(block, REG_ESP, IREG_TOP_diff_stack_offset, REG_EAX); + } +} + +void codegen_backend_epilogue(codeblock_t *block) +{ + host_x86_ADD32_REG_IMM(block, REG_ESP, 64); + host_x86_POP(block, REG_EDI); + host_x86_POP(block, REG_ESI); + host_x86_POP(block, REG_EBP); + host_x86_POP(block, REG_EDX); + host_x86_RET(block); +} + +#endif diff --git a/src/cpu_new/codegen_backend_x86.h b/src/cpu_new/codegen_backend_x86.h new file mode 100644 index 000000000..a5aec727c --- /dev/null +++ b/src/cpu_new/codegen_backend_x86.h @@ -0,0 +1,12 @@ +#include "codegen_backend_x86_defs.h" + +#define BLOCK_SIZE 0x10000 +#define BLOCK_MASK 0xffff +#define BLOCK_START 0 + +#define HASH_SIZE 0x20000 +#define HASH_MASK 0x1ffff + +#define HASH(l) ((l) & 0x1ffff) + +#define BLOCK_MAX 0x3c0 diff --git a/src/cpu_new/codegen_backend_x86_defs.h b/src/cpu_new/codegen_backend_x86_defs.h new file mode 100644 index 000000000..25964ba3c --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_defs.h @@ -0,0 +1,50 @@ +#ifndef _CODEGEN_BACKEND_X86_DEFS_H_ +#define _CODEGEN_BACKEND_X86_DEFS_H_ + +#define REG_EAX 0 +#define REG_ECX 1 +#define REG_EDX 2 +#define REG_EBX 3 +#define REG_ESP 4 +#define REG_EBP 5 +#define REG_ESI 6 +#define REG_EDI 7 + +#define REG_XMM0 0 +#define REG_XMM1 1 +#define REG_XMM2 2 +#define REG_XMM3 3 +#define REG_XMM4 4 +#define REG_XMM5 5 +#define REG_XMM6 6 +#define REG_XMM7 7 + +#define REG_XMM_TEMP REG_XMM7 +#define REG_XMM_TEMP2 REG_XMM6 + +#define CODEGEN_HOST_REGS 3 +#define CODEGEN_HOST_FP_REGS 6 + +extern void *codegen_mem_load_byte; +extern void *codegen_mem_load_word; +extern void *codegen_mem_load_long; +extern void *codegen_mem_load_quad; +extern void *codegen_mem_load_single; +extern void *codegen_mem_load_double; + +extern void *codegen_mem_store_byte; +extern void *codegen_mem_store_word; +extern void *codegen_mem_store_long; +extern void *codegen_mem_store_quad; +extern void *codegen_mem_store_single; +extern void *codegen_mem_store_double; + +extern void *codegen_gpf_rout; +extern void *codegen_exit_rout; + +#define STACK_ARG0 (0) +#define STACK_ARG1 (4) +#define STACK_ARG2 (8) +#define STACK_ARG3 (12) + +#endif diff --git a/src/cpu_new/codegen_backend_x86_ops.c b/src/cpu_new/codegen_backend_x86_ops.c new file mode 100644 index 000000000..18f0171a5 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_ops.c @@ -0,0 +1,1295 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops.h" +#include "codegen_backend_x86_ops_helpers.h" + +#define RM_OP_ADD 0x00 +#define RM_OP_OR 0x08 +#define RM_OP_AND 0x20 +#define RM_OP_SUB 0x28 +#define RM_OP_XOR 0x30 +#define RM_OP_CMP 0x38 + +#define RM_OP_ROL 0x00 +#define RM_OP_ROR 0x08 +#define RM_OP_SHL 0x20 +#define RM_OP_SHR 0x28 +#define RM_OP_SAR 0x38 + +void host_x86_ADD32_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x03, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x03); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (dst_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x04, imm_data); /*ADD AL, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_ADD | dst_reg, imm_data); /*ADD dst_reg, imm_data*/ + } +} +void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_ADD | dst_reg, imm_data & 0xff); /*ADD dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x05); /*ADD AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_ADD | dst_reg); /*ADD dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_ADD | dst_reg, imm_data & 0xff); /*ADD dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x05); /*ADD EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_ADD | dst_reg); /*ADD dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x00, 0xc0 | dst_reg | (src_reg << 3)); /*ADD dst_reg, src_reg*/ +} +void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x01, 0xc0 | dst_reg | (src_reg << 3)); /*ADD dst_reg, src_reg*/ +} +void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte2(block, 0x01, 0xc0 | dst_reg | (src_reg << 3)); /*ADD dst_reg, src_reg*/ +} + +void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x24, imm_data); /*AND AL, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_AND | dst_reg, imm_data); /*AND dst_reg, imm_data*/ + } +} +void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_AND | dst_reg, imm_data & 0xff); /*AND dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x66, 0x25); /*AND AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_AND | dst_reg); /*AND dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_AND | dst_reg, imm_data & 0xff); /*AND dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x25); /*AND EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_AND | dst_reg); /*AND dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x20, 0xc0 | dst_reg | (src_reg << 3)); /*AND dst_reg, src_reg_b*/ +} +void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x21, 0xc0 | dst_reg | (src_reg << 3)); /*AND dst_reg, src_reg_b*/ +} +void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x21, 0xc0 | dst_reg | (src_reg << 3)); /*AND dst_reg, src_reg_b*/ +} + +void host_x86_CALL(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xe8); /*CALL*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block_write_data[block_pos + 4]); +} + +void host_x86_CMP16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x3d); /*CMP AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_CMP | dst_reg); /*CMP dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x3d); /*CMP EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_CMP | dst_reg); /*CMP dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x38, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ +} +void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ +} +void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ +} + +void host_x86_INC32_ABS(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0xff, 0x05); /*INC p*/ + codegen_addlong(block, (uint32_t)p); +} + +void host_x86_JMP(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xe9); /*JMP*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block_write_data[block_pos + 4]); +} +uint32_t *host_x86_JMP_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xe9); /*JMP*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} + +void host_x86_JNZ(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block_write_data[block_pos + 4]); +} +void host_x86_JZ(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x84); /*JZ*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block_write_data[block_pos + 4]); +} + +uint8_t *host_x86_JNZ_short(codeblock_t *block) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x75, 0); /*JNZ*/ + return &block_write_data[block_pos-1]; +} +uint8_t *host_x86_JS_short(codeblock_t *block) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x78, 0); /*JS*/ + return &block_write_data[block_pos-1]; +} +uint8_t *host_x86_JZ_short(codeblock_t *block) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x74, 0); /*JZ*/ + return &block_write_data[block_pos-1]; +} + +uint32_t *host_x86_JNB_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x83); /*JNB*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNBE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x87); /*JNBE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNL_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8d); /*JNL*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNLE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8f); /*JNLE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNO_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x81); /*JNO*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNS_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x89); /*JNS*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNZ_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JB_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x82); /*JB*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JBE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x86); /*JBE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JL_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8c); /*JL*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JLE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8e); /*JLE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JO_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x80); /*JO*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JS_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x88); /*JS*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JZ_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x84); /*JZ*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} + +void host_x86_LAHF(codeblock_t *block) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x9f); /*LAHF*/ +} + +void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t offset) +{ + if (offset) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x8d, 0x80 | (dst_reg << 3) | src_reg); /*LEA dst_reg, [offset+src_reg]*/ + codegen_addlong(block, offset); + } + else + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x8d, 0x00 | (dst_reg << 3) | src_reg); /*LEA dst_reg, [src_reg]*/ + } +} + +void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8d, 0x04 | (dst_reg << 3), (src_reg_b << 3) | src_reg_a); /*LEA dst_reg, [src_reg_a + src_reg_b]*/ +} +void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8d, 0x04 | (dst_reg << 3), (shift << 6) | (src_reg_b << 3) | src_reg_a); /*LEA dst_reg, [src_reg_a + src_reg_b * (1 << shift)]*/ +} + +void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[EBP], imm_data*/ + codegen_addbyte(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte2(block, 0xc6, 0x05); /*MOVB p, imm_data*/ + codegen_addlong(block, (uint32_t)p); + codegen_addbyte(block, imm_data); + } +} +void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[EBP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0xc7, 0x05); /*MOV p, imm_data*/ + codegen_addlong(block, (uint32_t)p); + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x88, 0x45 | (src_reg << 3), offset); /*MOVB offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x88); /*MOVB [p], src_reg*/ + codegen_addbyte(block, 0x05 | (src_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOV16_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x66, 0x89, 0x05 | (src_reg << 3)); /*MOV [p], src_reg*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x89); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (src_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_MOV8_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int base_reg, int idx_reg, int shift, int src_reg) +{ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x88, 0x44 | (src_reg << 3), base_reg | (idx_reg << 3) | (shift << 6), addr & 0xff); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x88, 0x84 | (src_reg << 3), base_reg | (idx_reg << 3) | (shift << 6)); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + codegen_addlong(block, addr); + } +} + +void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x88, 0x04 | (src_reg << 3), base_reg | (idx_reg << 3)); /*MOV B[base_reg + idx_reg], src_reg*/ +} +void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x89, 0x04 | (src_reg << 3), base_reg | (idx_reg << 3)); /*MOV W[base_reg + idx_reg], src_reg*/ +} +void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x89, 0x04 | (src_reg << 3), base_reg | (idx_reg << 3)); /*MOV L[base_reg + idx_reg], src_reg*/ +} + +void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8a, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x8a); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (dst_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x8b, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x66, 0x8b, 0x05 | (dst_reg << 3)); /*MOV [p], src_reg*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8b, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (dst_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_MOV32_REG_ABS_INDEX_SHIFT(codeblock_t *block, int dst_reg, void *p, int idx_reg, int shift) +{ + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x8b, 0x04 | (dst_reg << 3), (shift << 6) | (idx_reg << 3) | 0x05); /*MOV dst_reg, [p + idx_reg << shift]*/ + codegen_addlong(block, (uint32_t)p); +} + +void host_x86_MOV8_REG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int base_reg, int idx_reg, int shift) +{ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x8a, 0x44 | (dst_reg << 3), base_reg | (idx_reg << 3) | (shift << 6), addr & 0xff); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x8a, 0x84 | (dst_reg << 3), base_reg | (idx_reg << 3) | (shift << 6)); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + codegen_addlong(block, addr); + } +} + +void host_x86_MOV32_REG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8b, 0x04 | (dst_reg << 3), base_reg | (idx_reg << 3)); /*MOV dst_reg, L[base_reg + idx_reg]*/ +} + +void host_x86_MOV16_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x66); + codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + } + } + else + fatal("MOV16_REG_BASE_OFFSET - offset %i\n", offset); +} +void host_x86_MOV32_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + } + } + else + fatal("MOV32_REG_BASE_OFFSET - offset %i\n", offset); +} + +void host_x86_MOV16_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x66); + codegen_addbyte4(block, 0x89, 0x40 | base_reg | (src_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x89, 0x40 | base_reg | (src_reg << 3), offset); + } + } + else + fatal("MOV16_BASE_OFFSET_REG - offset %i\n", offset); +} +void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x89, 0x40 | base_reg | (src_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x89, 0x40 | base_reg | (src_reg << 3), offset); + } + } + else + fatal("MOV32_BASE_OFFSET_REG - offset %i\n", offset); +} + +void host_x86_MOV8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xb0 + dst_reg, imm_data); /*MOV reg, imm_data*/ +} +void host_x86_MOV16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (!imm_data) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x31, 0xc0 | dst_reg | (dst_reg << 3)); /*XOR dst_reg, dst_reg*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x66, 0xb8 + dst_reg); /*MOV reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_MOV32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (!imm_data) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x31, 0xc0 | dst_reg | (dst_reg << 3)); /*XOR dst_reg, dst_reg*/ + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xb8 + dst_reg); /*MOV reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x88, 0xc0 | dst_reg | (src_reg << 3)); +} +void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x89, 0xc0 | dst_reg | (src_reg << 3)); +} +void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x89, 0xc0 | dst_reg | (src_reg << 3)); +} + +void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data) +{ + if (!offset) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0xc7, 0x04, 0x24); /*MOV [ESP], imm_data*/ + codegen_addlong(block, imm_data); + } + else if (offset >= -80 || offset < 0x80) + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0xc7, 0x44, 0x24, offset & 0xff); /*MOV offset[ESP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 11); + codegen_addbyte3(block, 0xc7, 0x84, 0x24); /*MOV offset[ESP], imm_data*/ + codegen_addlong(block, offset); + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOVSX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xbe, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ +} +void host_x86_MOVSX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xbe, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ +} +void host_x86_MOVSX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xbf, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ +} + +void host_x86_MOVZX_REG_ABS_16_8(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x66); + codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | (dst_reg << 3), offset); /*MOV dest_reg, [EBP+offset]*/ + } + else + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0x66, 0x0f, 0xb6, 0x05 | (dst_reg << 3)); /*MOVZX dst_reg, [p]*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | (dst_reg << 3), offset); /*MOV dest_reg, [EBP+offset]*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x0f, 0xb6, 0x05 | (dst_reg << 3)); /*MOVZX dst_reg, [p]*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOVZX_REG_ABS_32_16(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb7, 0x45 | (dst_reg << 3), offset); /*MOV dest_reg, [EBP+offset]*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x0f, 0xb7, 0x05 | (dst_reg << 3)); /*MOVZX dst_reg, [p]*/ + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_MOVZX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xb6, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} +void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xb6, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} +void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xb7, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} + +void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb6, 0x04 | (dst_reg << 3), base_reg | (idx_reg << 3)); /*MOVZX dst_reg, B[base_reg + idx_reg]*/ +} +void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb7, 0x04 | (dst_reg << 3), base_reg | (idx_reg << 3)); /*MOVZX dst_reg, W[base_reg + idx_reg]*/ +} + +void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x08, 0xc0 | dst_reg | (src_reg << 3)); /*OR dst_reg, src_reg_b*/ +} +void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x09, 0xc0 | dst_reg | (src_reg << 3)); /*OR dst_reg, src_reg_b*/ +} +void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x09, 0xc0 | dst_reg | (src_reg << 3)); /*OR dst_reg, src_reg_b*/ +} + +void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x0c, imm_data); /*OR AL, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_OR | dst_reg, imm_data); /*OR dst_reg, imm_data*/ + } +} +void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_OR | dst_reg, imm_data & 0xff); /*OR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x66, 0x0d); /*OR AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_OR | dst_reg); /*OR dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_OR | dst_reg, imm_data & 0xff); /*OR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x0d); /*OR EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_OR | dst_reg); /*OR dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_POP(codeblock_t *block, int src_reg) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x58 | src_reg); /*POP reg*/ +} + +void host_x86_PUSH(codeblock_t *block, int src_reg) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x50 | src_reg); /*PUSH reg*/ +} + +void host_x86_RET(codeblock_t *block) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0xc3); /*RET*/ +} + +void host_x86_ROL8_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_ROL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_ROL16_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_ROL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_ROL32_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_ROL | dst_reg); /*SHL dst_reg, CL*/ +} + +void host_x86_ROL8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_ROL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_ROL16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_ROL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_ROL32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_ROL | dst_reg, shift); /*SHL dst_reg, shift*/ +} + +void host_x86_ROR8_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_ROR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_ROR16_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_ROR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_ROR32_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_ROR | dst_reg); /*SHR dst_reg, CL*/ +} + +void host_x86_ROR8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_ROR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_ROR16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_ROR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_ROR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_ROR | dst_reg, shift); /*SHR dst_reg, shift*/ +} + +#define MODRM_MOD_REG(rm, reg) (0xc0 | reg | (rm << 3)) + +void host_x86_SAR8_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_SAR | dst_reg); /*SAR dst_reg, CL*/ +} +void host_x86_SAR16_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_SAR | dst_reg); /*SAR dst_reg, CL*/ +} +void host_x86_SAR32_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_SAR | dst_reg); /*SAR dst_reg, CL*/ +} + +void host_x86_SAR8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_SAR | dst_reg, shift); /*SAR dst_reg, shift*/ +} +void host_x86_SAR16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_SAR | dst_reg, shift); /*SAR dst_reg, shift*/ +} +void host_x86_SAR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SAR | dst_reg, shift); /*SAR dst_reg, shift*/ +} + +void host_x86_SHL8_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_SHL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_SHL16_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_SHL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_SHL32_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_SHL | dst_reg); /*SHL dst_reg, CL*/ +} + +void host_x86_SHL8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_SHL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_SHL16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_SHL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_SHL32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SHL | dst_reg, shift); /*SHL dst_reg, shift*/ +} + +void host_x86_SHR8_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_SHR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_SHR16_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_SHR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_SHR32_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_SHR | dst_reg); /*SHR dst_reg, CL*/ +} + +void host_x86_SHR8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_SHR16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} + +void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x2c, imm_data); /*SUB AL, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_SUB | dst_reg, imm_data); /*SUB dst_reg, imm_data*/ + } +} +void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_SUB | dst_reg, imm_data & 0xff); /*SUB dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x2d); /*SUB AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_SUB | dst_reg); /*SUB dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_SUB | dst_reg, imm_data & 0xff); /*SUB dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x2d); /*SUB EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_SUB | dst_reg); /*SUB dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x28, 0xc0 | dst_reg | (src_reg << 3)); /*SUB dst_reg, src_reg*/ +} +void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x29, 0xc0 | dst_reg | (src_reg << 3)); /*SUB dst_reg, src_reg*/ +} +void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x29, 0xc0 | dst_reg | (src_reg << 3)); /*SUB dst_reg, src_reg*/ +} + +void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x84, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xa9); /*TEST EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0xf7, 0xc0 | dst_reg); /*TEST dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x30, 0xc0 | dst_reg | (src_reg << 3)); /*XOR dst_reg, src_reg*/ +} +void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x31, 0xc0 | dst_reg | (src_reg << 3)); /*XOR dst_reg, src_reg*/ +} +void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x31, 0xc0 | dst_reg | (src_reg << 3)); /*XOR dst_reg, src_reg*/ +} + +void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x34, imm_data); /*XOR AL, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_XOR | dst_reg, imm_data); /*XOR dst_reg, imm_data*/ + } +} +void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_XOR | dst_reg, imm_data & 0xff); /*XOR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x35); /*XOR AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_XOR | dst_reg); /*XOR dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_XOR | dst_reg, imm_data & 0xff); /*XOR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x35); /*XOR EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_XOR | dst_reg); /*XOR dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +#endif diff --git a/src/cpu_new/codegen_backend_x86_ops.h b/src/cpu_new/codegen_backend_x86_ops.h new file mode 100644 index 000000000..294b42236 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_ops.h @@ -0,0 +1,192 @@ +void host_x86_ADD32_REG_ABS(codeblock_t *block, int dst_reg, void *p); + +void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_CALL(codeblock_t *block, void *p); + +void host_x86_CMP16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); +void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); +void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); + +void host_x86_INC32_ABS(codeblock_t *block, void *p); + +void host_x86_JMP(codeblock_t *block, void *p); +uint32_t *host_x86_JMP_short(codeblock_t *block); +uint32_t *host_x86_JMP_long(codeblock_t *block); + +void host_x86_JNZ(codeblock_t *block, void *p); +void host_x86_JZ(codeblock_t *block, void *p); + +uint8_t *host_x86_JNZ_short(codeblock_t *block); +uint8_t *host_x86_JS_short(codeblock_t *block); +uint8_t *host_x86_JZ_short(codeblock_t *block); + +uint32_t *host_x86_JNB_long(codeblock_t *block); +uint32_t *host_x86_JNBE_long(codeblock_t *block); +uint32_t *host_x86_JNL_long(codeblock_t *block); +uint32_t *host_x86_JNLE_long(codeblock_t *block); +uint32_t *host_x86_JNO_long(codeblock_t *block); +uint32_t *host_x86_JNS_long(codeblock_t *block); +uint32_t *host_x86_JNZ_long(codeblock_t *block); +uint32_t *host_x86_JB_long(codeblock_t *block); +uint32_t *host_x86_JBE_long(codeblock_t *block); +uint32_t *host_x86_JL_long(codeblock_t *block); +uint32_t *host_x86_JLE_long(codeblock_t *block); +uint32_t *host_x86_JO_long(codeblock_t *block); +uint32_t *host_x86_JS_long(codeblock_t *block); +uint32_t *host_x86_JZ_long(codeblock_t *block); + +void host_x86_LAHF(codeblock_t *block); + +void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg_a, uint32_t offset); +void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift); + +void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); +void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); + +void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV16_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg); + +void host_x86_MOV8_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int base_reg, int idx_reg, int shift, int src_reg); + +void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); + +void host_x86_MOV16_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int dst_reg); +void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int dst_reg); + +void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p); + +void host_x86_MOV32_REG_ABS_INDEX_SHIFT(codeblock_t *block, int dst_reg, void *p, int idx_reg, int shift); + +void host_x86_MOV8_REG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_addr, uint32_t addr, int base_reg, int idx_reg, int shift); + +void host_x86_MOV32_REG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); + +void host_x86_MOV16_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); +void host_x86_MOV32_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); + +void host_x86_MOV8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_MOV16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_MOV32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +#define host_x86_MOV16_STACK_REG(block, offset, src_reg) host_x86_MOV16_BASE_OFFSET_REG(block, REG_ESP, offset, src_reg) + +void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data); + +void host_x86_MOVSX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVSX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVSX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVZX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVZX_REG_ABS_16_8(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVZX_REG_ABS_32_16(codeblock_t *block, int dst_reg, void *p); + +void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); +void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); + +void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_POP(codeblock_t *block, int src_reg); + +void host_x86_PUSH(codeblock_t *block, int src_reg); + +void host_x86_RET(codeblock_t *block); + +void host_x86_ROL8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROL16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROL32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_ROL8_CL(codeblock_t *block, int dst_reg); +void host_x86_ROL16_CL(codeblock_t *block, int dst_reg); +void host_x86_ROL32_CL(codeblock_t *block, int dst_reg); + +void host_x86_ROR8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROR16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_ROR8_CL(codeblock_t *block, int dst_reg); +void host_x86_ROR16_CL(codeblock_t *block, int dst_reg); +void host_x86_ROR32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SAR8_CL(codeblock_t *block, int dst_reg); +void host_x86_SAR16_CL(codeblock_t *block, int dst_reg); +void host_x86_SAR32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SAR8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SAR16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SAR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SHL8_CL(codeblock_t *block, int dst_reg); +void host_x86_SHL16_CL(codeblock_t *block, int dst_reg); +void host_x86_SHL32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SHL8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHL16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHL32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SHR8_CL(codeblock_t *block, int dst_reg); +void host_x86_SHR16_CL(codeblock_t *block, int dst_reg); +void host_x86_SHR32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SHR8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHR16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); +void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); +void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); + +void host_x86_TEST32_REG_IMM(codeblock_t *block, int src_host_reg, uint32_t imm_data); + +void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); diff --git a/src/cpu_new/codegen_backend_x86_ops_fpu.c b/src/cpu_new/codegen_backend_x86_ops_fpu.c new file mode 100644 index 000000000..dd1e658fb --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_ops_fpu.c @@ -0,0 +1,84 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops_fpu.h" +#include "codegen_backend_x86_ops_helpers.h" + +void host_x87_FILDq_BASE(codeblock_t *block, int base_reg) +{ + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xdf, 0x2c, 0x24); /*FILDq [ESP]*/ + } + else + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xdf, 0x28 | base_reg); /*FILDq [base_reg]*/ + } +} +void host_x87_FISTPq_BASE(codeblock_t *block, int base_reg) +{ + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xdf, 0x3c, 0x24); /*FISTPq [ESP]*/ + } + else + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xdf, 0x38 | base_reg); /*FISTPq [base_reg]*/ + } +} +void host_x87_FLDCW(codeblock_t *block, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xd9, 0x68 | REG_EBP, offset); /*FLDCW offset[EBP]*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0xd9, 0x2d); /*FLDCW [p]*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x87_FLDd_BASE(codeblock_t *block, int base_reg) +{ + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xdd, 0x04, 0x24); /*FILDq [ESP]*/ + } + else + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xdd, 0x08 | base_reg); /*FILDq [base_reg]*/ + } +} +void host_x87_FSTPd_BASE(codeblock_t *block, int base_reg) +{ + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xdd, 0x1c, 0x24); /*FILDq [ESP]*/ + } + else + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xdd, 0x18 | base_reg); /*FILDq [base_reg]*/ + } +} + +#endif diff --git a/src/cpu_new/codegen_backend_x86_ops_fpu.h b/src/cpu_new/codegen_backend_x86_ops_fpu.h new file mode 100644 index 000000000..e4479ae72 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_ops_fpu.h @@ -0,0 +1,5 @@ +void host_x87_FILDq_BASE(codeblock_t *block, int base_reg); +void host_x87_FISTPq_BASE(codeblock_t *block, int base_reg); +void host_x87_FLDCW(codeblock_t *block, void *p); +void host_x87_FLDd_BASE(codeblock_t *block, int base_reg); +void host_x87_FSTPd_BASE(codeblock_t *block, int base_reg); diff --git a/src/cpu_new/codegen_backend_x86_ops_helpers.h b/src/cpu_new/codegen_backend_x86_ops_helpers.h new file mode 100644 index 000000000..3fca4f4d2 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_ops_helpers.h @@ -0,0 +1,84 @@ +#define JMP_LEN_BYTES 5 + +static inline void codegen_addbyte(codeblock_t *block, uint8_t val) +{ + if (block_pos >= BLOCK_MAX) + fatal("codegen_addbyte over! %i\n", block_pos); + block_write_data[block_pos++] = val; +} +static inline void codegen_addbyte2(codeblock_t *block, uint8_t vala, uint8_t valb) +{ + if (block_pos > (BLOCK_MAX-2)) + fatal("codegen_addbyte2 over! %i\n", block_pos); + block_write_data[block_pos++] = vala; + block_write_data[block_pos++] = valb; +} +static inline void codegen_addbyte3(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc) +{ + if (block_pos > (BLOCK_MAX-3)) + fatal("codegen_addbyte3 over! %i\n", block_pos); + block_write_data[block_pos++] = vala; + block_write_data[block_pos++] = valb; + block_write_data[block_pos++] = valc; +} +static inline void codegen_addbyte4(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc, uint8_t vald) +{ + if (block_pos > (BLOCK_MAX-4)) + fatal("codegen_addbyte4 over! %i\n", block_pos); + block_write_data[block_pos++] = vala; + block_write_data[block_pos++] = valb; + block_write_data[block_pos++] = valc; + block_write_data[block_pos++] = vald; +} + +static inline void codegen_addword(codeblock_t *block, uint16_t val) +{ + if (block_pos > (BLOCK_MAX-2)) + fatal("codegen_addword over! %i\n", block_pos); + *(uint16_t *)&block_write_data[block_pos] = val; + block_pos += 2; +} + +static inline void codegen_addlong(codeblock_t *block, uint32_t val) +{ + if (block_pos > (BLOCK_MAX-4)) + fatal("codegen_addlong over! %i\n", block_pos); + *(uint32_t *)&block_write_data[block_pos] = val; + block_pos += 4; +} + +static inline void codegen_addquad(codeblock_t *block, uint64_t val) +{ + if (block_pos > (BLOCK_MAX-8)) + fatal("codegen_addquad over! %i\n", block_pos); + *(uint64_t *)&block_write_data[block_pos] = val; + block_pos += 8; +} + +static void codegen_allocate_new_block(codeblock_t *block) +{ + /*Current block is full. Allocate a new block*/ + struct mem_block_t *new_block = codegen_allocator_allocate(block->head_mem_block, get_block_nr(block)); + uint8_t *new_ptr = codeblock_allocator_get_ptr(new_block); + + /*Add a jump instruction to the new block*/ + codegen_addbyte(block, 0xe9); /*JMP*/ + codegen_addlong(block, (uintptr_t)new_ptr - (uintptr_t)&block_write_data[block_pos + 4]); + + /*Set write address to start of new block*/ + block_pos = 0; + block_write_data = new_ptr; +} + +static inline void codegen_alloc_bytes(codeblock_t *block, int size) +{ + if (block_pos > ((BLOCK_MAX - size) - JMP_LEN_BYTES)) + codegen_allocate_new_block(block); +} + +static inline int is_imm8(uint32_t imm_data) +{ + if (imm_data <= 0x7f || imm_data >= 0xffffff80) + return 1; + return 0; +} diff --git a/src/cpu_new/codegen_backend_x86_ops_sse.c b/src/cpu_new/codegen_backend_x86_ops_sse.c new file mode 100644 index 000000000..641d16532 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_ops_sse.c @@ -0,0 +1,578 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops_sse.h" +#include "codegen_backend_x86_ops_helpers.h" + +void host_x86_ADDPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x58, 0xc0 | src_reg | (dst_reg << 3)); /*ADDPS dst_reg, src_reg*/ +} +void host_x86_ADDSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x58, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_CMPPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg, int type) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xc2, 0xc0 | src_reg | (dst_reg << 3), type); /*CMPPS dst_reg, src_reg, type*/ +} + +void host_x86_COMISD_XREG_XREG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x2e, 0xc0 | src_reg_b | (src_reg_a << 3)); +} + +void host_x86_CVTDQ2PS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5b, 0xc0 | src_reg | (dst_reg << 3)); /*CVTDQ2PS dst_reg, src_reg*/ +} +void host_x86_CVTPS2DQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x5b, 0xc0 | src_reg | (dst_reg << 3)); /*CVTPS2DQ dst_reg, src_reg*/ +} + +void host_x86_CVTSD2SI_REG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x2d, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSD2SI dst_reg, src_reg*/ +} +void host_x86_CVTSD2SS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5a, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSD2SS dst_reg, src_reg*/ +} + +void host_x86_CVTSI2SD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x2a, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSI2SD dst_reg, src_reg*/ +} +void host_x86_CVTSI2SS_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x2a, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSI2SD dst_reg, src_reg*/ +} + +void host_x86_CVTSS2SD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x5a, 0xc0 | src_reg | (dst_reg << 3)); +} +void host_x86_CVTSS2SD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x5a, 0x04 | (dst_reg << 3)); /*CVTSS2SD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} + +void host_x86_DIVSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5e, 0xc0 | src_reg | (dst_reg << 3)); /*DIVSD dst_reg, src_reg*/ +} +void host_x86_DIVSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x5e, 0xc0 | src_reg | (dst_reg << 3)); /*DIVSS dst_reg, src_reg*/ +} + +void host_x86_LDMXCSR(codeblock_t *block, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xae, 0x50 | REG_EBP, offset); /*LDMXCSR offset[EBP]*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x0f, 0xae, 0x15); /*LDMXCSR [p]*/ + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_MAXSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5f, 0xc0 | src_reg | (dst_reg << 3)); /*MAXSD dst_reg, src_reg*/ +} + +void host_x86_MOVD_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x7e, 0x04 | (src_reg << 3)); /*MOVD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVD_REG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x7e, 0xc0 | dst_reg | (src_reg << 3)); +} +void host_x86_MOVD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x6e, 0x04 | (dst_reg << 3)); /*MOVD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x6e, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_MOVQ_ABS_XREG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x45 | (src_reg << 3)); /*MOVQ offset[EBP], src_reg*/ + codegen_addbyte(block, offset); + } + else + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x05 | (src_reg << 3)); /*MOVQ [p], src_reg*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(codeblock_t *block, uint32_t addr, int src_reg_a, int src_reg_b, int shift, int src_reg) +{ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte3(block, 0x66, 0x0f, 0xd6); /*MOVQ addr[src_reg_a + src_reg_b << shift], XMMx*/ + codegen_addbyte3(block, 0x44 | (src_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6), addr & 0xff); + } + else + { + codegen_alloc_bytes(block, 9); + codegen_addbyte3(block, 0x66, 0x0f, 0xd6); /*MOVQ addr[src_reg_a + src_reg_b << shift], XMMx*/ + codegen_addbyte2(block, 0x84 | (src_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6)); + codegen_addlong(block, addr); + } +} +void host_x86_MOVQ_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x04 | (src_reg << 3)); /*MOVQ XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVQ_BASE_OFFSET_XREG(codeblock_t *block, int base_reg, int offset, int src_reg) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x44 | (src_reg << 3)); /*MOVQ [ESP + offset], XMMx*/ + codegen_addbyte2(block, 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x40 | base_reg | (src_reg << 3)); /*MOVQ [base_reg + offset], XMMx*/ + codegen_addbyte(block, offset); + } + } + else + fatal("MOVQ_BASE_OFFSET_XREG - offset %i\n", offset); +} +void host_x86_MOVQ_STACK_OFFSET_XREG(codeblock_t *block, int offset, int src_reg) +{ + if (!offset) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x04 | (src_reg << 3)); /*MOVQ [ESP], src_reg*/ + codegen_addbyte(block, 0x24); + } + else if (offset >= -80 || offset < 0x80) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x44 | (src_reg << 3)); /*MOVQ offset[ESP], src_reg*/ + codegen_addbyte2(block, 0x24, offset & 0xff); + } + else + { + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x84 | (src_reg << 3)); /*MOVQ offset[ESP], src_reg*/ + codegen_addbyte(block, 0x24); + codegen_addlong(block, offset); + } + +} + +void host_x86_MOVQ_XREG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x45 | (dst_reg << 3)); /*MOVQ offset[EBP], src_reg*/ + codegen_addbyte(block, offset); + } + else + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x05 | (dst_reg << 3)); /*MOVQ [p], src_reg*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int src_reg_a, int src_reg_b, int shift) +{ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte3(block, 0xf3, 0x0f, 0x7e); /*MOVQ XMMx, addr[src_reg_a + src_reg_b << shift]*/ + codegen_addbyte3(block, 0x44 | (dst_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6), addr & 0xff); + } + else + { + codegen_alloc_bytes(block, 9); + codegen_addbyte3(block, 0xf3, 0x0f, 0x7e); /*MOVQ XMMx, addr[src_reg_a + src_reg_b << shift]*/ + codegen_addbyte2(block, 0x84 | (dst_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6)); + codegen_addlong(block, addr); + } +} +void host_x86_MOVQ_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x04 | (dst_reg << 3)); /*MOVQ XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVQ_XREG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x44 | (dst_reg << 3)); /*MOVQ XMMx, [ESP + offset]*/ + codegen_addbyte2(block, 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x40 | base_reg | (dst_reg << 3)); /*MOVQ XMMx, [base_reg + offset]*/ + codegen_addbyte(block, offset); + } + } + else + fatal("MOVQ_REG_BASE_OFFSET - offset %i\n", offset); +} +void host_x86_MOVQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0xc0 | src_reg | (dst_reg << 3)); /*MOVQ dst_reg, src_reg*/ +} + +void host_x86_MAXPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5f, 0xc0 | src_reg | (dst_reg << 3)); /*MAXPS dst_reg, src_reg*/ +} +void host_x86_MINPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5d, 0xc0 | src_reg | (dst_reg << 3)); /*MINPS dst_reg, src_reg*/ +} + +void host_x86_MULPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x59, 0xc0 | src_reg | (dst_reg << 3)); /*MULPS dst_reg, src_reg*/ +} +void host_x86_MULSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x59, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_PACKSSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x63, 0xc0 | src_reg | (dst_reg << 3)); /*PACKSSWB dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0x88 (move bits 64-95 to 32-63)*/ + codegen_addbyte(block, 0x88); +} +void host_x86_PACKSSDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x6b, 0xc0 | src_reg | (dst_reg << 3)); /*PACKSSDW dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0x88 (move bits 64-95 to 32-63)*/ + codegen_addbyte(block, 0x88); +} +void host_x86_PACKUSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x67, 0xc0 | src_reg | (dst_reg << 3)); /*PACKUSWB dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0x88 (move bits 64-95 to 32-63)*/ + codegen_addbyte(block, 0x88); +} + +void host_x86_PADDB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfc, 0xc0 | src_reg | (dst_reg << 3)); /*PADDB dst_reg, src_reg*/ +} +void host_x86_PADDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfd, 0xc0 | src_reg | (dst_reg << 3)); /*PADDW dst_reg, src_reg*/ +} +void host_x86_PADDD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfe, 0xc0 | src_reg | (dst_reg << 3)); /*PADDD dst_reg, src_reg*/ +} +void host_x86_PADDSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xec, 0xc0 | src_reg | (dst_reg << 3)); /*PADDSB dst_reg, src_reg*/ +} +void host_x86_PADDSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xed, 0xc0 | src_reg | (dst_reg << 3)); /*PADDSW dst_reg, src_reg*/ +} +void host_x86_PADDUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdc, 0xc0 | src_reg | (dst_reg << 3)); /*PADDUSB dst_reg, src_reg*/ +} +void host_x86_PADDUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdd, 0xc0 | src_reg | (dst_reg << 3)); /*PADDUSW dst_reg, src_reg*/ +} + +void host_x86_PAND_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdb, 0xc0 | src_reg | (dst_reg << 3)); /*PAND dst_reg, src_reg*/ +} +void host_x86_PANDN_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdf, 0xc0 | src_reg | (dst_reg << 3)); /*PANDN dst_reg, src_reg*/ +} +void host_x86_POR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xeb, 0xc0 | src_reg | (dst_reg << 3)); /*POR dst_reg, src_reg*/ +} +void host_x86_PXOR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xef, 0xc0 | src_reg | (dst_reg << 3)); /*PXOR dst_reg, src_reg*/ +} + +void host_x86_PCMPEQB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x74, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPEQB dst_reg, src_reg*/ +} +void host_x86_PCMPEQW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x75, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPEQW dst_reg, src_reg*/ +} +void host_x86_PCMPEQD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x76, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPEQD dst_reg, src_reg*/ +} +void host_x86_PCMPGTB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x64, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPGTB dst_reg, src_reg*/ +} +void host_x86_PCMPGTW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x65, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPGTW dst_reg, src_reg*/ +} +void host_x86_PCMPGTD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x66, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPGTD dst_reg, src_reg*/ +} + +void host_x86_PMADDWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xf5, 0xc0 | src_reg | (dst_reg << 3)); /*PMULLW dst_reg, src_reg*/ +} +void host_x86_PMULHW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xe5, 0xc0 | src_reg | (dst_reg << 3)); /*PMULLW dst_reg, src_reg*/ +} +void host_x86_PMULLW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xd5, 0xc0 | src_reg | (dst_reg << 3)); /*PMULLW dst_reg, src_reg*/ +} + +void host_x86_PSHUFD_XREG_XREG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t shuffle) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | src_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0xee (move top 64-bits to low 64-bits)*/ + codegen_addbyte(block, shuffle); +} + +void host_x86_PSLLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x71, 0xc0 | 0x30 | dst_reg); /*PSLLW dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSLLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x72, 0xc0 | 0x30 | dst_reg); /*PSLLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSLLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x73, 0xc0 | 0x30 | dst_reg); /*PSLLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRAW_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x71, 0xc0 | 0x20 | dst_reg); /*PSRAW dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRAD_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x72, 0xc0 | 0x20 | dst_reg); /*PSRAD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRAQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x73, 0xc0 | 0x20 | dst_reg); /*PSRAD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x71, 0xc0 | 0x10 | dst_reg); /*PSRLW dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x72, 0xc0 | 0x10 | dst_reg); /*PSRLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x73, 0xc0 | 0x10 | dst_reg); /*PSRLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} + +void host_x86_PSUBB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xf8, 0xc0 | src_reg | (dst_reg << 3)); /*PADDB dst_reg, src_reg*/ +} +void host_x86_PSUBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xf9, 0xc0 | src_reg | (dst_reg << 3)); /*PADDW dst_reg, src_reg*/ +} +void host_x86_PSUBD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfa, 0xc0 | src_reg | (dst_reg << 3)); /*PADDD dst_reg, src_reg*/ +} +void host_x86_PSUBSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xe8, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBSB dst_reg, src_reg*/ +} +void host_x86_PSUBSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xe9, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBSW dst_reg, src_reg*/ +} +void host_x86_PSUBUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xd8, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBUSB dst_reg, src_reg*/ +} +void host_x86_PSUBUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xd9, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBUSW dst_reg, src_reg*/ +} + +void host_x86_PUNPCKLBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x60, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLBW dst_reg, src_reg*/ +} +void host_x86_PUNPCKLWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x61, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLWD dst_reg, src_reg*/ +} +void host_x86_PUNPCKLDQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x62, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLDQ dst_reg, src_reg*/ +} + +void host_x86_SQRTSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x51, 0xc0 | src_reg | (dst_reg << 3)); /*SQRTSD dst_reg, src_reg*/ +} +void host_x86_SQRTSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x51, 0xc0 | src_reg | (dst_reg << 3)); /*SQRTSS dst_reg, src_reg*/ +} + +void host_x86_SUBPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5c, 0xc0 | src_reg | (dst_reg << 3)); /*SUBPS dst_reg, src_reg*/ +} +void host_x86_SUBSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5c, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_UNPCKLPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x14, 0xc0 | src_reg | (dst_reg << 3)); +} + +#endif diff --git a/src/cpu_new/codegen_backend_x86_ops_sse.h b/src/cpu_new/codegen_backend_x86_ops_sse.h new file mode 100644 index 000000000..0c895a605 --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_ops_sse.h @@ -0,0 +1,111 @@ +void host_x86_ADDPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_ADDSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +#define CMPPS_EQ 0 +#define CMPPS_NLT 5 +#define CMPPS_NLE 6 +void host_x86_CMPPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg, int type); + +void host_x86_COMISD_XREG_XREG(codeblock_t *block, int src_reg_a, int src_reg_b); + +void host_x86_CVTDQ2PS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTPS2DQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_CVTSD2SI_REG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSD2SS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_CVTSI2SD_XREG_REG(codeblock_t *block, int dest_reg, int src_reg); +void host_x86_CVTSI2SS_XREG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_CVTSS2SD_XREG_XREG(codeblock_t *block, int dest_reg, int src_reg); +void host_x86_CVTSS2SD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); + +void host_x86_DIVSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_DIVSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_LDMXCSR(codeblock_t *block, void *p); + +void host_x86_MAXSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVD_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOVD_REG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); +void host_x86_MOVD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVQ_ABS_XREG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(codeblock_t *block, uint32_t addr, int src_reg_a, int src_reg_b, int shift, int src_reg); +void host_x86_MOVQ_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOVQ_BASE_OFFSET_XREG(codeblock_t *block, int base_reg, int offset, int src_reg); +void host_x86_MOVQ_STACK_OFFSET_XREG(codeblock_t *block, int offset, int src_reg); + +void host_x86_MOVQ_XREG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int src_reg_a, int src_reg_b, int shift); +void host_x86_MOVQ_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); +void host_x86_MOVQ_XREG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); +void host_x86_MOVQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MAXPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MINPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MULPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MULSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PACKSSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PACKSSDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PACKUSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PADDB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PAND_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PANDN_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_POR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PXOR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PCMPEQB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPEQW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPEQD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPGTB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPGTW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPGTD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PMADDWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PMULHW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PMULLW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PSLLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSLLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSLLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRAW_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRAD_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRAQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_PSHUFD_XREG_XREG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t shuffle); + +void host_x86_PSUBB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PUNPCKLBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKLWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKLDQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_SQRTSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SQRTSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_SUBPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SUBSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_UNPCKLPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); diff --git a/src/cpu_new/codegen_backend_x86_uops.c b/src/cpu_new/codegen_backend_x86_uops.c new file mode 100644 index 000000000..679a7b77b --- /dev/null +++ b/src/cpu_new/codegen_backend_x86_uops.c @@ -0,0 +1,3141 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_ops.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops.h" +#include "codegen_backend_x86_ops_fpu.h" +#include "codegen_backend_x86_ops_sse.h" +#include "codegen_ir_defs.h" + +#define HOST_REG_IS_L(reg) (IREG_GET_SIZE(reg) == IREG_SIZE_L) +#define HOST_REG_IS_W(reg) (IREG_GET_SIZE(reg) == IREG_SIZE_W) +#define HOST_REG_IS_B(reg) (IREG_GET_SIZE(reg) == IREG_SIZE_B && IREG_GET_REG(reg) < 4) +#define HOST_REG_IS_BH(reg) (IREG_GET_SIZE(reg) == IREG_SIZE_BH && IREG_GET_REG(reg) < 4) + +#define HOST_REG_GET(reg) ((IREG_GET_SIZE(reg) == IREG_SIZE_BH) ? (IREG_GET_REG((reg) & 3) | 4) : (IREG_GET_REG(reg) & 7)) + +#define REG_IS_L(size) (size == IREG_SIZE_L) +#define REG_IS_W(size) (size == IREG_SIZE_W) +#define REG_IS_B(size) (size == IREG_SIZE_B || size == IREG_SIZE_BH) +#define REG_IS_BH(size) (size == IREG_SIZE_BH) +#define REG_IS_D(size) (size == IREG_SIZE_D) +#define REG_IS_Q(size) (size == IREG_SIZE_Q) + +static int codegen_ADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_LEA_REG_REG(block, dest_reg, src_reg_a, src_reg_b); + else + host_x86_ADD32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_ADD16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_ADD8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_LEA_REG_IMM(block, dest_reg, src_reg, uop->imm_data); + else + host_x86_ADD32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ADD16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ADD8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ADD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop) +{ + if (!uop->imm_data) + { + if (uop->dest_reg_a_real == uop->src_reg_a_real) + host_x86_ADD32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_b_real); + else + host_x86_LEA_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + } + else if (uop->imm_data < 4) + host_x86_LEA_REG_REG_SHIFT(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data); +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_ADD_LSHIFT - shift out of range %i\n", uop->imm_data); +#endif + return 0; +} + +static int codegen_AND(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PAND_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg_a); + host_x86_AND32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_AND16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_AND8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("AND %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_AND32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_AND16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_AND8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("AND_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_ANDN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), /*src_reg_a = HOST_REG_GET(uop->src_reg_a_real), */src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PANDN_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ANDN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_CALL_FUNC(codeblock_t *block, uop_t *uop) +{ + host_x86_CALL(block, uop->p); + + return 0; +} + +static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); +#ifdef RECOMPILER_DEBUG + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_L(dest_size)) + fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real); +#endif + host_x86_CALL(block, uop->p); + host_x86_MOV32_REG_REG(block, dest_reg, REG_EAX); + + return 0; +} + +static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) +{ + host_x86_CALL(block, uop->p); + host_x86_TEST32_REG(block, REG_EAX, REG_EAX); + host_x86_JNZ(block, codegen_exit_rout); +// host_x86_CALL(block, codegen_debug); + + return 0; +} + +static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real); +#endif + host_x86_JZ(block, uop->p); + + return 0; +} + +static int codegen_CMP_IMM_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_x86_CMP16_REG_IMM(block, src_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_IMM_JNZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNZ_long(block); + + return 0; +} +static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_x86_CMP16_REG_IMM(block, src_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JZ_long(block); + + return 0; +} + +static int codegen_CMP_JB(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JB %02x\n", uop->src_reg_a_real); +#endif + jump_p = host_x86_JB_long(block); + *jump_p = (uintptr_t)uop->p - ((uintptr_t)jump_p + 4); + + return 0; +} +static int codegen_CMP_JNBE(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNBE %02x\n", uop->src_reg_a_real); +#endif + jump_p = host_x86_JNBE_long(block); + *jump_p = (uintptr_t)uop->p - ((uintptr_t)jump_p + 4); + + return 0; +} + +static int codegen_CMP_JNB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNB_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNB_long(block); + + return 0; +} +static int codegen_CMP_JNBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNBE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNBE_long(block); + + return 0; +} +static int codegen_CMP_JNL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNL_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNL_long(block); + + return 0; +} +static int codegen_CMP_JNLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNLE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNLE_long(block); + + return 0; +} +static int codegen_CMP_JNO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNO_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNO_long(block); + + return 0; +} +static int codegen_CMP_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNZ_long(block); + + return 0; +} +static int codegen_CMP_JB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JB_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JB_long(block); + + return 0; +} +static int codegen_CMP_JBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JBE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JBE_long(block); + + return 0; +} +static int codegen_CMP_JL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JL_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JL_long(block); + + return 0; +} +static int codegen_CMP_JLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JLE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JLE_long(block); + + return 0; +} +static int codegen_CMP_JO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JO_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JO_long(block); + + return 0; +} +static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JZ_long(block); + + return 0; +} + +static int codegen_FABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && dest_reg == src_reg_a) + { + host_x86_PXOR_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + host_x86_SUBSD_XREG_XREG(block, REG_XMM_TEMP, dest_reg); + host_x86_MAXSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FABS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_FCHS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_PXOR_XREG_XREG(block, dest_reg, dest_reg); + host_x86_SUBSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FCHS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_FSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_SQRTSD_XREG_XREG(block, dest_reg, src_reg_a); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FSQRT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_FTST(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_PXOR_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + if (dest_reg != REG_EAX) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX); + host_x86_COMISD_XREG_XREG(block, src_reg_a, REG_XMM_TEMP); + host_x86_LAHF(block); + host_x86_AND16_REG_IMM(block, REG_EAX, C0|C2|C3); + if (dest_reg != REG_EAX) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX); + host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX); + } + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_FADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_ADDSD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FCOM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + if (dest_reg != REG_EAX) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX); + host_x86_COMISD_XREG_XREG(block, src_reg_a, src_reg_b); + host_x86_LAHF(block); + host_x86_AND16_REG_IMM(block, REG_EAX, C0|C2|C3); + if (dest_reg != REG_EAX) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX); + host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX); + } + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FCOM %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FDIV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_DIVSD_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_DIVSD_XREG_XREG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FDIV %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_MULSD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_SUBSD_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_SUBSD_XREG_XREG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_offset; + + host_x86_MOV32_REG_ABS(block, REG_ECX, &cr0); + host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); + branch_offset = host_x86_JZ_long(block); + host_x86_MOV32_ABS_IMM(block, &cpu_state.oldpc, uop->imm_data); + host_x86_MOV32_STACK_IMM(block, STACK_ARG0, 7); + host_x86_CALL(block, x86_int); + host_x86_JMP(block, codegen_exit_rout); + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; + + return 0; +} + +static int codegen_MMX_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_offset; + + host_x86_MOV32_REG_ABS(block, REG_ECX, &cr0); + host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); + branch_offset = host_x86_JZ_long(block); + host_x86_MOV32_ABS_IMM(block, &cpu_state.oldpc, uop->imm_data); + host_x86_MOV32_STACK_IMM(block, STACK_ARG0, 7); + host_x86_CALL(block, x86_int); + host_x86_JMP(block, codegen_exit_rout); + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; + host_x86_MOV32_ABS_IMM(block, &cpu_state.tag[0], 0x01010101); + host_x86_MOV32_ABS_IMM(block, &cpu_state.tag[4], 0x01010101); + host_x86_MOV32_ABS_IMM(block, &cpu_state.TOP, 0); + host_x86_MOV8_ABS_IMM(block, &cpu_state.ismmx, 1); + + return 0; +} + +static int codegen_JMP(codeblock_t *block, uop_t *uop) +{ + host_x86_JMP(block, uop->p); + + return 0; +} +static int codegen_JMP_DEST(codeblock_t *block, uop_t *uop) +{ + uop->p = host_x86_JMP_long(block); + + return 0; +} + +static int codegen_LOAD_FUNC_ARG0(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(src_size)) + { + host_x86_MOV16_STACK_REG(block, STACK_ARG0, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_LOAD_FUNC_ARG0 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG1(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG1 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG2(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG2 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG3(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG3 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_STACK_IMM(block, STACK_ARG0, uop->imm_data); + return 0; +} +static int codegen_LOAD_FUNC_ARG1_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_STACK_IMM(block, STACK_ARG1, uop->imm_data); + return 0; +} +static int codegen_LOAD_FUNC_ARG2_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_STACK_IMM(block, STACK_ARG2, uop->imm_data); + return 0; +} +static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_STACK_IMM(block, STACK_ARG3, uop->imm_data); + return 0; +} + +static int codegen_LOAD_SEG(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); +#ifdef RECOMPILER_DEBUG + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (!REG_IS_W(src_size)) + fatal("LOAD_SEG %02x %p\n", uop->src_reg_a_real, uop->p); +#endif + host_x86_MOV16_STACK_REG(block, STACK_ARG0, src_reg); + host_x86_MOV32_STACK_IMM(block, STACK_ARG1, (uint32_t)uop->p); + host_x86_CALL(block, loadseg); + host_x86_TEST32_REG(block, REG_EAX, REG_EAX); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_LOAD_ABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_x86_LEA_REG_IMM(block, REG_ESI, seg_reg, uop->imm_data); + if (REG_IS_B(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_long); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, REG_ECX); + } + + return 0; +} +static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + if (REG_IS_B(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_long); + } + else if (REG_IS_Q(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_quad); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_LOAD_REG - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_Q(dest_size)) + { + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } + + return 0; +} +static int codegen_MEM_LOAD_SINGLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); +#ifdef RECOMPILER_DEBUG + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_SINGLE - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_CALL(block, codegen_mem_load_single); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + + return 0; +} + +static int codegen_MEM_LOAD_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); +#ifdef RECOMPILER_DEBUG + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_DOUBLE - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_CALL(block, codegen_mem_load_double); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + + return 0; +} + +static int codegen_MEM_STORE_ABS(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_b_real); + int src_size = IREG_GET_SIZE(uop->src_reg_b_real); + + host_x86_LEA_REG_IMM(block, REG_ESI, seg_reg, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_long); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_STORE_ABS - %02x\n", uop->src_reg_b_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_long); + } + else if (REG_IS_Q(src_size)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg); + host_x86_CALL(block, codegen_mem_store_quad); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_STORE_REG - %02x\n", uop->src_reg_b_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_IMM_8(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV8_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_byte); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_16(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV16_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_word); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_32(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV32_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_long); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_SINGLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); +#ifdef RECOMPILER_DEBUG + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_SINGLE - %02x\n", uop->src_reg_b_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_CVTSD2SS_XREG_XREG(block, REG_XMM_TEMP, src_reg); + host_x86_CALL(block, codegen_mem_store_single); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); +#ifdef RECOMPILER_DEBUG + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_DOUBLE - %02x\n", uop->src_reg_b_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg); + host_x86_CALL(block, codegen_mem_store_double); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MOV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size)) + { + host_x86_MOVQ_XREG_XREG(block, dest_reg, src_reg); + } + else if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + host_x86_MOVQ_XREG_XREG(block, dest_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_IMM %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_PTR(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_REG_IMM(block, uop->dest_reg_a_real, (uint32_t)uop->p); + return 0; +} +static int codegen_MOV_REG_PTR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_ABS(block, dest_reg, uop->p); + } + else + fatal("MOV_REG_PTR %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_8(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOVZX_REG_ABS_32_8(block, dest_reg, uop->p); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOVZX_REG_ABS_16_8(block, dest_reg, uop->p); + } + else if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_ABS(block, dest_reg, uop->p); + } + else + fatal("MOVZX_REG_PTR_8 %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_16(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOVZX_REG_ABS_32_16(block, dest_reg, uop->p); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_ABS(block, dest_reg, uop->p); + } + else + fatal("MOVZX_REG_PTR_16 %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVSX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOVSX_REG_32_16(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVSX_REG_32_8(block, dest_reg, src_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVSX_REG_16_8(block, dest_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOVSX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOVZX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_L(src_size)) + { + host_x86_MOVD_XREG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_Q(src_size)) + { + host_x86_MOVD_REG_XREG(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOVZX_REG_32_16(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVZX_REG_32_8(block, dest_reg, src_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVZX_REG_16_8(block, dest_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOVZX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_MOV_DOUBLE_INT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_L(src_size)) + { + host_x86_CVTSI2SD_XREG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_D(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOVSX_REG_32_16(block, REG_ECX, src_reg); + host_x86_CVTSI2SD_XREG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_D(dest_size) && REG_IS_Q(src_size)) + { + /*There is no SSE instruction to convert a 64-bit integer to a floating point value. + Instead we have to bounce the integer through memory via x87.*/ + host_x86_MOVQ_BASE_OFFSET_XREG(block, REG_ESP, 0, src_reg); + host_x87_FILDq_BASE(block, REG_ESP); + host_x87_FSTPd_BASE(block, REG_ESP); + host_x86_MOVQ_XREG_BASE_OFFSET(block, dest_reg, REG_ESP, 0); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_DOUBLE_INT %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_INT_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_D(src_size)) + { + host_x86_LDMXCSR(block, &cpu_state.new_fp_control); + host_x86_CVTSD2SI_REG_XREG(block, dest_reg, src_reg); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + } + else if (REG_IS_W(dest_size) && REG_IS_D(src_size)) + { + host_x86_LDMXCSR(block, &cpu_state.new_fp_control); + host_x86_CVTSD2SI_REG_XREG(block, REG_ECX, src_reg); + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_INT_DOUBLE %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_MOV_INT_DOUBLE_64(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), src_64_reg = HOST_REG_GET(uop->src_reg_b_real), tag_reg = HOST_REG_GET(uop->src_reg_c_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real), src_64_size = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_D(src_size) && REG_IS_Q(src_64_size)) + { + uint32_t *branch_offset; + + /*If TAG_UINT64 is set then the source is MM[]. Otherwise it is a double in ST()*/ + host_x86_MOVQ_XREG_XREG(block, dest_reg, src_64_reg); + host_x86_TEST8_REG(block, tag_reg, tag_reg); + branch_offset = host_x86_JS_long(block); + + /*There is no SSE instruction to convert a floating point value to a 64-bit integer. + Instead we have to bounce through memory via x87.*/ + host_x87_FLDCW(block, &cpu_state.new_fp_control2); + host_x86_MOVQ_BASE_OFFSET_XREG(block, REG_ESP, 0, src_reg); + host_x87_FLDd_BASE(block, REG_ESP); + host_x87_FISTPq_BASE(block, REG_ESP); + host_x86_MOVQ_XREG_BASE_OFFSET(block, dest_reg, REG_ESP, 0); + host_x87_FLDCW(block, &cpu_state.old_fp_control2); + + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_INT_DOUBLE_64 %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_NOP(codeblock_t *block, uop_t *uop) +{ + return 0; +} + +static int codegen_OR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_POR_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg_a); + host_x86_OR32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_OR16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_OR8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("OR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_OR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size) && dest_reg == src_reg) + { + host_x86_OR32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && dest_reg == src_reg) + { + host_x86_OR16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && dest_reg == src_reg) + { + host_x86_OR8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("OR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_PACKSSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PACKSSWB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PACKSSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PACKSSDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PACKSSDW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PACKSSDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PACKUSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PACKUSWB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PACKUSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PADDB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDUSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDUSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PCMPEQB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPEQB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPEQB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPEQW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPEQW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPEQW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPEQD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPEQD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPEQD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPGTB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPGTB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPGTB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPGTW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPGTW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPGTW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPGTD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPGTD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPGTD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PF2ID(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_x86_LDMXCSR(block, &cpu_state.trunc_fp_control); + host_x86_CVTPS2DQ_XREG_XREG(block, dest_reg, src_reg_a); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PF2ID %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_PFADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_ADDPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFCMPEQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_CMPPS_XREG_XREG(block, dest_reg, src_reg_b, CMPPS_EQ); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFCMPEQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFCMPGE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_CMPPS_XREG_XREG(block, dest_reg, src_reg_b, CMPPS_NLT); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFCMPGE %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFCMPGT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_CMPPS_XREG_XREG(block, dest_reg, src_reg_b, CMPPS_NLE); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFCMPGT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFMAX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_MAXPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFMAX %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFMIN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_MINPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFMIN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_MULPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFRCP(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use RCPSS + iteration)*/ + host_x86_MOV32_REG_IMM(block, REG_ECX, 1); + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_CVTSI2SS_XREG_REG(block, dest_reg, REG_ECX); + host_x86_DIVSS_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + host_x86_UNPCKLPS_XREG_XREG(block, dest_reg, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFRCP %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_PFRSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use RSQRTSS + iteration)*/ + host_x86_SQRTSS_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_MOV32_REG_IMM(block, REG_ECX, 1); + host_x86_CVTSI2SS_XREG_REG(block, dest_reg, REG_ECX); + host_x86_DIVSS_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + host_x86_UNPCKLPS_XREG_XREG(block, dest_reg, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFRSQRT %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_PFSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_SUBPS_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_SUBPS_XREG_XREG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PI2FD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_x86_CVTDQ2PS_XREG_XREG(block, dest_reg, src_reg_a); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PI2FD %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} + +static int codegen_PMADDWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PMADDWD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PMULHW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PMULHW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PMULLW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PMULLW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PMULLW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PSLLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSLLW_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSLLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSLLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSLLD_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSLLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSLLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSLLQ_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSLLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRAW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRAW_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRAW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRAD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRAD_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRAD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRAQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRAQ_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRAQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRLW_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRLD_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRLQ_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_PSUBB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBUSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBUSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PUNPCKHBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLBW_XREG_XREG(block, dest_reg, src_reg_b); + host_x86_PSHUFD_XREG_XREG_IMM(block, dest_reg, dest_reg, 0xee); /*0xee = move top 64-bits to low 64-bits*/ + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKHBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKHWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLWD_XREG_XREG(block, dest_reg, src_reg_b); + host_x86_PSHUFD_XREG_XREG_IMM(block, dest_reg, dest_reg, 0xee); /*0xee = move top 64-bits to low 64-bits*/ + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKHWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKHDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLDQ_XREG_XREG(block, dest_reg, src_reg_b); + host_x86_PSHUFD_XREG_XREG_IMM(block, dest_reg, dest_reg, 0xee); /*0xee = move top 64-bits to low 64-bits*/ + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKHDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKLBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLBW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKLBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKLWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLWD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKLWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKLDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLDQ_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKLDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_ROL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROL32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROL16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROL8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_ROL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROL32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROL16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROL8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_ROR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROR32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROR16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROR8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_ROR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROR32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROR16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROR8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_SAR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SAR32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SAR16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SAR8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SAR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SAR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SAR32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SAR16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SAR8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SAR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHL32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHL16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHL8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHL32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHL16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHL8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHR32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHR16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHR8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHR32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHR16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHR8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_STORE_PTR_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_ABS_IMM(block, uop->p, uop->imm_data); + return 0; +} +static int codegen_STORE_PTR_IMM_8(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV8_ABS_IMM(block, uop->p, uop->imm_data); + return 0; +} + +static int codegen_SUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg_a); + host_x86_SUB32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_SUB16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_SUB8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_SUB_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SUB32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SUB16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SUB8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SUB_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_TEST_JNS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_TEST32_REG(block, src_reg, src_reg); + } + else if (REG_IS_W(src_size)) + { + host_x86_TEST16_REG(block, src_reg, src_reg); + } + else if (REG_IS_B(src_size)) + { + host_x86_TEST8_REG(block, src_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("TEST_JNS_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNS_long(block); + + return 0; +} +static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_TEST32_REG(block, src_reg, src_reg); + } + else if (REG_IS_W(src_size)) + { + host_x86_TEST16_REG(block, src_reg, src_reg); + } + else if (REG_IS_B(src_size)) + { + host_x86_TEST8_REG(block, src_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("TEST_JS_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JS_long(block); + + return 0; +} + +static int codegen_XOR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PXOR_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("XOR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("XOR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +#ifdef DEBUG_EXTRA +static int codegen_LOG_INSTR(codeblock_t *block, uop_t *uop) +{ + if (uop->imm_data > 256*256) + fatal("LOG_INSTR %08x\n", uop->imm_data); + host_x86_INC32_ABS(block, &instr_counts[uop->imm_data]); + return 0; +} +#endif + +const uOpFn uop_handlers[UOP_MAX] = +{ + [UOP_CALL_FUNC & UOP_MASK] = codegen_CALL_FUNC, + [UOP_CALL_FUNC_RESULT & UOP_MASK] = codegen_CALL_FUNC_RESULT, + [UOP_CALL_INSTRUCTION_FUNC & UOP_MASK] = codegen_CALL_INSTRUCTION_FUNC, + + [UOP_JMP & UOP_MASK] = codegen_JMP, + [UOP_JMP_DEST & UOP_MASK] = codegen_JMP_DEST, + + [UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG, + + [UOP_LOAD_FUNC_ARG_0 & UOP_MASK] = codegen_LOAD_FUNC_ARG0, + [UOP_LOAD_FUNC_ARG_1 & UOP_MASK] = codegen_LOAD_FUNC_ARG1, + [UOP_LOAD_FUNC_ARG_2 & UOP_MASK] = codegen_LOAD_FUNC_ARG2, + [UOP_LOAD_FUNC_ARG_3 & UOP_MASK] = codegen_LOAD_FUNC_ARG3, + + [UOP_LOAD_FUNC_ARG_0_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG0_IMM, + [UOP_LOAD_FUNC_ARG_1_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG1_IMM, + [UOP_LOAD_FUNC_ARG_2_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG2_IMM, + [UOP_LOAD_FUNC_ARG_3_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG3_IMM, + + [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, + [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, + [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, + [UOP_MEM_LOAD_SINGLE & UOP_MASK] = codegen_MEM_LOAD_SINGLE, + [UOP_MEM_LOAD_DOUBLE & UOP_MASK] = codegen_MEM_LOAD_DOUBLE, + + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, + [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, + [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, + [UOP_MEM_STORE_IMM_16 & UOP_MASK] = codegen_MEM_STORE_IMM_16, + [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, + [UOP_MEM_STORE_SINGLE & UOP_MASK] = codegen_MEM_STORE_SINGLE, + [UOP_MEM_STORE_DOUBLE & UOP_MASK] = codegen_MEM_STORE_DOUBLE, + + [UOP_MOV & UOP_MASK] = codegen_MOV, + [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, + [UOP_MOVSX & UOP_MASK] = codegen_MOVSX, + [UOP_MOVZX & UOP_MASK] = codegen_MOVZX, + [UOP_MOV_DOUBLE_INT & UOP_MASK] = codegen_MOV_DOUBLE_INT, + [UOP_MOV_INT_DOUBLE & UOP_MASK] = codegen_MOV_INT_DOUBLE, + [UOP_MOV_INT_DOUBLE_64 & UOP_MASK] = codegen_MOV_INT_DOUBLE_64, + [UOP_MOV_REG_PTR & UOP_MASK] = codegen_MOV_REG_PTR, + [UOP_MOVZX_REG_PTR_8 & UOP_MASK] = codegen_MOVZX_REG_PTR_8, + [UOP_MOVZX_REG_PTR_16 & UOP_MASK] = codegen_MOVZX_REG_PTR_16, + + [UOP_ADD & UOP_MASK] = codegen_ADD, + [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, + [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, + [UOP_AND & UOP_MASK] = codegen_AND, + [UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM, + [UOP_ANDN & UOP_MASK] = codegen_ANDN, + [UOP_OR & UOP_MASK] = codegen_OR, + [UOP_OR_IMM & UOP_MASK] = codegen_OR_IMM, + [UOP_SUB & UOP_MASK] = codegen_SUB, + [UOP_SUB_IMM & UOP_MASK] = codegen_SUB_IMM, + [UOP_XOR & UOP_MASK] = codegen_XOR, + [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM, + + [UOP_SAR & UOP_MASK] = codegen_SAR, + [UOP_SAR_IMM & UOP_MASK] = codegen_SAR_IMM, + [UOP_SHL & UOP_MASK] = codegen_SHL, + [UOP_SHL_IMM & UOP_MASK] = codegen_SHL_IMM, + [UOP_SHR & UOP_MASK] = codegen_SHR, + [UOP_SHR_IMM & UOP_MASK] = codegen_SHR_IMM, + [UOP_ROL & UOP_MASK] = codegen_ROL, + [UOP_ROL_IMM & UOP_MASK] = codegen_ROL_IMM, + [UOP_ROR & UOP_MASK] = codegen_ROR, + [UOP_ROR_IMM & UOP_MASK] = codegen_ROR_IMM, + + [UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ, + + [UOP_CMP_JB & UOP_MASK] = codegen_CMP_JB, + [UOP_CMP_JNBE & UOP_MASK] = codegen_CMP_JNBE, + + [UOP_CMP_JNB_DEST & UOP_MASK] = codegen_CMP_JNB_DEST, + [UOP_CMP_JNBE_DEST & UOP_MASK] = codegen_CMP_JNBE_DEST, + [UOP_CMP_JNL_DEST & UOP_MASK] = codegen_CMP_JNL_DEST, + [UOP_CMP_JNLE_DEST & UOP_MASK] = codegen_CMP_JNLE_DEST, + [UOP_CMP_JNO_DEST & UOP_MASK] = codegen_CMP_JNO_DEST, + [UOP_CMP_JNZ_DEST & UOP_MASK] = codegen_CMP_JNZ_DEST, + [UOP_CMP_JB_DEST & UOP_MASK] = codegen_CMP_JB_DEST, + [UOP_CMP_JBE_DEST & UOP_MASK] = codegen_CMP_JBE_DEST, + [UOP_CMP_JL_DEST & UOP_MASK] = codegen_CMP_JL_DEST, + [UOP_CMP_JLE_DEST & UOP_MASK] = codegen_CMP_JLE_DEST, + [UOP_CMP_JO_DEST & UOP_MASK] = codegen_CMP_JO_DEST, + [UOP_CMP_JZ_DEST & UOP_MASK] = codegen_CMP_JZ_DEST, + + [UOP_CMP_IMM_JNZ_DEST & UOP_MASK] = codegen_CMP_IMM_JNZ_DEST, + [UOP_CMP_IMM_JZ_DEST & UOP_MASK] = codegen_CMP_IMM_JZ_DEST, + + [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, + [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, + + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, + [UOP_MMX_ENTER & UOP_MASK] = codegen_MMX_ENTER, + + [UOP_FADD & UOP_MASK] = codegen_FADD, + [UOP_FDIV & UOP_MASK] = codegen_FDIV, + [UOP_FMUL & UOP_MASK] = codegen_FMUL, + [UOP_FSUB & UOP_MASK] = codegen_FSUB, + [UOP_FCOM & UOP_MASK] = codegen_FCOM, + + [UOP_FABS & UOP_MASK] = codegen_FABS, + [UOP_FCHS & UOP_MASK] = codegen_FCHS, + [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, + [UOP_FTST & UOP_MASK] = codegen_FTST, + + [UOP_PACKSSWB & UOP_MASK] = codegen_PACKSSWB, + [UOP_PACKSSDW & UOP_MASK] = codegen_PACKSSDW, + [UOP_PACKUSWB & UOP_MASK] = codegen_PACKUSWB, + + [UOP_PADDB & UOP_MASK] = codegen_PADDB, + [UOP_PADDW & UOP_MASK] = codegen_PADDW, + [UOP_PADDD & UOP_MASK] = codegen_PADDD, + [UOP_PADDSB & UOP_MASK] = codegen_PADDSB, + [UOP_PADDSW & UOP_MASK] = codegen_PADDSW, + [UOP_PADDUSB & UOP_MASK] = codegen_PADDUSB, + [UOP_PADDUSW & UOP_MASK] = codegen_PADDUSW, + + [UOP_PCMPEQB & UOP_MASK] = codegen_PCMPEQB, + [UOP_PCMPEQW & UOP_MASK] = codegen_PCMPEQW, + [UOP_PCMPEQD & UOP_MASK] = codegen_PCMPEQD, + [UOP_PCMPGTB & UOP_MASK] = codegen_PCMPGTB, + [UOP_PCMPGTW & UOP_MASK] = codegen_PCMPGTW, + [UOP_PCMPGTD & UOP_MASK] = codegen_PCMPGTD, + + [UOP_PF2ID & UOP_MASK] = codegen_PF2ID, + [UOP_PFADD & UOP_MASK] = codegen_PFADD, + [UOP_PFCMPEQ & UOP_MASK] = codegen_PFCMPEQ, + [UOP_PFCMPGE & UOP_MASK] = codegen_PFCMPGE, + [UOP_PFCMPGT & UOP_MASK] = codegen_PFCMPGT, + [UOP_PFMAX & UOP_MASK] = codegen_PFMAX, + [UOP_PFMIN & UOP_MASK] = codegen_PFMIN, + [UOP_PFMUL & UOP_MASK] = codegen_PFMUL, + [UOP_PFRCP & UOP_MASK] = codegen_PFRCP, + [UOP_PFRSQRT & UOP_MASK] = codegen_PFRSQRT, + [UOP_PFSUB & UOP_MASK] = codegen_PFSUB, + [UOP_PI2FD & UOP_MASK] = codegen_PI2FD, + + [UOP_PMADDWD & UOP_MASK] = codegen_PMADDWD, + [UOP_PMULHW & UOP_MASK] = codegen_PMULHW, + [UOP_PMULLW & UOP_MASK] = codegen_PMULLW, + + [UOP_PSLLW_IMM & UOP_MASK] = codegen_PSLLW_IMM, + [UOP_PSLLD_IMM & UOP_MASK] = codegen_PSLLD_IMM, + [UOP_PSLLQ_IMM & UOP_MASK] = codegen_PSLLQ_IMM, + [UOP_PSRAW_IMM & UOP_MASK] = codegen_PSRAW_IMM, + [UOP_PSRAD_IMM & UOP_MASK] = codegen_PSRAD_IMM, + [UOP_PSRAQ_IMM & UOP_MASK] = codegen_PSRAQ_IMM, + [UOP_PSRLW_IMM & UOP_MASK] = codegen_PSRLW_IMM, + [UOP_PSRLD_IMM & UOP_MASK] = codegen_PSRLD_IMM, + [UOP_PSRLQ_IMM & UOP_MASK] = codegen_PSRLQ_IMM, + + [UOP_PSUBB & UOP_MASK] = codegen_PSUBB, + [UOP_PSUBW & UOP_MASK] = codegen_PSUBW, + [UOP_PSUBD & UOP_MASK] = codegen_PSUBD, + [UOP_PSUBSB & UOP_MASK] = codegen_PSUBSB, + [UOP_PSUBSW & UOP_MASK] = codegen_PSUBSW, + [UOP_PSUBUSB & UOP_MASK] = codegen_PSUBUSB, + [UOP_PSUBUSW & UOP_MASK] = codegen_PSUBUSW, + + [UOP_PUNPCKHBW & UOP_MASK] = codegen_PUNPCKHBW, + [UOP_PUNPCKHWD & UOP_MASK] = codegen_PUNPCKHWD, + [UOP_PUNPCKHDQ & UOP_MASK] = codegen_PUNPCKHDQ, + [UOP_PUNPCKLBW & UOP_MASK] = codegen_PUNPCKLBW, + [UOP_PUNPCKLWD & UOP_MASK] = codegen_PUNPCKLWD, + [UOP_PUNPCKLDQ & UOP_MASK] = codegen_PUNPCKLDQ, + + [UOP_NOP_BARRIER & UOP_MASK] = codegen_NOP, + +#ifdef DEBUG_EXTRA + [UOP_LOG_INSTR & UOP_MASK] = codegen_LOG_INSTR +#endif +}; + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV8_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV16_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV32_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_pointer(codeblock_t *block, int host_reg, void *p) +{ + codegen_direct_read_32(block, host_reg, p); +} +void codegen_direct_read_64(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOVQ_XREG_ABS(block, host_reg, p); +} +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOVQ_XREG_ABS(block, host_reg, p); +} +void codegen_direct_read_st_8(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOV8_REG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_EBP, REG_ECX, 0); +} +void codegen_direct_read_st_64(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_EBP, REG_ECX, 3); +} +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_EBP, REG_ECX, 3); +} + +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV8_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_16(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV16_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV32_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_64(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOVQ_ABS_XREG(block, p, host_reg); +} +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOVQ_ABS_XREG(block, p, host_reg); +} +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOV8_ABS_REG_REG_SHIFT_REG(block, offset, REG_EBP, REG_ECX, 0, host_reg); +} +void codegen_direct_write_st_64(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(block, offset, REG_EBP, REG_ECX, 3, host_reg); +} +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(block, offset, REG_EBP, REG_ECX, 3, host_reg); +} + +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV32_ABS_REG(block, p, host_reg); +} + +void codegen_direct_read_16_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOV16_REG_BASE_OFFSET(block, host_reg, REG_ESP, stack_offset); +} +void codegen_direct_read_32_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOV32_REG_BASE_OFFSET(block, host_reg, REG_ESP, stack_offset); +} +void codegen_direct_read_pointer_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + codegen_direct_read_32_stack(block, host_reg, stack_offset); +} +void codegen_direct_read_64_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOVQ_XREG_BASE_OFFSET(block, host_reg, REG_ESP, stack_offset); +} +void codegen_direct_read_double_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOVQ_XREG_BASE_OFFSET(block, host_reg, REG_ESP, stack_offset); +} + +void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOV32_BASE_OFFSET_REG(block, REG_ESP, stack_offset, host_reg); +} +void codegen_direct_write_64_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOVQ_BASE_OFFSET_XREG(block, REG_ESP, stack_offset, host_reg); +} +void codegen_direct_write_double_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOVQ_BASE_OFFSET_XREG(block, REG_ESP, stack_offset, host_reg); +} + +void codegen_set_jump_dest(codeblock_t *block, void *p) +{ + *(uint32_t *)p = (uintptr_t)&block_write_data[block_pos] - ((uintptr_t)p + 4); +} + +#endif diff --git a/src/cpu_new/codegen_block.c b/src/cpu_new/codegen_block.c new file mode 100644 index 000000000..acff96a92 --- /dev/null +++ b/src/cpu_new/codegen_block.c @@ -0,0 +1,862 @@ +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.h" + +#include "386_common.h" + +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_ir.h" +#include "codegen_reg.h" + +uint8_t *block_write_data = NULL; + +int codegen_flat_ds, codegen_flat_ss; +int mmx_ebx_ecx_loaded; +int codegen_flags_changed = 0; +int codegen_fpu_entered = 0; +int codegen_mmx_entered = 0; +int codegen_fpu_loaded_iq[8]; +x86seg *op_ea_seg; +int op_ssegs; +uint32_t op_old_pc; + +uint32_t recomp_page = -1; + +int block_current = 0; +static int block_num; +int block_pos; + +int cpu_recomp_flushes, cpu_recomp_flushes_latched; +int cpu_recomp_evicted, cpu_recomp_evicted_latched; +int cpu_recomp_reuse, cpu_recomp_reuse_latched; +int cpu_recomp_removed, cpu_recomp_removed_latched; + +uint32_t codegen_endpc; + +int codegen_block_cycles; +static int codegen_block_ins; +static int codegen_block_full_ins; + +static uint32_t last_op32; +static x86seg *last_ea_seg; +static int last_ssegs; + +#ifdef DEBUG_EXTRA +uint32_t instr_counts[256*256]; +#endif + +static uint16_t block_free_list; +static void delete_block(codeblock_t *block); +static void delete_dirty_block(codeblock_t *block); + +/*Temporary list of code blocks that have recently been evicted. This allows for + some historical state to be kept when a block is the target of self-modifying + code. + + The size of this list is limited to DIRTY_LIST_MAX_SIZE blocks. When this is + exceeded the oldest entry will be moved to the free list.*/ +static uint16_t block_dirty_list_head, block_dirty_list_tail; +static int dirty_list_size = 0; +#define DIRTY_LIST_MAX_SIZE 64 + +static void block_free_list_add(codeblock_t *block) +{ + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + fatal("block_free_list_add: block=%p in dirty list\n", block); + if (block_free_list) + block->next = block_free_list; + else + block->next = 0; + block_free_list = get_block_nr(block); + block->flags = CODEBLOCK_IN_FREE_LIST; +} + +static void block_dirty_list_add(codeblock_t *block) +{ + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + fatal("block_dirty_list_add: block=%p already in dirty list\n", block); + if (block_dirty_list_head != BLOCK_INVALID) + { + codeblock_t *old_head = &codeblock[block_dirty_list_head]; + + block->next = block_dirty_list_head; + block->prev = BLOCK_INVALID; + block_dirty_list_head = old_head->prev = get_block_nr(block); + } + else + { + /*List empty*/ + block->prev = block->next = BLOCK_INVALID; + block_dirty_list_head = block_dirty_list_tail = get_block_nr(block); + } + block->flags |= CODEBLOCK_IN_DIRTY_LIST; + dirty_list_size++; + if (dirty_list_size > DIRTY_LIST_MAX_SIZE) + { + /*Evict oldest block to the free list*/ + codeblock_t *evict_block = &codeblock[block_dirty_list_tail]; + + if (!(evict_block->flags & CODEBLOCK_IN_DIRTY_LIST)) + fatal("block_dirty_list_add: evict_block=%p %x %x not in dirty list\n", evict_block, evict_block->phys, evict_block->flags); + if (!block_dirty_list_tail) + fatal("block_dirty_list_add - !block_dirty_list_tail\n"); + if (evict_block->prev == BLOCK_INVALID) + fatal("block_dirty_list_add - evict_block->prev == BLOCK_INVALID\n"); + + block_dirty_list_tail = evict_block->prev; + codeblock[evict_block->prev].next = BLOCK_INVALID; + + dirty_list_size--; + evict_block->flags &= ~CODEBLOCK_IN_DIRTY_LIST; + delete_dirty_block(evict_block); + } +} + +static void block_dirty_list_remove(codeblock_t *block) +{ + codeblock_t *prev_block = &codeblock[block->prev]; + codeblock_t *next_block = &codeblock[block->next]; + + if (!(block->flags & CODEBLOCK_IN_DIRTY_LIST)) + fatal("block_dirty_list_remove: block=%p not in dirty list\n", block); + + /*Is block head of list*/ + if (block->prev == BLOCK_INVALID) + block_dirty_list_head = block->next; + else + prev_block->next = block->next; + + /*Is block tail of list?*/ + if (block->next == BLOCK_INVALID) + block_dirty_list_tail = block->prev; + else + next_block->prev = block->prev; + + dirty_list_size--; + if (dirty_list_size < 0) + fatal("remove - dirty_list_size < 0!\n"); + block->flags &= ~CODEBLOCK_IN_DIRTY_LIST; +} + +int codegen_purge_purgable_list() +{ + if (purgable_page_list_head) + { + page_t *page = &pages[purgable_page_list_head]; + + if (page->code_present_mask & page->dirty_mask) + { + codegen_check_flush(page, page->dirty_mask, purgable_page_list_head << 12); + + if (block_free_list) + return 1; + } + } + return 0; +} + +static codeblock_t *block_free_list_get() +{ + codeblock_t *block = NULL; + + while (!block_free_list) + { + /*Free list is empty, check the dirty list*/ + if (block_dirty_list_tail) + { + if (dirty_list_size <= 0) + fatal("get - dirty_list_size <= 0!\n"); + + /*Reuse oldest block*/ + block = &codeblock[block_dirty_list_tail]; + + block_dirty_list_tail = block->prev; + if (block->prev == BLOCK_INVALID) + block_dirty_list_head = BLOCK_INVALID; + else + codeblock[block->prev].next = BLOCK_INVALID; + dirty_list_size--; + block->flags &= ~CODEBLOCK_IN_DIRTY_LIST; + delete_dirty_block(block); + block_free_list = get_block_nr(block); + break; + } + /*Free list is empty - free up a block*/ + if (!codegen_purge_purgable_list()) + codegen_delete_random_block(0); + } + + block = &codeblock[block_free_list]; + block_free_list = block->next; + block->flags &= ~CODEBLOCK_IN_FREE_LIST; + block->next = 0; + return block; +} + +void codegen_init() +{ + int c; + + codegen_allocator_init(); + + codegen_backend_init(); + block_free_list = 0; + for (c = 0; c < BLOCK_SIZE; c++) + block_free_list_add(&codeblock[c]); + block_dirty_list_head = block_dirty_list_tail = 0; + dirty_list_size = 0; +#ifdef DEBUG_EXTRA + memset(instr_counts, 0, sizeof(instr_counts)); +#endif +} + +void codegen_close() +{ +#ifdef DEBUG_EXTRA + pclog("Instruction counts :\n"); + while (1) + { + int c; + uint32_t highest_num = 0, highest_idx = 0; + + for (c = 0; c < 256*256; c++) + { + if (instr_counts[c] > highest_num) + { + highest_num = instr_counts[c]; + highest_idx = c; + } + } + if (!highest_num) + break; + + instr_counts[highest_idx] = 0; + if (highest_idx > 256) + pclog(" %02x %02x = %u\n", highest_idx >> 8, highest_idx & 0xff, highest_num); + else + pclog(" %02x = %u\n", highest_idx & 0xff, highest_num); + } +#endif +} + +void codegen_reset() +{ + int c; + + for (c = 1; c < BLOCK_SIZE; c++) + { + codeblock_t *block = &codeblock[c]; + + if (block->pc != BLOCK_PC_INVALID) + { + block->phys = 0; + block->phys_2 = 0; + delete_block(block); + } + } + + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(uint16_t)); + mem_reset_page_blocks(); + + block_free_list = 0; + for (c = 0; c < BLOCK_SIZE; c++) + { + codeblock[c].pc = BLOCK_PC_INVALID; + block_free_list_add(&codeblock[c]); + } +} + +void dump_block() +{ +/* codeblock_t *block = pages[0x119000 >> 12].block; + + pclog("dump_block:\n"); + while (block) + { + uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); + uint32_t end_pc = (block->endpc & 0xffc) | (block->phys & ~0xfff); + pclog(" %p : %08x-%08x %08x-%08x %p %p\n", (void *)block, start_pc, end_pc, block->pc, block->endpc, (void *)block->prev, (void *)block->next); + if (!block->pc) + fatal("Dead PC=0\n"); + + block = block->next; + } + pclog("dump_block done\n");*/ +} + +static void add_to_block_list(codeblock_t *block) +{ + uint16_t block_prev_nr = pages[block->phys >> 12].block; + uint16_t block_nr = get_block_nr(block); + + if (!block->page_mask) + fatal("add_to_block_list - mask = 0 %llx %llx\n", block->page_mask,block->page_mask2); + + if (block_prev_nr) + { + block->next = block_prev_nr; + codeblock[block_prev_nr].prev = block_nr; + pages[block->phys >> 12].block = block_nr; + } + else + { + block->next = BLOCK_INVALID; + pages[block->phys >> 12].block = block_nr; + } + + if (block->next) + { + if (codeblock[block->next].pc == BLOCK_PC_INVALID) + fatal("block->next->pc=BLOCK_PC_INVALID %p %p %x %x\n", (void *)&codeblock[block->next], (void *)codeblock, block_current, block_pos); + } + + if (block->page_mask2) + { + block->flags |= CODEBLOCK_HAS_PAGE2; + + block_prev_nr = pages[block->phys_2 >> 12].block_2; + + if (block_prev_nr) + { + block->next_2 = block_prev_nr; + codeblock[block_prev_nr].prev_2 = block_nr; + pages[block->phys_2 >> 12].block_2 = block_nr; + } + else + { + block->next_2 = BLOCK_INVALID; + pages[block->phys_2 >> 12].block_2 = block_nr; + } + } +} + +static void remove_from_block_list(codeblock_t *block, uint32_t pc) +{ + if (!block->page_mask) + return; + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + fatal("remove_from_block_list: in dirty list\n"); + + if (block->prev) + { + codeblock[block->prev].next = block->next; + if (block->next) + codeblock[block->next].prev = block->prev; + } + else + { + pages[block->phys >> 12].block = block->next; + if (block->next) + codeblock[block->next].prev = BLOCK_INVALID; + else + mem_flush_write_page(block->phys, 0); + } + + if (!(block->flags & CODEBLOCK_HAS_PAGE2)) + { + if (block->prev_2 || block->next_2) + fatal("Invalid block_2 %x %p %08x\n", block->flags, block, block->phys); + return; + } + block->flags &= ~CODEBLOCK_HAS_PAGE2; + + if (block->prev_2) + { + codeblock[block->prev_2].next_2 = block->next_2; + if (block->next_2) + codeblock[block->next_2].prev_2 = block->prev_2; + } + else + { + pages[block->phys_2 >> 12].block_2 = block->next_2; + if (block->next_2) + codeblock[block->next_2].prev_2 = BLOCK_INVALID; + else + mem_flush_write_page(block->phys_2, 0); + } +} + +static void invalidate_block(codeblock_t *block) +{ + uint32_t old_pc = block->pc; + + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + fatal("invalidate_block: already in dirty list\n"); + if (block->pc == BLOCK_PC_INVALID) + fatal("Invalidating deleted block\n"); + + remove_from_block_list(block, old_pc); + block_dirty_list_add(block); + if (block->head_mem_block) + codegen_allocator_free(block->head_mem_block); + block->head_mem_block = NULL; +} + +static void delete_block(codeblock_t *block) +{ + uint32_t old_pc = block->pc; + + if (block == &codeblock[codeblock_hash[HASH(block->phys)]]) + codeblock_hash[HASH(block->phys)] = BLOCK_INVALID; + + if (block->pc == BLOCK_PC_INVALID) + fatal("Deleting deleted block\n"); + block->pc = BLOCK_PC_INVALID; + + codeblock_tree_delete(block); + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + block_dirty_list_remove(block); + else + remove_from_block_list(block, old_pc); + if (block->head_mem_block) + codegen_allocator_free(block->head_mem_block); + block->head_mem_block = NULL; + block_free_list_add(block); +} + +static void delete_dirty_block(codeblock_t *block) +{ + if (block == &codeblock[codeblock_hash[HASH(block->phys)]]) + codeblock_hash[HASH(block->phys)] = BLOCK_INVALID; + + if (block->pc == BLOCK_PC_INVALID) + fatal("Deleting deleted block\n"); + block->pc = BLOCK_PC_INVALID; + + codeblock_tree_delete(block); + block_free_list_add(block); +} + +void codegen_delete_block(codeblock_t *block) +{ + if (block->pc != BLOCK_PC_INVALID) + delete_block(block); +} + +void codegen_delete_random_block(int required_mem_block) +{ + int block_nr = rand() & BLOCK_MASK; + + while (1) + { + if (block_nr && block_nr != block_current) + { + codeblock_t *block = &codeblock[block_nr]; + + if (block->pc != BLOCK_PC_INVALID && (!required_mem_block || block->head_mem_block)) + { + delete_block(block); + return; + } + } + block_nr = (block_nr + 1) & BLOCK_MASK; + } +} + +void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) +{ + uint16_t block_nr = page->block; + int remove_from_evict_list = 0; + int c; + + while (block_nr) + { + codeblock_t *block = &codeblock[block_nr]; + uint16_t next_block = block->next; + + if (*block->dirty_mask & block->page_mask) + { + invalidate_block(block); + cpu_recomp_evicted++; + } + if (block_nr == next_block) + fatal("Broken 1\n"); + block_nr = next_block; + } + + block_nr = page->block_2; + + while (block_nr) + { + codeblock_t *block = &codeblock[block_nr]; + uint16_t next_block = block->next_2; + + if (*block->dirty_mask2 & block->page_mask2) + { + invalidate_block(block); + cpu_recomp_evicted++; + } + if (block_nr == next_block) + fatal("Broken 2\n"); + block_nr = next_block; + } + + if (page->code_present_mask & page->dirty_mask) + remove_from_evict_list = 1; + page->code_present_mask &= ~page->dirty_mask; + page->dirty_mask = 0; + + for (c = 0; c < 64; c++) + { + if (page->byte_code_present_mask[c] & page->byte_dirty_mask[c]) + remove_from_evict_list = 0; + page->byte_code_present_mask[c] &= ~page->byte_dirty_mask[c]; + page->byte_dirty_mask[c] = 0; + } + if (remove_from_evict_list) + page_remove_from_evict_list(page); +} + +void codegen_block_init(uint32_t phys_addr) +{ + codeblock_t *block; + page_t *page = &pages[phys_addr >> 12]; + + if (!page->block) + mem_flush_write_page(phys_addr, cs+cpu_state.pc); + block = block_free_list_get(); + if (!block) + fatal("codegen_block_init: block_free_list_get() returned NULL\n"); + block_current = get_block_nr(block); + + block_num = HASH(phys_addr); + codeblock_hash[block_num] = block_current; + + block->ins = 0; + block->pc = cs + cpu_state.pc; + block->_cs = cs; + block->phys = phys_addr; + block->dirty_mask = &page->dirty_mask; + block->dirty_mask2 = NULL; + block->next = block->prev = BLOCK_INVALID; + block->next_2 = block->prev_2 = BLOCK_INVALID; + block->page_mask = block->page_mask2 = 0; + block->flags = CODEBLOCK_STATIC_TOP; + block->status = cpu_cur_status; + + recomp_page = block->phys & ~0xfff; + codeblock_tree_add(block); +} + +static ir_data_t *ir_data; + +ir_data_t *codegen_get_ir_data() +{ + return ir_data; +} + +void codegen_block_start_recompile(codeblock_t *block) +{ + page_t *page = &pages[block->phys >> 12]; + + if (!page->block) + mem_flush_write_page(block->phys, cs+cpu_state.pc); + + block_num = HASH(block->phys); + block_current = get_block_nr(block);//block->pnt; + + if (block->pc != cs + cpu_state.pc || (block->flags & CODEBLOCK_WAS_RECOMPILED)) + fatal("Recompile to used block!\n"); + + block->head_mem_block = codegen_allocator_allocate(NULL, block_current); + block->data = codeblock_allocator_get_ptr(block->head_mem_block); + + block->status = cpu_cur_status; + + block->page_mask = block->page_mask2 = 0; + block->ins = 0; + + cpu_block_end = 0; + + last_op32 = -1; + last_ea_seg = NULL; + last_ssegs = -1; + + codegen_block_cycles = 0; + codegen_timing_block_start(); + + codegen_block_ins = 0; + codegen_block_full_ins = 0; + + recomp_page = block->phys & ~0xfff; + + codegen_flags_changed = 0; + codegen_fpu_entered = 0; + codegen_mmx_entered = 0; + + codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] = + codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0; + + cpu_state.seg_ds.checked = cpu_state.seg_es.checked = cpu_state.seg_fs.checked = cpu_state.seg_gs.checked = (cr0 & 1) ? 0 : 1; + + block->TOP = cpu_state.TOP & 7; + block->flags |= CODEBLOCK_WAS_RECOMPILED; + + codegen_flat_ds = !(cpu_cur_status & CPU_STATUS_NOTFLATDS); + codegen_flat_ss = !(cpu_cur_status & CPU_STATUS_NOTFLATSS); + + if (block->flags & CODEBLOCK_BYTE_MASK) + { + block->dirty_mask = &page->byte_dirty_mask[(block->phys >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK]; + block->dirty_mask2 = NULL; + } + + ir_data = codegen_ir_init(); + ir_data->block = block; + codegen_reg_reset(); + codegen_accumulate_reset(); + codegen_generate_reset(); +} + + +void codegen_block_remove() +{ + codeblock_t *block = &codeblock[block_current]; + + delete_block(block); + cpu_recomp_removed++; + + recomp_page = -1; +} + +void codegen_block_generate_end_mask_recompile() +{ + codeblock_t *block = &codeblock[block_current]; + page_t *p; + + p = &pages[block->phys >> 12]; + if (block->flags & CODEBLOCK_BYTE_MASK) + { + int offset = (block->phys >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + + p->byte_code_present_mask[offset] |= block->page_mask; + } + else + p->code_present_mask |= block->page_mask; + + if ((*(block->dirty_mask) & block->page_mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + + block->phys_2 = -1; + block->next_2 = block->prev_2 = BLOCK_INVALID; + if (block->page_mask2) + { + block->phys_2 = get_phys_noabrt(codegen_endpc); + if (block->phys_2 != -1) + { + page_t *page_2 = &pages[block->phys_2 >> 12]; + + if (block->flags & CODEBLOCK_BYTE_MASK) + { + int offset = (block->phys_2 >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + + page_2->byte_code_present_mask[offset] |= block->page_mask2; + block->dirty_mask2 = &page_2->byte_dirty_mask[offset]; + } + else + { + page_2->code_present_mask |= block->page_mask2; + block->dirty_mask2 = &page_2->dirty_mask; + } + if (((*block->dirty_mask2) & block->page_mask2) && !page_in_evict_list(page_2)) + page_add_to_evict_list(page_2); + + if (!pages[block->phys_2 >> 12].block_2) + mem_flush_write_page(block->phys_2, codegen_endpc); + + if (!block->page_mask2) + fatal("!page_mask2\n"); + if (block->next_2) + { + if (codeblock[block->next_2].pc == BLOCK_PC_INVALID) + fatal("block->next_2->pc=BLOCK_PC_INVALID %p\n", (void *)&codeblock[block->next_2]); + } + } + else + { + /*Second page not present. page_mask2 is most likely set only because + the recompiler didn't know how long the last instruction was, so + clear it*/ + block->page_mask2 = 0; + } + } + + recomp_page = -1; +} + +void codegen_block_generate_end_mask_mark() +{ + codeblock_t *block = &codeblock[block_current]; + uint32_t start_pc; + uint32_t end_pc; + page_t *p; + + if (block->flags & CODEBLOCK_BYTE_MASK) + fatal("codegen_block_generate_end_mask2() - BYTE_MASK\n"); + + block->page_mask = 0; + start_pc = (block->pc & 0xfff) & ~63; + if ((block->pc ^ codegen_endpc) & ~0xfff) + end_pc = 0xfff & ~63; + else + end_pc = (codegen_endpc & 0xfff) & ~63; + if (end_pc < start_pc) + end_pc = 0xfff; + start_pc >>= PAGE_MASK_SHIFT; + end_pc >>= PAGE_MASK_SHIFT; + + for (; start_pc <= end_pc; start_pc++) + { + block->page_mask |= ((uint64_t)1 << start_pc); + } + + p = &pages[block->phys >> 12]; + p->code_present_mask |= block->page_mask; + if ((p->dirty_mask & block->page_mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + + block->phys_2 = -1; + block->page_mask2 = 0; + block->next_2 = block->prev_2 = BLOCK_INVALID; + if ((block->pc ^ codegen_endpc) & ~0xfff) + { + block->phys_2 = get_phys_noabrt(codegen_endpc); + if (block->phys_2 != -1) + { + page_t *page_2 = &pages[block->phys_2 >> 12]; + + start_pc = 0; + end_pc = (codegen_endpc & 0xfff) >> PAGE_MASK_SHIFT; + for (; start_pc <= end_pc; start_pc++) + block->page_mask2 |= ((uint64_t)1 << start_pc); + + page_2->code_present_mask |= block->page_mask2; + if ((page_2->dirty_mask & block->page_mask2) && !page_in_evict_list(page_2)) + page_add_to_evict_list(page_2); + + if (!pages[block->phys_2 >> 12].block_2) + mem_flush_write_page(block->phys_2, codegen_endpc); + + if (!block->page_mask2) + fatal("!page_mask2\n"); + if (block->next_2) + { + if (codeblock[block->next_2].pc == BLOCK_PC_INVALID) + fatal("block->next_2->pc=BLOCK_PC_INVALID %p\n", (void *)&codeblock[block->next_2]); + } + + block->dirty_mask2 = &page_2->dirty_mask; + } + else + { + /*Second page not present. page_mask2 is most likely set only because + the recompiler didn't know how long the last instruction was, so + clear it*/ + block->page_mask2 = 0; + } + } + + recomp_page = -1; +} + +void codegen_block_end() +{ + codeblock_t *block = &codeblock[block_current]; + + codegen_block_generate_end_mask_mark(); + add_to_block_list(block); +} + +void codegen_block_end_recompile(codeblock_t *block) +{ + codegen_timing_block_end(); + codegen_accumulate(ACCREG_cycles, -codegen_block_cycles); + + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + block_dirty_list_remove(block); + else + remove_from_block_list(block, block->pc); + block->next = block->prev = BLOCK_INVALID; + block->next_2 = block->prev_2 = BLOCK_INVALID; + codegen_block_generate_end_mask_recompile(); + add_to_block_list(block); + + if (!(block->flags & CODEBLOCK_HAS_FPU)) + block->flags &= ~CODEBLOCK_STATIC_TOP; + + codegen_accumulate_flush(ir_data); + codegen_ir_compile(ir_data, block); +} + +void codegen_flush() +{ + return; +} + +void codegen_mark_code_present_multibyte(codeblock_t *block, uint32_t start_pc, int len) +{ + if (len) + { + uint32_t end_pc = start_pc + (len-1); + + if (block->flags & CODEBLOCK_BYTE_MASK) + { + uint32_t start_pc_masked = start_pc & PAGE_MASK_MASK; + uint32_t end_pc_masked = end_pc & PAGE_MASK_MASK; + + if ((start_pc ^ block->pc) & ~0x3f) /*Starts in second page*/ + { + for (; start_pc_masked <= end_pc_masked; start_pc_masked++) + block->page_mask2 |= ((uint64_t)1 << start_pc_masked); + } + else if (((start_pc + (len-1)) ^ block->pc) & ~0x3f) /*Crosses both pages*/ + { + for (; start_pc_masked <= 63; start_pc_masked++) + block->page_mask |= ((uint64_t)1 << start_pc_masked); + for (start_pc_masked = 0; start_pc_masked <= end_pc_masked; start_pc_masked++) + block->page_mask2 |= ((uint64_t)1 << start_pc_masked); + } + else /*First page only*/ + { + for (; start_pc_masked <= end_pc_masked; start_pc_masked++) + block->page_mask |= ((uint64_t)1 << start_pc_masked); + } + } + else + { + uint32_t start_pc_shifted = start_pc >> PAGE_MASK_SHIFT; + uint32_t end_pc_shifted = end_pc >> PAGE_MASK_SHIFT; + start_pc_shifted &= PAGE_MASK_MASK; + end_pc_shifted &= PAGE_MASK_MASK; + + if ((start_pc ^ block->pc) & ~0xfff) /*Starts in second page*/ + { + for (; start_pc_shifted <= end_pc_shifted; start_pc_shifted++) + block->page_mask2 |= ((uint64_t)1 << start_pc_shifted); + } + else if (((start_pc + (len-1)) ^ block->pc) & ~0xfff) /*Crosses both pages*/ + { + for (; start_pc_shifted <= 63; start_pc_shifted++) + block->page_mask |= ((uint64_t)1 << start_pc_shifted); + for (start_pc_shifted = 0; start_pc_shifted <= end_pc_shifted; start_pc_shifted++) + block->page_mask2 |= ((uint64_t)1 << start_pc_shifted); + } + else /*First page only*/ + { + for (; start_pc_shifted <= end_pc_shifted; start_pc_shifted++) + block->page_mask |= ((uint64_t)1 << start_pc_shifted); + } + } + } +} diff --git a/src/cpu_new/codegen_ir.c b/src/cpu_new/codegen_ir.c new file mode 100644 index 000000000..7d305737b --- /dev/null +++ b/src/cpu_new/codegen_ir.c @@ -0,0 +1,188 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_ir.h" +#include "codegen_reg.h" + +extern int has_ea; +static ir_data_t ir_block; + +static int codegen_unroll_start, codegen_unroll_count; +static int codegen_unroll_first_instruction; + +ir_data_t *codegen_ir_init() +{ + ir_block.wr_pos = 0; + + codegen_unroll_count = 0; + + return &ir_block; +} + +void codegen_ir_set_unroll(int count, int start, int first_instruction) +{ + codegen_unroll_count = count; + codegen_unroll_start = start; + codegen_unroll_first_instruction = first_instruction; +} + +static void duplicate_uop(ir_data_t *ir, uop_t *uop, int offset) +{ + uop_t *new_uop = uop_alloc(ir, uop->type); + + if (!ir_reg_is_invalid(uop->src_reg_a)) + new_uop->src_reg_a = codegen_reg_read(uop->src_reg_a.reg); + if (!ir_reg_is_invalid(uop->src_reg_b)) + new_uop->src_reg_b = codegen_reg_read(uop->src_reg_b.reg); + if (!ir_reg_is_invalid(uop->src_reg_c)) + new_uop->src_reg_c = codegen_reg_read(uop->src_reg_c.reg); + if (!ir_reg_is_invalid(uop->dest_reg_a)) + new_uop->dest_reg_a = codegen_reg_write(uop->dest_reg_a.reg, ir->wr_pos-1); + + new_uop->type = uop->type; + new_uop->imm_data = uop->imm_data; + new_uop->p = uop->p; + new_uop->pc = uop->pc; + + if (uop->jump_dest_uop != -1) + { + new_uop->jump_dest_uop = uop->jump_dest_uop + offset; + } +} + +void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) +{ + int jump_target_at_end = -1; + int c; + + if (codegen_unroll_count) + { + int unroll_count; + int unroll_end; + + codegen_set_loop_start(ir, codegen_unroll_first_instruction); + unroll_end = ir->wr_pos; + + for (unroll_count = 1; unroll_count < codegen_unroll_count; unroll_count++) + { + int offset = ir->wr_pos - codegen_unroll_start; + for (c = codegen_unroll_start; c < unroll_end; c++) + { + duplicate_uop(ir, &ir->uops[c], offset); + } + } + } + + codegen_reg_mark_as_required(); + codegen_reg_process_dead_list(ir); + block_write_data = codeblock_allocator_get_ptr(block->head_mem_block); + block_pos = 0; + codegen_backend_prologue(block); + + for (c = 0; c < ir->wr_pos; c++) + { + uop_t *uop = &ir->uops[c]; + + if (uop->type & UOP_TYPE_BARRIER) + codegen_reg_flush_invalidate(ir, block); + + if (uop->type & UOP_TYPE_JUMP_DEST) + { + uop_t *uop_dest = uop; + + while (uop_dest->jump_list_next != -1) + { + uop_dest = &ir->uops[uop_dest->jump_list_next]; + codegen_set_jump_dest(block, uop_dest->p); + } + } + + if ((uop->type & UOP_MASK) == UOP_INVALID) + continue; + + if (uop->type & UOP_TYPE_PARAMS_REGS) + { + codegen_reg_alloc_register(uop->dest_reg_a, uop->src_reg_a, uop->src_reg_b, uop->src_reg_c); + if (uop->src_reg_a.reg != IREG_INVALID) + { + uop->src_reg_a_real = codegen_reg_alloc_read_reg(block, uop->src_reg_a, NULL); + } + if (uop->src_reg_b.reg != IREG_INVALID) + { + uop->src_reg_b_real = codegen_reg_alloc_read_reg(block, uop->src_reg_b, NULL); + } + if (uop->src_reg_c.reg != IREG_INVALID) + { + uop->src_reg_c_real = codegen_reg_alloc_read_reg(block, uop->src_reg_c, NULL); + } + } + + if (uop->type & UOP_TYPE_ORDER_BARRIER) + codegen_reg_flush(ir, block); + + if (uop->type & UOP_TYPE_PARAMS_REGS) + { + if (uop->dest_reg_a.reg != IREG_INVALID) + { + uop->dest_reg_a_real = codegen_reg_alloc_write_reg(block, uop->dest_reg_a); + } + } + + if (!uop_handlers[uop->type & UOP_MASK]) + fatal("!uop_handlers[uop->type & UOP_MASK] %08x\n", uop->type); + uop_handlers[uop->type & UOP_MASK](block, uop); + + if (uop->type & UOP_TYPE_JUMP) + { + if (uop->jump_dest_uop == ir->wr_pos) + { + if (jump_target_at_end == -1) + jump_target_at_end = c; + else + { + uop_t *uop_dest = &ir->uops[jump_target_at_end]; + + while (uop_dest->jump_list_next != -1) + uop_dest = &ir->uops[uop_dest->jump_list_next]; + + uop_dest->jump_list_next = c; + } + } + else + { + uop_t *uop_dest = &ir->uops[uop->jump_dest_uop]; + + while (uop_dest->jump_list_next != -1) + uop_dest = &ir->uops[uop_dest->jump_list_next]; + + uop_dest->jump_list_next = c; + ir->uops[uop->jump_dest_uop].type |= UOP_TYPE_JUMP_DEST; + } + } + } + + codegen_reg_flush_invalidate(ir, block); + + if (jump_target_at_end != -1) + { + uop_t *uop_dest = &ir->uops[jump_target_at_end]; + + while (1) + { + codegen_set_jump_dest(block, uop_dest->p); + if (uop_dest->jump_list_next == -1) + break; + uop_dest = &ir->uops[uop_dest->jump_list_next]; + } + } + + codegen_backend_epilogue(block); + block_write_data = NULL; +// if (has_ea) +// fatal("IR compilation complete\n"); +} diff --git a/src/cpu_new/codegen_ir.h b/src/cpu_new/codegen_ir.h new file mode 100644 index 000000000..60e75cfc9 --- /dev/null +++ b/src/cpu_new/codegen_ir.h @@ -0,0 +1,6 @@ +#include "codegen_ir_defs.h" + +ir_data_t *codegen_ir_init(); + +void codegen_ir_set_unroll(int count, int start, int first_instruction); +void codegen_ir_compile(ir_data_t *ir, codeblock_t *block); diff --git a/src/cpu_new/codegen_ir_defs.h b/src/cpu_new/codegen_ir_defs.h new file mode 100644 index 000000000..9d6c0e69d --- /dev/null +++ b/src/cpu_new/codegen_ir_defs.h @@ -0,0 +1,810 @@ +#ifndef _CODEGEN_IR_DEFS_ +#define _CODEGEN_IR_DEFS_ + +#include "codegen_reg.h" + +#define UOP_REG(reg, size, version) ((reg) | (size) | (version << 8)) + +/*uOP is a barrier. All previous uOPs must have completed before this one executes. + All registers must have been written back or discarded. + This should be used when calling external functions that may change any emulated + registers.*/ +#define UOP_TYPE_BARRIER (1 << 31) + +/*uOP is a barrier. All previous uOPs must have completed before this one executes. + All registers must have been written back, but do not have to be discarded. + This should be used when calling functions that preserve registers, but can cause + the code block to exit (eg memory load/store functions).*/ +#define UOP_TYPE_ORDER_BARRIER (1 << 27) + +/*uOP uses source and dest registers*/ +#define UOP_TYPE_PARAMS_REGS (1 << 28) +/*uOP uses pointer*/ +#define UOP_TYPE_PARAMS_POINTER (1 << 29) +/*uOP uses immediate data*/ +#define UOP_TYPE_PARAMS_IMM (1 << 30) + +/*uOP is a jump, with the destination uOP in uop->jump_dest_uop. The compiler must + set jump_dest in the destination uOP to the address of the branch offset to be + written when known.*/ +#define UOP_TYPE_JUMP (1 << 26) +/*uOP is the destination of a jump, and must set the destination offset of the jump + at compile time.*/ +#define UOP_TYPE_JUMP_DEST (1 << 25) + + +#define UOP_LOAD_FUNC_ARG_0 (UOP_TYPE_PARAMS_REGS | 0x00) +#define UOP_LOAD_FUNC_ARG_1 (UOP_TYPE_PARAMS_REGS | 0x01) +#define UOP_LOAD_FUNC_ARG_2 (UOP_TYPE_PARAMS_REGS | 0x02) +#define UOP_LOAD_FUNC_ARG_3 (UOP_TYPE_PARAMS_REGS | 0x03) +#define UOP_LOAD_FUNC_ARG_0_IMM (UOP_TYPE_PARAMS_IMM | 0x08 | UOP_TYPE_BARRIER) +#define UOP_LOAD_FUNC_ARG_1_IMM (UOP_TYPE_PARAMS_IMM | 0x09 | UOP_TYPE_BARRIER) +#define UOP_LOAD_FUNC_ARG_2_IMM (UOP_TYPE_PARAMS_IMM | 0x0a | UOP_TYPE_BARRIER) +#define UOP_LOAD_FUNC_ARG_3_IMM (UOP_TYPE_PARAMS_IMM | 0x0b | UOP_TYPE_BARRIER) +#define UOP_CALL_FUNC (UOP_TYPE_PARAMS_POINTER | 0x10 | UOP_TYPE_BARRIER) +/*UOP_CALL_INSTRUCTION_FUNC - call instruction handler at p, check return value and exit block if non-zero*/ +#define UOP_CALL_INSTRUCTION_FUNC (UOP_TYPE_PARAMS_POINTER | 0x11 | UOP_TYPE_BARRIER) +#define UOP_STORE_P_IMM (UOP_TYPE_PARAMS_IMM | 0x12) +#define UOP_STORE_P_IMM_8 (UOP_TYPE_PARAMS_IMM | 0x13) +/*UOP_LOAD_SEG - load segment in src_reg_a to segment p via loadseg(), check return value and exit block if non-zero*/ +#define UOP_LOAD_SEG (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x14 | UOP_TYPE_BARRIER) +/*UOP_JMP - jump to ptr*/ +#define UOP_JMP (UOP_TYPE_PARAMS_POINTER | 0x15 | UOP_TYPE_ORDER_BARRIER) +/*UOP_CALL_FUNC - call instruction handler at p, dest_reg = return value*/ +#define UOP_CALL_FUNC_RESULT (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x16 | UOP_TYPE_BARRIER) +/*UOP_JMP_DEST - jump to ptr*/ +#define UOP_JMP_DEST (UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x17 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +#define UOP_NOP_BARRIER (UOP_TYPE_BARRIER | 0x18) + +#ifdef DEBUG_EXTRA +/*UOP_LOG_INSTR - log non-recompiled instruction in imm_data*/ +#define UOP_LOG_INSTR (UOP_TYPE_PARAMS_IMM | 0x1f) +#endif + +/*UOP_MOV_PTR - dest_reg = p*/ +#define UOP_MOV_PTR (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x20) +/*UOP_MOV_IMM - dest_reg = imm_data*/ +#define UOP_MOV_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x21) +/*UOP_MOV - dest_reg = src_reg_a*/ +#define UOP_MOV (UOP_TYPE_PARAMS_REGS | 0x22) +/*UOP_MOVZX - dest_reg = zero_extend(src_reg_a)*/ +#define UOP_MOVZX (UOP_TYPE_PARAMS_REGS | 0x23) +/*UOP_MOVSX - dest_reg = sign_extend(src_reg_a)*/ +#define UOP_MOVSX (UOP_TYPE_PARAMS_REGS | 0x24) +/*UOP_MOV_DOUBLE_INT - dest_reg = (double)src_reg_a*/ +#define UOP_MOV_DOUBLE_INT (UOP_TYPE_PARAMS_REGS | 0x25) +/*UOP_MOV_INT_DOUBLE - dest_reg = (int)src_reg_a. New rounding control in src_reg_b, old rounding control in src_reg_c*/ +#define UOP_MOV_INT_DOUBLE (UOP_TYPE_PARAMS_REGS | 0x26) +/*UOP_MOV_INT_DOUBLE_64 - dest_reg = (int)src_reg_a. New rounding control in src_reg_b, old rounding control in src_reg_c*/ +#define UOP_MOV_INT_DOUBLE_64 (UOP_TYPE_PARAMS_REGS | 0x27) +/*UOP_MOV_REG_PTR - dest_reg = *p*/ +#define UOP_MOV_REG_PTR (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x28) +/*UOP_MOVZX_REG_PTR_8 - dest_reg = *(uint8_t *)p*/ +#define UOP_MOVZX_REG_PTR_8 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x29) +/*UOP_MOVZX_REG_PTR_16 - dest_reg = *(uint16_t *)p*/ +#define UOP_MOVZX_REG_PTR_16 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x2a) +/*UOP_ADD - dest_reg = src_reg_a + src_reg_b*/ +#define UOP_ADD (UOP_TYPE_PARAMS_REGS | 0x30) +/*UOP_ADD_IMM - dest_reg = src_reg_a + immediate*/ +#define UOP_ADD_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x31) +/*UOP_AND - dest_reg = src_reg_a & src_reg_b*/ +#define UOP_AND (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x32) +/*UOP_AND_IMM - dest_reg = src_reg_a & immediate*/ +#define UOP_AND_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x33) +/*UOP_ADD_LSHIFT - dest_reg = src_reg_a + (src_reg_b << imm_data) + Intended for EA calcluations, imm_data must be between 0 and 3*/ +#define UOP_ADD_LSHIFT (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x34) +/*UOP_OR - dest_reg = src_reg_a | src_reg_b*/ +#define UOP_OR (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x35) +/*UOP_OR_IMM - dest_reg = src_reg_a | immediate*/ +#define UOP_OR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x36) +/*UOP_SUB - dest_reg = src_reg_a - src_reg_b*/ +#define UOP_SUB (UOP_TYPE_PARAMS_REGS | 0x37) +/*UOP_SUB_IMM - dest_reg = src_reg_a - immediate*/ +#define UOP_SUB_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x38) +/*UOP_XOR - dest_reg = src_reg_a ^ src_reg_b*/ +#define UOP_XOR (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x39) +/*UOP_XOR_IMM - dest_reg = src_reg_a ^ immediate*/ +#define UOP_XOR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x3a) +/*UOP_ANDN - dest_reg = ~src_reg_a & src_reg_b*/ +#define UOP_ANDN (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x3b) +/*UOP_MEM_LOAD_ABS - dest_reg = src_reg_a:[immediate]*/ +#define UOP_MEM_LOAD_ABS (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x40 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_LOAD_REG - dest_reg = src_reg_a:[src_reg_b]*/ +#define UOP_MEM_LOAD_REG (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x41 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_ABS - src_reg_a:[immediate] = src_reg_b*/ +#define UOP_MEM_STORE_ABS (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x42 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_REG - src_reg_a:[src_reg_b] = src_reg_c*/ +#define UOP_MEM_STORE_REG (UOP_TYPE_PARAMS_REGS | 0x43 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_IMM_8 - byte src_reg_a:[src_reg_b] = imm_data*/ +#define UOP_MEM_STORE_IMM_8 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x44 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_IMM_16 - word src_reg_a:[src_reg_b] = imm_data*/ +#define UOP_MEM_STORE_IMM_16 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x45 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_IMM_32 - long src_reg_a:[src_reg_b] = imm_data*/ +#define UOP_MEM_STORE_IMM_32 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x46 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_LOAD_SINGLE - dest_reg = (float)src_reg_a:[src_reg_b]*/ +#define UOP_MEM_LOAD_SINGLE (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x47 | UOP_TYPE_ORDER_BARRIER) +/*UOP_CMP_IMM_JZ - if (src_reg_a == imm_data) then jump to ptr*/ +#define UOP_CMP_IMM_JZ (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x48 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_LOAD_DOUBLE - dest_reg = (double)src_reg_a:[src_reg_b]*/ +#define UOP_MEM_LOAD_DOUBLE (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x49 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_SINGLE - src_reg_a:[src_reg_b] = src_reg_c*/ +#define UOP_MEM_STORE_SINGLE (UOP_TYPE_PARAMS_REGS | 0x4a | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_DOUBLE - src_reg_a:[src_reg_b] = src_reg_c*/ +#define UOP_MEM_STORE_DOUBLE (UOP_TYPE_PARAMS_REGS | 0x4b | UOP_TYPE_ORDER_BARRIER) +/*UOP_CMP_JB - if (src_reg_a < src_reg_b) then jump to ptr*/ +#define UOP_CMP_JB (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x4c | UOP_TYPE_ORDER_BARRIER) +/*UOP_CMP_JNBE - if (src_reg_a > src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNBE (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x4d | UOP_TYPE_ORDER_BARRIER) + +/*UOP_SAR - dest_reg = src_reg_a >> src_reg_b*/ +#define UOP_SAR (UOP_TYPE_PARAMS_REGS | 0x50) +/*UOP_SAR_IMM - dest_reg = src_reg_a >> immediate*/ +#define UOP_SAR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x51) +/*UOP_SHL - dest_reg = src_reg_a << src_reg_b*/ +#define UOP_SHL (UOP_TYPE_PARAMS_REGS | 0x52) +/*UOP_SHL_IMM - dest_reg = src_reg_a << immediate*/ +#define UOP_SHL_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x53) +/*UOP_SHR - dest_reg = src_reg_a >> src_reg_b*/ +#define UOP_SHR (UOP_TYPE_PARAMS_REGS | 0x54) +/*UOP_SHR_IMM - dest_reg = src_reg_a >> immediate*/ +#define UOP_SHR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x55) +/*UOP_ROL - dest_reg = src_reg_a rotate<< src_reg_b*/ +#define UOP_ROL (UOP_TYPE_PARAMS_REGS | 0x56) +/*UOP_ROL_IMM - dest_reg = src_reg_a rotate<< immediate*/ +#define UOP_ROL_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x57) +/*UOP_ROR - dest_reg = src_reg_a rotate>> src_reg_b*/ +#define UOP_ROR (UOP_TYPE_PARAMS_REGS | 0x58) +/*UOP_ROR_IMM - dest_reg = src_reg_a rotate>> immediate*/ +#define UOP_ROR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x59) + +/*UOP_CMP_IMM_JZ_DEST - if (src_reg_a == imm_data) then jump to ptr*/ +#define UOP_CMP_IMM_JZ_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x60 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_IMM_JNZ_DEST - if (src_reg_a != imm_data) then jump to ptr*/ +#define UOP_CMP_IMM_JNZ_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x61 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) + +/*UOP_CMP_JB_DEST - if (src_reg_a < src_reg_b) then jump to ptr*/ +#define UOP_CMP_JB_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x62 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JNB_DEST - if (src_reg_a >= src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNB_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x63 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JO_DEST - if (src_reg_a < src_reg_b) then jump to ptr*/ +#define UOP_CMP_JO_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x64 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JNO_DEST - if (src_reg_a >= src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNO_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x65 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JZ_DEST - if (src_reg_a == src_reg_b) then jump to ptr*/ +#define UOP_CMP_JZ_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x66 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JNZ_DEST - if (src_reg_a != src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNZ_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x67 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JL_DEST - if (signed)(src_reg_a < src_reg_b) then jump to ptr*/ +#define UOP_CMP_JL_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x68 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JNL_DEST - if (signed)(src_reg_a >= src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNL_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x69 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JBE_DEST - if (src_reg_a <= src_reg_b) then jump to ptr*/ +#define UOP_CMP_JBE_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x6a | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JNBE_DEST - if (src_reg_a > src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNBE_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x6b | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JLE_DEST - if (signed)(src_reg_a <= src_reg_b) then jump to ptr*/ +#define UOP_CMP_JLE_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x6c | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JNLE_DEST - if (signed)(src_reg_a > src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNLE_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x6d | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) + + +/*UOP_TEST_JNS_DEST - if (src_reg_a positive) then jump to ptr*/ +#define UOP_TEST_JNS_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x70 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_TEST_JS_DEST - if (src_reg_a positive) then jump to ptr*/ +#define UOP_TEST_JS_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x71 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) + +/*UOP_FP_ENTER - must be called before any FPU register accessed*/ +#define UOP_FP_ENTER (UOP_TYPE_PARAMS_IMM | 0x80 | UOP_TYPE_BARRIER) +/*UOP_FADD - (floating point) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_FADD (UOP_TYPE_PARAMS_REGS | 0x81) +/*UOP_FSUB - (floating point) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_FSUB (UOP_TYPE_PARAMS_REGS | 0x82) +/*UOP_FMUL - (floating point) dest_reg = src_reg_a * src_reg_b*/ +#define UOP_FMUL (UOP_TYPE_PARAMS_REGS | 0x83) +/*UOP_FDIV - (floating point) dest_reg = src_reg_a / src_reg_b*/ +#define UOP_FDIV (UOP_TYPE_PARAMS_REGS | 0x84) +/*UOP_FCOM - dest_reg = flags from compare(src_reg_a, src_reg_b)*/ +#define UOP_FCOM (UOP_TYPE_PARAMS_REGS | 0x85) +/*UOP_FABS - dest_reg = fabs(src_reg_a)*/ +#define UOP_FABS (UOP_TYPE_PARAMS_REGS | 0x86) +/*UOP_FCHS - dest_reg = fabs(src_reg_a)*/ +#define UOP_FCHS (UOP_TYPE_PARAMS_REGS | 0x87) +/*UOP_FTST - dest_reg = flags from compare(src_reg_a, 0)*/ +#define UOP_FTST (UOP_TYPE_PARAMS_REGS | 0x88) +/*UOP_FSQRT - dest_reg = fsqrt(src_reg_a)*/ +#define UOP_FSQRT (UOP_TYPE_PARAMS_REGS | 0x89) + +/*UOP_MMX_ENTER - must be called before any MMX registers accessed*/ +#define UOP_MMX_ENTER (UOP_TYPE_PARAMS_IMM | 0x90 | UOP_TYPE_BARRIER) +/*UOP_PADDB - (packed byte) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDB (UOP_TYPE_PARAMS_REGS | 0x91) +/*UOP_PADDW - (packed word) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDW (UOP_TYPE_PARAMS_REGS | 0x92) +/*UOP_PADDD - (packed long) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDD (UOP_TYPE_PARAMS_REGS | 0x93) +/*UOP_PADDSB - (packed byte with signed saturation) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDSB (UOP_TYPE_PARAMS_REGS | 0x94) +/*UOP_PADDSW - (packed word with signed saturation) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDSW (UOP_TYPE_PARAMS_REGS | 0x95) +/*UOP_PADDUSB - (packed byte with unsigned saturation) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDUSB (UOP_TYPE_PARAMS_REGS | 0x96) +/*UOP_PADDUSW - (packed word with unsigned saturation) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDUSW (UOP_TYPE_PARAMS_REGS | 0x97) +/*UOP_PSUBB - (packed byte) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBB (UOP_TYPE_PARAMS_REGS | 0x98) +/*UOP_PSUBW - (packed word) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBW (UOP_TYPE_PARAMS_REGS | 0x99) +/*UOP_PSUBD - (packed long) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBD (UOP_TYPE_PARAMS_REGS | 0x9a) +/*UOP_PSUBSB - (packed byte with signed saturation) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBSB (UOP_TYPE_PARAMS_REGS | 0x9b) +/*UOP_PSUBSW - (packed word with signed saturation) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBSW (UOP_TYPE_PARAMS_REGS | 0x9c) +/*UOP_PSUBUSB - (packed byte with unsigned saturation) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBUSB (UOP_TYPE_PARAMS_REGS | 0x9d) +/*UOP_PSUBUSW - (packed word with unsigned saturation) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBUSW (UOP_TYPE_PARAMS_REGS | 0x9e) +/*UOP_PSLLW_IMM - (packed word) dest_reg = src_reg_a << immediate*/ +#define UOP_PSLLW_IMM (UOP_TYPE_PARAMS_REGS | 0x9f) +/*UOP_PSLLD_IMM - (packed long) dest_reg = src_reg_a << immediate*/ +#define UOP_PSLLD_IMM (UOP_TYPE_PARAMS_REGS | 0xa0) +/*UOP_PSLLQ_IMM - (packed quad) dest_reg = src_reg_a << immediate*/ +#define UOP_PSLLQ_IMM (UOP_TYPE_PARAMS_REGS | 0xa1) +/*UOP_PSRAW_IMM - (packed word) dest_reg = src_reg_a >> immediate*/ +#define UOP_PSRAW_IMM (UOP_TYPE_PARAMS_REGS | 0xa2) +/*UOP_PSRAD_IMM - (packed long) dest_reg = src_reg_a >> immediate*/ +#define UOP_PSRAD_IMM (UOP_TYPE_PARAMS_REGS | 0xa3) +/*UOP_PSRAQ_IMM - (packed quad) dest_reg = src_reg_a >> immediate*/ +#define UOP_PSRAQ_IMM (UOP_TYPE_PARAMS_REGS | 0xa4) +/*UOP_PSRLW_IMM - (packed word) dest_reg = src_reg_a >> immediate*/ +#define UOP_PSRLW_IMM (UOP_TYPE_PARAMS_REGS | 0xa5) +/*UOP_PSRLD_IMM - (packed long) dest_reg = src_reg_a >> immediate*/ +#define UOP_PSRLD_IMM (UOP_TYPE_PARAMS_REGS | 0xa6) +/*UOP_PSRLQ_IMM - (packed quad) dest_reg = src_reg_a >> immediate*/ +#define UOP_PSRLQ_IMM (UOP_TYPE_PARAMS_REGS | 0xa7) +/*UOP_PCMPEQB - (packed byte) dest_reg = (src_reg_a == src_reg_b) ? ~0 : 0*/ +#define UOP_PCMPEQB (UOP_TYPE_PARAMS_REGS | 0xa8) +/*UOP_PCMPEQW - (packed word) dest_reg = (src_reg_a == src_reg_b) ? ~0 : 0*/ +#define UOP_PCMPEQW (UOP_TYPE_PARAMS_REGS | 0xa9) +/*UOP_PCMPEQD - (packed long) dest_reg = (src_reg_a == src_reg_b) ? ~0 : 0*/ +#define UOP_PCMPEQD (UOP_TYPE_PARAMS_REGS | 0xaa) +/*UOP_PCMPGTB - (packed signed byte) dest_reg = (src_reg_a > src_reg_b) ? ~0 : 0*/ +#define UOP_PCMPGTB (UOP_TYPE_PARAMS_REGS | 0xab) +/*UOP_PCMPGTW - (packed signed word) dest_reg = (src_reg_a > src_reg_b) ? ~0 : 0*/ +#define UOP_PCMPGTW (UOP_TYPE_PARAMS_REGS | 0xac) +/*UOP_PCMPGTD - (packed signed long) dest_reg = (src_reg_a > src_reg_b) ? ~0 : 0*/ +#define UOP_PCMPGTD (UOP_TYPE_PARAMS_REGS | 0xad) +/*UOP_PUNPCKLBW - (packed byte) dest_reg = interleave low src_reg_a/src_reg_b*/ +#define UOP_PUNPCKLBW (UOP_TYPE_PARAMS_REGS | 0xae) +/*UOP_PUNPCKLWD - (packed word) dest_reg = interleave low src_reg_a/src_reg_b*/ +#define UOP_PUNPCKLWD (UOP_TYPE_PARAMS_REGS | 0xaf) +/*UOP_PUNPCKLDQ - (packed long) dest_reg = interleave low src_reg_a/src_reg_b*/ +#define UOP_PUNPCKLDQ (UOP_TYPE_PARAMS_REGS | 0xb0) +/*UOP_PUNPCKHBW - (packed byte) dest_reg = interleave high src_reg_a/src_reg_b*/ +#define UOP_PUNPCKHBW (UOP_TYPE_PARAMS_REGS | 0xb1) +/*UOP_PUNPCKHWD - (packed word) dest_reg = interleave high src_reg_a/src_reg_b*/ +#define UOP_PUNPCKHWD (UOP_TYPE_PARAMS_REGS | 0xb2) +/*UOP_PUNPCKHDQ - (packed long) dest_reg = interleave high src_reg_a/src_reg_b*/ +#define UOP_PUNPCKHDQ (UOP_TYPE_PARAMS_REGS | 0xb3) +/*UOP_PACKSSWB - dest_reg = interleave src_reg_a/src_reg_b, converting words to bytes with signed saturation*/ +#define UOP_PACKSSWB (UOP_TYPE_PARAMS_REGS | 0xb4) +/*UOP_PACKSSDW - dest_reg = interleave src_reg_a/src_reg_b, converting longs to words with signed saturation*/ +#define UOP_PACKSSDW (UOP_TYPE_PARAMS_REGS | 0xb5) +/*UOP_PACKUSWB - dest_reg = interleave src_reg_a/src_reg_b, converting words to bytes with unsigned saturation*/ +#define UOP_PACKUSWB (UOP_TYPE_PARAMS_REGS | 0xb6) +/*UOP_PMULLW - (packed word) dest_reg = (src_reg_a * src_reg_b) & 0xffff*/ +#define UOP_PMULLW (UOP_TYPE_PARAMS_REGS | 0xb7) +/*UOP_PMULHW - (packed word) dest_reg = (src_reg_a * src_reg_b) >> 16*/ +#define UOP_PMULHW (UOP_TYPE_PARAMS_REGS | 0xb8) +/*UOP_PMADDWD - (packed word) dest_reg = (src_reg_a * src_reg_b) >> 16*/ +#define UOP_PMADDWD (UOP_TYPE_PARAMS_REGS | 0xb9) + +/*UOP_PFADD - (packed float) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PFADD (UOP_TYPE_PARAMS_REGS | 0xba) +/*UOP_PFSUB - (packed float) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PFSUB (UOP_TYPE_PARAMS_REGS | 0xbb) +/*UOP_PFMUL - (packed float) dest_reg = src_reg_a * src_reg_b*/ +#define UOP_PFMUL (UOP_TYPE_PARAMS_REGS | 0xbc) +/*UOP_PFMAX - (packed float) dest_reg = MAX(src_reg_a, src_reg_b)*/ +#define UOP_PFMAX (UOP_TYPE_PARAMS_REGS | 0xbd) +/*UOP_PFMIN - (packed float) dest_reg = MIN(src_reg_a, src_reg_b)*/ +#define UOP_PFMIN (UOP_TYPE_PARAMS_REGS | 0xbe) +/*UOP_PFCMPEQ - (packed float) dest_reg = (src_reg_a == src_reg_b) ? ~0 : 0*/ +#define UOP_PFCMPEQ (UOP_TYPE_PARAMS_REGS | 0xbf) +/*UOP_PFCMPGE - (packed float) dest_reg = (src_reg_a >= src_reg_b) ? ~0 : 0*/ +#define UOP_PFCMPGE (UOP_TYPE_PARAMS_REGS | 0xc0) +/*UOP_PFCMPGT - (packed float) dest_reg = (src_reg_a > src_reg_b) ? ~0 : 0*/ +#define UOP_PFCMPGT (UOP_TYPE_PARAMS_REGS | 0xc1) +/*UOP_PF2ID - (packed long)dest_reg = (packed float)src_reg_a*/ +#define UOP_PF2ID (UOP_TYPE_PARAMS_REGS | 0xc2) +/*UOP_PI2FD - (packed float)dest_reg = (packed long)src_reg_a*/ +#define UOP_PI2FD (UOP_TYPE_PARAMS_REGS | 0xc3) +/*UOP_PFRCP - (packed float) dest_reg[0] = dest_reg[1] = 1.0 / src_reg[0]*/ +#define UOP_PFRCP (UOP_TYPE_PARAMS_REGS | 0xc4) +/*UOP_PFRSQRT - (packed float) dest_reg[0] = dest_reg[1] = 1.0 / sqrt(src_reg[0])*/ +#define UOP_PFRSQRT (UOP_TYPE_PARAMS_REGS | 0xc5) + +#define UOP_MAX 0xc6 + +#define UOP_INVALID 0xff + +#define UOP_MASK 0xffff + +typedef struct uop_t +{ + uint32_t type; + ir_reg_t dest_reg_a; + ir_reg_t src_reg_a; + ir_reg_t src_reg_b; + ir_reg_t src_reg_c; + uint32_t imm_data; + void *p; + ir_host_reg_t dest_reg_a_real; + ir_host_reg_t src_reg_a_real, src_reg_b_real, src_reg_c_real; + int jump_dest_uop; + int jump_list_next; + void *jump_dest; + uint32_t pc; +} uop_t; + +#define UOP_NR_MAX 4096 + +typedef struct ir_data_t +{ + uop_t uops[UOP_NR_MAX]; + int wr_pos; + struct codeblock_t *block; +} ir_data_t; + +static inline uop_t *uop_alloc(ir_data_t *ir, uint32_t uop_type) +{ + uop_t *uop; + + if (ir->wr_pos >= UOP_NR_MAX) + fatal("Exceeded uOP max\n"); + + uop = &ir->uops[ir->wr_pos++]; + + uop->dest_reg_a = invalid_ir_reg; + uop->src_reg_a = invalid_ir_reg; + uop->src_reg_b = invalid_ir_reg; + uop->src_reg_c = invalid_ir_reg; + + uop->pc = cpu_state.oldpc; + + uop->jump_dest_uop = -1; + uop->jump_list_next = -1; + + if (uop_type & (UOP_TYPE_BARRIER | UOP_TYPE_ORDER_BARRIER)) + codegen_reg_mark_as_required(); + + return uop; +} + +static inline void uop_set_jump_dest(ir_data_t *ir, int jump_uop) +{ + uop_t *uop = &ir->uops[jump_uop]; + + uop->jump_dest_uop = ir->wr_pos; +} + +static inline int uop_gen(uint32_t uop_type, ir_data_t *ir) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + + return ir->wr_pos-1; +} + +static inline int uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int src_reg_a) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + + return ir->wr_pos-1; +} + +static inline void uop_gen_reg_src1_arg(uint32_t uop_type, ir_data_t *ir, int arg, int src_reg_a) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); +} + +static inline int uop_gen_reg_src1_imm(uint32_t uop_type, ir_data_t *ir, int src_reg, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg); + uop->imm_data = imm; + + return ir->wr_pos-1; +} + +static inline void uop_gen_reg_dst_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); + uop->imm_data = imm; +} + +static inline void uop_gen_reg_dst_pointer(uint32_t uop_type, ir_data_t *ir, int dest_reg, void *p) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); + uop->p = p; +} + +static inline void uop_gen_reg_dst_src1(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); +} + +static inline void uop_gen_reg_dst_src1_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); + uop->imm_data = imm; +} + +static inline void uop_gen_reg_dst_src2(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); +} + +static inline void uop_gen_reg_dst_src2_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); + uop->imm_data = imm; +} + +static inline void uop_gen_reg_dst_src3(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b, int src_reg_c) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->src_reg_c = codegen_reg_read(src_reg_c); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); +} + +static inline void uop_gen_reg_dst_src_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); + uop->imm_data = imm; +} + +static inline int uop_gen_reg_src2(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + + return ir->wr_pos-1; +} + +static inline void uop_gen_reg_src2_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->imm_data = imm; +} + +static inline void uop_gen_reg_src3(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, int src_reg_c) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->src_reg_c = codegen_reg_read(src_reg_c); +} + +static inline void uop_gen_reg_src3_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, int src_reg_c, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->src_reg_c = codegen_reg_read(src_reg_c); + uop->imm_data = imm; +} + +static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->imm_data = imm; +} + +static inline void uop_gen_pointer(uint32_t uop_type, ir_data_t *ir, void *p) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->p = p; +} + +static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->p = p; + uop->imm_data = imm; +} + +static inline void uop_gen_reg_src_pointer(uint32_t uop_type, ir_data_t *ir, int src_reg_a, void *p) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->p = p; +} + +static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, void *p, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->p = p; + uop->imm_data = imm; +} + +static inline void uop_gen_reg_src2_pointer(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, void *p) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->p = p; +} + +#define uop_LOAD_FUNC_ARG_REG(ir, arg, reg) uop_gen_reg_src1(UOP_LOAD_FUNC_ARG_0 + arg, ir, reg) + +#define uop_LOAD_FUNC_ARG_IMM(ir, arg, imm) uop_gen_imm(UOP_LOAD_FUNC_ARG_0_IMM + arg, ir, imm) + +#define uop_ADD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_ADD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_ADD_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_ADD_IMM, ir, dst_reg, src_reg, imm) +#define uop_ADD_LSHIFT(ir, dst_reg, src_reg_a, src_reg_b, shift) uop_gen_reg_dst_src2_imm(UOP_ADD_LSHIFT, ir, dst_reg, src_reg_a, src_reg_b, shift) +#define uop_AND(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_AND, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_AND_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_AND_IMM, ir, dst_reg, src_reg, imm) +#define uop_ANDN(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_ANDN, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_OR(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_OR, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_OR_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_OR_IMM, ir, dst_reg, src_reg, imm) +#define uop_SUB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_SUB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_SUB_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_SUB_IMM, ir, dst_reg, src_reg, imm) +#define uop_XOR(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_XOR, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_XOR_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_XOR_IMM, ir, dst_reg, src_reg, imm) + +#define uop_SAR(ir, dst_reg, src_reg, shift_reg) uop_gen_reg_dst_src2(UOP_SAR, ir, dst_reg, src_reg, shift_reg) +#define uop_SAR_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_SAR_IMM, ir, dst_reg, src_reg, imm) +#define uop_SHL(ir, dst_reg, src_reg, shift_reg) uop_gen_reg_dst_src2(UOP_SHL, ir, dst_reg, src_reg, shift_reg) +#define uop_SHL_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_SHL_IMM, ir, dst_reg, src_reg, imm) +#define uop_SHR(ir, dst_reg, src_reg, shift_reg) uop_gen_reg_dst_src2(UOP_SHR, ir, dst_reg, src_reg, shift_reg) +#define uop_SHR_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_SHR_IMM, ir, dst_reg, src_reg, imm) +#define uop_ROL(ir, dst_reg, src_reg, shift_reg) uop_gen_reg_dst_src2(UOP_ROL, ir, dst_reg, src_reg, shift_reg) +#define uop_ROL_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_ROL_IMM, ir, dst_reg, src_reg, imm) +#define uop_ROR(ir, dst_reg, src_reg, shift_reg) uop_gen_reg_dst_src2(UOP_ROR, ir, dst_reg, src_reg, shift_reg) +#define uop_ROR_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_ROR_IMM, ir, dst_reg, src_reg, imm) + +#define uop_CALL_FUNC(ir, p) uop_gen_pointer(UOP_CALL_FUNC, ir, p) +#define uop_CALL_FUNC_RESULT(ir, dst_reg, p) uop_gen_reg_dst_pointer(UOP_CALL_FUNC_RESULT, ir, dst_reg, p) +#define uop_CALL_INSTRUCTION_FUNC(ir, p) uop_gen_pointer(UOP_CALL_INSTRUCTION_FUNC, ir, p) + +#define uop_CMP_IMM_JZ(ir, src_reg, imm, p) uop_gen_reg_src_pointer_imm(UOP_CMP_IMM_JZ, ir, src_reg, p, imm) + +#define uop_CMP_IMM_JNZ_DEST(ir, src_reg, imm) uop_gen_reg_src1_imm(UOP_CMP_IMM_JNZ_DEST, ir, src_reg, imm) +#define uop_CMP_IMM_JZ_DEST(ir, src_reg, imm) uop_gen_reg_src1_imm(UOP_CMP_IMM_JZ_DEST, ir, src_reg, imm) + +#define uop_CMP_JB(ir, src_reg_a, src_reg_b, p) uop_gen_reg_src2_pointer(UOP_CMP_JB, ir, src_reg_a, src_reg_b, p) +#define uop_CMP_JNBE(ir, src_reg_a, src_reg_b, p) uop_gen_reg_src2_pointer(UOP_CMP_JNBE, ir, src_reg_a, src_reg_b, p) + +#define uop_CMP_JNB_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNB_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JNBE_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNBE_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JNL_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNL_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JNLE_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNLE_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JNO_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNO_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JNZ_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNZ_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JB_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JB_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JBE_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JBE_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JL_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JL_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JLE_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JLE_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JO_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JO_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JZ_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JZ_DEST, ir, src_reg_a, src_reg_b) + +#define uop_FADD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FADD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_FCOM(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FCOM, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_FDIV(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FDIV, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_FMUL(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FMUL, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_FSUB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FSUB, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_FABS(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_FABS, ir, dst_reg, src_reg) +#define uop_FCHS(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_FCHS, ir, dst_reg, src_reg) +#define uop_FSQRT(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_FSQRT, ir, dst_reg, src_reg) +#define uop_FTST(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_FTST, ir, dst_reg, src_reg) + +#define uop_FP_ENTER(ir) do { if (!codegen_fpu_entered) uop_gen_imm(UOP_FP_ENTER, ir, cpu_state.oldpc); codegen_fpu_entered = 1; codegen_mmx_entered = 0; } while (0) +#define uop_MMX_ENTER(ir) do { if (!codegen_mmx_entered) uop_gen_imm(UOP_MMX_ENTER, ir, cpu_state.oldpc); codegen_mmx_entered = 1; codegen_fpu_entered = 0; } while (0) + +#define uop_JMP(ir, p) uop_gen_pointer(UOP_JMP, ir, p) +#define uop_JMP_DEST(ir) uop_gen(UOP_JMP_DEST, ir) + +#define uop_LOAD_SEG(ir, p, src_reg) uop_gen_reg_src_pointer(UOP_LOAD_SEG, ir, src_reg, p) + +#define uop_MEM_LOAD_ABS(ir, dst_reg, seg_reg, imm) uop_gen_reg_dst_src_imm(UOP_MEM_LOAD_ABS, ir, dst_reg, seg_reg, imm) +#define uop_MEM_LOAD_REG(ir, dst_reg, seg_reg, addr_reg) uop_gen_reg_dst_src2_imm(UOP_MEM_LOAD_REG, ir, dst_reg, seg_reg, addr_reg, 0) +#define uop_MEM_LOAD_REG_OFFSET(ir, dst_reg, seg_reg, addr_reg, offset) uop_gen_reg_dst_src2_imm(UOP_MEM_LOAD_REG, ir, dst_reg, seg_reg, addr_reg, offset) +#define uop_MEM_LOAD_SINGLE(ir, dst_reg, seg_reg, addr_reg) uop_gen_reg_dst_src2_imm(UOP_MEM_LOAD_SINGLE, ir, dst_reg, seg_reg, addr_reg, 0) +#define uop_MEM_LOAD_DOUBLE(ir, dst_reg, seg_reg, addr_reg) uop_gen_reg_dst_src2_imm(UOP_MEM_LOAD_DOUBLE, ir, dst_reg, seg_reg, addr_reg, 0) +#define uop_MEM_STORE_ABS(ir, seg_reg, imm, src_reg) uop_gen_reg_src2_imm(UOP_MEM_STORE_ABS, ir, seg_reg, src_reg, imm) +#define uop_MEM_STORE_REG(ir, seg_reg, addr_reg, src_reg) uop_gen_reg_src3_imm(UOP_MEM_STORE_REG, ir, seg_reg, addr_reg, src_reg, 0) +#define uop_MEM_STORE_REG_OFFSET(ir, seg_reg, addr_reg, offset, src_reg) uop_gen_reg_src3_imm(UOP_MEM_STORE_REG, ir, seg_reg, addr_reg, src_reg, offset) +#define uop_MEM_STORE_IMM_8(ir, seg_reg, addr_reg, imm) uop_gen_reg_src2_imm(UOP_MEM_STORE_IMM_8, ir, seg_reg, addr_reg, imm) +#define uop_MEM_STORE_IMM_16(ir, seg_reg, addr_reg, imm) uop_gen_reg_src2_imm(UOP_MEM_STORE_IMM_16, ir, seg_reg, addr_reg, imm) +#define uop_MEM_STORE_IMM_32(ir, seg_reg, addr_reg, imm) uop_gen_reg_src2_imm(UOP_MEM_STORE_IMM_32, ir, seg_reg, addr_reg, imm) +#define uop_MEM_STORE_SINGLE(ir, seg_reg, addr_reg, src_reg) uop_gen_reg_src3_imm(UOP_MEM_STORE_SINGLE, ir, seg_reg, addr_reg, src_reg, 0) +#define uop_MEM_STORE_DOUBLE(ir, seg_reg, addr_reg, src_reg) uop_gen_reg_src3_imm(UOP_MEM_STORE_DOUBLE, ir, seg_reg, addr_reg, src_reg, 0) + +#define uop_MOV(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_MOV, ir, dst_reg, src_reg) +#define uop_MOV_IMM(ir, reg, imm) uop_gen_reg_dst_imm(UOP_MOV_IMM, ir, reg, imm) +#define uop_MOV_PTR(ir, reg, p) uop_gen_reg_dst_pointer(UOP_MOV_PTR, ir, reg, p) +#define uop_MOV_REG_PTR(ir, reg, p) uop_gen_reg_dst_pointer(UOP_MOV_REG_PTR, ir, reg, p) +#define uop_MOVZX_REG_PTR_8(ir, reg, p) uop_gen_reg_dst_pointer(UOP_MOVZX_REG_PTR_8, ir, reg, p) +#define uop_MOVZX_REG_PTR_16(ir, reg, p) uop_gen_reg_dst_pointer(UOP_MOVZX_REG_PTR_16, ir, reg, p) +#define uop_MOVSX(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_MOVSX, ir, dst_reg, src_reg) +#define uop_MOVZX(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_MOVZX, ir, dst_reg, src_reg) +#define uop_MOV_DOUBLE_INT(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_MOV_DOUBLE_INT, ir, dst_reg, src_reg) +#define uop_MOV_INT_DOUBLE(ir, dst_reg, src_reg/*, nrc, orc*/) uop_gen_reg_dst_src1(UOP_MOV_INT_DOUBLE, ir, dst_reg, src_reg/*, nrc, orc*/) +#define uop_MOV_INT_DOUBLE_64(ir, dst_reg, src_reg_d, src_reg_q, tag) uop_gen_reg_dst_src3(UOP_MOV_INT_DOUBLE_64, ir, dst_reg, src_reg_d, src_reg_q, tag) + +#define uop_NOP_BARRIER(ir) uop_gen(UOP_NOP_BARRIER, ir) + +#define uop_PACKSSWB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PACKSSWB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PACKSSDW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PACKSSDW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PACKUSWB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PACKUSWB, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_PADDB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PADDW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PADDD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PADDSB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDSB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PADDSW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDSW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PADDUSB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDUSB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PADDUSW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDUSW, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_PCMPEQB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PCMPEQB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PCMPEQW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PCMPEQW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PCMPEQD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PCMPEQD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PCMPGTB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PCMPGTB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PCMPGTW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PCMPGTW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PCMPGTD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PCMPGTD, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_PF2ID(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_PF2ID, ir, dst_reg, src_reg) +#define uop_PFADD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFADD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFCMPEQ(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFCMPEQ, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFCMPGE(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFCMPGE, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFCMPGT(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFCMPGT, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFMAX(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFMAX, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFMIN(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFMIN, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFMUL(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFMUL, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFRCP(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_PFRCP, ir, dst_reg, src_reg) +#define uop_PFRSQRT(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_PFRSQRT, ir, dst_reg, src_reg) +#define uop_PFSUB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFSUB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PI2FD(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_PI2FD, ir, dst_reg, src_reg) + +#define uop_PMADDWD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PMADDWD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PMULHW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PMULHW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PMULLW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PMULLW, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_PSLLW_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSLLW_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSLLD_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSLLD_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSLLQ_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSLLQ_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSRAW_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSRAW_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSRAD_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSRAD_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSRAQ_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSRAQ_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSRLW_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSRLW_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSRLD_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSRLD_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSRLQ_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSRLQ_IMM, ir, dst_reg, src_reg, imm) + +#define uop_PSUBB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PSUBW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PSUBD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PSUBSB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBSB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PSUBSW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBSW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PSUBUSB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBUSB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PSUBUSW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBUSW, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_PUNPCKHBW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PUNPCKHBW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PUNPCKHWD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PUNPCKHWD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PUNPCKHDQ(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PUNPCKHDQ, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PUNPCKLBW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PUNPCKLBW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PUNPCKLWD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PUNPCKLWD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PUNPCKLDQ(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PUNPCKLDQ, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_STORE_PTR_IMM(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM, ir, p, imm) +#define uop_STORE_PTR_IMM_8(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM_8, ir, p, imm) + +#define uop_TEST_JNS_DEST(ir, src_reg) uop_gen_reg_src1(UOP_TEST_JNS_DEST, ir, src_reg) +#define uop_TEST_JS_DEST(ir, src_reg) uop_gen_reg_src1(UOP_TEST_JS_DEST, ir, src_reg) + +#ifdef DEBUG_EXTRA +#define uop_LOG_INSTR(ir, imm) uop_gen_imm(UOP_LOG_INSTR, ir, imm) +#endif + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_64(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_pointer(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_st_8(codeblock_t *block, int host_reg, void *base, int reg_idx); +void codegen_direct_read_st_64(codeblock_t *block, int host_reg, void *base, int reg_idx); +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx); + +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_16(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_64(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_pointer(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg); +void codegen_direct_write_st_64(codeblock_t *block, void *base, int reg_idx, int host_reg); +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg); + +void codegen_direct_read_16_stack(codeblock_t *block, int host_reg, int stack_offset); +void codegen_direct_read_32_stack(codeblock_t *block, int host_reg, int stack_offset); +void codegen_direct_read_64_stack(codeblock_t *block, int host_reg, int stack_offset); +void codegen_direct_read_pointer_stack(codeblock_t *block, int host_reg, int stack_offset); +void codegen_direct_read_double_stack(codeblock_t *block, int host_reg, int stack_offset); + +void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int host_reg); +void codegen_direct_write_64_stack(codeblock_t *block, int stack_offset, int host_reg); +void codegen_direct_write_pointer_stack(codeblock_t *block, int stack_offset, int host_reg); +void codegen_direct_write_double_stack(codeblock_t *block, int stack_offset, int host_reg); + +void codegen_set_jump_dest(codeblock_t *block, void *p); + +#endif diff --git a/src/cpu_new/codegen_ops.c b/src/cpu_new/codegen_ops.c new file mode 100644 index 000000000..c1c6e54e7 --- /dev/null +++ b/src/cpu_new/codegen_ops.c @@ -0,0 +1,522 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_3dnow.h" +#include "codegen_ops_arith.h" +#include "codegen_ops_branch.h" +#include "codegen_ops_fpu_arith.h" +#include "codegen_ops_fpu_constant.h" +#include "codegen_ops_fpu_loadstore.h" +#include "codegen_ops_fpu_misc.h" +#include "codegen_ops_jump.h" +#include "codegen_ops_logic.h" +#include "codegen_ops_misc.h" +#include "codegen_ops_mmx_arith.h" +#include "codegen_ops_mmx_cmp.h" +#include "codegen_ops_mmx_loadstore.h" +#include "codegen_ops_mmx_logic.h" +#include "codegen_ops_mmx_pack.h" +#include "codegen_ops_mmx_shift.h" +#include "codegen_ops_mov.h" +#include "codegen_ops_shift.h" +#include "codegen_ops_stack.h" + +RecompOpFn recomp_opcodes[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropADD_b_rmw, ropADD_w_rmw, ropADD_b_rm, ropADD_w_rm, ropADD_AL_imm, ropADD_AX_imm, ropPUSH_ES_16, ropPOP_ES_16, ropOR_b_rmw, ropOR_w_rmw, ropOR_b_rm, ropOR_w_rm, ropOR_AL_imm, ropOR_AX_imm, ropPUSH_CS_16, NULL, +/*10*/ ropADC_b_rmw, ropADC_w_rmw, ropADC_b_rm, ropADC_w_rm, ropADC_AL_imm, ropADC_AX_imm, ropPUSH_SS_16, NULL, ropSBB_b_rmw, ropSBB_w_rmw, ropSBB_b_rm, ropSBB_w_rm, ropSBB_AL_imm, ropSBB_AX_imm, ropPUSH_DS_16, ropPOP_DS_16, +/*20*/ ropAND_b_rmw, ropAND_w_rmw, ropAND_b_rm, ropAND_w_rm, ropAND_AL_imm, ropAND_AX_imm, NULL, NULL, ropSUB_b_rmw, ropSUB_w_rmw, ropSUB_b_rm, ropSUB_w_rm, ropSUB_AL_imm, ropSUB_AX_imm, NULL, NULL, +/*30*/ ropXOR_b_rmw, ropXOR_w_rmw, ropXOR_b_rm, ropXOR_w_rm, ropXOR_AL_imm, ropXOR_AX_imm, NULL, NULL, ropCMP_b_rmw, ropCMP_w_rmw, ropCMP_b_rm, ropCMP_w_rm, ropCMP_AL_imm, ropCMP_AX_imm, NULL, NULL, + +/*40*/ ropINC_r16, ropINC_r16, ropINC_r16, ropINC_r16, ropINC_r16, ropINC_r16, ropINC_r16, ropINC_r16, ropDEC_r16, ropDEC_r16, ropDEC_r16, ropDEC_r16, ropDEC_r16, ropDEC_r16, ropDEC_r16, ropDEC_r16, +/*50*/ ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, +/*60*/ ropPUSHA_16, ropPOPA_16, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_16, NULL, ropPUSH_imm_16_8,NULL, NULL, NULL, NULL, NULL, +/*70*/ ropJO_8, ropJNO_8, ropJB_8, ropJNB_8, ropJE_8, ropJNE_8, ropJBE_8, ropJNBE_8, ropJS_8, ropJNS_8, ropJP_8, ropJNP_8, ropJL_8, ropJNL_8, ropJLE_8, ropJNLE_8, + +/*80*/ rop80, rop81_w, rop80, rop83_w, ropTEST_b_rm, ropTEST_w_rm, ropXCHG_8, ropXCHG_16, ropMOV_b_r, ropMOV_w_r, ropMOV_r_b, ropMOV_r_w, ropMOV_w_seg, ropLEA_16, ropMOV_seg_w, ropPOP_W, +/*90*/ ropNOP, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropCBW, ropCWD, NULL, NULL, ropPUSHF, NULL, NULL, NULL, +/*a0*/ ropMOV_AL_abs, ropMOV_AX_abs, ropMOV_abs_AL, ropMOV_abs_AX, NULL, NULL, NULL, NULL, ropTEST_AL_imm, ropTEST_AX_imm, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, + +/*c0*/ ropC0, ropC1_w, ropRET_imm_16, ropRET_16, ropLES_16, ropLDS_16, ropMOV_b_imm, ropMOV_w_imm, NULL, ropLEAVE_16, ropRETF_imm_16, ropRETF_16, NULL, NULL, NULL, NULL, +/*d0*/ ropD0, ropD1_w, ropD2, ropD3_w, NULL, NULL, NULL, ropXLAT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropLOOPNE, ropLOOPE, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r16, ropJMP_r16, ropJMP_far_16, ropJMP_r8, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, ropCMC, ropF6, ropF7_16, ropCLC, ropSTC, ropCLI, ropSTI, ropCLD, ropSTD, ropINCDEC, ropFF_16, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropADD_b_rmw, ropADD_l_rmw, ropADD_b_rm, ropADD_l_rm, ropADD_AL_imm, ropADD_EAX_imm, ropPUSH_ES_32, ropPOP_ES_32, ropOR_b_rmw, ropOR_l_rmw, ropOR_b_rm, ropOR_l_rm, ropOR_AL_imm, ropOR_EAX_imm, ropPUSH_CS_32, NULL, +/*10*/ ropADC_b_rmw, ropADC_l_rmw, ropADC_b_rm, ropADC_l_rm, ropADC_AL_imm, ropADC_EAX_imm, ropPUSH_SS_32, NULL, ropSBB_b_rmw, ropSBB_l_rmw, ropSBB_b_rm, ropSBB_l_rm, ropSBB_AL_imm, ropSBB_EAX_imm, ropPUSH_DS_32, ropPOP_DS_32, +/*20*/ ropAND_b_rmw, ropAND_l_rmw, ropAND_b_rm, ropAND_l_rm, ropAND_AL_imm, ropAND_EAX_imm, NULL, NULL, ropSUB_b_rmw, ropSUB_l_rmw, ropSUB_b_rm, ropSUB_l_rm, ropSUB_AL_imm, ropSUB_EAX_imm, NULL, NULL, +/*30*/ ropXOR_b_rmw, ropXOR_l_rmw, ropXOR_b_rm, ropXOR_l_rm, ropXOR_AL_imm, ropXOR_EAX_imm, NULL, NULL, ropCMP_b_rmw, ropCMP_l_rmw, ropCMP_b_rm, ropCMP_l_rm, ropCMP_AL_imm, ropCMP_EAX_imm, NULL, NULL, + +/*40*/ ropINC_r32, ropINC_r32, ropINC_r32, ropINC_r32, ropINC_r32, ropINC_r32, ropINC_r32, ropINC_r32, ropDEC_r32, ropDEC_r32, ropDEC_r32, ropDEC_r32, ropDEC_r32, ropDEC_r32, ropDEC_r32, ropDEC_r32, +/*50*/ ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, +/*60*/ ropPUSHA_32, ropPOPA_32, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_32, NULL, ropPUSH_imm_32_8,NULL, NULL, NULL, NULL, NULL, +/*70*/ ropJO_8, ropJNO_8, ropJB_8, ropJNB_8, ropJE_8, ropJNE_8, ropJBE_8, ropJNBE_8, ropJS_8, ropJNS_8, ropJP_8, ropJNP_8, ropJL_8, ropJNL_8, ropJLE_8, ropJNLE_8, + +/*80*/ rop80, rop81_l, rop80, rop83_l, ropTEST_b_rm, ropTEST_l_rm, ropXCHG_8, ropXCHG_32, ropMOV_b_r, ropMOV_l_r, ropMOV_r_b, ropMOV_r_l, ropMOV_l_seg, ropLEA_32, ropMOV_seg_w, ropPOP_L, +/*90*/ ropNOP, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropCWDE, ropCDQ, NULL, NULL, ropPUSHFD, NULL, NULL, NULL, +/*a0*/ ropMOV_AL_abs, ropMOV_EAX_abs, ropMOV_abs_AL, ropMOV_abs_EAX, NULL, NULL, NULL, NULL, ropTEST_AL_imm, ropTEST_EAX_imm,NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, + +/*c0*/ ropC0, ropC1_l, ropRET_imm_32, ropRET_32, ropLES_32, ropLDS_32, ropMOV_b_imm, ropMOV_l_imm, NULL, ropLEAVE_32, ropRETF_imm_32, ropRETF_32, NULL, NULL, NULL, NULL, +/*d0*/ ropD0, ropD1_l, ropD2, ropD3_l, NULL, NULL, NULL, ropXLAT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropLOOPNE, ropLOOPE, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r32, ropJMP_r32, ropJMP_far_32, ropJMP_r8, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, ropCMC, ropF6, ropF7_32, ropCLC, ropSTC, ropCLI, ropSTI, ropCLD, ropSTD, ropINCDEC, ropFF_32 +}; + + +RecompOpFn recomp_opcodes_0f[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ ropPUNPCKLBW, ropPUNPCKLWD, ropPUNPCKLDQ, ropPACKSSWB, ropPCMPGTB, ropPCMPGTW, ropPCMPGTD, ropPACKUSWB, ropPUNPCKHBW, ropPUNPCKHWD, ropPUNPCKHDQ, ropPACKSSDW, NULL, NULL, ropMOVD_r_d, ropMOVQ_r_q, +/*70*/ NULL, ropPSxxW_imm, ropPSxxD_imm, ropPSxxQ_imm, ropPCMPEQB, ropPCMPEQW, ropPCMPEQD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVD_d_r, ropMOVQ_q_r, + +/*80*/ ropJO_16, ropJNO_16, ropJB_16, ropJNB_16, ropJE_16, ropJNE_16, ropJBE_16, ropJNBE_16, ropJS_16, ropJNS_16, ropJP_16, ropJNP_16, ropJL_16, ropJNL_16, ropJLE_16, ropJNLE_16, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropPUSH_FS_16, ropPOP_FS_16, NULL, NULL, ropSHLD_16_imm, NULL, NULL, NULL, ropPUSH_GS_16, ropPOP_GS_16, NULL, NULL, ropSHRD_16_imm, NULL, NULL, NULL, +/*b0*/ NULL, NULL, ropLSS_16, NULL, ropLFS_16, ropLGS_16, ropMOVZX_16_8, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_16_8, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, ropPMULLW, NULL, NULL, ropPSUBUSB, ropPSUBUSW, NULL, ropPAND, ropPADDUSB, ropPADDUSW, NULL, ropPANDN, +/*e0*/ NULL, NULL, NULL, NULL, NULL, ropPMULHW, NULL, NULL, ropPSUBSB, ropPSUBSW, NULL, ropPOR, ropPADDSB, ropPADDSW, NULL, ropPXOR, +/*f0*/ NULL, NULL, NULL, NULL, NULL, ropPMADDWD, NULL, NULL, ropPSUBB, ropPSUBW, ropPSUBD, NULL, ropPADDB, ropPADDW, ropPADDD, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ ropPUNPCKLBW, ropPUNPCKLWD, ropPUNPCKLDQ, ropPACKSSWB, ropPCMPGTB, ropPCMPGTW, ropPCMPGTD, ropPACKUSWB, ropPUNPCKHBW, ropPUNPCKHWD, ropPUNPCKHDQ, ropPACKSSDW, NULL, NULL, ropMOVD_r_d, ropMOVQ_r_q, +/*70*/ NULL, ropPSxxW_imm, ropPSxxD_imm, ropPSxxQ_imm, ropPCMPEQB, ropPCMPEQW, ropPCMPEQD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVD_d_r, ropMOVQ_q_r, + +/*80*/ ropJO_32, ropJNO_32, ropJB_32, ropJNB_32, ropJE_32, ropJNE_32, ropJBE_32, ropJNBE_32, ropJS_32, ropJNS_32, ropJP_32, ropJNP_32, ropJL_32, ropJNL_32, ropJLE_32, ropJNLE_32, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropPUSH_FS_32, ropPOP_FS_32, NULL, NULL, ropSHLD_32_imm, NULL, NULL, NULL, ropPUSH_GS_32, ropPOP_GS_32, NULL, NULL, ropSHRD_32_imm, NULL, NULL, NULL, +/*b0*/ NULL, NULL, ropLSS_32, NULL, ropLFS_32, ropLGS_32, ropMOVZX_32_8, ropMOVZX_32_16, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_32_8, ropMOVSX_32_16, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, ropPMULLW, NULL, NULL, ropPSUBUSB, ropPSUBUSW, NULL, ropPAND, ropPADDUSB, ropPADDUSW, NULL, ropPANDN, +/*e0*/ NULL, NULL, NULL, NULL, NULL, ropPMULHW, NULL, NULL, ropPSUBSB, ropPSUBSW, NULL, ropPOR, ropPADDSB, ropPADDSW, NULL, ropPXOR, +/*f0*/ NULL, NULL, NULL, NULL, NULL, ropPMADDWD, NULL, NULL, ropPSUBB, ropPSUBW, ropPSUBD, NULL, ropPADDB, ropPADDW, ropPADDD, NULL, +}; + +RecompOpFn recomp_opcodes_3DNOW[256] = +{ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPI2FD, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPF2ID, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropPFCMPGE, NULL, NULL, NULL, ropPFMIN, NULL, ropPFRCP, ropPFRSQRT, NULL, NULL, ropPFSUB, NULL, NULL, NULL, ropPFADD, NULL, +/*a0*/ ropPFCMPGT, NULL, NULL, NULL, ropPFMAX, NULL, ropPFRCPIT, ropPFRSQIT1, NULL, NULL, ropPFSUBR, NULL, NULL, NULL, NULL, NULL, +/*b0*/ ropPFCMPEQ, NULL, NULL, NULL, ropPFMUL, NULL, ropPFRCPIT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_d8[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*10*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*20*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*30*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*40*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*50*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*60*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*70*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*80*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*90*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*a0*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*b0*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*c0*/ ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, +/*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*10*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*20*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*30*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*40*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*50*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*60*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*70*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*80*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*90*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*a0*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*b0*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*c0*/ ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, +/*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, +}; + +RecompOpFn recomp_opcodes_d9[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*40*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*80*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*c0*/ ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, +/*e0*/ ropFCHS, ropFABS, NULL, NULL, ropFTST, NULL, NULL, NULL, ropFLD1, NULL, NULL, NULL, NULL, NULL, ropFLDZ, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSQRT, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*40*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*80*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*c0*/ ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, +/*e0*/ ropFCHS, ropFABS, NULL, NULL, ropFTST, NULL, NULL, NULL, ropFLD1, NULL, NULL, NULL, NULL, NULL, ropFLDZ, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSQRT, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_da[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, +/*10*/ ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, +/*20*/ ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, +/*30*/ ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, + +/*40*/ ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, +/*50*/ ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, +/*60*/ ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, +/*70*/ ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, + +/*80*/ ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, +/*90*/ ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, +/*a0*/ ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, +/*b0*/ ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFUCOMPP, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, +/*10*/ ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, +/*20*/ ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, +/*30*/ ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, + +/*40*/ ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, +/*50*/ ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, +/*60*/ ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, +/*70*/ ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, + +/*80*/ ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, +/*90*/ ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, +/*a0*/ ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, +/*b0*/ ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFUCOMPP, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_db[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_dc[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*10*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*20*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*30*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*40*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*50*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*60*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*70*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*80*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*90*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*a0*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*b0*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*c0*/ ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, +/*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*10*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*20*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*30*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*40*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*50*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*60*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*70*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*80*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*90*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*a0*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*b0*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*c0*/ ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, +/*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, +}; + +RecompOpFn recomp_opcodes_dd[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, + +/*40*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, + +/*80*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, + +/*c0*/ ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, +/*e0*/ ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, + +/*40*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, + +/*80*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, + +/*c0*/ ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, +/*e0*/ ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_de[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, +/*10*/ ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, +/*20*/ ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, +/*30*/ ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, + +/*40*/ ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, +/*50*/ ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, +/*60*/ ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, +/*70*/ ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, + +/*80*/ ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, +/*90*/ ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, +/*a0*/ ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, +/*b0*/ ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, + +/*c0*/ ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFCOMPP, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, +/*f0*/ ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, +/*10*/ ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, +/*20*/ ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, +/*30*/ ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, + +/*40*/ ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, +/*50*/ ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, +/*60*/ ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, +/*70*/ ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, + +/*80*/ ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, +/*90*/ ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, +/*a0*/ ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, +/*b0*/ ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, + +/*c0*/ ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFCOMPP, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, +/*f0*/ ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, +}; + +RecompOpFn recomp_opcodes_df[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*40*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*80*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSTSW_AX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*40*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*80*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSTSW_AX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; diff --git a/src/cpu_new/codegen_ops.h b/src/cpu_new/codegen_ops.h new file mode 100644 index 000000000..361479b6d --- /dev/null +++ b/src/cpu_new/codegen_ops.h @@ -0,0 +1,49 @@ +#ifndef _CODEGEN_OPS_H_ +#define _CODEGEN_OPS_H_ + +#include "codegen.h" + +struct ir_data_t; + +typedef uint32_t (*RecompOpFn)(codeblock_t *block, struct ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +extern RecompOpFn recomp_opcodes[512]; +extern RecompOpFn recomp_opcodes_0f[512]; +extern RecompOpFn recomp_opcodes_3DNOW[256]; +extern RecompOpFn recomp_opcodes_d8[512]; +extern RecompOpFn recomp_opcodes_d9[512]; +extern RecompOpFn recomp_opcodes_da[512]; +extern RecompOpFn recomp_opcodes_db[512]; +extern RecompOpFn recomp_opcodes_dc[512]; +extern RecompOpFn recomp_opcodes_dd[512]; +extern RecompOpFn recomp_opcodes_de[512]; +extern RecompOpFn recomp_opcodes_df[512]; +/*extern RecompOpFn recomp_opcodes_REPE[512]; +extern RecompOpFn recomp_opcodes_REPNE[512];*/ + +#define REG_EAX 0 +#define REG_ECX 1 +#define REG_EDX 2 +#define REG_EBX 3 +#define REG_ESP 4 +#define REG_EBP 5 +#define REG_ESI 6 +#define REG_EDI 7 +#define REG_AX 0 +#define REG_CX 1 +#define REG_DX 2 +#define REG_BX 3 +#define REG_SP 4 +#define REG_BP 5 +#define REG_SI 6 +#define REG_DI 7 +#define REG_AL 0 +#define REG_AH 4 +#define REG_CL 1 +#define REG_CH 5 +#define REG_DL 2 +#define REG_DH 6 +#define REG_BL 3 +#define REG_BH 7 + +#endif diff --git a/src/cpu_new/codegen_ops_3dnow.c b/src/cpu_new/codegen_ops_3dnow.c new file mode 100644 index 000000000..2406fe8e0 --- /dev/null +++ b/src/cpu_new/codegen_ops_3dnow.c @@ -0,0 +1,211 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_3dnow.h" +#include "codegen_ops_helpers.h" + +#define ropParith(func) \ +uint32_t rop ## func(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + uop_MMX_ENTER(ir); \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + int src_reg = fetchdat & 7; \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ + } \ + else \ + { \ + x86seg *target_seg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ + } \ + \ + codegen_mark_code_present(block, cs+op_pc+1, 1); \ + return op_pc + 2; \ +} + +ropParith(PFADD) +ropParith(PFCMPEQ) +ropParith(PFCMPGE) +ropParith(PFCMPGT) +ropParith(PFMAX) +ropParith(PFMIN) +ropParith(PFMUL) +ropParith(PFSUB) + +uint32_t ropPF2ID(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_PF2ID(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_PF2ID(ir, IREG_MM(dest_reg), IREG_temp0_Q); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} + +uint32_t ropPFSUBR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_PFSUB(ir, IREG_MM(dest_reg), IREG_MM(src_reg), IREG_MM(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_PFSUB(ir, IREG_MM(dest_reg), IREG_temp0_Q, IREG_MM(dest_reg)); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} + +uint32_t ropPI2FD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_PI2FD(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_PI2FD(ir, IREG_MM(dest_reg), IREG_temp0_Q); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} + +uint32_t ropPFRCPIT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOV(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_MM(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t ropPFRCP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_PFRCP(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_PFRCP(ir, IREG_MM(dest_reg), IREG_temp0_Q); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t ropPFRSQRT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_PFRSQRT(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_PFRSQRT(ir, IREG_MM(dest_reg), IREG_temp0_Q); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} + +uint32_t ropPFRSQIT1(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MMX_ENTER(ir); + + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} diff --git a/src/cpu_new/codegen_ops_3dnow.h b/src/cpu_new/codegen_ops_3dnow.h new file mode 100644 index 000000000..0b44a0e18 --- /dev/null +++ b/src/cpu_new/codegen_ops_3dnow.h @@ -0,0 +1,15 @@ +uint32_t ropPF2ID(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFADD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFCMPEQ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFCMPGE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFCMPGT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFMAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFMIN(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFMUL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFRCP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFRCPIT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFRSQRT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFRSQIT1(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFSUB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFSUBR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPI2FD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_arith.c b/src/cpu_new/codegen_ops_arith.c new file mode 100644 index 000000000..70eddd4a9 --- /dev/null +++ b/src/cpu_new/codegen_ops_arith.c @@ -0,0 +1,2520 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_arith.h" +#include "codegen_ops_helpers.h" + +static inline void get_cf(ir_data_t *ir, int dest_reg) +{ + uop_CALL_FUNC_RESULT(ir, dest_reg, CF_SET); +} + +uint32_t ropADC_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + get_cf(ir, IREG_temp0); + uop_MOVZX(ir, IREG_flags_op1, IREG_AL); + uop_ADD_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_ADD(ir, IREG_AL, IREG_AL, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropADC_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + get_cf(ir, IREG_temp0); + uop_MOVZX(ir, IREG_flags_op1, IREG_AX); + uop_ADD_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_ADD(ir, IREG_AX, IREG_AX, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropADC_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + fetchdat = fastreadl(cs + op_pc); + + get_cf(ir, IREG_temp0); + uop_MOV(ir, IREG_flags_op1, IREG_EAX); + uop_ADD_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + uop_MOV_IMM(ir, IREG_flags_op2, fetchdat); + uop_ADD(ir, IREG_EAX, IREG_EAX, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} +uint32_t ropADC_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp1_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADC_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ADD(ir, IREG_temp2_B, IREG_temp0_B, IREG_8(src_reg)); + uop_ADD(ir, IREG_temp2_B, IREG_temp2_B, IREG_temp1_B); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp2_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp2_B); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADC_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADC_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ADD(ir, IREG_temp2_W, IREG_temp0_W, IREG_16(src_reg)); + uop_ADD(ir, IREG_temp2_W, IREG_temp2_W, IREG_temp1_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp2_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp2_W); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADC_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_flags_op2, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_flags_op2); + } + + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADC_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ADD(ir, IREG_temp2, IREG_temp0, IREG_32(src_reg)); + uop_ADD(ir, IREG_temp2, IREG_temp2, IREG_temp1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp2); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_temp2); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropADD_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_MOVZX(ir, IREG_flags_op1, IREG_AL); + uop_ADD_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropADD_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_MOVZX(ir, IREG_flags_op1, IREG_AX); + uop_ADD_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropADD_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV(ir, IREG_flags_op1, IREG_EAX); + + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); + uop_ADD(ir, IREG_EAX, IREG_EAX, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + fetchdat = fastreadl(cs + op_pc); + uop_ADD_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + uop_MOV_IMM(ir, IREG_flags_op2, fetchdat); + codegen_mark_code_present(block, cs+op_pc, 4); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + codegen_flags_changed = 1; + return op_pc + 4; +} +uint32_t ropADD_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADD_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ADD(ir, IREG_temp1_B, IREG_temp0_B, IREG_8(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADD_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADD_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ADD(ir, IREG_temp1_W, IREG_temp0_W, IREG_16(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADD_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_flags_op2, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_flags_op2); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADD_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ADD(ir, IREG_temp1, IREG_temp0, IREG_32(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropCMP_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_MOVZX(ir, IREG_flags_op1, IREG_AL); + uop_SUB_IMM(ir, IREG_flags_res_B, IREG_AL, imm_data); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropCMP_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_MOVZX(ir, IREG_flags_op1, IREG_AX); + uop_SUB_IMM(ir, IREG_flags_res_W, IREG_AX, imm_data); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropCMP_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + fetchdat = fastreadl(cs + op_pc); + + uop_MOV(ir, IREG_flags_op1, IREG_EAX); + uop_SUB_IMM(ir, IREG_flags_res, IREG_EAX, fetchdat); + uop_MOV_IMM(ir, IREG_flags_op2, fetchdat); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} +uint32_t ropCMP_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_flags_res_B, IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + uop_SUB(ir, IREG_flags_res_B, IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropCMP_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_flags_res_B, IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_flags_res_B, IREG_temp0_B, IREG_8(src_reg)); + } + + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropCMP_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_flags_res_W, IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + uop_SUB(ir, IREG_flags_res_W, IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropCMP_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_flags_res_W, IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_flags_res_W, IREG_temp0_W, IREG_16(src_reg)); + } + + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropCMP_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_flags_res, IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + uop_SUB(ir, IREG_flags_res, IREG_32(dest_reg), IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropCMP_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_flags_res, IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_flags_res, IREG_temp0, IREG_32(src_reg)); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropSBB_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + get_cf(ir, IREG_temp0); + uop_MOVZX(ir, IREG_flags_op1, IREG_AL); + uop_SUB_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_SUB(ir, IREG_AL, IREG_AL, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropSBB_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + get_cf(ir, IREG_temp0); + uop_MOVZX(ir, IREG_flags_op1, IREG_AX); + uop_SUB_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_SUB(ir, IREG_AX, IREG_AX, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropSBB_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + fetchdat = fastreadl(cs + op_pc); + + get_cf(ir, IREG_temp0); + uop_MOV(ir, IREG_flags_op1, IREG_EAX); + uop_SUB_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + uop_MOV_IMM(ir, IREG_flags_op2, fetchdat); + uop_SUB(ir, IREG_EAX, IREG_EAX, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} +uint32_t ropSBB_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp1_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSBB_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_SUB(ir, IREG_temp2_B, IREG_temp0_B, IREG_8(src_reg)); + uop_SUB(ir, IREG_temp2_B, IREG_temp2_B, IREG_temp1_B); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp2_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp2_B); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSBB_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSBB_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_SUB(ir, IREG_temp2_W, IREG_temp0_W, IREG_16(src_reg)); + uop_SUB(ir, IREG_temp2_W, IREG_temp2_W, IREG_temp1_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp2_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp2_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSBB_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_flags_op2, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_flags_op2); + } + + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSBB_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_SUB(ir, IREG_temp2, IREG_temp0, IREG_32(src_reg)); + uop_SUB(ir, IREG_temp2, IREG_temp2, IREG_temp1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp2); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_temp2); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropSUB_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_MOVZX(ir, IREG_flags_op1, IREG_AL); + uop_SUB_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropSUB_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_MOVZX(ir, IREG_flags_op1, IREG_AX); + uop_SUB_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropSUB_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV(ir, IREG_flags_op1, IREG_EAX); + + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); + uop_SUB(ir, IREG_EAX, IREG_EAX, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + fetchdat = fastreadl(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 4); + uop_SUB_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + uop_MOV_IMM(ir, IREG_flags_op2, fetchdat); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + + codegen_flags_changed = 1; + return op_pc + 4; +} +uint32_t ropSUB_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSUB_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_SUB(ir, IREG_temp1_B, IREG_temp0_B, IREG_8(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSUB_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSUB_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_SUB(ir, IREG_temp1_W, IREG_temp0_W, IREG_16(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSUB_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_flags_op2, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_flags_op2); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSUB_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_SUB(ir, IREG_temp1, IREG_temp0, IREG_32(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t rop80(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int skip_immediate = 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uint8_t imm = fastreadb(cs + op_pc + 1); + + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + skip_immediate = 1; + LOAD_IMMEDIATE_FROM_RAM_8(block, ir, IREG_temp0_B, cs+op_pc+1); + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + } + else + { + uop_ADD_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x08: /*OR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_OR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + else + uop_OR_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp1); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + } + else + { + uop_ADD_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp1_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp1); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + } + else + { + uop_SUB_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp1_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x20: /*AND*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_AND(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + else + uop_AND_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x28: /*SUB*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + } + else + { + uop_SUB_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x30: /*XOR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_XOR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + else + uop_XOR_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x38: /*CMP*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_flags_res_B, IREG_8(dest_reg), IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + } + else + { + uop_SUB_IMM(ir, IREG_flags_res_B, IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + uint8_t imm; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x38) == 0x38) /*CMP*/ + codegen_check_seg_read(block, ir, target_seg); + else + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadb(cs + op_pc + 1); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_ADD_IMM(ir, IREG_temp1_B, IREG_temp0_B, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x08: /*OR*/ + uop_OR_IMM(ir, IREG_temp0_B, IREG_temp0_B, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp2); + uop_ADD_IMM(ir, IREG_temp1_B, IREG_temp0_B, imm); + uop_ADD(ir, IREG_temp1_B, IREG_temp1_B, IREG_temp2_B); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp2); + uop_SUB_IMM(ir, IREG_temp1_B, IREG_temp0_B, imm); + uop_SUB(ir, IREG_temp1_B, IREG_temp1_B, IREG_temp2_B); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x20: /*AND*/ + uop_AND_IMM(ir, IREG_temp0_B, IREG_temp0_B, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + break; + + case 0x28: /*SUB*/ + uop_SUB_IMM(ir, IREG_temp1_B, IREG_temp0_B, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x30: /*XOR*/ + uop_XOR_IMM(ir, IREG_temp0_B, IREG_temp0_B, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + break; + + case 0x38: /*CMP*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB_IMM(ir, IREG_flags_res_B, IREG_temp0_B, imm); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + if (!skip_immediate) + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t rop81_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int skip_immediate = 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uint16_t imm = fastreadw(cs + op_pc + 1); + + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + skip_immediate = 1; + LOAD_IMMEDIATE_FROM_RAM_16(block, ir, IREG_temp0_W, cs+op_pc+1); + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + } + else + { + uop_ADD_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x08: /*OR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_OR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + else + uop_OR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp1); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + } + else + { + uop_ADD_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp1); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + } + else + { + uop_SUB_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x20: /*AND*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_AND(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + else + uop_AND_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x28: /*SUB*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + } + else + { + uop_SUB_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x30: /*XOR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_XOR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + else + uop_XOR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x38: /*CMP*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_flags_res_W, IREG_16(dest_reg), IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + } + else + { + uop_SUB_IMM(ir, IREG_flags_res_W, IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + uint16_t imm; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x38) == 0x38) /*CMP*/ + codegen_check_seg_read(block, ir, target_seg); + else + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadw(cs + op_pc + 1); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + skip_immediate = 1; + LOAD_IMMEDIATE_FROM_RAM_16(block, ir, IREG_temp2_W, cs+op_pc+1); + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_ADD(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2_W); + else + uop_ADD_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOVZX(ir, IREG_flags_op2, IREG_temp2_W); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x08: /*OR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_OR(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp2_W); + else + uop_OR_IMM(ir, IREG_temp0_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp3); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_ADD(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2_W); + else + uop_ADD_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_ADD(ir, IREG_temp1_W, IREG_temp1_W, IREG_temp3_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOVZX(ir, IREG_flags_op2, IREG_temp2_W); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp3); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_SUB(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2_W); + else + uop_SUB_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_SUB(ir, IREG_temp1_W, IREG_temp1_W, IREG_temp3_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOVZX(ir, IREG_flags_op2, IREG_temp2_W); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x20: /*AND*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_AND(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp2_W); + else + uop_AND_IMM(ir, IREG_temp0_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + break; + + case 0x28: /*SUB*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_SUB(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2_W); + else + uop_SUB_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOVZX(ir, IREG_flags_op2, IREG_temp2_W); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x30: /*XOR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_XOR(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp2_W); + else + uop_XOR_IMM(ir, IREG_temp0_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + break; + + case 0x38: /*CMP*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_MOVZX(ir, IREG_flags_op2, IREG_temp2_W); + uop_SUB(ir, IREG_flags_res_W, IREG_temp0_W, IREG_temp2_W); + } + else + { + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB_IMM(ir, IREG_flags_res_W, IREG_temp0_W, imm); + } + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + if (!skip_immediate) + codegen_mark_code_present(block, cs+op_pc+1, 2); + return op_pc + 3; +} +uint32_t rop81_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int skip_immediate = 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uint32_t imm = fastreadl(cs + op_pc + 1); + + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + skip_immediate = 1; + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs+op_pc+1); + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + uop_ADD_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x08: /*OR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_OR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + else + uop_OR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + uop_ADD_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + uop_SUB_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x20: /*AND*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_AND(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + else + uop_AND_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x28: /*SUB*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + uop_SUB_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x30: /*XOR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_XOR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + else + uop_XOR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x38: /*CMP*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_flags_res, IREG_32(dest_reg), IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + uop_SUB_IMM(ir, IREG_flags_res, IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + uint32_t imm; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x38) == 0x38) /*CMP*/ + codegen_check_seg_read(block, ir, target_seg); + else + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadl(cs + op_pc + 1); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + skip_immediate = 1; + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp2, cs+op_pc+1); + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_ADD(ir, IREG_temp1, IREG_temp0, IREG_temp2); + else + uop_ADD_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x08: /*OR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_OR(ir, IREG_temp0, IREG_temp0, IREG_temp2); + else + uop_OR_IMM(ir, IREG_temp0, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp3); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_ADD(ir, IREG_temp1, IREG_temp0, IREG_temp2); + else + uop_ADD_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_ADD(ir, IREG_temp1, IREG_temp1, IREG_temp3); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp3); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_SUB(ir, IREG_temp1, IREG_temp0, IREG_temp2); + else + uop_SUB_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_SUB(ir, IREG_temp1, IREG_temp1, IREG_temp3); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x20: /*AND*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_AND(ir, IREG_temp0, IREG_temp0, IREG_temp2); + else + uop_AND_IMM(ir, IREG_temp0, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + break; + + case 0x28: /*SUB*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_SUB(ir, IREG_temp1, IREG_temp0, IREG_temp2); + else + uop_SUB_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x30: /*XOR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_XOR(ir, IREG_temp0, IREG_temp0, IREG_temp2); + else + uop_XOR_IMM(ir, IREG_temp0, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + break; + + case 0x38: /*CMP*/ + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_SUB(ir, IREG_flags_res, IREG_temp0, IREG_temp2); + } + else + { + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB_IMM(ir, IREG_flags_res, IREG_temp0, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + if (!skip_immediate) + codegen_mark_code_present(block, cs+op_pc+1, 4); + return op_pc + 5; +} + +uint32_t rop83_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uint16_t imm = (int16_t)(int8_t)fastreadb(cs + op_pc + 1); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_ADD_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x08: /*OR*/ + uop_OR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp1); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_ADD_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp1); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SUB_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x20: /*AND*/ + uop_AND_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x28: /*SUB*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SUB_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x30: /*XOR*/ + uop_XOR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x38: /*CMP*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SUB_IMM(ir, IREG_flags_res_W, IREG_16(dest_reg), imm); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + uint16_t imm; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x38) == 0x38) /*CMP*/ + codegen_check_seg_read(block, ir, target_seg); + else + codegen_check_seg_write(block, ir, target_seg); + imm = (int16_t)(int8_t)fastreadb(cs + op_pc + 1); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_ADD_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x08: /*OR*/ + uop_OR_IMM(ir, IREG_temp0_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp2); + uop_ADD_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_ADD(ir, IREG_temp1_W, IREG_temp1_W, IREG_temp2_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp2); + uop_SUB_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_SUB(ir, IREG_temp1_W, IREG_temp1_W, IREG_temp2_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x20: /*AND*/ + uop_AND_IMM(ir, IREG_temp0_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + break; + + case 0x28: /*SUB*/ + uop_SUB_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x30: /*XOR*/ + uop_XOR_IMM(ir, IREG_temp0_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + break; + + case 0x38: /*CMP*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB_IMM(ir, IREG_flags_res_W, IREG_temp0_W, imm); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t rop83_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uint32_t imm = (int32_t)(int8_t)fastreadb(cs + op_pc + 1); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_ADD_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x08: /*OR*/ + uop_OR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_ADD_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SUB_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x20: /*AND*/ + uop_AND_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x28: /*SUB*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SUB_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x30: /*XOR*/ + uop_XOR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x38: /*CMP*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SUB_IMM(ir, IREG_flags_res, IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + uint32_t imm; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x38) == 0x38) /*CMP*/ + codegen_check_seg_read(block, ir, target_seg); + else + codegen_check_seg_write(block, ir, target_seg); + imm = (int32_t)(int8_t)fastreadb(cs + op_pc + 1); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_ADD_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x08: /*OR*/ + uop_OR_IMM(ir, IREG_temp0, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp2); + uop_ADD_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_ADD(ir, IREG_temp1, IREG_temp1, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp2); + uop_SUB_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_SUB(ir, IREG_temp1, IREG_temp1, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x20: /*AND*/ + uop_AND_IMM(ir, IREG_temp0, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + break; + + case 0x28: /*SUB*/ + uop_SUB_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x30: /*XOR*/ + uop_XOR_IMM(ir, IREG_temp0, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + break; + + case 0x38: /*CMP*/ + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB_IMM(ir, IREG_flags_res, IREG_temp0, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} + +static void rebuild_c(ir_data_t *ir) +{ + int needs_rebuild = 1; + + if (codegen_flags_changed) + { + switch (cpu_state.flags_op) + { + case FLAGS_INC8: case FLAGS_INC16: case FLAGS_INC32: + case FLAGS_DEC8: case FLAGS_DEC16: case FLAGS_DEC32: + needs_rebuild = 0; + break; + } + } + + if (needs_rebuild) + { + uop_CALL_FUNC(ir, flags_rebuild_c); + } +} + +uint32_t ropINC_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + rebuild_c(ir); + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(opcode & 7)); + uop_ADD_IMM(ir, IREG_16(opcode & 7), IREG_16(opcode & 7), 1); + uop_MOVZX(ir, IREG_flags_res, IREG_16(opcode & 7)); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC16); + codegen_flags_changed = 1; + + return op_pc; +} +uint32_t ropINC_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + rebuild_c(ir); + + uop_MOV(ir, IREG_flags_op1, IREG_32(opcode & 7)); + uop_ADD_IMM(ir, IREG_32(opcode & 7), IREG_32(opcode & 7), 1); + uop_MOV(ir, IREG_flags_res, IREG_32(opcode & 7)); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC32); + codegen_flags_changed = 1; + + return op_pc; +} + +uint32_t ropDEC_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + rebuild_c(ir); + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(opcode & 7)); + uop_SUB_IMM(ir, IREG_16(opcode & 7), IREG_16(opcode & 7), 1); + uop_MOVZX(ir, IREG_flags_res, IREG_16(opcode & 7)); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC16); + codegen_flags_changed = 1; + + return op_pc; +} +uint32_t ropDEC_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + rebuild_c(ir); + + uop_MOV(ir, IREG_flags_op1, IREG_32(opcode & 7)); + uop_SUB_IMM(ir, IREG_32(opcode & 7), IREG_32(opcode & 7), 1); + uop_MOV(ir, IREG_flags_res, IREG_32(opcode & 7)); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC32); + codegen_flags_changed = 1; + + return op_pc; +} + +uint32_t ropINCDEC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + codegen_mark_code_present(block, cs+op_pc, 1); + rebuild_c(ir); + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOVZX(ir, IREG_flags_op1, IREG_8(fetchdat & 7)); + if (fetchdat & 0x38) + { + uop_SUB_IMM(ir, IREG_8(fetchdat & 7), IREG_8(fetchdat & 7), 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC8); + } + else + { + uop_ADD_IMM(ir, IREG_8(fetchdat & 7), IREG_8(fetchdat & 7), 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC8); + } + uop_MOVZX(ir, IREG_flags_res, IREG_8(fetchdat & 7)); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + + if (fetchdat & 0x38) + { + uop_SUB_IMM(ir, IREG_temp1_B, IREG_temp0_B, 1); + } + else + { + uop_ADD_IMM(ir, IREG_temp1_B, IREG_temp0_B, 1); + } + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + if (fetchdat & 0x38) + { + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC8); + } + else + { + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC8); + } + } + + return op_pc+1; +} diff --git a/src/cpu_new/codegen_ops_arith.h b/src/cpu_new/codegen_ops_arith.h new file mode 100644 index 000000000..d1bbaa75d --- /dev/null +++ b/src/cpu_new/codegen_ops_arith.h @@ -0,0 +1,64 @@ +uint32_t ropADC_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropADD_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropCMP_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropSBB_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropSUB_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t rop80(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t rop81_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t rop81_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t rop83_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t rop83_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + + +uint32_t ropDEC_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropDEC_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropINC_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropINC_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropINCDEC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_branch.c b/src/cpu_new/codegen_ops_branch.c new file mode 100644 index 000000000..5bea31781 --- /dev/null +++ b/src/cpu_new/codegen_ops_branch.c @@ -0,0 +1,1014 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "386_common.h" +#include "x86_flags.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_mov.h" + +static int NF_SET_01() +{ + return NF_SET() ? 1 : 0; +} +static int VF_SET_01() +{ + return VF_SET() ? 1 : 0; +} + +static int ropJO_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: + /*Overflow is always zero*/ + return 0; + + case FLAGS_SUB8: case FLAGS_DEC8: + jump_uop = uop_CMP_JNO_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + + case FLAGS_SUB16: case FLAGS_DEC16: + jump_uop = uop_CMP_JNO_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + + case FLAGS_SUB32: case FLAGS_DEC32: + jump_uop = uop_CMP_JNO_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, VF_SET); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + break; + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 0; +} +static int ropJNO_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: + /*Overflow is always zero*/ + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + return 0; + + case FLAGS_SUB8: case FLAGS_DEC8: + jump_uop = uop_CMP_JO_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + + case FLAGS_SUB16: case FLAGS_DEC16: + jump_uop = uop_CMP_JO_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + + case FLAGS_SUB32: case FLAGS_DEC32: + jump_uop = uop_CMP_JO_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, VF_SET); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + break; + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 0; +} + +static int ropJB_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + int do_unroll = (CF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: + /*Carry is always zero*/ + return 0; + + case FLAGS_SUB8: + if (do_unroll) + jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + + case FLAGS_SUB16: + if (do_unroll) + jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + + case FLAGS_SUB32: + if (do_unroll) + jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET); + if (do_unroll) + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + else + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + break; + } + uop_MOV_IMM(ir, IREG_pc, do_unroll ? next_pc : dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return do_unroll ? 1 : 0; +} +static int ropJNB_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + int do_unroll = (!CF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: + /*Carry is always zero*/ + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + return 0; + + case FLAGS_SUB8: + if (do_unroll) + jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + + case FLAGS_SUB16: + if (do_unroll) + jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + + case FLAGS_SUB32: + if (do_unroll) + jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET); + if (do_unroll) + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + else + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + break; + } + uop_MOV_IMM(ir, IREG_pc, do_unroll ? next_pc : dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return do_unroll ? 1 : 0; +} + +static int ropJE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + + if (ZF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)) + { + if (!codegen_flags_changed || !flags_res_valid()) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + } + else + { + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0); + } + uop_MOV_IMM(ir, IREG_pc, next_pc); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 1; + } + else + { + if (!codegen_flags_changed || !flags_res_valid()) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + } + else + { + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0); + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + } + return 0; +} +int ropJNE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + + if (!ZF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)) + { + if (!codegen_flags_changed || !flags_res_valid()) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + } + else + { + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0); + } + uop_MOV_IMM(ir, IREG_pc, next_pc); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 1; + } + else + { + if (!codegen_flags_changed || !flags_res_valid()) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + } + else + { + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0); + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + } + return 0; +} + +static int ropJBE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop, jump_uop2 = -1; + int do_unroll = ((CF_SET() || ZF_SET()) && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: + /*Carry is always zero, so test zero only*/ + if (do_unroll) + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0); + else + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0); + break; + + case FLAGS_SUB8: + if (do_unroll) + jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + case FLAGS_SUB16: + if (do_unroll) + jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + case FLAGS_SUB32: + if (do_unroll) + jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + if (do_unroll) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + } + else + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + } + break; + } + if (do_unroll) + { + uop_MOV_IMM(ir, IREG_pc, next_pc); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + return 1; + } + else + { + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 0; + } +} +static int ropJNBE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop, jump_uop2 = -1; + int do_unroll = ((!CF_SET() && !ZF_SET()) && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: + /*Carry is always zero, so test zero only*/ + if (do_unroll) + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0); + else + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0); + break; + + case FLAGS_SUB8: + if (do_unroll) + jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + case FLAGS_SUB16: + if (do_unroll) + jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + case FLAGS_SUB32: + if (do_unroll) + jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + if (do_unroll) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + } + else + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + } + break; + } + if (do_unroll) + { + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + uop_MOV_IMM(ir, IREG_pc, next_pc); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 1; + } + else + { + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + return 0; + } +} + +static int ropJS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + int do_unroll = (NF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: + case FLAGS_ADD8: + case FLAGS_SUB8: + case FLAGS_SHL8: + case FLAGS_SHR8: + case FLAGS_SAR8: + case FLAGS_INC8: + case FLAGS_DEC8: + if (do_unroll) + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B); + else + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B); + break; + + case FLAGS_ZN16: + case FLAGS_ADD16: + case FLAGS_SUB16: + case FLAGS_SHL16: + case FLAGS_SHR16: + case FLAGS_SAR16: + case FLAGS_INC16: + case FLAGS_DEC16: + if (do_unroll) + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W); + else + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W); + break; + + case FLAGS_ZN32: + case FLAGS_ADD32: + case FLAGS_SUB32: + case FLAGS_SHL32: + case FLAGS_SHR32: + case FLAGS_SAR32: + case FLAGS_INC32: + case FLAGS_DEC32: + if (do_unroll) + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res); + else + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET); + if (do_unroll) + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + else + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + break; + } + uop_MOV_IMM(ir, IREG_pc, do_unroll ? next_pc : dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return do_unroll ? 1 : 0; +} +static int ropJNS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + int do_unroll = (!NF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: + case FLAGS_ADD8: + case FLAGS_SUB8: + case FLAGS_SHL8: + case FLAGS_SHR8: + case FLAGS_SAR8: + case FLAGS_INC8: + case FLAGS_DEC8: + if (do_unroll) + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B); + else + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B); + break; + + case FLAGS_ZN16: + case FLAGS_ADD16: + case FLAGS_SUB16: + case FLAGS_SHL16: + case FLAGS_SHR16: + case FLAGS_SAR16: + case FLAGS_INC16: + case FLAGS_DEC16: + if (do_unroll) + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W); + else + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W); + break; + + case FLAGS_ZN32: + case FLAGS_ADD32: + case FLAGS_SUB32: + case FLAGS_SHL32: + case FLAGS_SHR32: + case FLAGS_SAR32: + case FLAGS_INC32: + case FLAGS_DEC32: + if (do_unroll) + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res); + else + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET); + if (do_unroll) + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + else + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + break; + } + uop_MOV_IMM(ir, IREG_pc, do_unroll ? next_pc : dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return do_unroll ? 1 : 0; +} + +static int ropJP_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + + uop_CALL_FUNC_RESULT(ir, IREG_temp0, PF_SET); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 0; +} +static int ropJNP_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + + uop_CALL_FUNC_RESULT(ir, IREG_temp0, PF_SET); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 0; +} + +static int ropJL_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + int do_unroll = ((NF_SET() ? 1 : 0) != (VF_SET() ? 1 : 0) && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: + /*V flag is always clear. Condition is true if N is set*/ + if (do_unroll) + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B); + else + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B); + break; + case FLAGS_ZN16: + if (do_unroll) + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W); + else + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W); + break; + case FLAGS_ZN32: + if (do_unroll) + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res); + else + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res); + break; + + case FLAGS_SUB8: case FLAGS_DEC8: + if (do_unroll) + jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + case FLAGS_SUB16: case FLAGS_DEC16: + if (do_unroll) + jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + case FLAGS_SUB32: case FLAGS_DEC32: + if (do_unroll) + jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01); + uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01); + if (do_unroll) + jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1); + else + jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1); + break; + } + if (do_unroll) + uop_MOV_IMM(ir, IREG_pc, next_pc); + else + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return do_unroll ? 1 : 0; +} +static int ropJNL_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + int do_unroll = ((NF_SET() ? 1 : 0) == (VF_SET() ? 1 : 0) && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: + /*V flag is always clear. Condition is true if N is set*/ + if (do_unroll) + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B); + else + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B); + break; + case FLAGS_ZN16: + if (do_unroll) + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W); + else + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W); + break; + case FLAGS_ZN32: + if (do_unroll) + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res); + else + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res); + break; + + case FLAGS_SUB8: case FLAGS_DEC8: + if (do_unroll) + jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + case FLAGS_SUB16: case FLAGS_DEC16: + if (do_unroll) + jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + case FLAGS_SUB32: case FLAGS_DEC32: + if (do_unroll) + jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01); + uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01); + if (do_unroll) + jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1); + else + jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1); + break; + } + if (do_unroll) + uop_MOV_IMM(ir, IREG_pc, next_pc); + else + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return do_unroll ? 1 : 0; +} + +static int ropJLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop, jump_uop2 = -1; + int do_unroll = (((NF_SET() ? 1 : 0) != (VF_SET() ? 1 : 0) || ZF_SET()) && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: case FLAGS_DEC8: + if (do_unroll) + jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + case FLAGS_SUB16: case FLAGS_DEC16: + if (do_unroll) + jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + case FLAGS_SUB32: case FLAGS_DEC32: + if (do_unroll) + jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + if (do_unroll) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01); + uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01); + jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1); + } + else + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01); + uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01); + jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1); + } + break; + } + if (do_unroll) + { + uop_MOV_IMM(ir, IREG_pc, next_pc); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + return 1; + } + else + { + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 0; + } +} +static int ropJNLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop, jump_uop2 = -1; + int do_unroll = ((NF_SET() ? 1 : 0) == (VF_SET() ? 1 : 0) && !ZF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: case FLAGS_DEC8: + if (do_unroll) + jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + case FLAGS_SUB16: case FLAGS_DEC16: + if (do_unroll) + jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + case FLAGS_SUB32: case FLAGS_DEC32: + if (do_unroll) + jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + if (do_unroll) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01); + uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01); + jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1); + } + else + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01); + uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01); + jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1); + } + break; + } + if (do_unroll) + { + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + uop_MOV_IMM(ir, IREG_pc, next_pc); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 1; + } + else + { + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + return 0; + } +} + +#define ropJ(cond) \ +uint32_t ropJ ## cond ## _8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); \ + uint32_t dest_addr = op_pc + 1 + offset; \ + int ret; \ + \ + if (!(op_32 & 0x100)) \ + dest_addr &= 0xffff; \ + ret = ropJ ## cond ## _common(block, ir, dest_addr, op_pc+1); \ + \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + return ret ? dest_addr : (op_pc+1); \ +} \ +uint32_t ropJ ## cond ## _16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + uint32_t offset = (int32_t)(int16_t)fastreadw(cs + op_pc); \ + uint32_t dest_addr = (op_pc + 2 + offset) & 0xffff; \ + int ret; \ + \ + ret = ropJ ## cond ## _common(block, ir, dest_addr, op_pc+2); \ + \ + codegen_mark_code_present(block, cs+op_pc, 2); \ + return ret ? dest_addr : (op_pc+2); \ +} \ +uint32_t ropJ ## cond ## _32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + uint32_t offset = fastreadl(cs + op_pc); \ + uint32_t dest_addr = op_pc + 4 + offset; \ + int ret; \ + \ + ret = ropJ ## cond ## _common(block, ir, dest_addr, op_pc+4); \ + \ + codegen_mark_code_present(block, cs+op_pc, 4); \ + return ret ? dest_addr : (op_pc+4); \ +} + +ropJ(O) +ropJ(NO) +ropJ(B) +ropJ(NB) +ropJ(E) +ropJ(NE) +ropJ(BE) +ropJ(NBE) +ropJ(S) +ropJ(NS) +ropJ(P) +ropJ(NP) +ropJ(L) +ropJ(NL) +ropJ(LE) +ropJ(NLE) + + +uint32_t ropJCXZ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); + uint32_t dest_addr = op_pc + 1 + offset; + int jump_uop; + + if (!(op_32 & 0x100)) + dest_addr &= 0xffff; + + if (op_32 & 0x200) + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_ECX, 0); + else + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_CX, 0); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc+1; +} + +uint32_t ropLOOP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); + uint32_t dest_addr = op_pc + 1 + offset; + uint32_t ret_addr; + int jump_uop; + + if (!(op_32 & 0x100)) + dest_addr &= 0xffff; + + if (((op_32 & 0x200) ? ECX : CX) != 1 && codegen_can_unroll(block, ir, op_pc+1, dest_addr)) + { + if (op_32 & 0x200) + { + uop_SUB_IMM(ir, IREG_ECX, IREG_ECX, 1); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_ECX, 0); + } + else + { + uop_SUB_IMM(ir, IREG_CX, IREG_CX, 1); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_CX, 0); + } + uop_MOV_IMM(ir, IREG_pc, op_pc+1); + ret_addr = dest_addr; + CPU_BLOCK_END(); + } + else + { + if (op_32 & 0x200) + { + uop_SUB_IMM(ir, IREG_ECX, IREG_ECX, 1); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_ECX, 0); + } + else + { + uop_SUB_IMM(ir, IREG_CX, IREG_CX, 1); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_CX, 0); + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + ret_addr = op_pc+1; + } + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + + codegen_mark_code_present(block, cs+op_pc, 1); + return ret_addr; +} + +uint32_t ropLOOPE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); + uint32_t dest_addr = op_pc + 1 + offset; + int jump_uop, jump_uop2; + + if (!(op_32 & 0x100)) + dest_addr &= 0xffff; + + if (op_32 & 0x200) + { + uop_SUB_IMM(ir, IREG_ECX, IREG_ECX, 1); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_ECX, 0); + } + else + { + uop_SUB_IMM(ir, IREG_CX, IREG_CX, 1); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_CX, 0); + } + if (!codegen_flags_changed || !flags_res_valid()) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + } + else + { + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0); + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_NOP_BARRIER(ir); + uop_set_jump_dest(ir, jump_uop); + uop_set_jump_dest(ir, jump_uop2); + + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc+1; +} +uint32_t ropLOOPNE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); + uint32_t dest_addr = op_pc + 1 + offset; + int jump_uop, jump_uop2; + + if (!(op_32 & 0x100)) + dest_addr &= 0xffff; + + if (op_32 & 0x200) + { + uop_SUB_IMM(ir, IREG_ECX, IREG_ECX, 1); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_ECX, 0); + } + else + { + uop_SUB_IMM(ir, IREG_CX, IREG_CX, 1); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_CX, 0); + } + if (!codegen_flags_changed || !flags_res_valid()) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + } + else + { + jump_uop2 = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0); + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_NOP_BARRIER(ir); + uop_set_jump_dest(ir, jump_uop); + uop_set_jump_dest(ir, jump_uop2); + + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc+1; +} diff --git a/src/cpu_new/codegen_ops_branch.h b/src/cpu_new/codegen_ops_branch.h new file mode 100644 index 000000000..3a5007125 --- /dev/null +++ b/src/cpu_new/codegen_ops_branch.h @@ -0,0 +1,69 @@ +uint32_t ropJB_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJB_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJB_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNB_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNB_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNB_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJBE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJBE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJBE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNBE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNBE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNBE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJL_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJL_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJL_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNL_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNL_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNL_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJLE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJLE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJLE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNLE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNLE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNLE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJO_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJO_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJO_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNO_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNO_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNO_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJP_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJP_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJP_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNP_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNP_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNP_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJS_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNS_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJCXZ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropLOOP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLOOPE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLOOPNE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_fpu_arith.c b/src/cpu_new/codegen_ops_fpu_arith.c new file mode 100644 index 000000000..3f5621c3c --- /dev/null +++ b/src/cpu_new/codegen_ops_fpu_arith.c @@ -0,0 +1,575 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_fpu_arith.h" +#include "codegen_ops_helpers.h" + +uint32_t ropFADD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFADDr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FADD(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFADDP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FADD(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + fpu_POP(block, ir); + + return op_pc; +} + +uint32_t ropFCOM(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + + return op_pc; +} +uint32_t ropFCOMP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + fpu_POP(block, ir); + + return op_pc; +} +uint32_t ropFCOMPP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(1)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + fpu_POP2(block, ir); + + return op_pc; +} + +uint32_t ropFDIV(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFDIVR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(0), IREG_ST(src_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFDIVr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFDIVRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFDIVP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + fpu_POP(block, ir); + + return op_pc; +} +uint32_t ropFDIVRP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + fpu_POP(block, ir); + + return op_pc; +} + +uint32_t ropFMUL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFMULr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FMUL(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFMULP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FMUL(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + fpu_POP(block, ir); + + return op_pc; +} + +uint32_t ropFSUB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFSUBR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(0), IREG_ST(src_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFSUBr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFSUBRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFSUBP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + fpu_POP(block, ir); + + return op_pc; +} +uint32_t ropFSUBRP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + fpu_POP(block, ir); + + return op_pc; +} + +uint32_t ropFUCOM(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + + return op_pc; +} +uint32_t ropFUCOMP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + fpu_POP(block, ir); + + return op_pc; +} +uint32_t ropFUCOMPP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(1)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + fpu_POP2(block, ir); + + return op_pc; +} + +#define ropF_arith_mem(name, load_uop) \ +uint32_t ropFADD ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + if ((cpu_state.npxc >> 10) & 3) \ + return 0; \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFCOM ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); \ + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFCOMP ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); \ + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ + fpu_POP(block, ir); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFDIV ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFDIVR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FDIV(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFMUL ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFSUB ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFSUBR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FSUB(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} + +ropF_arith_mem(s, uop_MEM_LOAD_SINGLE) +ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE) + +#define ropFI_arith_mem(name, temp_reg) \ +uint32_t ropFIADD ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFICOM ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); \ + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFICOMP ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); \ + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ + fpu_POP(block, ir); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFIDIV ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFIDIVR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)\ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FDIV(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFIMUL ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFISUB ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFISUBR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)\ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FSUB(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} + +ropFI_arith_mem(l, IREG_temp0) +ropFI_arith_mem(w, IREG_temp0_W) + + +uint32_t ropFABS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FABS(ir, IREG_ST(0), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} + +uint32_t ropFCHS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FCHS(ir, IREG_ST(0), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFSQRT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FSQRT(ir, IREG_ST(0), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFTST(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FTST(ir, IREG_temp0_W, IREG_ST(0)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + + return op_pc; +} diff --git a/src/cpu_new/codegen_ops_fpu_arith.h b/src/cpu_new/codegen_ops_fpu_arith.h new file mode 100644 index 000000000..01c41ae32 --- /dev/null +++ b/src/cpu_new/codegen_ops_fpu_arith.h @@ -0,0 +1,63 @@ +uint32_t ropFADD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFADDr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFADDP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOM(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOMP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOMPP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIV(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVRP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFMUL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFMULr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFMULP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBRP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFUCOM(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFUCOMP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFUCOMPP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFADDs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFADDd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOMs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOMd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOMPs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOMPd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVRs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVRd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFMULs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFMULd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBRs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBRd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFIADDl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIADDw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFICOMl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFICOMw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFICOMPl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFICOMPw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIDIVl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIDIVw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIDIVRl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIDIVRw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIMULl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIMULw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISUBl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISUBw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISUBRl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISUBRw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFABS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCHS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSQRT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFTST(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_fpu_constant.c b/src/cpu_new/codegen_ops_fpu_constant.c new file mode 100644 index 000000000..bca268ee3 --- /dev/null +++ b/src/cpu_new/codegen_ops_fpu_constant.c @@ -0,0 +1,36 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_fpu_constant.h" +#include "codegen_ops_helpers.h" + +uint32_t ropFLD1(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_temp0, 1); + uop_MOV_DOUBLE_INT(ir, IREG_ST(-1), IREG_temp0); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); + fpu_PUSH(block, ir); + + return op_pc; +} +uint32_t ropFLDZ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_temp0, 0); + uop_MOV_DOUBLE_INT(ir, IREG_ST(-1), IREG_temp0); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); + fpu_PUSH(block, ir); + + return op_pc; +} diff --git a/src/cpu_new/codegen_ops_fpu_constant.h b/src/cpu_new/codegen_ops_fpu_constant.h new file mode 100644 index 000000000..4be90f5fe --- /dev/null +++ b/src/cpu_new/codegen_ops_fpu_constant.h @@ -0,0 +1,2 @@ +uint32_t ropFLD1(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFLDZ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_fpu_loadstore.c b/src/cpu_new/codegen_ops_fpu_loadstore.c new file mode 100644 index 000000000..599ab800e --- /dev/null +++ b/src/cpu_new/codegen_ops_fpu_loadstore.c @@ -0,0 +1,234 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_fpu_arith.h" +#include "codegen_ops_helpers.h" + +uint32_t ropFLDs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_SINGLE(ir, IREG_ST(-1), ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); + fpu_PUSH(block, ir); + + return op_pc+1; +} +uint32_t ropFLDd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_DOUBLE(ir, IREG_ST(-1), ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); + fpu_PUSH(block, ir); + + return op_pc+1; +} + +uint32_t ropFSTs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_SINGLE(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_ST(0)); + + return op_pc+1; +} +uint32_t ropFSTPs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_SINGLE(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + fpu_POP(block, ir); + + return op_pc+1; +} +uint32_t ropFSTd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 7); + uop_MEM_STORE_DOUBLE(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_ST(0)); + + return op_pc+1; +} +uint32_t ropFSTPd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 7); + uop_MEM_STORE_DOUBLE(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + fpu_POP(block, ir); + + return op_pc+1; +} + + +uint32_t ropFILDw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV_DOUBLE_INT(ir, IREG_ST(-1), IREG_temp0_W); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); + fpu_PUSH(block, ir); + + return op_pc+1; +} +uint32_t ropFILDl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV_DOUBLE_INT(ir, IREG_ST(-1), IREG_temp0); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); + fpu_PUSH(block, ir); + + return op_pc+1; +} +uint32_t ropFILDq(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_ST_i64(-1), ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV_DOUBLE_INT(ir, IREG_ST(-1), IREG_ST_i64(-1)); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID | TAG_UINT64); + fpu_PUSH(block, ir); + + return op_pc+1; +} + +uint32_t ropFISTw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MOV_INT_DOUBLE(ir, IREG_temp0_W, IREG_ST(0)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + + return op_pc+1; +} +uint32_t ropFISTPw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MOV_INT_DOUBLE(ir, IREG_temp0_W, IREG_ST(0)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + fpu_POP(block, ir); + + return op_pc+1; +} +uint32_t ropFISTl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MOV_INT_DOUBLE(ir, IREG_temp0, IREG_ST(0)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + + return op_pc+1; +} +uint32_t ropFISTPl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MOV_INT_DOUBLE(ir, IREG_temp0, IREG_ST(0)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + fpu_POP(block, ir); + + return op_pc+1; +} +uint32_t ropFISTPq(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MOV_INT_DOUBLE_64(ir, IREG_temp0_Q, IREG_ST(0), IREG_ST_i64(0), IREG_tag(0)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_Q); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + fpu_POP(block, ir); + + return op_pc+1; +} diff --git a/src/cpu_new/codegen_ops_fpu_loadstore.h b/src/cpu_new/codegen_ops_fpu_loadstore.h new file mode 100644 index 000000000..a29124560 --- /dev/null +++ b/src/cpu_new/codegen_ops_fpu_loadstore.h @@ -0,0 +1,17 @@ +uint32_t ropFLDs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFLDd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFSTs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSTPs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSTd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSTPd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFILDw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFILDl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFILDq(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFISTw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISTPw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISTl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISTPl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISTPq(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_fpu_misc.c b/src/cpu_new/codegen_ops_fpu_misc.c new file mode 100644 index 000000000..7de92a39c --- /dev/null +++ b/src/cpu_new/codegen_ops_fpu_misc.c @@ -0,0 +1,114 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_fpu_misc.h" +#include "codegen_ops_helpers.h" + +uint32_t ropFFREE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_MOV(ir, IREG_tag(dest_reg), TAG_EMPTY); + + return op_pc; +} + +uint32_t ropFLD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_MOV(ir, IREG_ST(-1), IREG_ST(src_reg)); + uop_MOV(ir, IREG_ST_i64(-1), IREG_ST_i64(src_reg)); + uop_MOV(ir, IREG_tag(-1), IREG_tag(src_reg)); + fpu_PUSH(block, ir); + + return op_pc; +} + +uint32_t ropFST(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_MOV(ir, IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV(ir, IREG_ST_i64(dest_reg), IREG_ST_i64(0)); + uop_MOV(ir, IREG_tag(dest_reg), IREG_tag(0)); + + return op_pc; +} +uint32_t ropFSTP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_MOV(ir, IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV(ir, IREG_ST_i64(dest_reg), IREG_ST_i64(0)); + uop_MOV(ir, IREG_tag(dest_reg), IREG_tag(0)); + fpu_POP(block, ir); + + return op_pc; +} + +uint32_t ropFSTCW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_NPXC); + + return op_pc+1; +} +uint32_t ropFSTSW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_NPXS); + + return op_pc+1; +} +uint32_t ropFSTSW_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_MOV(ir, IREG_AX, IREG_NPXS); + + return op_pc; +} + +uint32_t ropFXCH(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_MOV(ir, IREG_temp0_D, IREG_ST(0)); + uop_MOV(ir, IREG_temp1_Q, IREG_ST_i64(0)); + uop_MOV(ir, IREG_temp2, IREG_tag(0)); + uop_MOV(ir, IREG_ST(0), IREG_ST(dest_reg)); + uop_MOV(ir, IREG_ST_i64(0), IREG_ST_i64(dest_reg)); + uop_MOV(ir, IREG_tag(0), IREG_tag(dest_reg)); + uop_MOV(ir, IREG_ST(dest_reg), IREG_temp0_D); + uop_MOV(ir, IREG_ST_i64(dest_reg), IREG_temp1_Q); + uop_MOV(ir, IREG_tag(dest_reg), IREG_temp2); + + return op_pc; +} diff --git a/src/cpu_new/codegen_ops_fpu_misc.h b/src/cpu_new/codegen_ops_fpu_misc.h new file mode 100644 index 000000000..4aa49907f --- /dev/null +++ b/src/cpu_new/codegen_ops_fpu_misc.h @@ -0,0 +1,12 @@ +uint32_t ropFFREE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFLD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFST(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSTP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFSTCW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSTSW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSTSW_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFXCH(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_helpers.c b/src/cpu_new/codegen_ops_helpers.c new file mode 100644 index 000000000..9fc754e6c --- /dev/null +++ b/src/cpu_new/codegen_ops_helpers.c @@ -0,0 +1,75 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ir_defs.h" +#include "codegen_reg.h" +#include "codegen_ops_helpers.h" + +void LOAD_IMMEDIATE_FROM_RAM_16_unaligned(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr) +{ + /*Word access that crosses two pages. Perform reads from both pages, shift and combine*/ + uop_MOVZX_REG_PTR_8(ir, IREG_temp3_W, get_ram_ptr(addr)); + uop_MOVZX_REG_PTR_8(ir, dest_reg, get_ram_ptr(addr+1)); + uop_SHL_IMM(ir, IREG_temp3_W, IREG_temp3_W, 8); + uop_OR(ir, dest_reg, dest_reg, IREG_temp3_W); +} + +void LOAD_IMMEDIATE_FROM_RAM_32_unaligned(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr) +{ + /*Dword access that crosses two pages. Perform reads from both pages, shift and combine*/ + uop_MOV_REG_PTR(ir, dest_reg, get_ram_ptr(addr & ~3)); + uop_MOV_REG_PTR(ir, IREG_temp3, get_ram_ptr((addr + 4) & ~3)); + uop_SHR_IMM(ir, dest_reg, dest_reg, (addr & 3) * 8); + uop_SHL_IMM(ir, IREG_temp3, IREG_temp3, (4 - (addr & 3)) * 8); + uop_OR(ir, dest_reg, dest_reg, IREG_temp3); +} + +#define UNROLL_MAX_REG_REFERENCES 200 +#define UNROLL_MAX_UOPS 1000 +#define UNROLL_MAX_COUNT 10 +int codegen_can_unroll_full(codeblock_t *block, ir_data_t *ir, uint32_t next_pc, uint32_t dest_addr) +{ + int start; + int max_unroll; + int first_instruction; + int TOP = -1; + + /*Check that dest instruction was actually compiled into block*/ + start = codegen_get_instruction_uop(block, dest_addr, &first_instruction, &TOP); + + /*Couldn't find any uOPs corresponding to the destination instruction*/ + if (start == -1) + { + /*Is instruction jumping to itself?*/ + if (dest_addr != cpu_state.oldpc) + { + return 0; + } + else + { + start = ir->wr_pos; + TOP = cpu_state.TOP; + } + } + + if (TOP != cpu_state.TOP) + return 0; + + max_unroll = UNROLL_MAX_UOPS / ((ir->wr_pos-start)+6); + if (max_unroll > (UNROLL_MAX_REG_REFERENCES / max_version_refcount)) + max_unroll = (UNROLL_MAX_REG_REFERENCES / max_version_refcount); + if (max_unroll > UNROLL_MAX_COUNT) + max_unroll = UNROLL_MAX_COUNT; + if (max_unroll <= 1) + return 0; + + codegen_ir_set_unroll(max_unroll, start, first_instruction); + + return 1; +} diff --git a/src/cpu_new/codegen_ops_helpers.h b/src/cpu_new/codegen_ops_helpers.h new file mode 100644 index 000000000..41ffe297f --- /dev/null +++ b/src/cpu_new/codegen_ops_helpers.h @@ -0,0 +1,126 @@ +#include "386_common.h" +#include "codegen_backend.h" + +static inline int LOAD_SP_WITH_OFFSET(ir_data_t *ir, int offset) +{ + if (stack32) + { + if (offset) + { + uop_ADD_IMM(ir, IREG_eaaddr, IREG_ESP, offset); + return IREG_eaaddr; + } + else + return IREG_ESP; + } + else + { + if (offset) + { + uop_ADD_IMM(ir, IREG_eaaddr_W, IREG_SP, offset); + uop_MOVZX(ir, IREG_eaaddr, IREG_eaaddr_W); + return IREG_eaaddr; + } + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + return IREG_eaaddr; + } + } +} + +static inline int LOAD_SP(ir_data_t *ir) +{ + return LOAD_SP_WITH_OFFSET(ir, 0); +} + +static inline void ADD_SP(ir_data_t *ir, int offset) +{ + if (stack32) + uop_ADD_IMM(ir, IREG_ESP, IREG_ESP, offset); + else + uop_ADD_IMM(ir, IREG_SP, IREG_SP, offset); +} +static inline void SUB_SP(ir_data_t *ir, int offset) +{ + if (stack32) + uop_SUB_IMM(ir, IREG_ESP, IREG_ESP, offset); + else + uop_SUB_IMM(ir, IREG_SP, IREG_SP, offset); +} + +static inline void fpu_POP(codeblock_t *block, ir_data_t *ir) +{ + if (block->flags & CODEBLOCK_STATIC_TOP) + uop_MOV_IMM(ir, IREG_FPU_TOP, cpu_state.TOP + 1); + else + uop_ADD_IMM(ir, IREG_FPU_TOP, IREG_FPU_TOP, 1); +} +static inline void fpu_POP2(codeblock_t *block, ir_data_t *ir) +{ + if (block->flags & CODEBLOCK_STATIC_TOP) + uop_MOV_IMM(ir, IREG_FPU_TOP, cpu_state.TOP + 2); + else + uop_ADD_IMM(ir, IREG_FPU_TOP, IREG_FPU_TOP, 2); +} +static inline void fpu_PUSH(codeblock_t *block, ir_data_t *ir) +{ + if (block->flags & CODEBLOCK_STATIC_TOP) + uop_MOV_IMM(ir, IREG_FPU_TOP, cpu_state.TOP - 1); + else + uop_SUB_IMM(ir, IREG_FPU_TOP, IREG_FPU_TOP, 1); +} + +static inline void CHECK_SEG_LIMITS(codeblock_t *block, ir_data_t *ir, x86seg *seg, int addr_reg, int end_offset) +{ + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || + (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + return; + + uop_CMP_JB(ir, addr_reg, ireg_seg_limit_low(seg), codegen_gpf_rout); + if (end_offset) + { + uop_ADD_IMM(ir, IREG_temp3, addr_reg, end_offset); + uop_CMP_JNBE(ir, IREG_temp3, ireg_seg_limit_high(seg), codegen_gpf_rout); + } + else + uop_CMP_JNBE(ir, addr_reg, ireg_seg_limit_high(seg), codegen_gpf_rout); +} + +static inline void LOAD_IMMEDIATE_FROM_RAM_8(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr) +{ + uop_MOVZX_REG_PTR_8(ir, dest_reg, get_ram_ptr(addr)); +} + +void LOAD_IMMEDIATE_FROM_RAM_16_unaligned(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr); +static inline void LOAD_IMMEDIATE_FROM_RAM_16(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr) +{ + if ((addr & 0xfff) == 0xfff) + LOAD_IMMEDIATE_FROM_RAM_16_unaligned(block, ir, dest_reg, addr); + else + uop_MOVZX_REG_PTR_16(ir, dest_reg, get_ram_ptr(addr)); +} + +void LOAD_IMMEDIATE_FROM_RAM_32_unaligned(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr); +static inline void LOAD_IMMEDIATE_FROM_RAM_32(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr) +{ + if ((addr & 0xfff) >= 0xffd) + LOAD_IMMEDIATE_FROM_RAM_32_unaligned(block, ir, dest_reg, addr); + else + uop_MOV_REG_PTR(ir, dest_reg, get_ram_ptr(addr)); +} + +int codegen_can_unroll_full(codeblock_t *block, ir_data_t *ir, uint32_t next_pc, uint32_t dest_addr); +static inline int codegen_can_unroll(codeblock_t *block, ir_data_t *ir, uint32_t next_pc, uint32_t dest_addr) +{ + if (block->flags & CODEBLOCK_BYTE_MASK) + return 0; + + /*Is dest within block?*/ + if (dest_addr > next_pc) + return 0; + if ((cs+dest_addr) < block->pc) + return 0; + + return codegen_can_unroll_full(block, ir, next_pc, dest_addr); +} diff --git a/src/cpu_new/codegen_ops_jump.c b/src/cpu_new/codegen_ops_jump.c new file mode 100644 index 000000000..4363c9040 --- /dev/null +++ b/src/cpu_new/codegen_ops_jump.c @@ -0,0 +1,292 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_mov.h" + +uint32_t ropJMP_r8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); + uint32_t dest_addr = op_pc+1+offset; + + if (!(op_32 & 0x100)) + dest_addr &= 0xffff; + + if (offset < 0) + codegen_can_unroll(block, ir, op_pc+1, dest_addr); + codegen_mark_code_present(block, cs+op_pc, 1); + return dest_addr; +} +uint32_t ropJMP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int16_t)fastreadw(cs + op_pc); + uint32_t dest_addr = op_pc+2+offset; + + dest_addr &= 0xffff; + + if (offset < 0) + codegen_can_unroll(block, ir, op_pc+1, dest_addr); + codegen_mark_code_present(block, cs+op_pc, 2); + return dest_addr; +} +uint32_t ropJMP_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = fastreadl(cs + op_pc); + uint32_t dest_addr = op_pc+4+offset; + + if (offset < 0) + codegen_can_unroll(block, ir, op_pc+1, dest_addr); + codegen_mark_code_present(block, cs+op_pc, 4); + return dest_addr; +} + +uint32_t ropJMP_far_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t new_pc = fastreadw(cs + op_pc); + uint16_t new_cs = fastreadw(cs + op_pc + 2); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + uop_MOV_IMM(ir, IREG_pc, new_pc); + uop_LOAD_FUNC_ARG_IMM(ir, 0, new_cs); + uop_LOAD_FUNC_ARG_IMM(ir, 1, op_pc + 4); + uop_CALL_FUNC(ir, loadcsjmp); + + codegen_mark_code_present(block, cs+op_pc, 4); + return -1; +} +uint32_t ropJMP_far_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t new_pc = fastreadl(cs + op_pc); + uint16_t new_cs = fastreadw(cs + op_pc + 4); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + uop_MOV_IMM(ir, IREG_pc, new_pc); + uop_LOAD_FUNC_ARG_IMM(ir, 0, new_cs); + uop_LOAD_FUNC_ARG_IMM(ir, 1, op_pc + 4); + uop_CALL_FUNC(ir, loadcsjmp); + + codegen_mark_code_present(block, cs+op_pc, 6); + return -1; +} + +uint32_t ropCALL_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int16_t)fastreadw(cs + op_pc); + uint16_t ret_addr = op_pc + 2; + uint16_t dest_addr = ret_addr + offset; + int sp_reg; + + dest_addr &= 0xffff; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_IMM_16(ir, IREG_SS_base, sp_reg, ret_addr); + SUB_SP(ir, 2); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + + codegen_mark_code_present(block, cs+op_pc, 2); + return -1; +} +uint32_t ropCALL_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = fastreadl(cs + op_pc); + uint32_t ret_addr = op_pc + 4; + uint32_t dest_addr = ret_addr + offset; + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_IMM_32(ir, IREG_SS_base, sp_reg, ret_addr); + SUB_SP(ir, 4); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + + codegen_mark_code_present(block, cs+op_pc, 4); + return -1; +} + +uint32_t ropRET_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); + } + ADD_SP(ir, 2); + uop_MOVZX(ir, IREG_pc, IREG_temp0_W); + + return -1; +} +uint32_t ropRET_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_pc, IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_pc, IREG_SS_base, IREG_eaaddr); + } + ADD_SP(ir, 4); + + return -1; +} + +uint32_t ropRET_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t offset = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); + } + ADD_SP(ir, 2+offset); + uop_MOVZX(ir, IREG_pc, IREG_temp0_W); + + codegen_mark_code_present(block, cs+op_pc, 2); + return -1; +} +uint32_t ropRET_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t offset = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_pc, IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_pc, IREG_SS_base, IREG_eaaddr); + } + ADD_SP(ir, 4+offset); + + codegen_mark_code_present(block, cs+op_pc, 2); + return -1; +} + +uint32_t ropRETF_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) + return 0; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + { + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_ESP, 2); + } + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_eaaddr, 2); + } + uop_MOVZX(ir, IREG_pc, IREG_temp0_W); + uop_LOAD_FUNC_ARG_REG(ir, 0, IREG_temp1_W); + uop_CALL_FUNC(ir, loadcs); + ADD_SP(ir, 4); + + return -1; +} +uint32_t ropRETF_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) + return 0; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + { + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_ESP); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_ESP, 4); + } + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_eaaddr); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_eaaddr, 4); + } + uop_MOV(ir, IREG_pc, IREG_temp0); + uop_LOAD_FUNC_ARG_REG(ir, 0, IREG_temp1_W); + uop_CALL_FUNC(ir, loadcs); + ADD_SP(ir, 8); + + return -1; +} + +uint32_t ropRETF_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t offset; + + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) + return 0; + + offset = fastreadw(cs + op_pc); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + { + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_ESP, 2); + } + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_eaaddr, 2); + } + uop_MOVZX(ir, IREG_pc, IREG_temp0_W); + uop_LOAD_FUNC_ARG_REG(ir, 0, IREG_temp1_W); + uop_CALL_FUNC(ir, loadcs); + ADD_SP(ir, 4+offset); + + codegen_mark_code_present(block, cs+op_pc, 2); + return -1; +} +uint32_t ropRETF_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t offset; + + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) + return 0; + + offset = fastreadw(cs + op_pc); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + { + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_ESP); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_ESP, 4); + } + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_eaaddr); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_eaaddr, 4); + } + uop_MOV(ir, IREG_pc, IREG_temp0); + uop_LOAD_FUNC_ARG_REG(ir, 0, IREG_temp1_W); + uop_CALL_FUNC(ir, loadcs); + ADD_SP(ir, 8+offset); + + codegen_mark_code_present(block, cs+op_pc, 2); + return -1; +} diff --git a/src/cpu_new/codegen_ops_jump.h b/src/cpu_new/codegen_ops_jump.h new file mode 100644 index 000000000..31a544721 --- /dev/null +++ b/src/cpu_new/codegen_ops_jump.h @@ -0,0 +1,21 @@ +uint32_t ropJMP_r8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJMP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJMP_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJMP_far_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJMP_far_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropCALL_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCALL_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropRET_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropRET_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropRET_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropRET_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropRETF_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropRETF_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropRETF_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropRETF_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_logic.c b/src/cpu_new/codegen_ops_logic.c new file mode 100644 index 000000000..87607ab2d --- /dev/null +++ b/src/cpu_new/codegen_ops_logic.c @@ -0,0 +1,807 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_logic.h" + +uint32_t ropAND_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_AND_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropAND_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_AND_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropAND_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); + uop_AND(ir, IREG_EAX, IREG_EAX, IREG_temp0); + } + else + { + fetchdat = fastreadl(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 4); + uop_AND_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + + codegen_flags_changed = 1; + return op_pc + 4; +} +uint32_t ropAND_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_AND(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropAND_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_AND(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_temp0_B, IREG_temp0_B, IREG_8(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropAND_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_AND(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropAND_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_AND(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_temp0_W, IREG_temp0_W, IREG_16(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropAND_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_AND(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropAND_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_AND(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_temp0, IREG_temp0, IREG_32(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropOR_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_OR_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropOR_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_OR_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropOR_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); + uop_OR(ir, IREG_EAX, IREG_EAX, IREG_temp0); + } + else + { + fetchdat = fastreadl(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 4); + uop_OR_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} +uint32_t ropOR_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_OR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropOR_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_OR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_temp0_B, IREG_temp0_B, IREG_8(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropOR_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_OR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropOR_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_OR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_temp0_W, IREG_temp0_W, IREG_16(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropOR_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_OR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, dest_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropOR_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_OR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_temp0, IREG_temp0, IREG_32(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropTEST_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_AND_IMM(ir, IREG_flags_res, IREG_EAX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropTEST_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_AND_IMM(ir, IREG_flags_res, IREG_EAX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropTEST_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); + uop_AND(ir, IREG_flags_res, IREG_EAX, IREG_temp0); + } + else + { + fetchdat = fastreadl(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 4); + uop_AND_IMM(ir, IREG_flags_res, IREG_EAX, fetchdat); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} +uint32_t ropTEST_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_AND(ir, IREG_flags_res_B, IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_flags_res_B, IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropTEST_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_AND(ir, IREG_flags_res_W, IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_flags_res_W, IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropTEST_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_AND(ir, IREG_flags_res, IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_flags_res, IREG_32(dest_reg), IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropXOR_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_XOR_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropXOR_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_XOR_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropXOR_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); + uop_XOR(ir, IREG_EAX, IREG_EAX, IREG_temp0); + } + else + { + fetchdat = fastreadl(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 4); + uop_XOR_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} +uint32_t ropXOR_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_XOR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropXOR_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_XOR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_temp0_B, IREG_temp0_B, IREG_8(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropXOR_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_XOR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropXOR_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_XOR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_temp0_W, IREG_temp0_W, IREG_16(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropXOR_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_XOR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, dest_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropXOR_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_XOR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_temp0, IREG_temp0, IREG_32(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + + codegen_flags_changed = 1; + return op_pc + 1; +} diff --git a/src/cpu_new/codegen_ops_logic.h b/src/cpu_new/codegen_ops_logic.h new file mode 100644 index 000000000..dd020676e --- /dev/null +++ b/src/cpu_new/codegen_ops_logic.h @@ -0,0 +1,36 @@ +uint32_t ropAND_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropOR_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropTEST_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropTEST_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropTEST_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropTEST_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropTEST_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropTEST_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropXOR_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_misc.c b/src/cpu_new/codegen_ops_misc.c new file mode 100644 index 000000000..3896e7ebc --- /dev/null +++ b/src/cpu_new/codegen_ops_misc.c @@ -0,0 +1,614 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_misc.h" + +uint32_t ropLEA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + if ((fetchdat & 0xc0) == 0xc0) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + uop_MOV(ir, IREG_16(dest_reg), IREG_eaaddr_W); + + return op_pc + 1; +} +uint32_t ropLEA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + if ((fetchdat & 0xc0) == 0xc0) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + uop_MOV(ir, IREG_32(dest_reg), IREG_eaaddr); + + return op_pc + 1; +} + +uint32_t ropF6(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + uint8_t imm_data; + int reg; + + if (fetchdat & 0x20) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + reg = IREG_8(fetchdat & 7); + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x30) == 0x10) /*NEG/NOT*/ + codegen_check_seg_write(block, ir, target_seg); + else + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + reg = IREG_temp0_B; + } + + switch (fetchdat & 0x38) + { + case 0x00: case 0x08: /*TEST*/ + imm_data = fastreadb(cs + op_pc + 1); + + uop_AND_IMM(ir, IREG_flags_res_B, reg, imm_data); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc+2; + + case 0x10: /*NOT*/ + uop_XOR_IMM(ir, reg, reg, 0xff); + if ((fetchdat & 0xc0) != 0xc0) + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg); + + codegen_flags_changed = 1; + return op_pc+1; + + case 0x18: /*NEG*/ + uop_MOV_IMM(ir, IREG_temp1_B, 0); + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOVZX(ir, IREG_flags_op2, reg); + uop_SUB(ir, IREG_temp1_B, IREG_temp1_B, reg); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + uop_MOV(ir, reg, IREG_temp1_B); + } + else + { + uop_SUB(ir, IREG_temp1_B, IREG_temp1_B, reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + uop_MOV_IMM(ir, IREG_flags_op1, 0); + + codegen_flags_changed = 1; + return op_pc+1; + } + return 0; +} +uint32_t ropF7_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + uint16_t imm_data; + int reg; + + if (fetchdat & 0x20) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + reg = IREG_16(fetchdat & 7); + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x30) == 0x10) /*NEG/NOT*/ + codegen_check_seg_write(block, ir, target_seg); + else + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + reg = IREG_temp0_W; + } + + switch (fetchdat & 0x38) + { + case 0x00: case 0x08: /*TEST*/ + imm_data = fastreadw(cs + op_pc + 1); + + uop_AND_IMM(ir, IREG_flags_res_W, reg, imm_data); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc+1, 2); + return op_pc+3; + + case 0x10: /*NOT*/ + uop_XOR_IMM(ir, reg, reg, 0xffff); + if ((fetchdat & 0xc0) != 0xc0) + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg); + + codegen_flags_changed = 1; + return op_pc+1; + + case 0x18: /*NEG*/ + uop_MOV_IMM(ir, IREG_temp1_W, 0); + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOVZX(ir, IREG_flags_op2, reg); + uop_SUB(ir, IREG_temp1_W, IREG_temp1_W, reg); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + uop_MOV(ir, reg, IREG_temp1_W); + } + else + { + uop_SUB(ir, IREG_temp1_W, IREG_temp1_W, reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOV_IMM(ir, IREG_flags_op1, 0); + + codegen_flags_changed = 1; + return op_pc+1; + } + return 0; +} +uint32_t ropF7_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + uint32_t imm_data; + int reg; + + if (fetchdat & 0x20) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + reg = IREG_32(fetchdat & 7); + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x30) == 0x10) /*NEG/NOT*/ + codegen_check_seg_write(block, ir, target_seg); + else + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + reg = IREG_temp0; + } + + switch (fetchdat & 0x38) + { + case 0x00: case 0x08: /*TEST*/ + imm_data = fastreadl(cs + op_pc + 1); + + uop_AND_IMM(ir, IREG_flags_res, reg, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc+1, 4); + return op_pc+5; + + case 0x10: /*NOT*/ + uop_XOR_IMM(ir, reg, reg, 0xffffffff); + if ((fetchdat & 0xc0) != 0xc0) + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg); + + codegen_flags_changed = 1; + return op_pc+1; + + case 0x18: /*NEG*/ + uop_MOV_IMM(ir, IREG_temp1, 0); + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOV(ir, IREG_flags_op2, reg); + uop_SUB(ir, IREG_temp1, IREG_temp1, reg); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + uop_MOV(ir, reg, IREG_temp1); + } + else + { + uop_SUB(ir, IREG_temp1, IREG_temp1, reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV_IMM(ir, IREG_flags_op1, 0); + + codegen_flags_changed = 1; + return op_pc+1; + } + return 0; +} + +static void rebuild_c(ir_data_t *ir) +{ + int needs_rebuild = 1; + + if (codegen_flags_changed) + { + switch (cpu_state.flags_op) + { + case FLAGS_INC8: case FLAGS_INC16: case FLAGS_INC32: + case FLAGS_DEC8: case FLAGS_DEC16: case FLAGS_DEC32: + needs_rebuild = 0; + break; + } + } + + if (needs_rebuild) + { + uop_CALL_FUNC(ir, flags_rebuild_c); + } +} + +uint32_t ropFF_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + int src_reg, sp_reg; + + if ((fetchdat & 0x38) != 0x00 && (fetchdat & 0x38) != 0x08 && (fetchdat & 0x38) != 0x10 && (fetchdat & 0x38) != 0x20 && (fetchdat & 0x38) != 0x28 && (fetchdat & 0x38) != 0x30) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + if ((fetchdat & 0x38) == 0x28) + return 0; + src_reg = IREG_16(fetchdat & 7); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if (!(fetchdat & 0x30)) /*INC/DEC*/ + codegen_check_seg_write(block, ir, target_seg); + else + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + src_reg = IREG_temp0_W; + } + + switch (fetchdat & 0x38) + { + case 0x00: /*INC*/ + rebuild_c(ir); + codegen_flags_changed = 1; + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOVZX(ir, IREG_flags_op1, src_reg); + uop_ADD_IMM(ir, src_reg, src_reg, 1); + uop_MOVZX(ir, IREG_flags_res, src_reg); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC16); + } + else + { + uop_ADD_IMM(ir, IREG_temp1_W, src_reg, 1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, src_reg); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC16); + } + return op_pc+1; + + case 0x08: /*DEC*/ + rebuild_c(ir); + codegen_flags_changed = 1; + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOVZX(ir, IREG_flags_op1, src_reg); + uop_SUB_IMM(ir, src_reg, src_reg, 1); + uop_MOVZX(ir, IREG_flags_res, src_reg); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC16); + } + else + { + uop_SUB_IMM(ir, IREG_temp1_W, src_reg, 1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, src_reg); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC16); + } + return op_pc+1; + + case 0x10: /*CALL*/ + if ((fetchdat & 0xc0) == 0xc0) + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_IMM_16(ir, IREG_SS_base, sp_reg, op_pc + 1); + SUB_SP(ir, 2); + uop_MOVZX(ir, IREG_pc, src_reg); + return -1; + + case 0x20: /*JMP*/ + uop_MOVZX(ir, IREG_pc, src_reg); + return -1; + + case 0x28: /*JMP far*/ + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 2); + uop_LOAD_FUNC_ARG_REG(ir, 0, IREG_temp1_W); + uop_LOAD_FUNC_ARG_IMM(ir, 1, cpu_state.oldpc); + uop_CALL_FUNC(ir, loadcsjmp); + uop_MOVZX(ir, IREG_pc, src_reg); + return -1; + + case 0x30: /*PUSH*/ + if ((fetchdat & 0xc0) == 0xc0) + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, src_reg); + SUB_SP(ir, 2); + return op_pc+1; + } + return 0; +} + +uint32_t ropFF_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + int src_reg, sp_reg; + + if ((fetchdat & 0x38) != 0x00 && (fetchdat & 0x38) != 0x08 && (fetchdat & 0x38) != 0x10 && (fetchdat & 0x38) != 0x20 && (fetchdat & 0x38) != 0x28 && (fetchdat & 0x38) != 0x30) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + if ((fetchdat & 0x38) == 0x28) + return 0; + src_reg = IREG_32(fetchdat & 7); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if (!(fetchdat & 0x30)) /*INC/DEC*/ + codegen_check_seg_write(block, ir, target_seg); + else + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + src_reg = IREG_temp0; + } + + switch (fetchdat & 0x38) + { + case 0x00: /*INC*/ + rebuild_c(ir); + codegen_flags_changed = 1; + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOV(ir, IREG_flags_op1, src_reg); + uop_ADD_IMM(ir, src_reg, src_reg, 1); + uop_MOV(ir, IREG_flags_res, src_reg); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC32); + } + else + { + uop_ADD_IMM(ir, IREG_temp1, src_reg, 1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, src_reg); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC32); + } + return op_pc+1; + + case 0x08: /*DEC*/ + rebuild_c(ir); + codegen_flags_changed = 1; + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOV(ir, IREG_flags_op1, src_reg); + uop_SUB_IMM(ir, src_reg, src_reg, 1); + uop_MOV(ir, IREG_flags_res, src_reg); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC32); + } + else + { + uop_SUB_IMM(ir, IREG_temp1, src_reg, 1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, src_reg); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC32); + } + return op_pc+1; + + case 0x10: /*CALL*/ + if ((fetchdat & 0xc0) == 0xc0) + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_IMM_32(ir, IREG_SS_base, sp_reg, op_pc + 1); + SUB_SP(ir, 4); + uop_MOV(ir, IREG_pc, src_reg); + return -1; + + case 0x20: /*JMP*/ + uop_MOV(ir, IREG_pc, src_reg); + return -1; + + case 0x28: /*JMP far*/ + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 4); + uop_LOAD_FUNC_ARG_REG(ir, 0, IREG_temp1_W); + uop_LOAD_FUNC_ARG_IMM(ir, 1, cpu_state.oldpc); + uop_CALL_FUNC(ir, loadcsjmp); + uop_MOV(ir, IREG_pc, src_reg); + return -1; + + case 0x30: /*PUSH*/ + if ((fetchdat & 0xc0) == 0xc0) + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, src_reg); + SUB_SP(ir, 4); + return op_pc+1; + } + return 0; +} + +uint32_t ropNOP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + return op_pc; +} + +uint32_t ropCBW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOVSX(ir, IREG_AX, IREG_AL); + + return op_pc; +} +uint32_t ropCDQ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_SAR_IMM(ir, IREG_EDX, IREG_EAX, 31); + + return op_pc; +} +uint32_t ropCWD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_SAR_IMM(ir, IREG_DX, IREG_AX, 15); + + return op_pc; +} +uint32_t ropCWDE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOVSX(ir, IREG_EAX, IREG_AX); + + return op_pc; +} + +#define ropLxS(name, seg) \ +uint32_t rop ## name ## _16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg = NULL; \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + return 0; \ + \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 2); \ + uop_LOAD_SEG(ir, seg, IREG_temp1_W); \ + uop_MOV(ir, IREG_16(dest_reg), IREG_temp0_W); \ + \ + if (seg == &cpu_state.seg_ss) \ + CPU_BLOCK_END(); \ + \ + return op_pc + 1; \ +} \ +uint32_t rop ## name ## _32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg = NULL; \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + return 0; \ + \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 4); \ + uop_LOAD_SEG(ir, seg, IREG_temp1_W); \ + uop_MOV(ir, IREG_32(dest_reg), IREG_temp0); \ + \ + if (seg == &cpu_state.seg_ss) \ + CPU_BLOCK_END(); \ + \ + return op_pc + 1; \ +} + +ropLxS(LDS, &cpu_state.seg_ds) +ropLxS(LES, &cpu_state.seg_es) +ropLxS(LFS, &cpu_state.seg_fs) +ropLxS(LGS, &cpu_state.seg_gs) +ropLxS(LSS, &cpu_state.seg_ss) + +uint32_t ropCLC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_CALL_FUNC(ir, flags_rebuild); + uop_AND_IMM(ir, IREG_flags, IREG_flags, ~C_FLAG); + return op_pc; +} +uint32_t ropCMC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_CALL_FUNC(ir, flags_rebuild); + uop_XOR_IMM(ir, IREG_flags, IREG_flags, C_FLAG); + return op_pc; +} +uint32_t ropSTC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_CALL_FUNC(ir, flags_rebuild); + uop_OR_IMM(ir, IREG_flags, IREG_flags, C_FLAG); + return op_pc; +} + +uint32_t ropCLD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_AND_IMM(ir, IREG_flags, IREG_flags, ~D_FLAG); + return op_pc; +} +uint32_t ropSTD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_OR_IMM(ir, IREG_flags, IREG_flags, D_FLAG); + return op_pc; +} + +uint32_t ropCLI(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) + return 0; + + uop_AND_IMM(ir, IREG_flags, IREG_flags, ~I_FLAG); + return op_pc; +} +uint32_t ropSTI(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) + return 0; + + uop_OR_IMM(ir, IREG_flags, IREG_flags, I_FLAG); + return op_pc; +} diff --git a/src/cpu_new/codegen_ops_misc.h b/src/cpu_new/codegen_ops_misc.h new file mode 100644 index 000000000..d335e2a05 --- /dev/null +++ b/src/cpu_new/codegen_ops_misc.h @@ -0,0 +1,37 @@ +uint32_t ropLEA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLEA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropF6(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropF7_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropF7_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFF_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFF_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropNOP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropCBW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCDQ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCWD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCWDE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropLDS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLDS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLES_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLES_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLFS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLFS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLGS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLGS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLSS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLSS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropCLC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSTC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropCLD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSTD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropCLI(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSTI(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_mmx_arith.c b/src/cpu_new/codegen_ops_mmx_arith.c new file mode 100644 index 000000000..6b42273fa --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_arith.c @@ -0,0 +1,60 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_mmx_arith.h" +#include "codegen_ops_helpers.h" + +#define ropParith(func) \ +uint32_t rop ## func(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + uop_MMX_ENTER(ir); \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + int src_reg = fetchdat & 7; \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ + } \ + else \ + { \ + x86seg *target_seg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ + } \ + \ + return op_pc + 1; \ +} + +ropParith(PADDB) +ropParith(PADDW) +ropParith(PADDD) +ropParith(PADDSB) +ropParith(PADDSW) +ropParith(PADDUSB) +ropParith(PADDUSW) + +ropParith(PSUBB) +ropParith(PSUBW) +ropParith(PSUBD) +ropParith(PSUBSB) +ropParith(PSUBSW) +ropParith(PSUBUSB) +ropParith(PSUBUSW) + +ropParith(PMADDWD) +ropParith(PMULHW) +ropParith(PMULLW) diff --git a/src/cpu_new/codegen_ops_mmx_arith.h b/src/cpu_new/codegen_ops_mmx_arith.h new file mode 100644 index 000000000..2ac0acd83 --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_arith.h @@ -0,0 +1,19 @@ +uint32_t ropPADDB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPADDW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPADDD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPADDSB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPADDSW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPADDUSB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPADDUSW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPSUBB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSUBW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSUBD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSUBSB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSUBSW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSUBUSB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSUBUSW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPMADDWD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPMULHW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPMULLW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_mmx_cmp.c b/src/cpu_new/codegen_ops_mmx_cmp.c new file mode 100644 index 000000000..649e8550f --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_cmp.c @@ -0,0 +1,47 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_mmx_cmp.h" +#include "codegen_ops_helpers.h" + +#define ropPcmp(func) \ +uint32_t rop ## func(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + uop_MMX_ENTER(ir); \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + int src_reg = fetchdat & 7; \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ + } \ + else \ + { \ + x86seg *target_seg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ + } \ + \ + return op_pc + 1; \ +} + +ropPcmp(PCMPEQB) +ropPcmp(PCMPEQW) +ropPcmp(PCMPEQD) +ropPcmp(PCMPGTB) +ropPcmp(PCMPGTW) +ropPcmp(PCMPGTD) diff --git a/src/cpu_new/codegen_ops_mmx_cmp.h b/src/cpu_new/codegen_ops_mmx_cmp.h new file mode 100644 index 000000000..8f25cded4 --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_cmp.h @@ -0,0 +1,6 @@ +uint32_t ropPCMPEQB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPCMPEQW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPCMPEQD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPCMPGTB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPCMPGTW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPCMPGTD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_mmx_loadstore.c b/src/cpu_new/codegen_ops_mmx_loadstore.c new file mode 100644 index 000000000..37ab3199a --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_loadstore.c @@ -0,0 +1,113 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_mmx_loadstore.h" +#include "codegen_ops_helpers.h" + +uint32_t ropMOVD_r_d(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVZX(ir, IREG_MM(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_MM(dest_reg), IREG_temp0); + } + + return op_pc + 1; +} +uint32_t ropMOVD_d_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOVZX(ir, IREG_32(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 3); + uop_MOVZX(ir, IREG_temp0, IREG_MM(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + } + + return op_pc + 1; +} + +uint32_t ropMOVQ_r_q(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOV(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_MM(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + } + + return op_pc + 1; +} + +uint32_t ropMOVQ_q_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOV(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 7); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_MM(src_reg)); + } + + return op_pc + 1; +} diff --git a/src/cpu_new/codegen_ops_mmx_loadstore.h b/src/cpu_new/codegen_ops_mmx_loadstore.h new file mode 100644 index 000000000..1a2d4b032 --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_loadstore.h @@ -0,0 +1,5 @@ +uint32_t ropMOVD_r_d(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOVD_d_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropMOVQ_r_q(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOVQ_q_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_mmx_logic.c b/src/cpu_new/codegen_ops_mmx_logic.c new file mode 100644 index 000000000..4a554b238 --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_logic.c @@ -0,0 +1,111 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_mmx_logic.h" +#include "codegen_ops_helpers.h" + +uint32_t ropPAND(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_AND(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); + } + + return op_pc + 1; +} +uint32_t ropPANDN(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_ANDN(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ANDN(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); + } + + return op_pc + 1; +} +uint32_t ropPOR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_OR(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); + } + + return op_pc + 1; +} +uint32_t ropPXOR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_XOR(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); + } + + return op_pc + 1; +} diff --git a/src/cpu_new/codegen_ops_mmx_logic.h b/src/cpu_new/codegen_ops_mmx_logic.h new file mode 100644 index 000000000..4295c6c14 --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_logic.h @@ -0,0 +1,4 @@ +uint32_t ropPAND(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPANDN(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPXOR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_mmx_pack.c b/src/cpu_new/codegen_ops_mmx_pack.c new file mode 100644 index 000000000..6e9616271 --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_pack.c @@ -0,0 +1,50 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_mmx_pack.h" +#include "codegen_ops_helpers.h" + +#define ropPpack(func) \ +uint32_t rop ## func(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + uop_MMX_ENTER(ir); \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + int src_reg = fetchdat & 7; \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ + } \ + else \ + { \ + x86seg *target_seg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ + } \ + \ + return op_pc + 1; \ +} + +ropPpack(PACKSSWB) +ropPpack(PACKSSDW) +ropPpack(PACKUSWB) +ropPpack(PUNPCKLBW) +ropPpack(PUNPCKLWD) +ropPpack(PUNPCKLDQ) +ropPpack(PUNPCKHBW) +ropPpack(PUNPCKHWD) +ropPpack(PUNPCKHDQ) diff --git a/src/cpu_new/codegen_ops_mmx_pack.h b/src/cpu_new/codegen_ops_mmx_pack.h new file mode 100644 index 000000000..351940d6b --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_pack.h @@ -0,0 +1,9 @@ +uint32_t ropPACKSSWB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPACKSSDW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPACKUSWB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUNPCKLBW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUNPCKLWD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUNPCKLDQ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUNPCKHBW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUNPCKHWD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUNPCKHDQ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_mmx_shift.c b/src/cpu_new/codegen_ops_mmx_shift.c new file mode 100644 index 000000000..014001d53 --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_shift.c @@ -0,0 +1,96 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_mmx_shift.h" +#include "codegen_ops_helpers.h" + +uint32_t ropPSxxW_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = fastreadb(cs + op_pc + 1); + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + switch (op) + { + case 0x10: /*PSRLW*/ + uop_PSRLW_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + case 0x20: /*PSRAW*/ + uop_PSRAW_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + case 0x30: /*PSLLW*/ + uop_PSLLW_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + default: + return 0; + + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t ropPSxxD_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = fastreadb(cs + op_pc + 1); + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + switch (op) + { + case 0x10: /*PSRLD*/ + uop_PSRLD_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + case 0x20: /*PSRAD*/ + uop_PSRAD_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + case 0x30: /*PSLLD*/ + uop_PSLLD_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + default: + return 0; + + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t ropPSxxQ_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = fastreadb(cs + op_pc + 1); + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + switch (op) + { + case 0x10: /*PSRLQ*/ + uop_PSRLQ_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + case 0x20: /*PSRAQ*/ + uop_PSRAQ_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + case 0x30: /*PSLLQ*/ + uop_PSLLQ_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + default: + return 0; + + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} diff --git a/src/cpu_new/codegen_ops_mmx_shift.h b/src/cpu_new/codegen_ops_mmx_shift.h new file mode 100644 index 000000000..31ef9be6d --- /dev/null +++ b/src/cpu_new/codegen_ops_mmx_shift.h @@ -0,0 +1,7 @@ +uint32_t ropPSxxW_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSxxD_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSxxQ_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPSLLW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSLLD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSLLQ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_mov.c b/src/cpu_new/codegen_ops_mov.c new file mode 100644 index 000000000..87d7bc8bb --- /dev/null +++ b/src/cpu_new/codegen_ops_mov.c @@ -0,0 +1,773 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_mov.h" + +uint32_t ropMOV_rb_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm = fastreadb(cs + op_pc); + + uop_MOV_IMM(ir, IREG_8(opcode & 7), imm); + + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropMOV_rw_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_16(opcode & 7), imm); + + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropMOV_rl_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_32(opcode & 7), cs + op_pc); + } + else + { + fetchdat = fastreadl(cs + op_pc); + uop_MOV_IMM(ir, IREG_32(opcode & 7), fetchdat); + codegen_mark_code_present(block, cs+op_pc, 4); + } + return op_pc + 4; +} + + + +uint32_t ropMOV_b_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOV(ir, IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 0); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_8(src_reg)); + } + + return op_pc + 1; +} +uint32_t ropMOV_w_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOV(ir, IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_16(src_reg)); + } + + return op_pc + 1; +} +uint32_t ropMOV_l_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOV(ir, IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 3); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_32(src_reg)); + } + + return op_pc + 1; +} +uint32_t ropMOV_r_b(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOV(ir, IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_8(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + } + + return op_pc + 1; +} +uint32_t ropMOV_r_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOV(ir, IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_16(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + } + + return op_pc + 1; +} +uint32_t ropMOV_r_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOV(ir, IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_32(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + } + + return op_pc + 1; +} + +uint32_t ropMOV_AL_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_read(block, ir, op_ea_seg); + uop_MEM_LOAD_ABS(ir, IREG_AL, ireg_seg_base(op_ea_seg), addr); + + codegen_mark_code_present(block, cs+op_pc, (op_32 & 0x200) ? 4 : 2); + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +uint32_t ropMOV_AX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_read(block, ir, op_ea_seg); + uop_MEM_LOAD_ABS(ir, IREG_AX, ireg_seg_base(op_ea_seg), addr); + + codegen_mark_code_present(block, cs+op_pc, (op_32 & 0x200) ? 4 : 2); + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +uint32_t ropMOV_EAX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr = 0; + + if (op_32 & 0x200) + { + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_eaaddr, cs + op_pc); + } + else + { + addr = fastreadl(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 4); + } + } + else + { + addr = fastreadw(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 2); + } + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_read(block, ir, op_ea_seg); + if ((block->flags & CODEBLOCK_NO_IMMEDIATES) && (op_32 & 0x200)) + uop_MEM_LOAD_REG(ir, IREG_EAX, ireg_seg_base(op_ea_seg), IREG_eaaddr); + else + uop_MEM_LOAD_ABS(ir, IREG_EAX, ireg_seg_base(op_ea_seg), addr); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} + +uint32_t ropMOV_abs_AL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_write(block, ir, op_ea_seg); + uop_MEM_STORE_ABS(ir, ireg_seg_base(op_ea_seg), addr, IREG_AL); + + codegen_mark_code_present(block, cs+op_pc, (op_32 & 0x200) ? 4 : 2); + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +uint32_t ropMOV_abs_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_write(block, ir, op_ea_seg); + uop_MEM_STORE_ABS(ir, ireg_seg_base(op_ea_seg), addr, IREG_AX); + + codegen_mark_code_present(block, cs+op_pc, (op_32 & 0x200) ? 4 : 2); + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +uint32_t ropMOV_abs_EAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_write(block, ir, op_ea_seg); + uop_MEM_STORE_ABS(ir, ireg_seg_base(op_ea_seg), addr, IREG_EAX); + + codegen_mark_code_present(block, cs+op_pc, (op_32 & 0x200) ? 4 : 2); + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} + +uint32_t ropMOV_b_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + uint8_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + imm = fastreadb(cs + op_pc + 1); + uop_MOV_IMM(ir, IREG_8(dest_reg), imm); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadb(cs + op_pc + 1); + uop_MEM_STORE_IMM_8(ir, ireg_seg_base(target_seg), IREG_eaaddr, imm); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t ropMOV_w_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + uint16_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + imm = fastreadw(cs + op_pc + 1); + uop_MOV_IMM(ir, IREG_16(dest_reg), imm); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadw(cs + op_pc + 1); + uop_MEM_STORE_IMM_16(ir, ireg_seg_base(target_seg), IREG_eaaddr, imm); + } + + codegen_mark_code_present(block, cs+op_pc+1, 2); + return op_pc + 3; +} +uint32_t ropMOV_l_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + uint32_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + imm = fastreadl(cs + op_pc + 1); + uop_MOV_IMM(ir, IREG_32(dest_reg), imm); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadl(cs + op_pc + 1); + uop_MEM_STORE_IMM_32(ir, ireg_seg_base(target_seg), IREG_eaaddr, imm); + } + + codegen_mark_code_present(block, cs+op_pc+1, 4); + return op_pc + 5; +} + +uint32_t ropMOV_w_seg(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg; + + codegen_mark_code_present(block, cs+op_pc, 1); + switch (fetchdat & 0x38) + { + case 0x00: /*ES*/ + src_reg = IREG_ES_seg_W; + break; + case 0x08: /*CS*/ + src_reg = IREG_CS_seg_W; + break; + case 0x18: /*DS*/ + src_reg = IREG_DS_seg_W; + break; + case 0x10: /*SS*/ + src_reg = IREG_SS_seg_W; + break; + case 0x20: /*FS*/ + src_reg = IREG_FS_seg_W; + break; + case 0x28: /*GS*/ + src_reg = IREG_GS_seg_W; + break; + default: + return 0; + } + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOV(ir, IREG_16(dest_reg), src_reg); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, src_reg); + } + + return op_pc + 1; +} +uint32_t ropMOV_l_seg(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg; + + codegen_mark_code_present(block, cs+op_pc, 1); + switch (fetchdat & 0x38) + { + case 0x00: /*ES*/ + src_reg = IREG_ES_seg_W; + break; + case 0x08: /*CS*/ + src_reg = IREG_CS_seg_W; + break; + case 0x18: /*DS*/ + src_reg = IREG_DS_seg_W; + break; + case 0x10: /*SS*/ + src_reg = IREG_SS_seg_W; + break; + case 0x20: /*FS*/ + src_reg = IREG_FS_seg_W; + break; + case 0x28: /*GS*/ + src_reg = IREG_GS_seg_W; + break; + default: + return 0; + } + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOVZX(ir, IREG_32(dest_reg), src_reg); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, src_reg); + } + + return op_pc + 1; +} + +uint32_t ropMOV_seg_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg; + x86seg *rseg; + + codegen_mark_code_present(block, cs+op_pc, 1); + switch (fetchdat & 0x38) + { + case 0x00: /*ES*/ + rseg = &cpu_state.seg_es; + break; + case 0x18: /*DS*/ + rseg = &cpu_state.seg_ds; + break; + case 0x20: /*FS*/ + rseg = &cpu_state.seg_fs; + break; + case 0x28: /*GS*/ + rseg = &cpu_state.seg_gs; + break; + default: + return 0; + } + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOV(ir, IREG_temp0_W, IREG_16(fetchdat & 7)); + src_reg = IREG_temp0_W; + } + else + { + x86seg *target_seg; + + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + src_reg = IREG_temp0_W; + } + + uop_LOAD_SEG(ir, rseg, src_reg); + + return op_pc + 1; +} + +uint32_t ropMOVSX_16_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVSX(ir, IREG_16(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVSX(ir, IREG_16(dest_reg), IREG_temp0_B); + } + + return op_pc + 1; +} +uint32_t ropMOVSX_32_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVSX(ir, IREG_32(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVSX(ir, IREG_32(dest_reg), IREG_temp0_B); + } + + return op_pc + 1; +} +uint32_t ropMOVSX_32_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVSX(ir, IREG_32(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVSX(ir, IREG_32(dest_reg), IREG_temp0_W); + } + + return op_pc + 1; +} + +uint32_t ropMOVZX_16_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVZX(ir, IREG_16(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_16(dest_reg), IREG_temp0_B); + } + + return op_pc + 1; +} +uint32_t ropMOVZX_32_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVZX(ir, IREG_32(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_32(dest_reg), IREG_temp0_B); + } + + return op_pc + 1; +} +uint32_t ropMOVZX_32_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVZX(ir, IREG_32(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_32(dest_reg), IREG_temp0_W); + } + + return op_pc + 1; +} + + +uint32_t ropXCHG_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg2 = IREG_16(opcode & 7); + + uop_MOV(ir, IREG_temp0_W, IREG_AX); + uop_MOV(ir, IREG_AX, reg2); + uop_MOV(ir, reg2, IREG_temp0_W); + + return op_pc; +} +uint32_t ropXCHG_EAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg2 = IREG_32(opcode & 7); + + uop_MOV(ir, IREG_temp0, IREG_EAX); + uop_MOV(ir, IREG_EAX, reg2); + uop_MOV(ir, reg2, IREG_temp0); + + return op_pc; +} + +uint32_t ropXCHG_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg1 = IREG_8((fetchdat >> 3) & 7); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int reg2 = IREG_8(fetchdat & 7); + + uop_MOV(ir, IREG_temp0_B, reg1); + uop_MOV(ir, reg1, reg2); + uop_MOV(ir, reg2, IREG_temp0_B); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg1); + uop_MOV(ir, reg1, IREG_temp0_B); + } + + return op_pc + 1; +} +uint32_t ropXCHG_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg1 = IREG_16((fetchdat >> 3) & 7); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int reg2 = IREG_16(fetchdat & 7); + + uop_MOV(ir, IREG_temp0_W, reg1); + uop_MOV(ir, reg1, reg2); + uop_MOV(ir, reg2, IREG_temp0_W); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg1); + uop_MOV(ir, reg1, IREG_temp0_W); + } + + return op_pc + 1; +} +uint32_t ropXCHG_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg1 = IREG_32((fetchdat >> 3) & 7); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int reg2 = IREG_32(fetchdat & 7); + + uop_MOV(ir, IREG_temp0, reg1); + uop_MOV(ir, reg1, reg2); + uop_MOV(ir, reg2, IREG_temp0); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg1); + uop_MOV(ir, reg1, IREG_temp0); + } + + return op_pc + 1; +} + +uint32_t ropXLAT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + uop_MOVZX(ir, IREG_eaaddr, IREG_AL); + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, IREG_EBX); + if (!(op_32 & 0x200)) + uop_AND_IMM(ir, IREG_eaaddr, IREG_eaaddr, 0xffff); + + uop_MEM_LOAD_REG(ir, IREG_AL, ireg_seg_base(op_ea_seg), IREG_eaaddr); + + return op_pc; +} diff --git a/src/cpu_new/codegen_ops_mov.h b/src/cpu_new/codegen_ops_mov.h new file mode 100644 index 000000000..c6bf57460 --- /dev/null +++ b/src/cpu_new/codegen_ops_mov.h @@ -0,0 +1,43 @@ +uint32_t ropMOV_rb_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_rw_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_rl_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropMOV_b_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_w_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_l_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_r_b(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_r_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_r_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropMOV_AL_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_AX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_EAX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropMOV_abs_AL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_abs_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_abs_EAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropMOV_b_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_w_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_l_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropMOV_w_seg(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_l_seg(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_seg_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropMOVSX_16_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOVSX_32_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOVSX_32_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropMOVZX_16_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOVZX_32_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOVZX_32_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropXCHG_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXCHG_EAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropXCHG_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXCHG_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXCHG_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropXLAT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_shift.c b/src/cpu_new/codegen_ops_shift.c new file mode 100644 index 000000000..2d0b760d2 --- /dev/null +++ b/src/cpu_new/codegen_ops_shift.c @@ -0,0 +1,1138 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_shift.h" + +static uint32_t shift_common_8(ir_data_t *ir, uint32_t fetchdat, uint32_t op_pc, x86seg *target_seg, int count) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_SHL_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_SHR_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_SAR_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + default: + return 0; + } + } + else + { + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL_IMM(ir, IREG_temp0_B, IREG_temp0_B, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR_IMM(ir, IREG_temp0_B, IREG_temp0_B, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL_IMM(ir, IREG_temp1_B, IREG_temp0_B, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x28: /*SHR*/ + uop_SHR_IMM(ir, IREG_temp1_B, IREG_temp0_B, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x38: /*SAR*/ + uop_SAR_IMM(ir, IREG_temp1_B, IREG_temp0_B, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} + +static uint32_t shift_common_16(ir_data_t *ir, uint32_t fetchdat, uint32_t op_pc, x86seg *target_seg, int count) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SHL_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SHR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SAR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + default: + return 0; + } + } + else + { + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL_IMM(ir, IREG_temp0_W, IREG_temp0_W, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR_IMM(ir, IREG_temp0_W, IREG_temp0_W, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL_IMM(ir, IREG_temp1_W, IREG_temp0_W, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x28: /*SHR*/ + uop_SHR_IMM(ir, IREG_temp1_W, IREG_temp0_W, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x38: /*SAR*/ + uop_SAR_IMM(ir, IREG_temp1_W, IREG_temp0_W, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t shift_common_32(ir_data_t *ir, uint32_t fetchdat, uint32_t op_pc, x86seg *target_seg, int count) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHL_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SAR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + default: + return 0; + } + } + else + { + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL_IMM(ir, IREG_temp0, IREG_temp0, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL32); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR_IMM(ir, IREG_temp0, IREG_temp0, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR32); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL_IMM(ir, IREG_temp1, IREG_temp0, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x28: /*SHR*/ + uop_SHR_IMM(ir, IREG_temp1, IREG_temp0, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x38: /*SAR*/ + uop_SAR_IMM(ir, IREG_temp1, IREG_temp0, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} + +static uint32_t shift_common_variable_32(ir_data_t *ir, uint32_t fetchdat, uint32_t op_pc, x86seg *target_seg, int count_reg) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_32(dest_reg), IREG_32(dest_reg), count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_32(dest_reg), IREG_32(dest_reg), count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHL(ir, IREG_32(dest_reg), IREG_32(dest_reg), count_reg); + uop_MOV(ir, IREG_flags_op2, count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHR(ir, IREG_32(dest_reg), IREG_32(dest_reg), count_reg); + uop_MOV(ir, IREG_flags_op2, count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SAR(ir, IREG_32(dest_reg), IREG_32(dest_reg), count_reg); + uop_MOV(ir, IREG_flags_op2, count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + default: + return 0; + } + } + else + { + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_temp0, IREG_temp0, count_reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL32); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_temp0, IREG_temp0, count_reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR32); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL(ir, IREG_temp1, IREG_temp0, count_reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x28: /*SHR*/ + uop_SHR(ir, IREG_temp1, IREG_temp0, count_reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x38: /*SAR*/ + uop_SAR(ir, IREG_temp1, IREG_temp0, count_reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropC0(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + uint8_t imm; + + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + } + imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (imm) + return shift_common_8(ir, fetchdat, op_pc, target_seg, imm) + 1; + return op_pc+1; +} +uint32_t ropC1_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + uint8_t imm; + + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + } + imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (imm) + return shift_common_16(ir, fetchdat, op_pc, target_seg, imm) + 1; + return op_pc+1; +} +uint32_t ropC1_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + } + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uint32_t new_pc; + int jump_uop; + + LOAD_IMMEDIATE_FROM_RAM_8(block, ir, IREG_temp2, cs + op_pc + 1); + uop_AND_IMM(ir, IREG_temp2, IREG_temp2, 0x1f); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp2, 0); + + new_pc = shift_common_variable_32(ir, fetchdat, op_pc, target_seg, IREG_temp2) + 1; + uop_NOP_BARRIER(ir); + uop_set_jump_dest(ir, jump_uop); + return new_pc; + } + else + { + uint8_t imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (imm) + return shift_common_32(ir, fetchdat, op_pc, target_seg, imm) + 1; + } + return op_pc+1; +} + +uint32_t ropD0(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + } + + return shift_common_8(ir, fetchdat, op_pc, target_seg, 1); +} +uint32_t ropD1_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + } + + return shift_common_16(ir, fetchdat, op_pc, target_seg, 1); +} +uint32_t ropD1_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + } + + return shift_common_32(ir, fetchdat, op_pc, target_seg, 1); +} + +uint32_t ropD2(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + if (!(CL & 0x1f) || !block->ins) + return 0; + + uop_AND_IMM(ir, IREG_temp2, REG_ECX, 0x1f); + uop_CMP_IMM_JZ(ir, IREG_temp2, 0, codegen_exit_rout); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_SHL(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_SHR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_SAR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_temp0_B, IREG_temp0_B, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_temp0_B, IREG_temp0_B, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL(ir, IREG_temp1_B, IREG_temp0_B, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x28: /*SHR*/ + uop_SHR(ir, IREG_temp1_B, IREG_temp0_B, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x38: /*SAR*/ + uop_SAR(ir, IREG_temp1_B, IREG_temp0_B, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropD3_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + if (!(CL & 0x1f) || !block->ins) + return 0; + + uop_AND_IMM(ir, IREG_temp2, REG_ECX, 0x1f); + uop_CMP_IMM_JZ(ir, IREG_temp2, 0, codegen_exit_rout); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SHL(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SHR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SAR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x28: /*SHR*/ + uop_SHR(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x38: /*SAR*/ + uop_SAR(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropD3_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + if (!(CL & 0x1f) || !block->ins) + return 0; + + uop_AND_IMM(ir, IREG_temp2, REG_ECX, 0x1f); + uop_CMP_IMM_JZ(ir, IREG_temp2, 0, codegen_exit_rout); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHL(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SAR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_temp0, IREG_temp0, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL32); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_temp0, IREG_temp0, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR32); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL(ir, IREG_temp1, IREG_temp0, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x28: /*SHR*/ + uop_SHR(ir, IREG_temp1, IREG_temp0, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x38: /*SAR*/ + uop_SAR(ir, IREG_temp1, IREG_temp0, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropSHLD_16_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + int src_reg = (fetchdat >> 3) & 7; + uint8_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + } + imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (!imm) + return op_pc+2; + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SHL_IMM(ir, IREG_temp0_W, IREG_16(dest_reg), imm); + uop_SHR_IMM(ir, IREG_temp1_W, IREG_16(src_reg), 16 - imm); + uop_OR(ir, IREG_16(dest_reg), IREG_temp0_W, IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp2_W, ireg_seg_base(target_seg), IREG_eaaddr); + + uop_SHL_IMM(ir, IREG_temp0_W, IREG_temp2, imm); + uop_SHR_IMM(ir, IREG_temp1_W, IREG_16(src_reg), 16 - imm); + uop_OR(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp1_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + + uop_MOVZX(ir, IREG_flags_op1, IREG_temp2_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL16); + } + + return op_pc+2; +} +uint32_t ropSHLD_32_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + int src_reg = (fetchdat >> 3) & 7; + uint8_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + } + imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (!imm) + return op_pc+2; + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHL_IMM(ir, IREG_temp0, IREG_32(dest_reg), imm); + uop_SHR_IMM(ir, IREG_temp1, IREG_32(src_reg), 32 - imm); + uop_OR(ir, IREG_32(dest_reg), IREG_temp0, IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp2, ireg_seg_base(target_seg), IREG_eaaddr); + + uop_SHL_IMM(ir, IREG_temp0, IREG_temp2, imm); + uop_SHR_IMM(ir, IREG_temp1, IREG_32(src_reg), 32 - imm); + uop_OR(ir, IREG_temp0, IREG_temp0, IREG_temp1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + + uop_MOV(ir, IREG_flags_op1, IREG_temp2); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + } + + return op_pc+2; +} +uint32_t ropSHRD_16_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + int src_reg = (fetchdat >> 3) & 7; + uint8_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + } + imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (!imm) + return op_pc+2; + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SHR_IMM(ir, IREG_temp0_W, IREG_16(dest_reg), imm); + uop_SHL_IMM(ir, IREG_temp1_W, IREG_16(src_reg), 16 - imm); + uop_OR(ir, IREG_16(dest_reg), IREG_temp0_W, IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp2_W, ireg_seg_base(target_seg), IREG_eaaddr); + + uop_SHR_IMM(ir, IREG_temp0_W, IREG_temp2, imm); + uop_SHL_IMM(ir, IREG_temp1_W, IREG_16(src_reg), 16 - imm); + uop_OR(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp1_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + + uop_MOVZX(ir, IREG_flags_op1, IREG_temp2_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR16); + } + + return op_pc+2; +} +uint32_t ropSHRD_32_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + int src_reg = (fetchdat >> 3) & 7; + uint8_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + } + imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (!imm) + return op_pc+2; + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHR_IMM(ir, IREG_temp0, IREG_32(dest_reg), imm); + uop_SHL_IMM(ir, IREG_temp1, IREG_32(src_reg), 32 - imm); + uop_OR(ir, IREG_32(dest_reg), IREG_temp0, IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp2, ireg_seg_base(target_seg), IREG_eaaddr); + + uop_SHR_IMM(ir, IREG_temp0, IREG_temp2, imm); + uop_SHL_IMM(ir, IREG_temp1, IREG_32(src_reg), 32 - imm); + uop_OR(ir, IREG_temp0, IREG_temp0, IREG_temp1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + + uop_MOV(ir, IREG_flags_op1, IREG_temp2); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + } + + return op_pc+2; +} diff --git a/src/cpu_new/codegen_ops_shift.h b/src/cpu_new/codegen_ops_shift.h new file mode 100644 index 000000000..72166ad8f --- /dev/null +++ b/src/cpu_new/codegen_ops_shift.h @@ -0,0 +1,16 @@ +uint32_t ropC0(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropC1_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropC1_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropD0(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropD1_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropD1_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropD2(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropD3_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropD3_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropSHLD_16_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSHLD_32_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSHRD_16_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSHRD_32_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_ops_stack.c b/src/cpu_new/codegen_ops_stack.c new file mode 100644 index 000000000..28b346446 --- /dev/null +++ b/src/cpu_new/codegen_ops_stack.c @@ -0,0 +1,412 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_misc.h" + +uint32_t ropPUSH_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_16(opcode & 7)); + SUB_SP(ir, 2); + + return op_pc; +} +uint32_t ropPUSH_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_32(opcode & 7)); + SUB_SP(ir, 4); + + return op_pc; +} + +uint32_t ropPOP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_16(opcode & 7), IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_16(opcode & 7), IREG_SS_base, IREG_eaaddr); + } + if ((opcode & 7) != REG_SP) + ADD_SP(ir, 2); + + return op_pc; +} +uint32_t ropPOP_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_32(opcode & 7), IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_32(opcode & 7), IREG_SS_base, IREG_eaaddr); + } + if ((opcode & 7) != REG_ESP) + ADD_SP(ir, 4); + + return op_pc; +} + +uint32_t ropPUSH_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm = fastreadw(cs + op_pc); + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_IMM_16(ir, IREG_SS_base, sp_reg, imm); + SUB_SP(ir, 2); + + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropPUSH_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t imm = fastreadl(cs + op_pc); + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_IMM_32(ir, IREG_SS_base, sp_reg, imm); + SUB_SP(ir, 4); + + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} + +uint32_t ropPUSH_imm_16_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm = (int16_t)(int8_t)fastreadb(cs + op_pc); + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_IMM_16(ir, IREG_SS_base, sp_reg, imm); + SUB_SP(ir, 2); + + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropPUSH_imm_32_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t imm = (int32_t)(int8_t)fastreadb(cs + op_pc); + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_IMM_32(ir, IREG_SS_base, sp_reg, imm); + SUB_SP(ir, 4); + + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} + +uint32_t ropPOP_W(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_16(fetchdat & 7), IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_16(fetchdat & 7), IREG_SS_base, IREG_eaaddr); + } + } + else + { + x86seg *target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 2); + codegen_check_seg_write(block, ir, target_seg); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_temp0, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_temp0); + } + + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + } + + if ((fetchdat & 0xc7) != (0xc0 | REG_SP)) + ADD_SP(ir, 2); + + return op_pc + 1; +} +uint32_t ropPOP_L(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_32(fetchdat & 7), IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_32(fetchdat & 7), IREG_SS_base, IREG_eaaddr); + } + } + else + { + x86seg *target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 4); + codegen_check_seg_write(block, ir, target_seg); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_temp0, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_temp0); + } + + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + } + + if ((fetchdat & 0xc7) != (0xc0 | REG_ESP)) + ADD_SP(ir, 4); + + return op_pc + 1; +} + +#define ROP_PUSH_SEG(seg) \ +uint32_t ropPUSH_ ## seg ## _16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + int sp_reg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); \ + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_ ## seg ## _seg_W); \ + SUB_SP(ir, 2); \ + \ + return op_pc; \ +} \ +uint32_t ropPUSH_ ## seg ## _32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + int sp_reg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); \ + uop_MOVZX(ir, IREG_temp0, IREG_ ## seg ## _seg_W); \ + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_temp0); \ + SUB_SP(ir, 4); \ + \ + return op_pc; \ +} + +#define ROP_POP_SEG(seg, rseg) \ +uint32_t ropPOP_ ## seg ## _16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + \ + if (stack32) \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); \ + else \ + { \ + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); \ + } \ + uop_LOAD_SEG(ir, &rseg, IREG_temp0_W); \ + ADD_SP(ir, 2); \ + \ + return op_pc; \ +} \ +uint32_t ropPOP_ ## seg ## _32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + \ + if (stack32) \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); \ + else \ + { \ + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); \ + } \ + uop_LOAD_SEG(ir, &rseg, IREG_temp0_W); \ + ADD_SP(ir, 4); \ + \ + return op_pc; \ +} + + +ROP_PUSH_SEG(CS) +ROP_PUSH_SEG(DS) +ROP_PUSH_SEG(ES) +ROP_PUSH_SEG(FS) +ROP_PUSH_SEG(GS) +ROP_PUSH_SEG(SS) +ROP_POP_SEG(DS, cpu_state.seg_ds) +ROP_POP_SEG(ES, cpu_state.seg_es) +ROP_POP_SEG(FS, cpu_state.seg_fs) +ROP_POP_SEG(GS, cpu_state.seg_gs) + +uint32_t ropLEAVE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_EBP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_BP); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); + } + uop_ADD_IMM(ir, IREG_SP, IREG_BP, 2); + uop_MOV(ir, IREG_BP, IREG_temp0_W); + + return op_pc; +} +uint32_t ropLEAVE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_EBP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_BP); + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_eaaddr); + } + uop_ADD_IMM(ir, IREG_ESP, IREG_EBP, 4); + uop_MOV(ir, IREG_EBP, IREG_temp0); + + return op_pc; +} + + +uint32_t ropPUSHA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -16); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 14, IREG_AX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 12, IREG_CX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 10, IREG_DX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 8, IREG_BX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 6, IREG_SP); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 4, IREG_BP); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 2, IREG_SI); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_DI); + SUB_SP(ir, 16); + + return op_pc; +} +uint32_t ropPUSHA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -32); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 28, IREG_EAX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 24, IREG_ECX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 20, IREG_EDX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 16, IREG_EBX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 12, IREG_ESP); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 8, IREG_EBP); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 4, IREG_ESI); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_EDI); + SUB_SP(ir, 32); + + return op_pc; +} + +uint32_t ropPOPA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP(ir); + uop_MEM_LOAD_REG(ir, IREG_DI, IREG_SS_base, sp_reg); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_SI, IREG_SS_base, sp_reg, 2); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_BP, IREG_SS_base, sp_reg, 4); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_BX, IREG_SS_base, sp_reg, 8); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_DX, IREG_SS_base, sp_reg, 10); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_CX, IREG_SS_base, sp_reg, 12); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_AX, IREG_SS_base, sp_reg, 14); + ADD_SP(ir, 16); + + return op_pc; +} +uint32_t ropPOPA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP(ir); + uop_MEM_LOAD_REG(ir, IREG_EDI, IREG_SS_base, sp_reg); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_ESI, IREG_SS_base, sp_reg, 4); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_EBP, IREG_SS_base, sp_reg, 8); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_EBX, IREG_SS_base, sp_reg, 16); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_EDX, IREG_SS_base, sp_reg, 20); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_ECX, IREG_SS_base, sp_reg, 24); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_EAX, IREG_SS_base, sp_reg, 28); + ADD_SP(ir, 32); + + return op_pc; +} + +uint32_t ropPUSHF(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + return 0; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + uop_CALL_FUNC(ir, flags_rebuild); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_flags); + SUB_SP(ir, 2); + + return op_pc; +} +uint32_t ropPUSHFD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + return 0; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + uop_CALL_FUNC(ir, flags_rebuild); + + if (cpu_CR4_mask & CR4_VME) + uop_AND_IMM(ir, IREG_temp0_W, IREG_eflags, 0x3c); + else if (CPUID) + uop_AND_IMM(ir, IREG_temp0_W, IREG_eflags, 0x24); + else + uop_AND_IMM(ir, IREG_temp0_W, IREG_eflags, 4); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_flags); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 2, IREG_temp0_W); + SUB_SP(ir, 4); + + return op_pc; +} diff --git a/src/cpu_new/codegen_ops_stack.h b/src/cpu_new/codegen_ops_stack.h new file mode 100644 index 000000000..dbbbd372b --- /dev/null +++ b/src/cpu_new/codegen_ops_stack.h @@ -0,0 +1,49 @@ +uint32_t ropPUSH_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPOP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPUSH_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_imm_16_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_imm_32_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPOP_W(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_L(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPUSH_CS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_DS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_ES_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_FS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_GS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_SS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPUSH_CS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_DS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_ES_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_FS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_GS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_SS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPOP_DS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_ES_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_FS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_GS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPOP_DS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_ES_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_FS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_GS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropLEAVE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLEAVE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPUSHA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSHA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPOPA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOPA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPUSHF(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSHFD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/cpu_new/codegen_reg.c b/src/cpu_new/codegen_reg.c new file mode 100644 index 000000000..70b654998 --- /dev/null +++ b/src/cpu_new/codegen_reg.c @@ -0,0 +1,767 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_ir_defs.h" +#include "codegen_reg.h" + +int max_version_refcount; +uint16_t reg_dead_list = 0; + +uint8_t reg_last_version[IREG_COUNT]; +reg_version_t reg_version[IREG_COUNT][256]; + +ir_reg_t invalid_ir_reg = {IREG_INVALID}; + +ir_reg_t _host_regs[CODEGEN_HOST_REGS]; +static uint8_t _host_reg_dirty[CODEGEN_HOST_REGS]; + +ir_reg_t host_fp_regs[CODEGEN_HOST_FP_REGS]; +static uint8_t host_fp_reg_dirty[CODEGEN_HOST_FP_REGS]; + +typedef struct host_reg_set_t +{ + ir_reg_t *regs; + uint8_t *dirty; + host_reg_def_t *reg_list; + uint16_t locked; + int nr_regs; +} host_reg_set_t; + +static host_reg_set_t host_reg_set, host_fp_reg_set; + +enum +{ + REG_BYTE, + REG_WORD, + REG_DWORD, + REG_QWORD, + REG_POINTER, + REG_DOUBLE, + REG_FPU_ST_BYTE, + REG_FPU_ST_DOUBLE, + REG_FPU_ST_QWORD +}; + +enum +{ + REG_INTEGER, + REG_FP +}; + +enum +{ + /*Register may be accessed outside of code block, and must be written + back before any control transfers*/ + REG_PERMANENT = 0, + /*Register will not be accessed outside of code block, and does not need + to be written back if there are no readers remaining*/ + REG_VOLATILE = 1 +}; + +struct +{ + int native_size; + void *p; + int type; + int is_volatile; +} ireg_data[IREG_COUNT] = +{ + [IREG_EAX] = {REG_DWORD, &EAX, REG_INTEGER, REG_PERMANENT}, + [IREG_ECX] = {REG_DWORD, &ECX, REG_INTEGER, REG_PERMANENT}, + [IREG_EDX] = {REG_DWORD, &EDX, REG_INTEGER, REG_PERMANENT}, + [IREG_EBX] = {REG_DWORD, &EBX, REG_INTEGER, REG_PERMANENT}, + [IREG_ESP] = {REG_DWORD, &ESP, REG_INTEGER, REG_PERMANENT}, + [IREG_EBP] = {REG_DWORD, &EBP, REG_INTEGER, REG_PERMANENT}, + [IREG_ESI] = {REG_DWORD, &ESI, REG_INTEGER, REG_PERMANENT}, + [IREG_EDI] = {REG_DWORD, &EDI, REG_INTEGER, REG_PERMANENT}, + + [IREG_flags_op] = {REG_DWORD, &cpu_state.flags_op, REG_INTEGER, REG_PERMANENT}, + [IREG_flags_res] = {REG_DWORD, &cpu_state.flags_res, REG_INTEGER, REG_PERMANENT}, + [IREG_flags_op1] = {REG_DWORD, &cpu_state.flags_op1, REG_INTEGER, REG_PERMANENT}, + [IREG_flags_op2] = {REG_DWORD, &cpu_state.flags_op2, REG_INTEGER, REG_PERMANENT}, + + [IREG_pc] = {REG_DWORD, &cpu_state.pc, REG_INTEGER, REG_PERMANENT}, + [IREG_oldpc] = {REG_DWORD, &cpu_state.oldpc, REG_INTEGER, REG_PERMANENT}, + + [IREG_eaaddr] = {REG_DWORD, &cpu_state.eaaddr, REG_INTEGER, REG_PERMANENT}, + [IREG_ea_seg] = {REG_POINTER, &cpu_state.ea_seg, REG_INTEGER, REG_PERMANENT}, + + [IREG_op32] = {REG_DWORD, &cpu_state.op32, REG_INTEGER, REG_PERMANENT}, + [IREG_ssegsx] = {REG_BYTE, &cpu_state.ssegs, REG_INTEGER, REG_PERMANENT}, + + [IREG_rm_mod_reg] = {REG_DWORD, &cpu_state.rm_data.rm_mod_reg_data, REG_INTEGER, REG_PERMANENT}, + + [IREG_ins] = {REG_DWORD, &cpu_state.cpu_recomp_ins, REG_INTEGER, REG_PERMANENT}, + [IREG_cycles] = {REG_DWORD, &cpu_state._cycles, REG_INTEGER, REG_PERMANENT}, + + [IREG_CS_base] = {REG_DWORD, &cpu_state.seg_cs.base, REG_INTEGER, REG_PERMANENT}, + [IREG_DS_base] = {REG_DWORD, &cpu_state.seg_ds.base, REG_INTEGER, REG_PERMANENT}, + [IREG_ES_base] = {REG_DWORD, &cpu_state.seg_es.base, REG_INTEGER, REG_PERMANENT}, + [IREG_FS_base] = {REG_DWORD, &cpu_state.seg_fs.base, REG_INTEGER, REG_PERMANENT}, + [IREG_GS_base] = {REG_DWORD, &cpu_state.seg_gs.base, REG_INTEGER, REG_PERMANENT}, + [IREG_SS_base] = {REG_DWORD, &cpu_state.seg_ss.base, REG_INTEGER, REG_PERMANENT}, + + [IREG_CS_seg] = {REG_WORD, &cpu_state.seg_cs.seg, REG_INTEGER, REG_PERMANENT}, + [IREG_DS_seg] = {REG_WORD, &cpu_state.seg_ds.seg, REG_INTEGER, REG_PERMANENT}, + [IREG_ES_seg] = {REG_WORD, &cpu_state.seg_es.seg, REG_INTEGER, REG_PERMANENT}, + [IREG_FS_seg] = {REG_WORD, &cpu_state.seg_fs.seg, REG_INTEGER, REG_PERMANENT}, + [IREG_GS_seg] = {REG_WORD, &cpu_state.seg_gs.seg, REG_INTEGER, REG_PERMANENT}, + [IREG_SS_seg] = {REG_WORD, &cpu_state.seg_ss.seg, REG_INTEGER, REG_PERMANENT}, + + [IREG_FPU_TOP] = {REG_DWORD, &cpu_state.TOP, REG_INTEGER, REG_PERMANENT}, + + [IREG_ST0] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST1] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST2] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST3] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST4] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST5] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST6] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST7] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + + [IREG_tag0] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag1] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag2] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag3] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag4] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag5] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag6] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag7] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + + [IREG_ST0_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST1_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST2_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST3_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST4_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST5_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST6_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST7_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + + [IREG_MM0x] = {REG_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_MM1x] = {REG_QWORD, &cpu_state.MM[1], REG_FP, REG_PERMANENT}, + [IREG_MM2x] = {REG_QWORD, &cpu_state.MM[2], REG_FP, REG_PERMANENT}, + [IREG_MM3x] = {REG_QWORD, &cpu_state.MM[3], REG_FP, REG_PERMANENT}, + [IREG_MM4x] = {REG_QWORD, &cpu_state.MM[4], REG_FP, REG_PERMANENT}, + [IREG_MM5x] = {REG_QWORD, &cpu_state.MM[5], REG_FP, REG_PERMANENT}, + [IREG_MM6x] = {REG_QWORD, &cpu_state.MM[6], REG_FP, REG_PERMANENT}, + [IREG_MM7x] = {REG_QWORD, &cpu_state.MM[7], REG_FP, REG_PERMANENT}, + + [IREG_NPXCx] = {REG_WORD, &cpu_state.npxc, REG_INTEGER, REG_PERMANENT}, + [IREG_NPXSx] = {REG_WORD, &cpu_state.npxs, REG_INTEGER, REG_PERMANENT}, + + [IREG_flagsx] = {REG_WORD, &cpu_state.flags, REG_INTEGER, REG_PERMANENT}, + [IREG_eflagsx] = {REG_WORD, &cpu_state.eflags, REG_INTEGER, REG_PERMANENT}, + + [IREG_CS_limit_low] = {REG_DWORD, &cpu_state.seg_cs.limit_low, REG_INTEGER, REG_PERMANENT}, + [IREG_DS_limit_low] = {REG_DWORD, &cpu_state.seg_ds.limit_low, REG_INTEGER, REG_PERMANENT}, + [IREG_ES_limit_low] = {REG_DWORD, &cpu_state.seg_es.limit_low, REG_INTEGER, REG_PERMANENT}, + [IREG_FS_limit_low] = {REG_DWORD, &cpu_state.seg_fs.limit_low, REG_INTEGER, REG_PERMANENT}, + [IREG_GS_limit_low] = {REG_DWORD, &cpu_state.seg_gs.limit_low, REG_INTEGER, REG_PERMANENT}, + [IREG_SS_limit_low] = {REG_DWORD, &cpu_state.seg_ss.limit_low, REG_INTEGER, REG_PERMANENT}, + + [IREG_CS_limit_high] = {REG_DWORD, &cpu_state.seg_cs.limit_high, REG_INTEGER, REG_PERMANENT}, + [IREG_DS_limit_high] = {REG_DWORD, &cpu_state.seg_ds.limit_high, REG_INTEGER, REG_PERMANENT}, + [IREG_ES_limit_high] = {REG_DWORD, &cpu_state.seg_es.limit_high, REG_INTEGER, REG_PERMANENT}, + [IREG_FS_limit_high] = {REG_DWORD, &cpu_state.seg_fs.limit_high, REG_INTEGER, REG_PERMANENT}, + [IREG_GS_limit_high] = {REG_DWORD, &cpu_state.seg_gs.limit_high, REG_INTEGER, REG_PERMANENT}, + [IREG_SS_limit_high] = {REG_DWORD, &cpu_state.seg_ss.limit_high, REG_INTEGER, REG_PERMANENT}, + + /*Temporary registers are stored on the stack, and are not guaranteed to + be preserved across uOPs. They will not be written back if they will + not be read again.*/ + [IREG_temp0] = {REG_DWORD, (void *)16, REG_INTEGER, REG_VOLATILE}, + [IREG_temp1] = {REG_DWORD, (void *)20, REG_INTEGER, REG_VOLATILE}, + [IREG_temp2] = {REG_DWORD, (void *)24, REG_INTEGER, REG_VOLATILE}, + [IREG_temp3] = {REG_DWORD, (void *)28, REG_INTEGER, REG_VOLATILE}, + + [IREG_temp0d] = {REG_DOUBLE, (void *)40, REG_FP, REG_VOLATILE}, + [IREG_temp1d] = {REG_DOUBLE, (void *)48, REG_FP, REG_VOLATILE}, +}; + +void codegen_reg_mark_as_required() +{ + int reg; + + for (reg = 0; reg < IREG_COUNT; reg++) + { + int last_version = reg_last_version[reg]; + + if (last_version > 0 && ireg_data[reg].is_volatile == REG_PERMANENT) + reg_version[reg][last_version].flags |= REG_FLAGS_REQUIRED; + } +} + +int reg_is_native_size(ir_reg_t ir_reg) +{ + int native_size = ireg_data[IREG_GET_REG(ir_reg.reg)].native_size; + int requested_size = IREG_GET_SIZE(ir_reg.reg); + + switch (native_size) + { + case REG_BYTE: case REG_FPU_ST_BYTE: + return (requested_size == IREG_SIZE_B); + case REG_WORD: + return (requested_size == IREG_SIZE_W); + case REG_DWORD: + return (requested_size == IREG_SIZE_L); + case REG_QWORD: case REG_FPU_ST_QWORD: case REG_DOUBLE: case REG_FPU_ST_DOUBLE: + return ((requested_size == IREG_SIZE_D) || (requested_size == IREG_SIZE_Q)); + case REG_POINTER: + if (sizeof(void *) == 4) + return (requested_size == IREG_SIZE_L); + return (requested_size == IREG_SIZE_Q); + + default: + fatal("get_reg_is_native_size: unknown native size %i\n", native_size); + } + + return 0; +} + +void codegen_reg_reset() +{ + int c; + + host_reg_set.regs = _host_regs; + host_reg_set.dirty = _host_reg_dirty; + host_reg_set.reg_list = codegen_host_reg_list; + host_reg_set.locked = 0; + host_reg_set.nr_regs = CODEGEN_HOST_REGS; + host_fp_reg_set.regs = host_fp_regs; + host_fp_reg_set.dirty = host_fp_reg_dirty; + host_fp_reg_set.reg_list = codegen_host_fp_reg_list; + host_fp_reg_set.locked = 0; + host_fp_reg_set.nr_regs = CODEGEN_HOST_FP_REGS; + + for (c = 0; c < IREG_COUNT; c++) + { + reg_last_version[c] = 0; + reg_version[c][0].refcount = 0; + } + for (c = 0; c < CODEGEN_HOST_REGS; c++) + { + host_reg_set.regs[c] = invalid_ir_reg; + host_reg_set.dirty[c] = 0; + } + for (c = 0; c < CODEGEN_HOST_FP_REGS; c++) + { + host_fp_reg_set.regs[c] = invalid_ir_reg; + host_fp_reg_set.dirty[c] = 0; + } + + reg_dead_list = 0; + max_version_refcount = 0; +} + +static inline int ir_get_refcount(ir_reg_t ir_reg) +{ + return reg_version[IREG_GET_REG(ir_reg.reg)][ir_reg.version].refcount; +} + +static inline host_reg_set_t *get_reg_set(ir_reg_t ir_reg) +{ + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type == REG_INTEGER) + return &host_reg_set; + else + return &host_fp_reg_set; +} + +static void codegen_reg_load(host_reg_set_t *reg_set, codeblock_t *block, int c, ir_reg_t ir_reg) +{ + switch (ireg_data[IREG_GET_REG(ir_reg.reg)].native_size) + { + case REG_WORD: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_WORD !REG_INTEGER\n"); + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_16_stack(block, reg_set->reg_list[c].reg, (int)(uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else + codegen_direct_read_16(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); + break; + + case REG_DWORD: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_DWORD !REG_INTEGER\n"); + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_32_stack(block, reg_set->reg_list[c].reg, (int)(uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else + codegen_direct_read_32(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); + break; + + case REG_QWORD: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_QWORD !REG_FP\n"); + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_64_stack(block, reg_set->reg_list[c].reg, (int)(uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else + codegen_direct_read_64(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); + break; + + case REG_POINTER: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_POINTER !REG_INTEGER\n"); + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_pointer_stack(block, reg_set->reg_list[c].reg, (int)(uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else + codegen_direct_read_pointer(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); + break; + + case REG_DOUBLE: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_DOUBLE !REG_FP\n"); + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_double_stack(block, reg_set->reg_list[c].reg, (int)(uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else + codegen_direct_read_double(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); + break; + + case REG_FPU_ST_BYTE: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_FPU_ST_BYTE !REG_INTEGER\n"); + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_read_8(block, reg_set->reg_list[c].reg, &cpu_state.tag[ir_reg.reg & 7]); + else + codegen_direct_read_st_8(block, reg_set->reg_list[c].reg, &cpu_state.tag[0], ir_reg.reg & 7); + break; + + case REG_FPU_ST_QWORD: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_FPU_ST_QWORD !REG_FP\n"); + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_read_64(block, reg_set->reg_list[c].reg, &cpu_state.MM[ir_reg.reg & 7]); + else + codegen_direct_read_st_64(block, reg_set->reg_list[c].reg, &cpu_state.MM[0], ir_reg.reg & 7); + break; + + case REG_FPU_ST_DOUBLE: + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_FPU_ST_DOUBLE !REG_FP\n"); + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_read_double(block, reg_set->reg_list[c].reg, &cpu_state.ST[ir_reg.reg & 7]); + else + codegen_direct_read_st_double(block, reg_set->reg_list[c].reg, &cpu_state.ST[0], ir_reg.reg & 7); + break; + + default: fatal("codegen_reg_load - native_size=%i reg=%i\n", ireg_data[IREG_GET_REG(ir_reg.reg)].native_size, IREG_GET_REG(ir_reg.reg)); + } + + reg_set->regs[c] = ir_reg; +} + +static void codegen_reg_writeback(host_reg_set_t *reg_set, codeblock_t *block, int c, int invalidate) +{ + int ir_reg = IREG_GET_REG(reg_set->regs[c].reg); + void *p = ireg_data[ir_reg].p; + + if (!reg_version[ir_reg][reg_set->regs[c].version].refcount && + ireg_data[ir_reg].is_volatile) + return; + + switch (ireg_data[ir_reg].native_size) + { + case REG_BYTE: + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_BYTE !REG_INTEGER\n"); + if ((uintptr_t)p < 256) + fatal("codegen_reg_writeback - REG_BYTE %p\n", p); + codegen_direct_write_8(block, p, reg_set->reg_list[c].reg); + break; + + case REG_WORD: + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_WORD !REG_INTEGER\n"); + if ((uintptr_t)p < 256) + fatal("codegen_reg_writeback - REG_WORD %p\n", p); + codegen_direct_write_16(block, p, reg_set->reg_list[c].reg); + break; + + case REG_DWORD: + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_DWORD !REG_INTEGER\n"); + if ((uintptr_t)p < 256) + codegen_direct_write_32_stack(block, (int)(uintptr_t)p, reg_set->reg_list[c].reg); + else + codegen_direct_write_32(block, p, reg_set->reg_list[c].reg); + break; + + case REG_QWORD: + if (ireg_data[ir_reg].type != REG_FP) + fatal("codegen_reg_writeback - REG_QWORD !REG_FP\n"); + if ((uintptr_t)p < 256) + codegen_direct_write_64_stack(block, (int)(uintptr_t)p, reg_set->reg_list[c].reg); + else + codegen_direct_write_64(block, p, reg_set->reg_list[c].reg); + break; + + case REG_POINTER: + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_POINTER !REG_INTEGER\n"); + if ((uintptr_t)p < 256) + fatal("codegen_reg_writeback - REG_POINTER %p\n", p); + codegen_direct_write_ptr(block, p, reg_set->reg_list[c].reg); + break; + + case REG_DOUBLE: + if (ireg_data[ir_reg].type != REG_FP) + fatal("codegen_reg_writeback - REG_DOUBLE !REG_FP\n"); + if ((uintptr_t)p < 256) + codegen_direct_write_double_stack(block, (int)(uintptr_t)p, reg_set->reg_list[c].reg); + else + codegen_direct_write_double(block, p, reg_set->reg_list[c].reg); + break; + + case REG_FPU_ST_BYTE: + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_FPU_ST_BYTE !REG_INTEGER\n"); + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_write_8(block, &cpu_state.tag[reg_set->regs[c].reg & 7], reg_set->reg_list[c].reg); + else + codegen_direct_write_st_8(block, &cpu_state.tag[0], reg_set->regs[c].reg & 7, reg_set->reg_list[c].reg); + break; + + case REG_FPU_ST_QWORD: + if (ireg_data[ir_reg].type != REG_FP) + fatal("codegen_reg_writeback - REG_FPU_ST_QWORD !REG_FP\n"); + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_write_64(block, &cpu_state.MM[reg_set->regs[c].reg & 7], reg_set->reg_list[c].reg); + else + codegen_direct_write_st_64(block, &cpu_state.MM[0], reg_set->regs[c].reg & 7, reg_set->reg_list[c].reg); + break; + + case REG_FPU_ST_DOUBLE: + if (ireg_data[ir_reg].type != REG_FP) + fatal("codegen_reg_writeback - REG_FPU_ST_DOUBLE !REG_FP\n"); + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_write_double(block, &cpu_state.ST[reg_set->regs[c].reg & 7], reg_set->reg_list[c].reg); + else + codegen_direct_write_st_double(block, &cpu_state.ST[0], reg_set->regs[c].reg & 7, reg_set->reg_list[c].reg); + break; + + default: + fatal("codegen_reg_flush - native_size=%i\n", ireg_data[ir_reg].native_size); + } + + if (invalidate) + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; +} + +static void alloc_reg(ir_reg_t ir_reg) +{ + host_reg_set_t *reg_set = get_reg_set(ir_reg); + int nr_regs = (reg_set == &host_reg_set) ? CODEGEN_HOST_REGS : CODEGEN_HOST_FP_REGS; + int c; + + for (c = 0; c < nr_regs; c++) + { + if (IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg)) + { + if (reg_set->regs[c].version != ir_reg.version) + fatal("alloc_reg - host_regs[c].version != ir_reg.version %i %p %p %i %i\n", c, reg_set, &host_reg_set, reg_set->regs[c].reg, ir_reg.reg); + reg_set->locked |= (1 << c); + return; + } + } +} + +static void alloc_dest_reg(ir_reg_t ir_reg, int dest_reference) +{ + host_reg_set_t *reg_set = get_reg_set(ir_reg); + int nr_regs = (reg_set == &host_reg_set) ? CODEGEN_HOST_REGS : CODEGEN_HOST_FP_REGS; + int c; + + for (c = 0; c < nr_regs; c++) + { + if (IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg)) + { + if (reg_set->regs[c].version == ir_reg.version) + { + reg_set->locked |= (1 << c); + } + else + { + /*The immediate prior version may have been + optimised out, so search backwards to find the + last valid version*/ + int prev_version = ir_reg.version-1; + while (prev_version >= 0) + { + reg_version_t *regv = ®_version[IREG_GET_REG(reg_set->regs[c].reg)][prev_version]; + + if (!(regv->flags & REG_FLAGS_DEAD) && regv->refcount == dest_reference) + { + reg_set->locked |= (1 << c); + return; + } + prev_version--; + } + fatal("codegen_reg_alloc_register - host_regs[c].version != dest_reg_a.version %i,%i %i\n", reg_set->regs[c].version, ir_reg.version, dest_reference); + } + return; + } + } +} + +void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b, ir_reg_t src_reg_c) +{ + int dest_reference = 0; + + host_reg_set.locked = 0; + host_fp_reg_set.locked = 0; + + if (!ir_reg_is_invalid(dest_reg_a)) + { + if (!ir_reg_is_invalid(src_reg_a) && IREG_GET_REG(src_reg_a.reg) == IREG_GET_REG(dest_reg_a.reg) && src_reg_a.version == dest_reg_a.version-1) + dest_reference++; + if (!ir_reg_is_invalid(src_reg_b) && IREG_GET_REG(src_reg_b.reg) == IREG_GET_REG(dest_reg_a.reg) && src_reg_b.version == dest_reg_a.version-1) + dest_reference++; + if (!ir_reg_is_invalid(src_reg_c) && IREG_GET_REG(src_reg_c.reg) == IREG_GET_REG(dest_reg_a.reg) && src_reg_c.version == dest_reg_a.version-1) + dest_reference++; + } + if (!ir_reg_is_invalid(src_reg_a)) + alloc_reg(src_reg_a); + if (!ir_reg_is_invalid(src_reg_b)) + alloc_reg(src_reg_b); + if (!ir_reg_is_invalid(src_reg_c)) + alloc_reg(src_reg_c); + if (!ir_reg_is_invalid(dest_reg_a)) + alloc_dest_reg(dest_reg_a, dest_reference); +} + +ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, int *host_reg_idx) +{ + host_reg_set_t *reg_set = get_reg_set(ir_reg); + int c; + + /*Search for required register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_set->regs[c].version == ir_reg.version) + break; + + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_set->regs[c].version <= ir_reg.version) + { + reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount++; + break; + } + + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount) + fatal("codegen_reg_alloc_read_reg - version mismatch!\n"); + } + + if (c == reg_set->nr_regs) + { + /*No unused registers. Search for an unlocked register with no pending reads*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!(reg_set->locked & (1 << c)) && IREG_GET_REG(reg_set->regs[c].reg) != IREG_INVALID && !ir_get_refcount(reg_set->regs[c])) + break; + } + if (c == reg_set->nr_regs) + { + /*Search for any unlocked register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!(reg_set->locked & (1 << c))) + break; + } + if (c == reg_set->nr_regs) + fatal("codegen_reg_alloc_read_reg - out of registers\n"); + } + if (reg_set->dirty[c]) + codegen_reg_writeback(reg_set, block, c, 1); + codegen_reg_load(reg_set, block, c, ir_reg); + reg_set->locked |= (1 << c); + reg_set->dirty[c] = 0; + } + + reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount--; + if (reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount == (uint8_t)-1) + fatal("codegen_reg_alloc_read_reg - refcount < 0\n"); + + if (host_reg_idx) + *host_reg_idx = c; + return reg_set->reg_list[c].reg | IREG_GET_SIZE(ir_reg.reg); +} + +ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) +{ + host_reg_set_t *reg_set = get_reg_set(ir_reg); + int c; + + if (!reg_is_native_size(ir_reg)) + { + /*Read in parent register so we can do partial accesses to it*/ + ir_reg_t parent_reg; + + parent_reg.reg = IREG_GET_REG(ir_reg.reg) | IREG_SIZE_L; + parent_reg.version = ir_reg.version - 1; + reg_version[IREG_GET_REG(ir_reg.reg)][ir_reg.version - 1].refcount++; + + codegen_reg_alloc_read_reg(block, parent_reg, &c); + + if (IREG_GET_REG(reg_set->regs[c].reg) != IREG_GET_REG(ir_reg.reg) || reg_set->regs[c].version > ir_reg.version-1) + fatal("codegen_reg_alloc_write_reg sub_reg - doesn't match %i %02x.%i %02x.%i\n", c, + reg_set->regs[c].reg,reg_set->regs[c].version, + ir_reg.reg,ir_reg.version); + + reg_set->regs[c].reg = ir_reg.reg; + reg_set->regs[c].version = ir_reg.version; + reg_set->dirty[c] = 1; + return reg_set->reg_list[c].reg | IREG_GET_SIZE(ir_reg.reg); + } + + /*Search for previous version in host register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg)) + { + if (reg_set->regs[c].version <= ir_reg.version-1) + { + if (reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount != 0) + fatal("codegen_reg_alloc_write_reg - previous version refcount != 0\n"); + break; + } + } + } + + if (c == reg_set->nr_regs) + { + /*Search for unused registers*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (ir_reg_is_invalid(reg_set->regs[c])) + break; + } + + if (c == reg_set->nr_regs) + { + /*No unused registers. Search for an unlocked register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!(reg_set->locked & (1 << c))) + break; + } + if (c == reg_set->nr_regs) + fatal("codegen_reg_alloc_write_reg - out of registers\n"); + if (reg_set->dirty[c]) + codegen_reg_writeback(reg_set, block, c, 1); + } + } + + reg_set->regs[c].reg = ir_reg.reg; + reg_set->regs[c].version = ir_reg.version; + reg_set->dirty[c] = 1; + return reg_set->reg_list[c].reg | IREG_GET_SIZE(ir_reg.reg); +} + +void codegen_reg_flush(ir_data_t *ir, codeblock_t *block) +{ + host_reg_set_t *reg_set; + int c; + + reg_set = &host_reg_set; + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && reg_set->dirty[c]) + { + codegen_reg_writeback(reg_set, block, c, 0); + } + if (reg_set->reg_list[c].flags & HOST_REG_FLAG_VOLATILE) + { + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; + } + } + + reg_set = &host_fp_reg_set; + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && reg_set->dirty[c]) + { + codegen_reg_writeback(reg_set, block, c, 0); + } + if (reg_set->reg_list[c].flags & HOST_REG_FLAG_VOLATILE) + { + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; + } + } +} + +void codegen_reg_flush_invalidate(ir_data_t *ir, codeblock_t *block) +{ + host_reg_set_t *reg_set; + int c; + + reg_set = &host_reg_set; + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && reg_set->dirty[c]) + { + codegen_reg_writeback(reg_set, block, c, 1); + } + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; + } + + reg_set = &host_fp_reg_set; + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && reg_set->dirty[c]) + { + codegen_reg_writeback(reg_set, block, c, 1); + } + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; + } +} + +/*Process dead register list, and optimise out register versions and uOPs where + possible*/ +void codegen_reg_process_dead_list(ir_data_t *ir) +{ + while (reg_dead_list) + { + int version = reg_dead_list & 0xff; + int reg = reg_dead_list >> 8; + reg_version_t *regv = ®_version[reg][version]; + uop_t *uop = &ir->uops[regv->parent_uop]; + + /*Barrier uOPs should be preserved*/ + if (!(uop->type & (UOP_TYPE_BARRIER | UOP_TYPE_ORDER_BARRIER))) + { + uop->type = UOP_INVALID; + /*Adjust refcounts on source registers. If these drop to + zero then those registers can be considered for removal*/ + if (uop->src_reg_a.reg != IREG_INVALID) + { + reg_version_t *src_regv = ®_version[IREG_GET_REG(uop->src_reg_a.reg)][uop->src_reg_a.version]; + src_regv->refcount--; + if (!src_regv->refcount) + add_to_dead_list(src_regv, IREG_GET_REG(uop->src_reg_a.reg), uop->src_reg_a.version); + } + if (uop->src_reg_b.reg != IREG_INVALID) + { + reg_version_t *src_regv = ®_version[IREG_GET_REG(uop->src_reg_b.reg)][uop->src_reg_b.version]; + src_regv->refcount--; + if (!src_regv->refcount) + add_to_dead_list(src_regv, IREG_GET_REG(uop->src_reg_b.reg), uop->src_reg_b.version); + } + if (uop->src_reg_c.reg != IREG_INVALID) + { + reg_version_t *src_regv = ®_version[IREG_GET_REG(uop->src_reg_c.reg)][uop->src_reg_c.version]; + src_regv->refcount--; + if (!src_regv->refcount) + add_to_dead_list(src_regv, IREG_GET_REG(uop->src_reg_c.reg), uop->src_reg_c.version); + } + regv->flags |= REG_FLAGS_DEAD; + } + + reg_dead_list = regv->next; + } +} diff --git a/src/cpu_new/codegen_reg.h b/src/cpu_new/codegen_reg.h new file mode 100644 index 000000000..85bb9f142 --- /dev/null +++ b/src/cpu_new/codegen_reg.h @@ -0,0 +1,402 @@ +#ifndef _CODEGEN_REG_H_ +#define _CODEGEN_REG_H_ + +#define IREG_REG_MASK 0xff +#define IREG_SIZE_SHIFT 8 +#define IREG_SIZE_MASK (7 << IREG_SIZE_SHIFT) + +#define IREG_GET_REG(reg) ((reg) & IREG_REG_MASK) +#define IREG_GET_SIZE(reg) ((reg) & IREG_SIZE_MASK) + +#define IREG_SIZE_L (0 << IREG_SIZE_SHIFT) +#define IREG_SIZE_W (1 << IREG_SIZE_SHIFT) +#define IREG_SIZE_B (2 << IREG_SIZE_SHIFT) +#define IREG_SIZE_BH (3 << IREG_SIZE_SHIFT) +#define IREG_SIZE_D (4 << IREG_SIZE_SHIFT) +#define IREG_SIZE_Q (5 << IREG_SIZE_SHIFT) + +enum +{ + IREG_EAX = 0, + IREG_ECX = 1, + IREG_EDX = 2, + IREG_EBX = 3, + IREG_ESP = 4, + IREG_EBP = 5, + IREG_ESI = 6, + IREG_EDI = 7, + + IREG_flags_op = 8, + IREG_flags_res = 9, + IREG_flags_op1 = 10, + IREG_flags_op2 = 11, + + IREG_pc = 12, + IREG_oldpc = 13, + + IREG_eaaddr = 14, + IREG_ea_seg = 15, + IREG_op32 = 16, + IREG_ssegsx = 17, + + IREG_rm_mod_reg = 18, + + IREG_ins = 19, + IREG_cycles = 20, + + IREG_CS_base = 21, + IREG_DS_base = 22, + IREG_ES_base = 23, + IREG_FS_base = 24, + IREG_GS_base = 25, + IREG_SS_base = 26, + + IREG_CS_seg = 27, + IREG_DS_seg = 28, + IREG_ES_seg = 29, + IREG_FS_seg = 30, + IREG_GS_seg = 31, + IREG_SS_seg = 32, + + /*Temporary registers are stored on the stack, and are not guaranteed to + be preserved across uOPs. They will not be written back if they will + not be read again.*/ + IREG_temp0 = 33, + IREG_temp1 = 34, + IREG_temp2 = 35, + IREG_temp3 = 36, + + IREG_FPU_TOP = 37, + + IREG_temp0d = 38, + IREG_temp1d = 39, + + /*FPU stack registers are physical registers. Use IREG_ST() / IREG_tag() + to access. + When CODEBLOCK_STATIC_TOP is set, the physical register number will be + used directly to index the stack. When it is clear, the difference + between the current value of TOP and the value when the block was + first compiled will be added to adjust for any changes in TOP.*/ + IREG_ST0 = 40, + IREG_ST1 = 41, + IREG_ST2 = 42, + IREG_ST3 = 43, + IREG_ST4 = 44, + IREG_ST5 = 45, + IREG_ST6 = 46, + IREG_ST7 = 47, + + IREG_tag0 = 48, + IREG_tag1 = 49, + IREG_tag2 = 50, + IREG_tag3 = 51, + IREG_tag4 = 52, + IREG_tag5 = 53, + IREG_tag6 = 54, + IREG_tag7 = 55, + + IREG_ST0_i64 = 56, + IREG_ST1_i64 = 57, + IREG_ST2_i64 = 58, + IREG_ST3_i64 = 59, + IREG_ST4_i64 = 60, + IREG_ST5_i64 = 61, + IREG_ST6_i64 = 62, + IREG_ST7_i64 = 63, + + IREG_MM0x = 64, + IREG_MM1x = 65, + IREG_MM2x = 66, + IREG_MM3x = 67, + IREG_MM4x = 68, + IREG_MM5x = 69, + IREG_MM6x = 70, + IREG_MM7x = 71, + + IREG_NPXCx = 72, + IREG_NPXSx = 73, + + IREG_flagsx = 74, + IREG_eflagsx = 75, + + IREG_CS_limit_low = 76, + IREG_DS_limit_low = 77, + IREG_ES_limit_low = 78, + IREG_FS_limit_low = 79, + IREG_GS_limit_low = 80, + IREG_SS_limit_low = 81, + + IREG_CS_limit_high = 82, + IREG_DS_limit_high = 83, + IREG_ES_limit_high = 84, + IREG_FS_limit_high = 85, + IREG_GS_limit_high = 86, + IREG_SS_limit_high = 87, + + IREG_COUNT = 88, + + IREG_INVALID = 255, + + IREG_AX = IREG_EAX + IREG_SIZE_W, + IREG_CX = IREG_ECX + IREG_SIZE_W, + IREG_DX = IREG_EDX + IREG_SIZE_W, + IREG_BX = IREG_EBX + IREG_SIZE_W, + IREG_SP = IREG_ESP + IREG_SIZE_W, + IREG_BP = IREG_EBP + IREG_SIZE_W, + IREG_SI = IREG_ESI + IREG_SIZE_W, + IREG_DI = IREG_EDI + IREG_SIZE_W, + + IREG_AL = IREG_EAX + IREG_SIZE_B, + IREG_CL = IREG_ECX + IREG_SIZE_B, + IREG_DL = IREG_EDX + IREG_SIZE_B, + IREG_BL = IREG_EBX + IREG_SIZE_B, + + IREG_AH = IREG_EAX + IREG_SIZE_BH, + IREG_CH = IREG_ECX + IREG_SIZE_BH, + IREG_DH = IREG_EDX + IREG_SIZE_BH, + IREG_BH = IREG_EBX + IREG_SIZE_BH, + + IREG_flags_res_W = IREG_flags_res + IREG_SIZE_W, + IREG_flags_op1_W = IREG_flags_op1 + IREG_SIZE_W, + IREG_flags_op2_W = IREG_flags_op2 + IREG_SIZE_W, + + IREG_flags_res_B = IREG_flags_res + IREG_SIZE_B, + IREG_flags_op1_B = IREG_flags_op1 + IREG_SIZE_B, + IREG_flags_op2_B = IREG_flags_op2 + IREG_SIZE_B, + + IREG_temp0_W = IREG_temp0 + IREG_SIZE_W, + IREG_temp1_W = IREG_temp1 + IREG_SIZE_W, + IREG_temp2_W = IREG_temp2 + IREG_SIZE_W, + IREG_temp3_W = IREG_temp3 + IREG_SIZE_W, + + IREG_temp0_B = IREG_temp0 + IREG_SIZE_B, + IREG_temp1_B = IREG_temp1 + IREG_SIZE_B, + IREG_temp2_B = IREG_temp2 + IREG_SIZE_B, + IREG_temp3_B = IREG_temp3 + IREG_SIZE_B, + + IREG_temp0_D = IREG_temp0d + IREG_SIZE_D, + IREG_temp1_D = IREG_temp1d + IREG_SIZE_D, + + IREG_temp0_Q = IREG_temp0d + IREG_SIZE_Q, + IREG_temp1_Q = IREG_temp1d + IREG_SIZE_Q, + + IREG_eaaddr_W = IREG_eaaddr + IREG_SIZE_W, + + IREG_CS_seg_W = IREG_CS_seg + IREG_SIZE_W, + IREG_DS_seg_W = IREG_DS_seg + IREG_SIZE_W, + IREG_ES_seg_W = IREG_ES_seg + IREG_SIZE_W, + IREG_FS_seg_W = IREG_FS_seg + IREG_SIZE_W, + IREG_GS_seg_W = IREG_GS_seg + IREG_SIZE_W, + IREG_SS_seg_W = IREG_SS_seg + IREG_SIZE_W, + + IREG_MM0 = IREG_MM0x + IREG_SIZE_Q, + IREG_MM1 = IREG_MM1x + IREG_SIZE_Q, + IREG_MM2 = IREG_MM2x + IREG_SIZE_Q, + IREG_MM3 = IREG_MM3x + IREG_SIZE_Q, + IREG_MM4 = IREG_MM4x + IREG_SIZE_Q, + IREG_MM5 = IREG_MM5x + IREG_SIZE_Q, + IREG_MM6 = IREG_MM6x + IREG_SIZE_Q, + IREG_MM7 = IREG_MM7x + IREG_SIZE_Q, + + IREG_NPXC = IREG_NPXCx + IREG_SIZE_W, + IREG_NPXS = IREG_NPXSx + IREG_SIZE_W, + + IREG_ssegs = IREG_ssegsx + IREG_SIZE_B, + + IREG_flags = IREG_flagsx + IREG_SIZE_W, + IREG_eflags = IREG_eflagsx + IREG_SIZE_W +}; + +#define IREG_8(reg) (((reg) & 4) ? (((reg) & 3) + IREG_AH) : ((reg) + IREG_AL)) +#define IREG_16(reg) ((reg) + IREG_AX) +#define IREG_32(reg) ((reg) + IREG_EAX) + +#define IREG_ST(r) (IREG_ST0 + ((cpu_state.TOP + (r)) & 7) + IREG_SIZE_D) +#define IREG_ST_i64(r) (IREG_ST0_i64 + ((cpu_state.TOP + (r)) & 7) + IREG_SIZE_Q) +#define IREG_tag(r) (IREG_tag0 + ((cpu_state.TOP + (r)) & 7)) +#define IREG_tag_B(r) (IREG_tag0 + ((cpu_state.TOP + (r)) & 7) + IREG_SIZE_B) + +#define IREG_MM(reg) ((reg) + IREG_MM0) + +#define IREG_TOP_diff_stack_offset 32 + +static inline int ireg_seg_base(x86seg *seg) +{ + if (seg == &cpu_state.seg_cs) + return IREG_CS_base; + if (seg == &cpu_state.seg_ds) + return IREG_DS_base; + if (seg == &cpu_state.seg_es) + return IREG_ES_base; + if (seg == &cpu_state.seg_fs) + return IREG_FS_base; + if (seg == &cpu_state.seg_gs) + return IREG_GS_base; + if (seg == &cpu_state.seg_ss) + return IREG_SS_base; + fatal("ireg_seg_base : unknown segment\n"); + return 0; +} + +static inline int ireg_seg_limit_low(x86seg *seg) +{ + if (seg == &cpu_state.seg_cs) + return IREG_CS_limit_low; + if (seg == &cpu_state.seg_ds) + return IREG_DS_limit_low; + if (seg == &cpu_state.seg_es) + return IREG_ES_limit_low; + if (seg == &cpu_state.seg_fs) + return IREG_FS_limit_low; + if (seg == &cpu_state.seg_gs) + return IREG_GS_limit_low; + if (seg == &cpu_state.seg_ss) + return IREG_SS_limit_low; + fatal("ireg_seg_limit_low : unknown segment\n"); + return 0; +} +static inline int ireg_seg_limit_high(x86seg *seg) +{ + if (seg == &cpu_state.seg_cs) + return IREG_CS_limit_high; + if (seg == &cpu_state.seg_ds) + return IREG_DS_limit_high; + if (seg == &cpu_state.seg_es) + return IREG_ES_limit_high; + if (seg == &cpu_state.seg_fs) + return IREG_FS_limit_high; + if (seg == &cpu_state.seg_gs) + return IREG_GS_limit_high; + if (seg == &cpu_state.seg_ss) + return IREG_SS_limit_high; + fatal("ireg_seg_limit_high : unknown segment\n"); + return 0; +} + +extern uint8_t reg_last_version[IREG_COUNT]; + +/*This version of the register must be calculated, regardless of whether it is + apparently required or not. Do not optimise out.*/ +#define REG_FLAGS_REQUIRED (1 << 0) +/*This register and the parent uOP have been optimised out.*/ +#define REG_FLAGS_DEAD (1 << 1) + +typedef struct +{ + /*Refcount of pending reads on this register version*/ + uint8_t refcount; + /*Flags*/ + uint8_t flags; + /*uOP that generated this register version*/ + uint16_t parent_uop; + /*Pointer to next register version in dead register list*/ + uint16_t next; +} reg_version_t; + +extern reg_version_t reg_version[IREG_COUNT][256]; + +/*Head of dead register list; a list of register versions that are not used and + can be optimised out*/ +extern uint16_t reg_dead_list; + +static inline void add_to_dead_list(reg_version_t *regv, int reg, int version) +{ + regv->next = reg_dead_list; + reg_dead_list = version | (reg << 8); +} + +typedef struct +{ + uint16_t reg; + uint16_t version; +} ir_reg_t; + +extern ir_reg_t invalid_ir_reg; + +typedef uint16_t ir_host_reg_t; + +extern int max_version_refcount; + +#define REG_VERSION_MAX 250 +#define REG_REFCOUNT_MAX 250 + +static inline ir_reg_t codegen_reg_read(int reg) +{ + ir_reg_t ireg; + reg_version_t *version; + + if (IREG_GET_REG(reg) == IREG_INVALID) + fatal("codegen_reg_read - IREG_INVALID\n"); + + ireg.reg = reg; + ireg.version = reg_last_version[IREG_GET_REG(reg)]; + version = ®_version[IREG_GET_REG(ireg.reg)][ireg.version]; + version->flags = 0; + version->refcount++; + if (!version->refcount) + fatal("codegen_reg_read - refcount overflow\n"); + else if (version->refcount > REG_REFCOUNT_MAX) + CPU_BLOCK_END(); + if (version->refcount > max_version_refcount) + max_version_refcount = version->refcount; + return ireg; +} + +int reg_is_native_size(ir_reg_t ir_reg); + +static inline ir_reg_t codegen_reg_write(int reg, int uop_nr) +{ + ir_reg_t ireg; + int last_version = reg_last_version[IREG_GET_REG(reg)]; + reg_version_t *version; + + if (IREG_GET_REG(reg) == IREG_INVALID) + fatal("codegen_reg_write - IREG_INVALID\n"); + + ireg.reg = reg; + ireg.version = last_version + 1; + + if (IREG_GET_REG(reg) > IREG_EBX && last_version && !reg_version[IREG_GET_REG(reg)][last_version].refcount && + !(reg_version[IREG_GET_REG(reg)][last_version].flags & REG_FLAGS_REQUIRED)) + { + if (reg_is_native_size(ireg)) /*Non-native size registers have an implicit dependency on the previous version, so don't add to dead list*/ + add_to_dead_list(®_version[IREG_GET_REG(reg)][last_version], IREG_GET_REG(reg), last_version); + } + + reg_last_version[IREG_GET_REG(reg)]++; + if (!reg_last_version[IREG_GET_REG(reg)]) + fatal("codegen_reg_write - version overflow\n"); + else if (reg_last_version[IREG_GET_REG(reg)] > REG_VERSION_MAX) + CPU_BLOCK_END(); + if (reg_last_version[IREG_GET_REG(reg)] > max_version_refcount) + max_version_refcount = reg_last_version[IREG_GET_REG(reg)]; + + version = ®_version[IREG_GET_REG(reg)][ireg.version]; + version->refcount = 0; + version->flags = 0; + version->parent_uop = uop_nr; + return ireg; +} + +static inline int ir_reg_is_invalid(ir_reg_t ir_reg) +{ + return (IREG_GET_REG(ir_reg.reg) == IREG_INVALID); +} + +struct ir_data_t; + +void codegen_reg_reset(); +/*Write back all dirty registers*/ +void codegen_reg_flush(struct ir_data_t *ir, codeblock_t *block); +/*Write back and evict all registers*/ +void codegen_reg_flush_invalidate(struct ir_data_t *ir, codeblock_t *block); + +/*Register ir_reg usage for this uOP. This ensures that required registers aren't evicted*/ +void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b, ir_reg_t src_reg_c); + +ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, int *host_reg_idx); +ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg); + +void codegen_reg_mark_as_required(); +void codegen_reg_process_dead_list(struct ir_data_t *ir); +#endif diff --git a/src/cpu_new/codegen_timing_486.c b/src/cpu_new/codegen_timing_486.c new file mode 100644 index 000000000..6b744472b --- /dev/null +++ b/src/cpu_new/codegen_timing_486.c @@ -0,0 +1,424 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + +#define CYCLES(c) (int *)c +#define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8)) + +static int *opcode_timings[256] = +{ +/*00*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm, &timing_rm, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(5), CYCLES(6), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_mod3[256] = +{ +/*00*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(2), CYCLES(1), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, +/*70*/ NULL, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rm, &timing_rm, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*e0*/ NULL, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*f0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, +}; +static int *opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, +/*70*/ NULL, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rr, &timing_rr, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*e0*/ NULL, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*f0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, +}; + +static int *opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static int *opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static int *opcode_timings_f6[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f6_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f7[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_f7_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_ff[8] = +{ + &timing_mm, &timing_mm, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; +static int *opcode_timings_ff_mod3[8] = +{ + &timing_rr, &timing_rr, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; + +static int *opcode_timings_d8[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP FSUB FSUBR FDIV FDIVR*/ + CYCLES(8), CYCLES(16), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs FLDENV FLDCW FSTENV FSTCW*/ + CYCLES(3), NULL, CYCLES(7), CYCLES(7), CYCLES(34), CYCLES(4), CYCLES(67), CYCLES(3) +}; +static int *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FXCH*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FNOP*/ + CYCLES(3), NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /*FSTP*/ + CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/* opFCHS opFABS opFTST opFXAM*/ + CYCLES(6), CYCLES(3), NULL, NULL, CYCLES(4), CYCLES(8), NULL, NULL, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI opFLDEG2 opFLDLN2 opFLDZ*/ + CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(4), NULL, +/* opF2XM1 opFYL2X opFPTAN opFPATAN opFDECSTP opFINCSTP,*/ + CYCLES(140), CYCLES(196), CYCLES(200), CYCLES(218), NULL, NULL, CYCLES(3), CYCLES(3), +/* opFPREM opFSQRT opFSINCOS opFRNDINT opFSCALE opFSIN opFCOS*/ + CYCLES(70), NULL, CYCLES(83), CYCLES(292), CYCLES(21), CYCLES(30), CYCLES(257), CYCLES(257) +}; + +static int *opcode_timings_da[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_da_mod3[8] = +{ + NULL, NULL, NULL, NULL, NULL, CYCLES(5), NULL, NULL +}; + + +static int *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil FLDe FSTPe*/ + CYCLES(9), NULL, CYCLES(28), CYCLES(28), NULL, CYCLES(5), NULL, CYCLES(6) +}; +static int *opcode_timings_db_mod3[64] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* opFNOP opFCLEX opFINIT opFNOP opFNOP*/ + NULL, CYCLES(3), CYCLES(7), CYCLES(17), CYCLES(3), CYCLES(3), NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static int *opcode_timings_dc[8] = +{ +/* opFADDd_a16 opFMULd_a16 opFCOMd_a16 opFCOMPd_a16 opFSUBd_a16 opFSUBRd_a16 opFDIVd_a16 opFDIVRd_a16*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + CYCLES(8), CYCLES(16), NULL, NULL, CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd FRSTOR FSAVE FSTSW*/ + CYCLES(3), NULL, CYCLES(8), CYCLES(8), CYCLES(131), NULL, CYCLES(154), CYCLES(3) +}; +static int *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), NULL, NULL +}; + +static int *opcode_timings_de[8] = +{ +/* FADDiw FMULiw FCOMiw FCOMPiw FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP FSUB FSUBR FDIV FDIVR*/ + CYCLES(8), CYCLES(16), NULL, CYCLES(5), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw FILDiq FBSTP FISTPiq*/ + CYCLES(13), NULL, CYCLES(29), CYCLES(29), NULL, CYCLES(10), CYCLES(172), CYCLES(28) +}; +static int *opcode_timings_df_mod3[8] = +{ +/* FFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), NULL, NULL +}; + +static int *opcode_timings_8x[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_8x_mod3[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_81[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_81_mod3[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; + +static int timing_count; +static uint8_t last_prefix; +static uint32_t regmask_modified; + +static inline int COUNT(int *c, int op_32) +{ + if ((uintptr_t)c <= 10000) + return (int)(uintptr_t)c; + if (((uintptr_t)c & ~0xffff) == (-1 & ~0xffff)) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + return *c; +} + +void codegen_timing_486_block_start() +{ + regmask_modified = 0; +} + +void codegen_timing_486_start() +{ + timing_count = 0; + last_prefix = 0; +} + +void codegen_timing_486_prefix(uint8_t prefix, uint32_t fetchdat) +{ + timing_count += COUNT(opcode_timings[prefix], 0); + last_prefix = prefix; +} + +void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +{ + int **timings; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + break; + } + } + + timing_count += COUNT(timings[opcode], op_32); + if (regmask_modified & get_addr_regmask(deps[opcode], fetchdat, op_32)) + timing_count++; /*AGI stall*/ + codegen_block_cycles += timing_count; + + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); +} + +void codegen_timing_486_block_end() +{ +} + +int codegen_timing_486_jump_cycles() +{ + return 0; +} + +codegen_timing_t codegen_timing_486 = +{ + codegen_timing_486_start, + codegen_timing_486_prefix, + codegen_timing_486_opcode, + codegen_timing_486_block_start, + codegen_timing_486_block_end, + codegen_timing_486_jump_cycles +}; diff --git a/src/cpu_new/codegen_timing_686.c b/src/cpu_new/codegen_timing_686.c new file mode 100644 index 000000000..6bcb7c44d --- /dev/null +++ b/src/cpu_new/codegen_timing_686.c @@ -0,0 +1,1061 @@ +/*Elements taken into account : + - X/Y pairing + - FPU/FXCH pairing + - Prefix decode delay + - AGI stalls + Elements not taken into account : + - Branch prediction (beyond most simplistic approximation) + - FPU queue + - Out of order execution (beyond most simplistic approximation) +*/ + +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_timing_common.h" + +/*Instruction has different execution time for 16 and 32 bit data. Does not pair */ +#define CYCLES_HAS_MULTI (1 << 31) + +#define CYCLES_MULTI(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*Instruction lasts given number of cycles. Does not pair*/ +#define CYCLES(c) (c) + +/*Instruction follows either register timing, read-modify, or read-modify-write. + May be pairable*/ +#define CYCLES_REG (1 << 0) +#define CYCLES_RM (1 << 0) +#define CYCLES_RMW (1 << 0) +#define CYCLES_BRANCH (1 << 0) + +#define CYCLES_MASK ((1 << 7) - 1) + +/*Instruction does not pair*/ +#define PAIR_NP (0 << 29) +/*Instruction pairs in X pipe only*/ +#define PAIR_X (1 << 29) +/*Instruction pairs in X pipe only, and can not pair with a following instruction*/ +#define PAIR_X_BRANCH (2 << 29) +/*Instruction pairs in both X and Y pipes*/ +#define PAIR_XY (3 << 29) + +#define PAIR_MASK (3 << 29) + +#define INVALID 0 + +static int prev_full; +static uint32_t prev_opcode; +static uint32_t *prev_timings; +static uint32_t prev_op_32; +static uint32_t prev_regmask; +static uint64_t *prev_deps; +static uint32_t prev_fetchdat; + +static uint32_t last_regmask_modified; +static uint32_t regmask_modified; + +static uint32_t opcode_timings[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* ADD ADD PUSH ES POP ES*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* OR OR PUSH CS */ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* ADC ADC PUSH SS POP SS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* SBB SBB PUSH DS POP DS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* AND AND DAA*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), +/* SUB SUB SUB SUB*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* SUB SUB DAS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* XOR XOR AAA*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), +/* CMP CMP CMP CMP*/ + PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* CMP CMP AAS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(9), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* Jxx*/ +/*70*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* MOV MOV MOV MOV*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES_REG, CYCLES(3), PAIR_XY | CYCLES(1), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), +/* PUSHF POPF SAHF LAHF*/ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(9), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV*/ +/*b0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_X_BRANCH | CYCLES(3), PAIR_X_BRANCH | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_XY | CYCLES(10), PAIR_XY | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(16), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(10), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_XY | CYCLES(18), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), +/* CALL JMP JMP JMP*/ + PAIR_X_BRANCH | CYCLES_REG, PAIR_X_BRANCH | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_X_BRANCH | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(5), PAIR_XY | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES_RMW, INVALID +}; + +static uint32_t opcode_timings_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* OR OR PUSH CS */ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* AND AND DAA*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), +/* SUB SUB SUB SUB*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* SUB SUB DAS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* XOR XOR AAA*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), +/* CMP CMP CMP CMP*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* CMP CMP AAS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(9), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(10), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* Jxx*/ +/*70*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*80*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* TEST TEST XCHG XCHG*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* MOV MOV MOV MOV*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_XY | CYCLES(1), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), +/* PUSHF POPF SAHF LAHF*/ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(9), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV*/ +/*b0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_X_BRANCH | CYCLES(3), PAIR_X_BRANCH | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_XY | CYCLES(13), PAIR_XY | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(16), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(10), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_XY | CYCLES(18), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), +/* CALL JMP JMP JMP*/ + PAIR_X_BRANCH | CYCLES_REG, PAIR_X_BRANCH | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_X_BRANCH | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES_REG, INVALID +}; + +static uint32_t opcode_timings_0f[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + INVALID, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + +/*70*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES(1), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + +/*80*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*90*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*a0*/ PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(12), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(5), INVALID, INVALID, + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, + +/*c0*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), + +/*d0*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + +/*e0*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, + INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + +/*f0*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, +}; +static uint32_t opcode_timings_0f_mod3[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + INVALID, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + +/*70*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES(1), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + +/*80*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*90*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*a0*/ PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(12), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(5), INVALID, INVALID, + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + INVALID, PAIR_X | CYCLES_REG, INVALID, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + +/*e0*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, + INVALID, PAIR_X | CYCLES_REG, INVALID, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + +/*f0*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + INVALID, PAIR_X | CYCLES_REG, INVALID, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, +}; + +static uint32_t opcode_timings_shift[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, +}; +static uint32_t opcode_timings_shift_mod3[8] = +{ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +}; +static uint32_t opcode_timings_shift_imm[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES(8), PAIR_XY | CYCLES(9), + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, +}; +static uint32_t opcode_timings_shift_imm_mod3[8] = +{ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +}; +static uint32_t opcode_timings_shift_cl[8] = +{ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(8), PAIR_XY | CYCLES(9), + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +}; +static uint32_t opcode_timings_shift_cl_mod3[8] = +{ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(8), PAIR_XY | CYCLES(9), + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +}; + +static uint32_t opcode_timings_f6[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_RM, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(18) +}; +static uint32_t opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(18) +}; +static uint32_t opcode_timings_f7[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(19,27), PAIR_NP | CYCLES_MULTI(22,30) +}; +static uint32_t opcode_timings_f7_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(19,27), PAIR_NP | CYCLES_MULTI(22,30) +}; +static uint32_t opcode_timings_ff[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), +/* JMP JMP far PUSH*/ + PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), PAIR_XY | CYCLES(1), INVALID +}; +static uint32_t opcode_timings_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_X_BRANCH | CYCLES(1), PAIR_XY | CYCLES(5), +/* JMP JMP far PUSH*/ + PAIR_X_BRANCH | CYCLES(1), PAIR_XY | CYCLES(5), PAIR_XY | CYCLES(2), INVALID +}; + +static uint32_t opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(6), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; +static uint32_t opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(6), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FLDENV FLDCW FSTENV FSTCW*/ + PAIR_X | CYCLES(30), PAIR_X | CYCLES(4), PAIR_X | CYCLES(24), PAIR_X | CYCLES(5) +}; +static uint32_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + /*FXCH*/ + PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), + PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), + /*FNOP*/ + PAIR_X | CYCLES(2), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* opFCHS opFABS*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), INVALID, INVALID, +/* opFTST opFXAM (oddly low) */ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + PAIR_X | CYCLES(92), PAIR_X | CYCLES(170), PAIR_X | CYCLES(129), PAIR_X | CYCLES(161), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, PAIR_X | CYCLES(4), PAIR_X | CYCLES(2), +/* opFPREM opFSQRT opFSINCOS*/ + PAIR_X | CYCLES(91), INVALID, PAIR_X | CYCLES(60), PAIR_X | CYCLES(161), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + PAIR_X | CYCLES(20), PAIR_X | CYCLES(14), PAIR_X | CYCLES(140), PAIR_X | CYCLES(141) +}; + +static uint32_t opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + PAIR_X | CYCLES(12), PAIR_X | CYCLES(11), PAIR_X | CYCLES(10), PAIR_X | CYCLES(10), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + PAIR_X | CYCLES(29), PAIR_X | CYCLES(27), PAIR_X | CYCLES(38), PAIR_X | CYCLES(48) +}; +static uint32_t opcode_timings_da_mod3[8] = +{ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + INVALID, PAIR_X | CYCLES(5), INVALID, INVALID +}; + + +static uint32_t opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FLDe FSTPe*/ + INVALID, PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2) +}; +static uint32_t opcode_timings_db_mod3[64] = +{ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + +/* opFNOP opFCLEX opFINIT*/ + INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(5), PAIR_X | CYCLES(8), +/* opFNOP opFNOP*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +}; + +static uint32_t opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; +static uint32_t opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FRSTOR FSAVE FSTSW*/ + PAIR_X | CYCLES(72), INVALID, PAIR_X | CYCLES(67), PAIR_X | CYCLES(2) +}; +static uint32_t opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + PAIR_X | CYCLES(3), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FUCOM FUCOMP*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, INVALID +}; + +static uint32_t opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + PAIR_X | CYCLES(12), PAIR_X | CYCLES(11), PAIR_X | CYCLES(10), PAIR_X | CYCLES(10), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + PAIR_X | CYCLES(27), PAIR_X | CYCLES(27), PAIR_X | CYCLES(38), PAIR_X | CYCLES(38) +}; +static uint32_t opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), INVALID, PAIR_X | CYCLES(7), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + PAIR_X | CYCLES(8), INVALID, PAIR_X | CYCLES(10), PAIR_X | CYCLES(13), +/* FILDiq FBSTP FISTPiq*/ + INVALID, PAIR_X | CYCLES(8), PAIR_X | CYCLES(63), PAIR_X | CYCLES(13) +}; +static uint32_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + PAIR_X | CYCLES(6), INVALID, INVALID, INVALID +}; + +static uint32_t opcode_timings_8x[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM +}; +static uint32_t opcode_timings_8x_mod3[8] = +{ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG +}; +static uint32_t opcode_timings_81[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM +}; +static uint32_t opcode_timings_81_mod3[8] = +{ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG +}; + +static int decode_delay; +static uint8_t last_prefix; + +static inline int COUNT(uint32_t c, int op_32) +{ + if (c & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + if (!(c & PAIR_MASK)) + return c & 0xffff; + + return c & CYCLES_MASK; +} + +void codegen_timing_686_block_start() +{ + prev_full = decode_delay = 0; + regmask_modified = last_regmask_modified = 0; +} + +void codegen_timing_686_start() +{ + decode_delay = 0; + last_prefix = 0; +} + +void codegen_timing_686_prefix(uint8_t prefix, uint32_t fetchdat) +{ + if ((prefix & 0xf8) == 0xd8) + { + last_prefix = prefix; + return; + } + if (prefix == 0x0f && (fetchdat & 0xf0) == 0x80) + { + /*0fh prefix is 'free' when used on conditional jumps*/ + last_prefix = prefix; + return; + } + + /*6x86 can decode 1 prefix per instruction per clock with no penalty. If + either instruction has more than one prefix then decode is delayed by + one cycle for each additional prefix*/ + decode_delay++; + last_prefix = prefix; +} + +static int check_agi(uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int op_32) +{ + uint32_t addr_regmask = get_addr_regmask(deps[opcode], fetchdat, op_32); + + if (addr_regmask & IMPL_ESP) + addr_regmask |= (1 << REG_ESP); + + if (regmask_modified & addr_regmask) + { + regmask_modified = 0; + return 2; + } + + if (last_regmask_modified & addr_regmask) + return 1; + + return 0; +} + +void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +{ + uint32_t *timings; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: + timings = mod3 ? opcode_timings_shift_imm_mod3 : opcode_timings_shift_imm; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xd0: case 0xd1: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_cl_mod3 : opcode_timings_shift_cl; + deps = mod3 ? opcode_deps_shift_cl_mod3 : opcode_deps_shift_cl; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + break; + } + } + + /*One prefix per instruction is free*/ + decode_delay--; + if (decode_delay < 0) + decode_delay = 0; + + if (prev_full) + { + uint32_t regmask = get_srcdep_mask(deps[opcode], fetchdat, bit8, op_32); + int agi_stall = 0; + + if (regmask & IMPL_ESP) + regmask |= SRCDEP_ESP | DSTDEP_ESP; + + agi_stall = check_agi(prev_deps, prev_opcode, prev_fetchdat, prev_op_32); + + /*Second instruction in the pair*/ + if ((timings[opcode] & PAIR_MASK) == PAIR_NP) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + agi_stall; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1 + agi_stall; + prev_full = 0; + last_regmask_modified = regmask_modified; + regmask_modified = prev_regmask; + } + else if (((timings[opcode] & PAIR_MASK) == PAIR_X || (timings[opcode] & PAIR_MASK) == PAIR_X_BRANCH) + && (prev_timings[opcode] & PAIR_MASK) == PAIR_X) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + agi_stall; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1 + agi_stall; + prev_full = 0; + last_regmask_modified = regmask_modified; + regmask_modified = prev_regmask; + } + else if (prev_regmask & regmask) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + agi_stall; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1 + agi_stall; + prev_full = 0; + last_regmask_modified = regmask_modified; + regmask_modified = prev_regmask; + } + else + { + int t1 = COUNT(prev_timings[prev_opcode], prev_op_32); + int t2 = COUNT(timings[opcode], op_32); + int t_pair = (t1 > t2) ? t1 : t2; + + if (!t_pair) + fatal("Pairable 0 cycles! %02x %02x\n", opcode, prev_opcode); + + agi_stall = check_agi(deps, opcode, fetchdat, op_32); + + codegen_block_cycles += t_pair + agi_stall; + decode_delay = (-t_pair) + 1 + agi_stall; + + last_regmask_modified = regmask_modified; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8) | prev_regmask; + prev_full = 0; + return; + } + } + + if (!prev_full) + { + /*First instruction in the pair*/ + if ((timings[opcode] & PAIR_MASK) == PAIR_NP || (timings[opcode] & PAIR_MASK) == PAIR_X_BRANCH) + { + /*Instruction not pairable*/ + int agi_stall = 0; + + agi_stall = check_agi(deps, opcode, fetchdat, op_32); + + codegen_block_cycles += COUNT(timings[opcode], op_32) + decode_delay + agi_stall; + decode_delay = (-COUNT(timings[opcode], op_32)) + 1 + agi_stall; + last_regmask_modified = regmask_modified; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); + } + else + { + /*Instruction might pair with next*/ + prev_full = 1; + prev_opcode = opcode; + prev_timings = timings; + prev_op_32 = op_32; + prev_regmask = get_dstdep_mask(deps[opcode], fetchdat, bit8); + if (prev_regmask & IMPL_ESP) + prev_regmask |= SRCDEP_ESP | DSTDEP_ESP; + prev_deps = deps; + prev_fetchdat = fetchdat; + return; + } + } +} + +void codegen_timing_686_block_end() +{ + if (prev_full) + { + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; + prev_full = 0; + } +} + +int codegen_timing_686_jump_cycles() +{ + return 0; +} + +codegen_timing_t codegen_timing_686 = +{ + codegen_timing_686_start, + codegen_timing_686_prefix, + codegen_timing_686_opcode, + codegen_timing_686_block_start, + codegen_timing_686_block_end, + codegen_timing_686_jump_cycles +}; diff --git a/src/cpu_new/codegen_timing_common.c b/src/cpu_new/codegen_timing_common.c new file mode 100644 index 000000000..3b47a2734 --- /dev/null +++ b/src/cpu_new/codegen_timing_common.c @@ -0,0 +1,847 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "codegen_timing_common.h" + +uint64_t opcode_deps[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* ADD ADD PUSH ES POP ES*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, +/* OR OR OR OR*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* OR OR PUSH CS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, 0, + +/* ADC ADC ADC ADC*/ +/*10*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* ADC ADC PUSH SS POP SS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, +/* SBB SBB SBB SBB*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* SBB SBB PUSH DS POP DS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, + +/* AND AND AND AND*/ +/*20*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* AND AND DAA*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, +/* SUB SUB SUB SUB*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* SUB SUB DAS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* XOR XOR XOR XOR*/ +/*30*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* XOR XOR AAA*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, +/* CMP CMP CMP CMP*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, +/* CMP CMP AAS*/ + SRCDEP_EAX, SRCDEP_EAX, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ SRCDEP_EAX | IMPL_ESP, SRCDEP_ECX | IMPL_ESP, SRCDEP_EDX | IMPL_ESP, SRCDEP_EBX | IMPL_ESP, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + SRCDEP_ESP | IMPL_ESP, SRCDEP_EBP | IMPL_ESP, SRCDEP_ESI | IMPL_ESP, SRCDEP_EDI | IMPL_ESP, +/* POP EAX POP ECX POP EDX POP EBX*/ + DSTDEP_EAX | IMPL_ESP, DSTDEP_ECX | IMPL_ESP, DSTDEP_EDX | IMPL_ESP, DSTDEP_EBX | IMPL_ESP, +/* POP ESP POP EBP POP ESI POP EDI*/ + DSTDEP_ESP | IMPL_ESP, DSTDEP_EBP | IMPL_ESP, DSTDEP_ESI | IMPL_ESP, DSTDEP_EDI | IMPL_ESP, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ IMPL_ESP, IMPL_ESP, 0, 0, + 0, 0, 0, 0, +/* PUSH imm IMUL PUSH imm IMUL*/ + IMPL_ESP, DSTDEP_REG | MODRM, IMPL_ESP, DSTDEP_REG | MODRM, +/* INSB INSW OUTSB OUTSW*/ + 0, 0, 0, 0, + +/* Jxx*/ +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, +/* TEST TEST XCHG XCHG*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* MOV MOV MOV MOV*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, +/* MOV from seg LEA MOV to seg POP*/ + MODRM, DSTDEP_REG | MODRM, MODRM, IMPL_ESP | MODRM, + +/* NOP XCHG XCHG XCHG*/ +/*90*/ 0, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBX | DSTDEP_EBX, +/* XCHG XCHG XCHG XCHG*/ + SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBP | DSTDEP_EBP, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDI | DSTDEP_EDI, +/* CBW CWD CALL far WAIT*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EDX, 0, 0, +/* PUSHF POPF SAHF LAHF*/ + IMPL_ESP, IMPL_ESP, SRCDEP_EAX, DSTDEP_EAX, + +/* MOV MOV MOV MOV*/ +/*a0*/ DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + 0, 0, 0, 0, +/* TEST TEST STOSB STOSW*/ + SRCDEP_EAX, SRCDEP_EAX, 0, 0, +/* LODSB LODSW SCASB SCASW*/ + 0, 0, 0, 0, + +/* MOV*/ +/*b0*/ DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_ESP, DSTDEP_EBP, DSTDEP_ESI, DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ 0, 0, SRCDEP_ESP | DSTDEP_ESP, IMPL_ESP, +/* LES LDS MOV MOV*/ + DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, MODRM, MODRM, +/* ENTER LEAVE RETF RETF*/ + IMPL_ESP, IMPL_ESP, IMPL_ESP, IMPL_ESP, +/* INT3 INT INTO IRET*/ + 0, 0, 0, 0, + + +/*d0*/ 0, 0, 0, 0, +/* AAM AAD SETALC XLAT*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX | SRCDEP_EBX, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX, +/* IN AL IN AX OUT_AL OUT_AX*/ + DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, +/* CALL JMP JMP JMP*/ + IMPL_ESP, 0, 0, 0, +/* IN AL IN AX OUT_AL OUT_AX*/ + SRCDEP_EDX | DSTDEP_EAX, SRCDEP_EDX | DSTDEP_EAX, SRCDEP_EDX | SRCDEP_EAX, SRCDEP_EDX | SRCDEP_EAX, + +/* REPNE REPE*/ +/*f0*/ 0, 0, 0, 0, +/* HLT CMC*/ + 0, 0, 0, 0, +/* CLC STC CLI STI*/ + 0, 0, 0, 0, +/* CLD STD INCDEC*/ + 0, 0, MODRM, 0 +}; + +uint64_t opcode_deps_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* ADD ADD PUSH ES POP ES*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, +/* OR OR OR OR*/ + SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* OR OR PUSH CS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, 0, + +/* ADC ADC ADC ADC*/ +/*10*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* ADC ADC PUSH SS POP SS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, +/* SBB SBB SBB SBB*/ + SRCDEP_REG |SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* SBB SBB PUSH DS POP DS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, + +/* AND AND AND AND*/ +/*20*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* AND AND DAA*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, +/* SUB SUB SUB SUB*/ + SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* SUB SUB DAS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* XOR XOR XOR XOR*/ +/*30*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* XOR XOR AAA*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, +/* CMP CMP CMP CMP*/ + SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, +/* CMP CMP AAS*/ + SRCDEP_EAX, SRCDEP_EAX, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ SRCDEP_EAX | IMPL_ESP, SRCDEP_ECX | IMPL_ESP, SRCDEP_EDX | IMPL_ESP, SRCDEP_EBX | IMPL_ESP, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + SRCDEP_ESP | IMPL_ESP, SRCDEP_EBP | IMPL_ESP, SRCDEP_ESI | IMPL_ESP, SRCDEP_EDI | IMPL_ESP, +/* POP EAX POP ECX POP EDX POP EBX*/ + DSTDEP_EAX | IMPL_ESP, DSTDEP_ECX | IMPL_ESP, DSTDEP_EDX | IMPL_ESP, DSTDEP_EBX | IMPL_ESP, +/* POP ESP POP EBP POP ESI POP EDI*/ + DSTDEP_ESP | IMPL_ESP, DSTDEP_EBP | IMPL_ESP, DSTDEP_ESI | IMPL_ESP, DSTDEP_EDI | IMPL_ESP, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ IMPL_ESP, IMPL_ESP, 0, 0, + 0, 0, 0, 0, +/* PUSH imm IMUL PUSH imm IMUL*/ + IMPL_ESP, DSTDEP_REG | SRCDEP_RM | MODRM, IMPL_ESP, DSTDEP_REG | SRCDEP_RM | MODRM, +/* INSB INSW OUTSB OUTSW*/ + 0, 0, 0, 0, + +/* Jxx*/ +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, +/* TEST TEST XCHG XCHG*/ + SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, +/* MOV MOV MOV MOV*/ + SRCDEP_REG | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_REG | MODRM, SRCDEP_RM | DSTDEP_REG | MODRM, +/* MOV from seg LEA MOV to seg POP*/ + DSTDEP_RM | MODRM, DSTDEP_REG | MODRM, SRCDEP_RM | MODRM, IMPL_ESP | DSTDEP_RM | MODRM, + +/* NOP XCHG XCHG XCHG*/ +/*90*/ 0, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBX | DSTDEP_EBX, +/* XCHG XCHG XCHG XCHG*/ + SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBP | DSTDEP_EBP, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDI | DSTDEP_EDI, +/* CBW CWD CALL far WAIT*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EDX, 0, 0, +/* PUSHF POPF SAHF LAHF*/ + IMPL_ESP, IMPL_ESP, SRCDEP_EAX, DSTDEP_EAX, + +/* MOV MOV MOV MOV*/ +/*a0*/ DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + 0, 0, 0, 0, +/* TEST TEST STOSB STOSW*/ + SRCDEP_EAX, SRCDEP_EAX, 0, 0, +/* LODSB LODSW SCASB SCASW*/ + 0, 0, 0, 0, + +/* MOV*/ +/*b0*/ DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_ESP, DSTDEP_EBP, DSTDEP_ESI, DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ 0, 0, SRCDEP_ESP | DSTDEP_ESP, IMPL_ESP, +/* LES LDS MOV MOV*/ + DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, DSTDEP_RM | MODRM, DSTDEP_RM | MODRM, +/* ENTER LEAVE RETF RETF*/ + IMPL_ESP, IMPL_ESP, IMPL_ESP, IMPL_ESP, +/* INT3 INT INTO IRET*/ + 0, 0, 0, 0, + + +/*d0*/ 0, 0, 0, 0, +/* AAM AAD SETALC XLAT*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX | SRCDEP_EBX, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX, +/* IN AL IN AX OUT_AL OUT_AX*/ + DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, +/* CALL JMP JMP JMP*/ + IMPL_ESP, 0, 0, 0, +/* IN AL IN AX OUT_AL OUT_AX*/ + SRCDEP_EDX | DSTDEP_EAX, SRCDEP_EDX | DSTDEP_EAX, SRCDEP_EDX | SRCDEP_EAX, SRCDEP_EDX | SRCDEP_EAX, + +/* REPNE REPE*/ +/*f0*/ 0, 0, 0, 0, +/* HLT CMC*/ + 0, 0, 0, 0, +/* CLC STC CLI STI*/ + 0, 0, 0, 0, +/* CLD STD INCDEC*/ + 0, 0, SRCDEP_RM | DSTDEP_RM | MODRM, 0 +}; + +uint64_t opcode_deps_0f[256] = +{ +/*00*/ MODRM, MODRM, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, MODRM, 0, MODRM, + +/*10*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*20*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*30*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*40*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*50*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*60*/ MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + MODRM, MODRM, MODRM, MODRM, + MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, 0, MODRM, MODRM, + +/*70*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + MODRM, MODRM, MODRM, 0, + 0, 0, 0, 0, + 0, 0, MODRM, MODRM, + +/*80*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*90*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + +/*a0*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*b0*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + 0, 0, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + +/*c0*/ MODRM, MODRM, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*d0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*e0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, 0, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*f0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, MODRM, 0, + MODRM, MODRM, MODRM, 0, +}; +uint64_t opcode_deps_0f_mod3[256] = +{ +/*00*/ MODRM, MODRM, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, MODRM, 0, MODRM, + +/*10*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*20*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*30*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*40*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*50*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*60*/ MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + MODRM, MODRM, MODRM, MODRM, + MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, 0, MODRM, MODRM, + +/*70*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + MODRM, MODRM, MODRM, 0, + 0, 0, 0, 0, + 0, 0, MODRM, MODRM, + +/*80*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*90*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + +/*a0*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*b0*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + 0, 0, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + +/*c0*/ MODRM, MODRM, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*d0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*e0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, 0, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*f0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, MODRM, 0, + MODRM, MODRM, MODRM, 0, +}; + +uint64_t opcode_deps_0f0f[256] = +{ +/*00*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, MODRM, 0, 0, + +/*10*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, MODRM, 0, 0, + +/*20*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*30*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*40*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*50*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*60*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*70*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*90*/ MODRM, 0, 0, 0, + MODRM, 0, MODRM, MODRM, + 0, 0, MODRM, 0, + 0, 0, MODRM, 0, + +/*a0*/ MODRM, 0, 0, 0, + MODRM, 0, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*b0*/ MODRM, 0, 0, 0, + MODRM, 0, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, MODRM, + +/*c0*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*d0*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*e0*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*f0*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, +}; +uint64_t opcode_deps_0f0f_mod3[256] = +{ +/*00*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, MODRM, 0, 0, + +/*10*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, MODRM, 0, 0, + +/*20*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*30*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*40*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*50*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*60*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*70*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*90*/ MODRM, 0, 0, 0, + MODRM, 0, MODRM, MODRM, + 0, 0, MODRM, 0, + 0, 0, MODRM, 0, + +/*a0*/ MODRM, 0, 0, 0, + MODRM, 0, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*b0*/ MODRM, 0, 0, 0, + MODRM, 0, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, MODRM, + +/*c0*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*d0*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*e0*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*f0*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, +}; + +uint64_t opcode_deps_shift[8] = +{ + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, +}; +uint64_t opcode_deps_shift_mod3[8] = +{ + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, +}; + +uint64_t opcode_deps_shift_cl[8] = +{ + MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, + MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, +}; +uint64_t opcode_deps_shift_cl_mod3[8] = +{ + SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, + SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, +}; + +uint64_t opcode_deps_f6[8] = +{ +/* TST NOT NEG*/ + MODRM, 0, MODRM, MODRM, +/* MUL IMUL DIV IDIV*/ + SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM +}; +uint64_t opcode_deps_f6_mod3[8] = +{ +/* TST NOT NEG*/ + SRCDEP_RM | MODRM, 0, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, +/* MUL IMUL DIV IDIV*/ + SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM +}; +uint64_t opcode_deps_f7[8] = +{ +/* TST NOT NEG*/ + MODRM, 0, MODRM, MODRM, +/* MUL IMUL DIV IDIV*/ + SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM +}; +uint64_t opcode_deps_f7_mod3[8] = +{ +/* TST NOT NEG*/ + SRCDEP_RM | MODRM, 0, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, +/* MUL IMUL DIV IDIV*/ + SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM +}; +uint64_t opcode_deps_ff[8] = +{ +/* INC DEC CALL CALL far*/ + MODRM, MODRM, MODRM | IMPL_ESP, MODRM, +/* JMP JMP far PUSH*/ + MODRM, MODRM, MODRM | IMPL_ESP, 0 +}; +uint64_t opcode_deps_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | MODRM | IMPL_ESP, MODRM, +/* JMP JMP far PUSH*/ + SRCDEP_RM | MODRM, MODRM, SRCDEP_RM | MODRM | IMPL_ESP, 0 +}; + +uint64_t opcode_deps_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_READ_ST0 | MODRM, FPU_POP | FPU_READ_ST0 | MODRM, +/* FSUBs FSUBRs FDIVs FDIVRs*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM +}; +uint64_t opcode_deps_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + FPU_RW_ST0 | FPU_READ_STREG, FPU_RW_ST0 | FPU_READ_STREG, FPU_READ_ST0 | FPU_READ_STREG, FPU_POP | FPU_READ_ST0 | FPU_READ_STREG, +/* FSUB FSUBR FDIV FDIVR*/ + FPU_RW_ST0 | FPU_READ_STREG, FPU_RW_ST0 | FPU_READ_STREG, FPU_RW_ST0 | FPU_READ_STREG, FPU_RW_ST0 | FPU_READ_STREG +}; + +uint64_t opcode_deps_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + FPU_PUSH | MODRM, 0, FPU_READ_ST0 | MODRM, FPU_POP | MODRM, +/* FLDENV FLDCW FSTENV FSTCW*/ + MODRM, MODRM, MODRM, MODRM +}; +uint64_t opcode_deps_d9_mod3[64] = +{ + /*FLD*/ + FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, + FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, + /*FXCH*/ + FPU_FXCH, FPU_FXCH, FPU_FXCH, FPU_FXCH, + FPU_FXCH, FPU_FXCH, FPU_FXCH, FPU_FXCH, + /*FNOP*/ + 0, 0, 0, 0, 0, 0, 0, 0, + /*FSTP*/ + FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, + FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, +/* opFCHS opFABS*/ + 0, 0, 0, 0, +/* opFTST opFXAM*/ + 0, 0, 0, 0, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + FPU_PUSH, FPU_PUSH, FPU_PUSH, FPU_PUSH, +/* opFLDEG2 opFLDLN2 opFLDZ*/ + FPU_PUSH, FPU_PUSH, FPU_PUSH, 0, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + 0, 0, 0, 0, +/* opFDECSTP opFINCSTP,*/ + 0, 0, 0, 0, +/* opFPREM opFSQRT opFSINCOS*/ + 0, 0, 0, 0, +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + 0, 0, 0, 0 +}; + +uint64_t opcode_deps_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM +}; +uint64_t opcode_deps_da_mod3[8] = +{ + 0, 0, 0, 0, +/* FCOMPP*/ + 0, FPU_POP2, 0, 0 +}; + + +uint64_t opcode_deps_db[8] = +{ +/* FLDil FSTil FSTPil*/ + FPU_PUSH | MODRM, 0, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FLDe FSTPe*/ + 0, FPU_PUSH | MODRM, 0, FPU_READ_ST0 | FPU_POP | MODRM +}; +uint64_t opcode_deps_db_mod3[64] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + + 0, 0, 0, 0, 0, 0, 0, 0, + +/* opFNOP opFCLEX opFINIT*/ + 0, 0, 0, 0, +/* opFNOP opFNOP*/ + 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +uint64_t opcode_deps_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FSUBd FSUBRd FDIVd FDIVRd*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM +}; +uint64_t opcode_deps_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + FPU_READ_ST0 | FPU_RW_STREG, FPU_READ_ST0 | FPU_RW_STREG, 0, 0, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + FPU_READ_ST0 | FPU_RW_STREG, FPU_READ_ST0 | FPU_RW_STREG, FPU_READ_ST0 | FPU_RW_STREG, FPU_READ_ST0 | FPU_RW_STREG +}; + +uint64_t opcode_deps_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + FPU_PUSH | MODRM, 0, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FRSTOR FSAVE FSTSW*/ + MODRM, 0, MODRM, MODRM +}; +uint64_t opcode_deps_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + 0, 0, FPU_READ_ST0 | FPU_WRITE_STREG, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, +/* FUCOM FUCOMP*/ + FPU_READ_ST0 | FPU_READ_STREG, FPU_READ_ST0 | FPU_READ_STREG | FPU_POP, 0, 0 +}; + +uint64_t opcode_deps_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM +}; +uint64_t opcode_deps_de_mod3[8] = +{ +/* FADDP FMULP FCOMPP*/ + FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, 0, FPU_READ_ST0 | FPU_READ_ST1 | FPU_POP2, +/* FSUBP FSUBRP FDIVP FDIVRP*/ + FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, FPU_READ_ST0 | FPU_RW_STREG | FPU_POP +}; + +uint64_t opcode_deps_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + FPU_PUSH | MODRM, 0, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FILDiq FBSTP FISTPiq*/ + 0, FPU_PUSH | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, FPU_READ_ST0 | FPU_POP | MODRM +}; +uint64_t opcode_deps_df_mod3[8] = +{ + 0, 0, 0, 0, +/* FSTSW AX*/ + 0, 0, 0, 0 +}; + +uint64_t opcode_deps_81[8] = +{ + MODRM | HAS_IMM1632, MODRM | HAS_IMM1632, MODRM | HAS_IMM1632, MODRM | HAS_IMM1632, + MODRM | HAS_IMM1632, MODRM | HAS_IMM1632, MODRM | HAS_IMM1632, MODRM | HAS_IMM1632 +}; +uint64_t opcode_deps_81_mod3[8] = +{ + SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, + SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, SRCDEP_RM | MODRM | HAS_IMM1632 +}; +uint64_t opcode_deps_8x[8] = +{ + MODRM | HAS_IMM8, MODRM | HAS_IMM8, MODRM | HAS_IMM8, MODRM | HAS_IMM8, + MODRM | HAS_IMM8, MODRM | HAS_IMM8, MODRM | HAS_IMM8, MODRM | HAS_IMM8 +}; +uint64_t opcode_deps_8x_mod3[8] = +{ + SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, + SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, SRCDEP_RM | MODRM | HAS_IMM8 +}; diff --git a/src/cpu_new/codegen_timing_common.h b/src/cpu_new/codegen_timing_common.h new file mode 100644 index 000000000..19c28b998 --- /dev/null +++ b/src/cpu_new/codegen_timing_common.h @@ -0,0 +1,231 @@ +#include "codegen_ops.h" + +/*Instruction has input dependency on register in REG field*/ +#define SRCDEP_REG (1ull << 0) +/*Instruction has input dependency on register in R/M field*/ +#define SRCDEP_RM (1ull << 1) +/*Instruction modifies register in REG field*/ +#define DSTDEP_REG (1ull << 2) +/*Instruction modifies register in R/M field*/ +#define DSTDEP_RM (1ull << 3) + +#define SRCDEP_SHIFT 4 +#define DSTDEP_SHIFT 12 + +/*Instruction has input dependency on given register*/ +#define SRCDEP_EAX (1ull << 4) +#define SRCDEP_ECX (1ull << 5) +#define SRCDEP_EDX (1ull << 6) +#define SRCDEP_EBX (1ull << 7) +#define SRCDEP_ESP (1ull << 8) +#define SRCDEP_EBP (1ull << 9) +#define SRCDEP_ESI (1ull << 10) +#define SRCDEP_EDI (1ull << 11) + +/*Instruction modifies given register*/ +#define DSTDEP_EAX (1ull << 12) +#define DSTDEP_ECX (1ull << 13) +#define DSTDEP_EDX (1ull << 14) +#define DSTDEP_EBX (1ull << 15) +#define DSTDEP_ESP (1ull << 16) +#define DSTDEP_EBP (1ull << 17) +#define DSTDEP_ESI (1ull << 18) +#define DSTDEP_EDI (1ull << 19) + +/*Instruction has ModR/M byte*/ +#define MODRM (1ull << 20) +/*Instruction implicitly uses ESP*/ +#define IMPL_ESP (1ull << 21) + +/*Instruction is MMX shift or pack/unpack instruction*/ +#define MMX_SHIFTPACK (1ull << 22) +/*Instruction is MMX multiply instruction*/ +#define MMX_MULTIPLY (1ull << 23) + +/*Instruction pops the FPU stack*/ +#define FPU_POP (1ull << 24) +/*Instruction pops the FPU stack twice*/ +#define FPU_POP2 (1ull << 25) +/*Instruction pushes onto the FPU stack*/ +#define FPU_PUSH (1ull << 26) + +/*Instruction writes to ST(0)*/ +#define FPU_WRITE_ST0 (1ull << 27) +/*Instruction reads from ST(0)*/ +#define FPU_READ_ST0 (1ull << 28) +/*Instruction reads from and writes to ST(0)*/ +#define FPU_RW_ST0 (3ull << 27) + +/*Instruction reads from ST(1)*/ +#define FPU_READ_ST1 (1ull << 29) +/*Instruction writes to ST(1)*/ +#define FPU_WRITE_ST1 (1ull << 30) +/*Instruction reads from and writes to ST(1)*/ +#define FPU_RW_ST1 (3ull << 29) + +/*Instruction reads from ST(reg)*/ +#define FPU_READ_STREG (1ull << 31) +/*Instruction writes to ST(reg)*/ +#define FPU_WRITE_STREG (1ull << 32) +/*Instruction reads from and writes to ST(reg)*/ +#define FPU_RW_STREG (3ull << 30) + +#define FPU_FXCH (1ull << 33) + +#define HAS_IMM8 (1ull << 34) +#define HAS_IMM1632 (1ull << 35) + + +#define REGMASK_IMPL_ESP (1 << 8) +#define REGMASK_SHIFTPACK (1 << 9) +#define REGMASK_MULTIPLY (1 << 9) + + +extern uint64_t opcode_deps[256]; +extern uint64_t opcode_deps_mod3[256]; +extern uint64_t opcode_deps_0f[256]; +extern uint64_t opcode_deps_0f_mod3[256]; +extern uint64_t opcode_deps_0f0f[256]; +extern uint64_t opcode_deps_0f0f_mod3[256]; +extern uint64_t opcode_deps_shift[8]; +extern uint64_t opcode_deps_shift_mod3[8]; +extern uint64_t opcode_deps_shift_cl[8]; +extern uint64_t opcode_deps_shift_cl_mod3[8]; +extern uint64_t opcode_deps_f6[8]; +extern uint64_t opcode_deps_f6_mod3[8]; +extern uint64_t opcode_deps_f7[8]; +extern uint64_t opcode_deps_f7_mod3[8]; +extern uint64_t opcode_deps_ff[8]; +extern uint64_t opcode_deps_ff_mod3[8]; +extern uint64_t opcode_deps_d8[8]; +extern uint64_t opcode_deps_d8_mod3[8]; +extern uint64_t opcode_deps_d9[8]; +extern uint64_t opcode_deps_d9_mod3[64]; +extern uint64_t opcode_deps_da[8]; +extern uint64_t opcode_deps_da_mod3[8]; +extern uint64_t opcode_deps_db[8]; +extern uint64_t opcode_deps_db_mod3[64]; +extern uint64_t opcode_deps_dc[8]; +extern uint64_t opcode_deps_dc_mod3[8]; +extern uint64_t opcode_deps_dd[8]; +extern uint64_t opcode_deps_dd_mod3[8]; +extern uint64_t opcode_deps_de[8]; +extern uint64_t opcode_deps_de_mod3[8]; +extern uint64_t opcode_deps_df[8]; +extern uint64_t opcode_deps_df_mod3[8]; +extern uint64_t opcode_deps_81[8]; +extern uint64_t opcode_deps_81_mod3[8]; +extern uint64_t opcode_deps_8x[8]; +extern uint64_t opcode_deps_8x_mod3[8]; + + + +static inline uint32_t get_addr_regmask(uint64_t data, uint32_t fetchdat, int op_32) +{ + uint32_t addr_regmask = 0; + + if (data & MODRM) + { + uint8_t modrm = fetchdat & 0xff; + + if ((modrm & 0xc0) != 0xc0) + { + if (op_32 & 0x200) + { + if ((modrm & 0x7) == 4) + { + uint8_t sib = (fetchdat >> 8) & 0xff; + + if ((modrm & 0xc0) != 0xc0 && (sib & 7) != 5) + { + addr_regmask = 1 << (sib & 7); + if ((sib & 0x38) != 0x20) + addr_regmask |= 1 << ((sib >> 3) & 7); + } + } + else if ((modrm & 0xc7) != 5) + { + addr_regmask = 1 << (modrm & 7); + } + } + else + { + if ((modrm & 0xc7) != 0x06) + { + switch (modrm & 7) + { + case 0: addr_regmask = REG_BX | REG_SI; break; + case 1: addr_regmask = REG_BX | REG_DI; break; + case 2: addr_regmask = REG_BP | REG_SI; break; + case 3: addr_regmask = REG_BP | REG_DI; break; + case 4: addr_regmask = REG_SI; break; + case 5: addr_regmask = REG_DI; break; + case 6: addr_regmask = REG_BP; break; + case 7: addr_regmask = REG_BX; break; + } + } + } + } + } + + if (data & IMPL_ESP) + addr_regmask |= REGMASK_IMPL_ESP; + + return addr_regmask; +} + +static inline uint32_t get_srcdep_mask(uint64_t data, uint32_t fetchdat, int bit8, int op_32) +{ + uint32_t mask = 0; + if (data & SRCDEP_REG) + { + int reg = (fetchdat >> 3) & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + if (data & SRCDEP_RM) + { + int reg = fetchdat & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + mask |= ((data >> SRCDEP_SHIFT) & 0xff); + if (data & MMX_SHIFTPACK) + mask |= REGMASK_SHIFTPACK; + if (data & MMX_MULTIPLY) + mask |= REGMASK_MULTIPLY; + + mask |= get_addr_regmask(data, fetchdat, op_32); + + return mask; +} + +static inline uint32_t get_dstdep_mask(uint64_t data, uint32_t fetchdat, int bit8) +{ + uint32_t mask = 0; + if (data & DSTDEP_REG) + { + int reg = (fetchdat >> 3) & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + if (data & DSTDEP_RM) + { + int reg = fetchdat & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + mask |= ((data >> DSTDEP_SHIFT) & 0xff); + if (data & MMX_SHIFTPACK) + mask |= REGMASK_SHIFTPACK; + if (data & MMX_MULTIPLY) + mask |= REGMASK_MULTIPLY; + if (data & IMPL_ESP) + mask |= REGMASK_IMPL_ESP | (1 << REG_ESP); + + return mask; +} diff --git a/src/cpu_new/codegen_timing_k6.c b/src/cpu_new/codegen_timing_k6.c new file mode 100644 index 000000000..9c216de9a --- /dev/null +++ b/src/cpu_new/codegen_timing_k6.c @@ -0,0 +1,2350 @@ +/*Most of the vector instructions here are a total guess. + Some of the timings are based on http://users.atw.hu/instlatx64/AuthenticAMD0000562_K6_InstLatX86.txt*/ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" +#include "../machine/machine.h" + +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + +typedef enum uop_type_t +{ + UOP_ALU = 0, /*Executes in Integer X or Y units*/ + UOP_ALUX, /*Executes in Integer X unit*/ + UOP_LOAD, /*Executes in Load unit*/ + UOP_STORE, /*Executes in Store unit*/ + UOP_FLOAD, /*Executes in Load unit*/ + UOP_FSTORE, /*Executes in Store unit*/ + UOP_MLOAD, /*Executes in Load unit*/ + UOP_MSTORE, /*Executes in Store unit*/ + UOP_FLOAT, /*Executes in Floating Point unit*/ + UOP_MEU, /*Executes in Multimedia unit*/ + UOP_MEU_SHIFT, /*Executes in Multimedia unit or ALU X/Y. Uses MMX shifter*/ + UOP_MEU_MUL, /*Executes in Multimedia unit or ALU X/Y. Uses MMX/3DNow multiplier*/ + UOP_MEU_3DN, /*Executes in Multimedia unit or ALU X/Y. Uses 3DNow ALU*/ + UOP_BRANCH, /*Executes in Branch unit*/ + UOP_LIMM /*Does not require an execution unit*/ +} uop_type_t; + +typedef enum decode_type_t +{ + DECODE_SHORT, + DECODE_LONG, + DECODE_VECTOR +} decode_type_t; + +#define MAX_UOPS 10 + +typedef struct risc86_uop_t +{ + uop_type_t type; + int throughput; + int latency; +} risc86_uop_t; + +typedef struct risc86_instruction_t +{ + int nr_uops; + decode_type_t decode_type; + risc86_uop_t uop[MAX_UOPS]; +} risc86_instruction_t; + +static const risc86_instruction_t alu_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t alux_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t load_alu_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t load_alux_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t alu_store_op = +{ + .nr_uops = 3, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t alux_store_op = +{ + .nr_uops = 3, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; + +static const risc86_instruction_t branch_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; + +static const risc86_instruction_t limm_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LIMM, .throughput = 1, .latency = 1} +}; + +static const risc86_instruction_t load_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2} +}; + +static const risc86_instruction_t store_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; + + +static const risc86_instruction_t bswap_op = +{ + .nr_uops = 1, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t leave_op = +{ + .nr_uops = 3, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t lods_op = +{ + .nr_uops = 2, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t loop_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t mov_reg_seg_op = +{ + .nr_uops = 1, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, +}; +static const risc86_instruction_t movs_op = +{ + .nr_uops = 4, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t pop_reg_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t pop_mem_op = +{ + .nr_uops = 3, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t push_imm_op = +{ + .nr_uops = 1, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_STORE, .throughput = 1, .latency = 2}, +}; +static const risc86_instruction_t push_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t push_seg_op = +{ + .nr_uops = 2, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t stos_op = +{ + .nr_uops = 2, + .decode_type = DECODE_LONG, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t test_reg_op = +{ + .nr_uops = 1, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t test_reg_b_op = +{ + .nr_uops = 1, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t test_mem_imm_op = +{ + .nr_uops = 2, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t test_mem_imm_b_op = +{ + .nr_uops = 2, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t xchg_op = +{ + .nr_uops = 3, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; + +static const risc86_instruction_t m3dn_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MEU_3DN, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t mmx_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MEU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t mmx_mul_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MEU_MUL, .throughput = 1, .latency = 2} +}; +static const risc86_instruction_t mmx_shift_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MEU_SHIFT, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t load_3dn_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_MEU_3DN, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t load_mmx_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_MEU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t load_mmx_mul_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_MEU_MUL, .throughput = 1, .latency = 2} +}; +static const risc86_instruction_t load_mmx_shift_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_MEU_SHIFT, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t mload_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MLOAD, .throughput = 1, .latency = 2} +}; + +static const risc86_instruction_t mstore_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MSTORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t pmul_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MEU_MUL, .throughput = 1, .latency = 2} +}; +static const risc86_instruction_t pmul_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_MEU_MUL, .throughput = 1, .latency = 2} +}; + +static const risc86_instruction_t float_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FLOAT, .throughput = 2, .latency = 2} +}; +static const risc86_instruction_t load_float_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FLOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAT, .throughput = 2, .latency = 2} +}; +static const risc86_instruction_t fstore_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FSTORE, .throughput = 1, .latency = 1} +}; + +static const risc86_instruction_t fdiv_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FLOAT, .throughput = 40, .latency = 40} +}; +static const risc86_instruction_t fdiv_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FLOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAT, .throughput = 40, .latency = 40} +}; +static const risc86_instruction_t fsin_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FLOAT, .throughput = 62, .latency = 62} +}; +static const risc86_instruction_t fsqrt_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FLOAT, .throughput = 41, .latency = 41} +}; + +static const risc86_instruction_t vector_fldcw_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_FLOAT, .throughput = 8, .latency = 8} +}; +static const risc86_instruction_t vector_float_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_FLOAT, .throughput = 2, .latency = 2} +}; +static const risc86_instruction_t vector_float_l_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_FLOAT, .throughput = 50, .latency = 50} +}; +static const risc86_instruction_t vector_flde_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_FLOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_FLOAT, .throughput = 2, .latency = 2} +}; +static const risc86_instruction_t vector_fste_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_FLOAT, .throughput = 2, .latency = 2}, + .uop[1] = {.type = UOP_FSTORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_FSTORE, .throughput = 1, .latency = 1} +}; + +static const risc86_instruction_t vector_alu1_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alu2_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alu3_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alu6_op = +{ + .nr_uops = 6, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alux1_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alux3_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alux6_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alu_store_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alux_store_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_arpl_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 3, .latency = 3}, + .uop[1] = {.type = UOP_ALU, .throughput = 3, .latency = 3} +}; +static const risc86_instruction_t vector_bound_op = +{ + .nr_uops = 4, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_bsx_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 10, .latency = 10} +}; +static const risc86_instruction_t vector_call_far_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 3, .latency = 3}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_cli_sti_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 7, .latency = 7} +}; +static const risc86_instruction_t vector_cmps_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_cmpsb_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_cmpxchg_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, +}; +static const risc86_instruction_t vector_cmpxchg_b_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, +}; +static const risc86_instruction_t vector_cpuid_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 22, .latency = 22} +}; +static const risc86_instruction_t vector_div16_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 10, .latency = 10} +}; +static const risc86_instruction_t vector_div16_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 10, .latency = 10} +}; +static const risc86_instruction_t vector_div32_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 18, .latency = 18} +}; +static const risc86_instruction_t vector_div32_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 18, .latency = 18} +}; +static const risc86_instruction_t vector_emms_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 25, .latency = 25} +}; +static const risc86_instruction_t vector_enter_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_STORE, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 10, .latency = 10} +}; +static const risc86_instruction_t vector_femms_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 6, .latency = 6} +}; +static const risc86_instruction_t vector_in_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 10, .latency = 11} +}; +static const risc86_instruction_t vector_ins_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 10, .latency = 11}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_int_op = +{ + .nr_uops = 5, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 20, .latency = 20}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_iret_op = +{ + .nr_uops = 5, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[3] = {.type = UOP_ALU, .throughput = 20, .latency = 20}, + .uop[4] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_invd_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1000, .latency = 1000} +}; +static const risc86_instruction_t vector_jmp_far_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 3, .latency = 3}, + .uop[1] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_load_alu_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_load_alux_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_loop_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_lss_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_ALU, .throughput = 3, .latency = 3} +}; +static const risc86_instruction_t vector_mov_mem_seg_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_mov_seg_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 3, .latency = 3} +}; +static const risc86_instruction_t vector_mov_seg_reg_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 3, .latency = 3} +}; +static const risc86_instruction_t vector_mul_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_mul_mem_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_mul64_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_mul64_mem_op = +{ + .nr_uops = 4, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_out_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_STORE, .throughput = 10, .latency = 10} +}; +static const risc86_instruction_t vector_outs_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STORE, .throughput = 10, .latency = 10}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_pusha_op = +{ + .nr_uops = 8, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_popa_op = +{ + .nr_uops = 8, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_LOAD, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_popf_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 17, .latency = 17} +}; +static const risc86_instruction_t vector_push_mem_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_pushf_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_ret_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_retf_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 3, .latency = 3}, + .uop[2] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_scas_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_scasb_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_setcc_mem_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_FSTORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_setcc_reg_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_test_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_test_mem_b_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_xchg_mem_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_xlat_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2} +}; +static const risc86_instruction_t vector_wbinvd_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 10000, .latency = 10000} +}; + +#define INVALID NULL + +static const risc86_instruction_t *opcode_timings[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ &alux_store_op, &alu_store_op, &load_alux_op, &load_alu_op, +/* ADD ADD PUSH ES POP ES*/ + &alux_op, &alu_op, &push_seg_op, &vector_mov_seg_mem_op, +/* OR OR OR OR*/ + &alux_store_op, &alu_store_op, &load_alux_op, &load_alu_op, +/* OR OR PUSH CS */ + &alux_op, &alu_op, &push_seg_op, INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ &vector_alux_store_op, &vector_alu_store_op, &vector_load_alux_op, &vector_load_alu_op, +/* ADC ADC PUSH SS POP SS*/ + &vector_alux1_op, &vector_alu1_op, &push_seg_op, &vector_mov_seg_mem_op, +/* SBB SBB SBB SBB*/ +/*10*/ &vector_alux_store_op, &vector_alu_store_op, &vector_load_alux_op, &vector_load_alu_op, +/* SBB SBB PUSH DS POP DS*/ + &vector_alux1_op, &vector_alu1_op, &push_seg_op, &vector_mov_seg_mem_op, + +/* AND AND AND AND*/ +/*20*/ &alux_store_op, &alu_store_op, &load_alux_op, &load_alu_op, +/* AND AND DAA*/ + &alux_op, &alu_op, INVALID, &vector_alux1_op, +/* SUB SUB SUB SUB*/ + &alux_store_op, &alu_store_op, &load_alux_op, &load_alu_op, +/* SUB SUB DAS*/ + &alux_op, &alu_op, INVALID, &vector_alux1_op, + +/* XOR XOR XOR XOR*/ +/*30*/ &alux_store_op, &alu_store_op, &load_alux_op, &load_alu_op, +/* XOR XOR AAA*/ + &alux_op, &alu_op, INVALID, &vector_alux6_op, +/* CMP CMP CMP CMP*/ + &load_alux_op, &load_alu_op, &load_alux_op, &load_alu_op, +/* CMP CMP AAS*/ + &alux_op, &alu_op, INVALID, &vector_alux6_op, + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ &alu_op, &alu_op, &alu_op, &alu_op, +/* INC ESP INC EBP INC ESI INC EDI*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + &alu_op, &alu_op, &alu_op, &alu_op, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ &store_op, &store_op, &store_op, &store_op, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + &store_op, &store_op, &store_op, &store_op, +/* POP EAX POP ECX POP EDX POP EBX*/ + &pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op, +/* POP ESP POP EBP POP ESI POP EDI*/ + &pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ &vector_pusha_op, &vector_popa_op, &vector_bound_op, &vector_arpl_op, + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + &push_imm_op, &vector_mul_op, &push_imm_op, &vector_mul_op, +/* INSB INSW OUTSB OUTSW*/ + &vector_ins_op, &vector_ins_op, &vector_outs_op, &vector_outs_op, + +/* Jxx*/ +/*70*/ &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + &vector_test_mem_b_op, &vector_test_mem_op, &vector_xchg_mem_op, &vector_xchg_mem_op, +/* MOV MOV MOV MOV*/ + &store_op, &store_op, &load_op, &load_op, +/* MOV from seg LEA MOV to seg POP*/ + &vector_mov_mem_seg_op, &store_op, &vector_mov_seg_mem_op, &pop_mem_op, + +/* NOP XCHG XCHG XCHG*/ +/*90*/ &limm_op, &xchg_op, &xchg_op, &xchg_op, +/* XCHG XCHG XCHG XCHG*/ + &xchg_op, &xchg_op, &xchg_op, &xchg_op, +/* CBW CWD CALL far WAIT*/ + &vector_alu1_op, &vector_alu1_op, &vector_call_far_op, &limm_op, +/* PUSHF POPF SAHF LAHF*/ + &vector_pushf_op, &vector_popf_op, &vector_alux1_op, &vector_alux1_op, + +/* MOV MOV MOV MOV*/ +/*a0*/ &load_op, &load_op, &store_op, &store_op, +/* MOVSB MOVSW CMPSB CMPSW*/ + &movs_op, &movs_op, &vector_cmpsb_op, &vector_cmps_op, +/* TEST TEST STOSB STOSW*/ + &test_reg_b_op, &test_reg_op, &stos_op, &stos_op, +/* LODSB LODSW SCASB SCASW*/ + &lods_op, &lods_op, &vector_scasb_op, &vector_scas_op, + +/* MOV*/ +/*b0*/ &limm_op, &limm_op, &limm_op, &limm_op, + &limm_op, &limm_op, &limm_op, &limm_op, + &limm_op, &limm_op, &limm_op, &limm_op, + &limm_op, &limm_op, &limm_op, &limm_op, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, &vector_ret_op, &vector_ret_op, +/* LES LDS MOV MOV*/ + &vector_lss_op, &vector_lss_op, &store_op, &store_op, +/* ENTER LEAVE RETF RETF*/ + &vector_enter_op, &leave_op, &vector_retf_op, &vector_retf_op, +/* INT3 INT INTO IRET*/ + &vector_int_op, &vector_int_op, &vector_int_op, &vector_iret_op, + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + &vector_alux6_op, &vector_alux3_op, &vector_alux1_op, &vector_xlat_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ &vector_loop_op, &vector_loop_op, &loop_op, &vector_loop_op, +/* IN AL IN AX OUT_AL OUT_AX*/ + &vector_in_op, &vector_in_op, &vector_out_op, &vector_out_op, +/* CALL JMP JMP JMP*/ + &store_op, &branch_op, &vector_jmp_far_op, &branch_op, +/* IN AL IN AX OUT_AL OUT_AX*/ + &vector_in_op, &vector_in_op, &vector_out_op, &vector_out_op, + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, INVALID, INVALID, +/* HLT CMC*/ + &vector_alux1_op, &vector_alu2_op, INVALID, INVALID, +/* CLC STC CLI STI*/ + &vector_alu1_op, &vector_alu1_op, &vector_cli_sti_op, &vector_cli_sti_op, +/* CLD STD INCDEC*/ + &vector_alu1_op, &vector_alu1_op, &alux_store_op, INVALID +}; + +static const risc86_instruction_t *opcode_timings_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ &alux_op, &alu_op, &alux_op, &alu_op, +/* ADD ADD PUSH ES POP ES*/ + &alux_op, &alu_op, &push_seg_op, &vector_mov_seg_mem_op, +/* OR OR OR OR*/ + &alux_op, &alu_op, &alux_op, &alu_op, +/* OR OR PUSH CS */ + &alux_op, &alu_op, &push_seg_op, INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ &vector_alux1_op, &vector_alu1_op, &vector_alux1_op, &vector_alu1_op, +/* ADC ADC PUSH SS POP SS*/ + &vector_alux1_op, &vector_alu1_op, &push_seg_op, &vector_mov_seg_mem_op, +/* SBB SBB SBB SBB*/ + &vector_alux1_op, &vector_alu1_op, &vector_alux1_op, &vector_alu1_op, +/* SBB SBB PUSH DS POP DS*/ + &vector_alux1_op, &vector_alu1_op, &push_seg_op, &vector_mov_seg_mem_op, + +/* AND AND AND AND*/ +/*20*/ &alux_op, &alu_op, &alux_op, &alu_op, +/* AND AND DAA*/ + &alux_op, &alu_op, INVALID, &vector_alux1_op, +/* SUB SUB SUB SUB*/ + &alux_op, &alu_op, &alux_op, &alu_op, +/* SUB SUB DAS*/ + &alux_op, &alu_op, INVALID, &vector_alux1_op, + +/* XOR XOR XOR XOR*/ +/*30*/ &alux_op, &alu_op, &alux_op, &alu_op, +/* XOR XOR AAA*/ + &alux_op, &alu_op, INVALID, &vector_alux6_op, +/* CMP CMP CMP CMP*/ + &alux_op, &alu_op, &alux_op, &alu_op, +/* CMP CMP AAS*/ + &alux_op, &alu_op, INVALID, &vector_alux6_op, + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ &alu_op, &alu_op, &alu_op, &alu_op, +/* INC ESP INC EBP INC ESI INC EDI*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + &alu_op, &alu_op, &alu_op, &alu_op, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ &store_op, &store_op, &store_op, &store_op, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + &store_op, &store_op, &store_op, &store_op, +/* POP EAX POP ECX POP EDX POP EBX*/ + &pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op, +/* POP ESP POP EBP POP ESI POP EDI*/ + &pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ &vector_pusha_op, &vector_popa_op, &vector_bound_op, &vector_arpl_op, + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + &push_imm_op, &vector_mul_op, &push_imm_op, &vector_mul_op, +/* INSB INSW OUTSB OUTSW*/ + &vector_ins_op, &vector_ins_op, &vector_outs_op, &vector_outs_op, + +/* Jxx*/ +/*70*/ &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + &vector_alu1_op, &vector_alu1_op, &vector_alu3_op, &vector_alu3_op, +/* MOV MOV MOV MOV*/ + &store_op, &store_op, &load_op, &load_op, +/* MOV from seg LEA MOV to seg POP*/ + &mov_reg_seg_op, &store_op, &vector_mov_seg_reg_op, &pop_reg_op, + +/* NOP XCHG XCHG XCHG*/ +/*90*/ &limm_op, &xchg_op, &xchg_op, &xchg_op, +/* XCHG XCHG XCHG XCHG*/ + &xchg_op, &xchg_op, &xchg_op, &xchg_op, +/* CBW CWD CALL far WAIT*/ + &vector_alu1_op, &vector_alu1_op, &vector_call_far_op, &limm_op, +/* PUSHF POPF SAHF LAHF*/ + &vector_pushf_op, &vector_popf_op, &vector_alux1_op, &vector_alux1_op, + +/* MOV MOV MOV MOV*/ +/*a0*/ &load_op, &load_op, &store_op, &store_op, +/* MOVSB MOVSW CMPSB CMPSW*/ + &movs_op, &movs_op, &vector_cmpsb_op, &vector_cmps_op, +/* TEST TEST STOSB STOSW*/ + &test_reg_b_op, &test_reg_op, &stos_op, &stos_op, +/* LODSB LODSW SCASB SCASW*/ + &lods_op, &lods_op, &vector_scasb_op, &vector_scas_op, + +/* MOV*/ +/*b0*/ &limm_op, &limm_op, &limm_op, &limm_op, + &limm_op, &limm_op, &limm_op, &limm_op, + &limm_op, &limm_op, &limm_op, &limm_op, + &limm_op, &limm_op, &limm_op, &limm_op, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, &vector_ret_op, &vector_ret_op, +/* LES LDS MOV MOV*/ + &vector_lss_op, &vector_lss_op, &store_op, &store_op, +/* ENTER LEAVE RETF RETF*/ + &vector_enter_op, &leave_op, &vector_retf_op, &vector_retf_op, +/* INT3 INT INTO IRET*/ + &vector_int_op, &vector_int_op, &vector_int_op, &vector_iret_op, + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + &vector_alux6_op, &vector_alux3_op, &vector_alux1_op, &vector_xlat_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ &vector_loop_op, &vector_loop_op, &loop_op, &vector_loop_op, +/* IN AL IN AX OUT_AL OUT_AX*/ + &vector_in_op, &vector_in_op, &vector_out_op, &vector_out_op, +/* CALL JMP JMP JMP*/ + &store_op, &branch_op, &vector_jmp_far_op, &branch_op, +/* IN AL IN AX OUT_AL OUT_AX*/ + &vector_in_op, &vector_in_op, &vector_out_op, &vector_out_op, + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, INVALID, INVALID, +/* HLT CMC*/ + &vector_alux1_op, &vector_alu2_op, INVALID, INVALID, +/* CLC STC CLI STI*/ + &vector_alu1_op, &vector_alu1_op, &vector_cli_sti_op, &vector_cli_sti_op, +/* CLD STD INCDEC*/ + &vector_alu1_op, &vector_alu1_op, &vector_alux1_op, INVALID +}; + +static const risc86_instruction_t *opcode_timings_0f[256] = +{ +/*00*/ &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, + INVALID, &vector_alu6_op, &vector_alu6_op, INVALID, + &vector_invd_op, &vector_wbinvd_op, INVALID, INVALID, + INVALID, &load_op, &vector_femms_op, &load_3dn_op, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, + &vector_alu6_op, &vector_alu6_op, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ &load_mmx_op, &load_mmx_op, &load_mmx_op, &load_mmx_op, + &load_mmx_op, &load_mmx_op, &load_mmx_op, &load_mmx_op, + &load_mmx_op, &load_mmx_op, &load_mmx_op, &load_mmx_op, + INVALID, INVALID, &mload_op, &mload_op, + +/*70*/ INVALID, &load_mmx_shift_op, &load_mmx_shift_op, &load_mmx_shift_op, + &load_mmx_op, &load_mmx_op, &load_mmx_op, &vector_emms_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, &mstore_op, &mstore_op, + +/*80*/ &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + +/*90*/ &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, + &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, + &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, + &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, + +/*a0*/ &push_seg_op, &vector_mov_seg_mem_op, &vector_cpuid_op, &vector_load_alu_op, + &vector_alu_store_op, &vector_alu_store_op, INVALID, INVALID, + &push_seg_op, &vector_mov_seg_mem_op, INVALID, &vector_load_alu_op, + &vector_alu_store_op, &vector_alu_store_op, INVALID, &vector_mul_op, + +/*b0*/ &vector_cmpxchg_b_op, &vector_cmpxchg_op, &vector_lss_op, &vector_load_alu_op, + &vector_lss_op, &vector_lss_op, &load_alux_op, &load_alu_op, + INVALID, INVALID, &vector_load_alu_op, &vector_load_alu_op, + &vector_bsx_op, &vector_bsx_op, &load_alux_op, &load_alu_op, + +/*c0*/ &vector_alux_store_op, &vector_alu_store_op, INVALID, INVALID, + INVALID, INVALID, INVALID, &vector_cmpxchg_op, + &bswap_op, &bswap_op, &bswap_op, &bswap_op, + &bswap_op, &bswap_op, &bswap_op, &bswap_op, + +/*d0*/ INVALID, &load_mmx_shift_op, &load_mmx_shift_op, &load_mmx_shift_op, + INVALID, &load_mmx_mul_op, INVALID, INVALID, + &load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op, + &load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op, + +/*e0*/ &load_mmx_op, &load_mmx_shift_op, &load_mmx_shift_op, INVALID, + INVALID, &pmul_mem_op, INVALID, INVALID, + &load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op, + &load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op, + +/*f0*/ INVALID, &load_mmx_shift_op, &load_mmx_shift_op, &load_mmx_shift_op, + INVALID, &pmul_mem_op, INVALID, INVALID, + &load_mmx_op, &load_mmx_op, &load_mmx_op, INVALID, + &load_mmx_op, &load_mmx_op, &load_mmx_op, INVALID, +}; +static const risc86_instruction_t *opcode_timings_0f_mod3[256] = +{ +/*00*/ &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, + INVALID, &vector_alu6_op, &vector_alu6_op, INVALID, + &vector_invd_op, &vector_wbinvd_op, INVALID, INVALID, + INVALID, INVALID, &vector_femms_op, &m3dn_op, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, + &vector_alu6_op, &vector_alu6_op, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ &mmx_op, &mmx_op, &mmx_op, &mmx_op, + &mmx_op, &mmx_op, &mmx_op, &mmx_op, + &mmx_op, &mmx_op, &mmx_op, &mmx_op, + INVALID, INVALID, &mmx_op, &mmx_op, + +/*70*/ INVALID, &mmx_shift_op, &mmx_shift_op, &mmx_shift_op, + &mmx_op, &mmx_op, &mmx_op, &vector_emms_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, &mmx_op, &mmx_op, + +/*80*/ &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + +/*90*/ &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, + &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, + &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, + &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, + +/*a0*/ &push_seg_op, &vector_mov_seg_mem_op, &vector_cpuid_op, &vector_alu1_op, + &vector_alu1_op, &vector_alu1_op, INVALID, INVALID, + &push_seg_op, &vector_mov_seg_mem_op, INVALID, &vector_alu1_op, + &vector_alu1_op, &vector_alu1_op, INVALID, &vector_mul_op, + +/*b0*/ &vector_cmpxchg_b_op, &vector_cmpxchg_op, &vector_lss_op, &vector_alu1_op, + &vector_lss_op, &vector_lss_op, &alux_op, &alu_op, + INVALID, INVALID, &vector_alu1_op, &vector_alu1_op, + &vector_bsx_op, &vector_bsx_op, &alux_op, &alu_op, + +/*c0*/ &vector_alux1_op, &vector_alu1_op, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + &bswap_op, &bswap_op, &bswap_op, &bswap_op, + &bswap_op, &bswap_op, &bswap_op, &bswap_op, + +/*d0*/ INVALID, &mmx_shift_op, &mmx_shift_op, &mmx_shift_op, + INVALID, &mmx_mul_op, INVALID, INVALID, + &mmx_op, &mmx_op, INVALID, &mmx_op, + &mmx_op, &mmx_op, INVALID, &mmx_op, + +/*e0*/ &mmx_op, &mmx_shift_op, &mmx_shift_op, INVALID, + INVALID, &pmul_op, INVALID, INVALID, + &mmx_op, &mmx_op, INVALID, &mmx_op, + &mmx_op, &mmx_op, INVALID, &mmx_op, + +/*f0*/ INVALID, &mmx_shift_op, &mmx_shift_op, &mmx_shift_op, + INVALID, &pmul_op, INVALID, INVALID, + &mmx_op, &mmx_op, &mmx_op, INVALID, + &mmx_op, &mmx_op, &mmx_op, INVALID, +}; + +static const risc86_instruction_t *opcode_timings_0f0f[256] = +{ +/*00*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, &load_3dn_op, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, &load_3dn_op, INVALID, INVALID, + +/*20*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*70*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*80*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*90*/ &load_3dn_op, INVALID, INVALID, INVALID, + &load_3dn_op, INVALID, &load_3dn_op, &load_3dn_op, + INVALID, INVALID, &load_3dn_op, INVALID, + INVALID, INVALID, &load_3dn_op, INVALID, + +/*a0*/ &load_3dn_op, INVALID, INVALID, INVALID, + &load_3dn_op, INVALID, &load_mmx_mul_op, &load_mmx_mul_op, + INVALID, INVALID, &load_3dn_op, INVALID, + INVALID, INVALID, &load_3dn_op, INVALID, + +/*b0*/ &load_3dn_op, INVALID, INVALID, INVALID, + &load_mmx_mul_op, INVALID, &load_mmx_mul_op, &load_mmx_mul_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, &load_mmx_op, + +/*c0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*d0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*e0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*f0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +}; +static const risc86_instruction_t *opcode_timings_0f0f_mod3[256] = +{ +/*00*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, &m3dn_op, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, &m3dn_op, INVALID, INVALID, + +/*20*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*70*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*80*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*90*/ &m3dn_op, INVALID, INVALID, INVALID, + &m3dn_op, INVALID, &m3dn_op, &m3dn_op, + INVALID, INVALID, &m3dn_op, INVALID, + INVALID, INVALID, &m3dn_op, INVALID, + +/*a0*/ &m3dn_op, INVALID, INVALID, INVALID, + &m3dn_op, INVALID, &mmx_mul_op, &mmx_mul_op, + INVALID, INVALID, &m3dn_op, INVALID, + INVALID, INVALID, &m3dn_op, INVALID, + +/*b0*/ &m3dn_op, INVALID, INVALID, INVALID, + &mmx_mul_op, INVALID, &mmx_mul_op, &mmx_mul_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, &mmx_op, + +/*c0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*d0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*e0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*f0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +}; + +static const risc86_instruction_t *opcode_timings_shift[8] = +{ + &vector_alu_store_op, &vector_alu_store_op, &vector_alu_store_op, &vector_alu_store_op, + &vector_alu_store_op, &vector_alu_store_op, &vector_alu_store_op, &vector_alu_store_op +}; +static const risc86_instruction_t *opcode_timings_shift_b[8] = +{ + &vector_alux_store_op, &vector_alux_store_op, &vector_alux_store_op, &vector_alux_store_op, + &vector_alux_store_op, &vector_alux_store_op, &vector_alux_store_op, &vector_alux_store_op +}; +static const risc86_instruction_t *opcode_timings_shift_mod3[8] = +{ + &vector_alu1_op, &vector_alu1_op, &vector_alu1_op, &vector_alu1_op, + &alu_op, &alu_op, &alu_op, &alu_op +}; +static const risc86_instruction_t *opcode_timings_shift_b_mod3[8] = +{ + &vector_alux1_op, &vector_alux1_op, &vector_alux1_op, &vector_alux1_op, + &alux_op, &alux_op, &alux_op, &alux_op +}; + +static const risc86_instruction_t *opcode_timings_80[8] = +{ + &alux_store_op, &alux_store_op, &vector_alux_store_op, &vector_alux_store_op, + &alux_store_op, &alux_store_op, &alux_store_op, &alux_store_op, +}; +static const risc86_instruction_t *opcode_timings_80_mod3[8] = +{ + &alux_op, &alux_op, &alux_store_op, &alux_store_op, + &alux_op, &alux_op, &alux_op, &alux_op, +}; +static const risc86_instruction_t *opcode_timings_8x[8] = +{ + &alu_store_op, &alu_store_op, &vector_alu_store_op, &vector_alu_store_op, + &alu_store_op, &alu_store_op, &alu_store_op, &alu_store_op, +}; +static const risc86_instruction_t *opcode_timings_8x_mod3[8] = +{ + &alu_op, &alu_op, &alu_store_op, &alu_store_op, + &alu_op, &alu_op, &alu_op, &alu_op, +}; + +static const risc86_instruction_t *opcode_timings_f6[8] = +{ +/* TST NOT NEG*/ + &test_mem_imm_b_op, INVALID, &vector_alux_store_op, &vector_alux_store_op, +/* MUL IMUL DIV IDIV*/ + &vector_mul_mem_op, &vector_mul_mem_op, &vector_div16_mem_op, &vector_div16_mem_op, +}; +static const risc86_instruction_t *opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + &test_reg_b_op, INVALID, &alux_op, &alux_op, +/* MUL IMUL DIV IDIV*/ + &vector_mul_op, &vector_mul_op, &vector_div16_op, &vector_div16_op, +}; +static const risc86_instruction_t *opcode_timings_f7[8] = +{ +/* TST NOT NEG*/ + &test_mem_imm_op, INVALID, &vector_alu_store_op, &vector_alu_store_op, +/* MUL IMUL DIV IDIV*/ + &vector_mul64_mem_op, &vector_mul64_mem_op, &vector_div32_mem_op, &vector_div32_mem_op, +}; +static const risc86_instruction_t *opcode_timings_f7_mod3[8] = +{ +/* TST NOT NEG*/ + &test_reg_op, INVALID, &alu_op, &alu_op, +/* MUL IMUL DIV IDIV*/ + &vector_mul64_op, &vector_mul64_op, &vector_div32_op, &vector_div32_op, +}; +static const risc86_instruction_t *opcode_timings_ff[8] = +{ +/* INC DEC CALL CALL far*/ + &alu_store_op, &alu_store_op, &store_op, &vector_call_far_op, +/* JMP JMP far PUSH*/ + &branch_op, &vector_jmp_far_op, &push_mem_op, INVALID +}; +static const risc86_instruction_t *opcode_timings_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + &vector_alu1_op, &vector_alu1_op, &store_op, &vector_call_far_op, +/* JMP JMP far PUSH*/ + &branch_op, &vector_jmp_far_op, &vector_push_mem_op, INVALID +}; + +static const risc86_instruction_t *opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + &load_float_op, &load_float_op, &load_float_op, &load_float_op, +/* FSUBs FSUBRs FDIVs FDIVRs*/ + &load_float_op, &load_float_op, &fdiv_mem_op, &fdiv_mem_op, +}; +static const risc86_instruction_t *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + &float_op, &float_op, &float_op, &float_op, +/* FSUB FSUBR FDIV FDIVR*/ + &float_op, &float_op, &fdiv_op, &fdiv_op, +}; + +static const risc86_instruction_t *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + &load_float_op, INVALID, &fstore_op, &fstore_op, +/* FLDENV FLDCW FSTENV FSTCW*/ + &vector_float_l_op, &vector_fldcw_op, &vector_float_l_op, &vector_float_op +}; +static const risc86_instruction_t *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + &float_op, &float_op, &float_op, &float_op, + &float_op, &float_op, &float_op, &float_op, + /*FXCH*/ + &float_op, &float_op, &float_op, &float_op, + &float_op, &float_op, &float_op, &float_op, + /*FNOP*/ + &float_op, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + &float_op, &float_op, &float_op, &float_op, + &float_op, &float_op, &float_op, &float_op, +/* opFCHS opFABS*/ + &float_op, &float_op, INVALID, INVALID, +/* opFTST opFXAM*/ + &float_op, &float_op, INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + &float_op, &float_op, &float_op, &float_op, +/* opFLDEG2 opFLDLN2 opFLDZ*/ + &float_op, &float_op, &float_op, INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + &fsin_op, &fsin_op, &fsin_op, &fsin_op, +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, &float_op, &float_op, +/* opFPREM opFSQRT opFSINCOS*/ + &fdiv_op, INVALID, &fsqrt_op, &fsin_op, +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + &float_op, &fdiv_op, &fsin_op, &fsin_op +}; + +static const risc86_instruction_t *opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + &load_float_op, &load_float_op, &load_float_op, &load_float_op, +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + &load_float_op, &load_float_op, &fdiv_mem_op, &fdiv_mem_op, +}; +static const risc86_instruction_t *opcode_timings_da_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FCOMPP*/ + INVALID, &float_op, INVALID, INVALID +}; + +static const risc86_instruction_t *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + &load_float_op, INVALID, &fstore_op, &fstore_op, +/* FLDe FSTPe*/ + INVALID, &vector_flde_op, INVALID, &vector_fste_op +}; +static const risc86_instruction_t *opcode_timings_db_mod3[64] = +{ + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* opFNOP opFCLEX opFINIT*/ + INVALID, &float_op, &float_op, &float_op, +/* opFNOP opFNOP*/ + &float_op, &float_op, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +}; + +static const risc86_instruction_t *opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + &load_float_op, &load_float_op, &load_float_op, &load_float_op, +/* FSUBd FSUBRd FDIVd FDIVRd*/ + &load_float_op, &load_float_op, &fdiv_mem_op, &fdiv_mem_op, +}; +static const risc86_instruction_t *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + &float_op, &float_op, INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + &float_op, &float_op, &fdiv_op, &fdiv_op +}; + +static const risc86_instruction_t *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + &load_float_op, INVALID, &fstore_op, &fstore_op, +/* FRSTOR FSAVE FSTSW*/ + &vector_float_l_op, INVALID, &vector_float_l_op, &vector_float_l_op +}; +static const risc86_instruction_t *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + &float_op, INVALID, &float_op, &float_op, +/* FUCOM FUCOMP*/ + &float_op, &float_op, INVALID, INVALID +}; + +static const risc86_instruction_t *opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + &load_float_op, &load_float_op, &load_float_op, &load_float_op, +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + &load_float_op, &load_float_op, &fdiv_mem_op, &fdiv_mem_op, +}; +static const risc86_instruction_t *opcode_timings_de_mod3[8] = +{ +/* FADDP FMULP FCOMPP*/ + &float_op, &float_op, INVALID, &float_op, +/* FSUBP FSUBRP FDIVP FDIVRP*/ + &float_op, &float_op, &fdiv_op, &fdiv_op, +}; + +static const risc86_instruction_t *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + &load_float_op, INVALID, &fstore_op, &fstore_op, +/* FILDiq FBSTP FISTPiq*/ + INVALID, &load_float_op, &vector_float_l_op, &fstore_op, +}; +static const risc86_instruction_t *opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + &float_op, INVALID, INVALID, INVALID +}; + + +static uint8_t last_prefix; +static int prefixes; + +static int decode_timestamp; +static int last_complete_timestamp; + +typedef struct k6_unit_t +{ + uint32_t uop_mask; + int first_available_cycle; +} k6_unit_t; + +static int nr_units; +static k6_unit_t *units; + +/*K6 has dedicated MMX unit*/ +static k6_unit_t k6_units[] = +{ + {.uop_mask = (1 << UOP_ALU) | (1 << UOP_ALUX)}, /*Integer X*/ + {.uop_mask = (1 << UOP_ALU)}, /*Integer Y*/ + {.uop_mask = (1 << UOP_MEU) | (1 << UOP_MEU_SHIFT) | (1 << UOP_MEU_MUL)}, /*Multimedia*/ + {.uop_mask = (1 << UOP_FLOAT)}, /*Floating point*/ + {.uop_mask = (1 << UOP_LOAD) | (1 << UOP_FLOAD) | (1 << UOP_MLOAD)}, /*Load*/ + {.uop_mask = (1 << UOP_STORE) | (1 << UOP_FSTORE) | (1 << UOP_MSTORE)}, /*Store*/ + {.uop_mask = (1 << UOP_BRANCH)} /*Branch*/ +}; +#define NR_K6_UNITS (sizeof(k6_units) / sizeof(k6_unit_t)) + +/*K6-2 and later integrate MMX into ALU X & Y, sharing multiplier, shifter and + 3DNow ALU between two execution units*/ +static k6_unit_t k6_2_units[] = +{ + {.uop_mask = (1 << UOP_ALU) | (1 << UOP_ALUX) | (1 << UOP_MEU) | /*Integer X*/ + (1 << UOP_MEU_SHIFT) | (1 << UOP_MEU_MUL) | (1 << UOP_MEU_3DN)}, + {.uop_mask = (1 << UOP_ALU) | (1 << UOP_MEU) | /*Integer Y*/ + (1 << UOP_MEU_SHIFT) | (1 << UOP_MEU_MUL) | (1 << UOP_MEU_3DN)}, + {.uop_mask = (1 << UOP_FLOAT)}, /*Floating point*/ + {.uop_mask = (1 << UOP_LOAD) | (1 << UOP_FLOAD) | (1 << UOP_MLOAD)}, /*Load*/ + {.uop_mask = (1 << UOP_STORE) | (1 << UOP_FSTORE) | (1 << UOP_MSTORE)}, /*Store*/ + {.uop_mask = (1 << UOP_BRANCH)} /*Branch*/ +}; +#define NR_K6_2_UNITS (sizeof(k6_2_units) / sizeof(k6_unit_t)) + +/*First available cycles of shared execution units. Each of these can be submitted + to by ALU X and Y*/ +static int mul_first_available_cycle; +static int shift_first_available_cycle; +static int m3dnow_first_available_cycle; + +static int uop_run(const risc86_uop_t *uop, int decode_time) +{ + int c; + k6_unit_t *best_unit = NULL; + int best_start_cycle = 99999; + + /*UOP_LIMM does not require execution*/ + if (uop->type == UOP_LIMM) + return decode_time; + + /*Handle shared units on K6-2 and later*/ + if (units == k6_2_units) + { + if (uop->type == UOP_MEU_MUL && decode_time < mul_first_available_cycle) + decode_time = mul_first_available_cycle; + else if (uop->type == UOP_MEU_SHIFT && decode_time < mul_first_available_cycle) + decode_time = shift_first_available_cycle; + else if (uop->type == UOP_MEU_3DN && decode_time < mul_first_available_cycle) + decode_time = m3dnow_first_available_cycle; + } + + /*Find execution unit for this uOP*/ + for (c = 0; c < nr_units; c++) + { + if (units[c].uop_mask & (1 << uop->type)) + { + if (units[c].first_available_cycle < best_start_cycle) + { + best_unit = &units[c]; + best_start_cycle = units[c].first_available_cycle; + } + } + } + if (!best_unit) + fatal("uop_run: can not find execution unit\n"); + + if (best_start_cycle < decode_time) + best_start_cycle = decode_time; + best_unit->first_available_cycle = best_start_cycle + uop->throughput; + + if (units == k6_2_units) + { + if (uop->type == UOP_MEU_MUL) + mul_first_available_cycle = best_start_cycle + uop->throughput; + else if (uop->type == UOP_MEU_SHIFT) + shift_first_available_cycle = best_start_cycle + uop->throughput; + else if (uop->type == UOP_MEU_3DN) + m3dnow_first_available_cycle = best_start_cycle + uop->throughput; + } + + return best_start_cycle + uop->throughput; +} + +/*The K6 decoder can decode, per clock : + - 1 or 2 'short' instructions, each up to 2 uOPs and 7 bytes long + - 1 'long' instruction, up to 4 uOPs + - 1 'vector' instruction, up to 4 uOPs per cycle, plus (I think) 1 cycle startup delay) +*/ +static struct +{ + int nr_uops; + const risc86_uop_t *uops[4]; + /*Earliest time a uop can start. If the timestamp is -1, then the uop is + part of a dependency chain and the start time is the completion time of + the previous uop*/ + int earliest_start[4]; +} decode_buffer; + +#define NR_OPQUADS 6 +/*Timestamps of when the last six opquads completed. The K6 scheduler retires + opquads in order, so this is needed to determine when the next can be scheduled*/ +static int opquad_completion_timestamp[NR_OPQUADS]; +static int next_opquad = 0; + +#define NR_REGS 8 +/*Timestamp of when last operation on an integer register completed*/ +static int reg_available_timestamp[NR_REGS]; +/*Timestamp of when last operation on an FPU register completed*/ +static int fpu_st_timestamp[8]; +/*Completion time of the last uop to be processed. Used to calculate timing of + dependent uop chains*/ +static int last_uop_timestamp = 0; + +void decode_flush() +{ + int c; + int uop_timestamp = 0; + + /*Decoded opquad can not be submitted if there are no free spaces in the + opquad buffer*/ + if (decode_timestamp < opquad_completion_timestamp[next_opquad]) + decode_timestamp = opquad_completion_timestamp[next_opquad]; + + /*Ensure that uops can not be submitted before they have been decoded*/ + if (decode_timestamp > last_uop_timestamp) + last_uop_timestamp = decode_timestamp; + + /*Submit uops to execution units, and determine the latest completion time*/ + for (c = 0; c < decode_buffer.nr_uops; c++) + { + int start_timestamp; + + if (decode_buffer.earliest_start[c] == -1) + start_timestamp = last_uop_timestamp; + else + start_timestamp = decode_buffer.earliest_start[c]; + + last_uop_timestamp = uop_run(decode_buffer.uops[c], start_timestamp); + if (last_uop_timestamp > uop_timestamp) + uop_timestamp = last_uop_timestamp; + } + + /*Calculate opquad completion time. Since opquads complete in order, it + must be after the last completion.*/ + if (uop_timestamp <= last_complete_timestamp) + last_complete_timestamp = last_complete_timestamp + 1; + else + last_complete_timestamp = uop_timestamp; + + /*Advance to next opquad in buffer*/ + opquad_completion_timestamp[next_opquad] = last_complete_timestamp; + next_opquad++; + if (next_opquad == NR_OPQUADS) + next_opquad = 0; + + decode_timestamp++; + decode_buffer.nr_uops = 0; +} + +/*The instruction is only of interest here if it's longer than 7 bytes, as that's the + limit on K6 short decoding*/ +static int codegen_timing_instr_length(uint64_t deps, uint32_t fetchdat, int op_32) +{ + int len = prefixes + 1; /*Opcode*/ + if (deps & MODRM) + { + len++; /*ModR/M*/ + if (deps & HAS_IMM8) + len++; + if (deps & HAS_IMM1632) + len += (op_32 & 0x100) ? 4 : 2; + + if (op_32 & 0x200) + { + if ((fetchdat & 7) == 4 && (fetchdat & 0xc0) != 0xc0) + { + /* Has SIB*/ + len++; + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0x700) == 0x500) + len += 4; + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0xc7) == 0x05) + len += 4; + } + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 2; + else if ((fetchdat & 0xc7) == 0x06) + len += 2; + } + } + + return len; +} + +static void decode_instruction(const risc86_instruction_t *ins, uint64_t deps, uint32_t fetchdat, int op_32, int bit8) +{ + uint32_t regmask_required; + uint32_t regmask_modified; + int c, d; + int earliest_start = 0; + decode_type_t decode_type = ins->decode_type; + int instr_length = codegen_timing_instr_length(deps, fetchdat, op_32); + + /*Generate input register mask, and determine the earliest time this + instruction can start. This is not accurate, as this is calculated per + x86 instruction when it should be handled per uop*/ + regmask_required = get_dstdep_mask(deps, fetchdat, bit8); + regmask_required |= get_addr_regmask(deps, fetchdat, op_32); + for (c = 0; c < 8; c++) + { + if (regmask_required & (1 << c)) + { + if (reg_available_timestamp[c] > decode_timestamp) + earliest_start = reg_available_timestamp[c]; + } + } + if ((deps & FPU_RW_ST0) && fpu_st_timestamp[0] > decode_timestamp) + earliest_start = fpu_st_timestamp[0]; + if ((deps & FPU_RW_ST1) && fpu_st_timestamp[1] > decode_timestamp) + earliest_start = fpu_st_timestamp[1]; + if ((deps & FPU_RW_STREG)) + { + int reg = fetchdat & 7; + + if (fpu_st_timestamp[reg] > decode_timestamp) + earliest_start = fpu_st_timestamp[reg]; + } + + /*Short decoders are limited to 7 bytes*/ + if (decode_type == DECODE_SHORT && instr_length > 7) + decode_type = DECODE_LONG; + /*Long decoder is limited to 11 bytes*/ + else if (instr_length > 11) + decode_type = DECODE_VECTOR; + + switch (decode_type) + { + case DECODE_SHORT: + if (decode_buffer.nr_uops) + { + decode_buffer.uops[decode_buffer.nr_uops] = &ins->uop[0]; + decode_buffer.earliest_start[decode_buffer.nr_uops] = earliest_start; + if (ins->nr_uops > 1) + { + decode_buffer.uops[decode_buffer.nr_uops+1] = &ins->uop[1]; + decode_buffer.earliest_start[decode_buffer.nr_uops+1] = -1; + } + decode_buffer.nr_uops += ins->nr_uops; + + decode_flush(); + } + else + { + decode_buffer.nr_uops = ins->nr_uops; + decode_buffer.uops[0] = &ins->uop[0]; + decode_buffer.earliest_start[0] = earliest_start; + if (ins->nr_uops > 1) + { + decode_buffer.uops[1] = &ins->uop[1]; + decode_buffer.earliest_start[1] = -1; + } + } + break; + + case DECODE_LONG: + if (decode_buffer.nr_uops) + decode_flush(); + + decode_buffer.nr_uops = ins->nr_uops; + for (c = 0; c < ins->nr_uops; c++) + { + decode_buffer.uops[c] = &ins->uop[c]; + if (c == 0) + decode_buffer.earliest_start[c] = earliest_start; + else + decode_buffer.earliest_start[c] = -1; + } + decode_flush(); + break; + + case DECODE_VECTOR: + if (decode_buffer.nr_uops) + decode_flush(); + + decode_timestamp++; + d = 0; + + for (c = 0; c < ins->nr_uops; c++) + { + decode_buffer.uops[d] = &ins->uop[c]; + if (c == 0) + decode_buffer.earliest_start[d] = earliest_start; + else + decode_buffer.earliest_start[d] = -1; + d++; + + if (d == 4) + { + d = 0; + decode_buffer.nr_uops = 4; + decode_flush(); + } + } + if (d) + { + decode_buffer.nr_uops = d; + decode_flush(); + } + break; + } + + /*Update write timestamps for any output registers*/ + regmask_modified = get_dstdep_mask(deps, fetchdat, bit8); + for (c = 0; c < 8; c++) + { + if (regmask_modified & (1 << c)) + reg_available_timestamp[c] = last_complete_timestamp; + } + if (deps & FPU_POP) + { + for (c = 0; c < 7; c++) + fpu_st_timestamp[c] = fpu_st_timestamp[c+1]; + fpu_st_timestamp[7] = 0; + } + if (deps & FPU_POP2) + { + for (c = 0; c < 6; c++) + fpu_st_timestamp[c] = fpu_st_timestamp[c+2]; + fpu_st_timestamp[6] = fpu_st_timestamp[7] = 0; + } + if (deps & FPU_PUSH) + { + for (c = 0; c < 7; c++) + fpu_st_timestamp[c+1] = fpu_st_timestamp[c]; + fpu_st_timestamp[0] = 0; + } + if (deps & FPU_WRITE_ST0) + fpu_st_timestamp[0] = last_complete_timestamp; + if (deps & FPU_WRITE_ST1) + fpu_st_timestamp[1] = last_complete_timestamp; + if (deps & FPU_WRITE_STREG) + { + int reg = fetchdat & 7; + if (deps & FPU_POP) + reg--; + if (reg >= 0 && + !(reg == 0 && (deps & FPU_WRITE_ST0)) && + !(reg == 1 && (deps & FPU_WRITE_ST1))) + fpu_st_timestamp[reg] = last_complete_timestamp; + } +} + +void codegen_timing_k6_block_start() +{ + int c; + + for (c = 0; c < nr_units; c++) + units[c].first_available_cycle = 0; + + mul_first_available_cycle = 0; + shift_first_available_cycle = 0; + m3dnow_first_available_cycle = 0; + + decode_timestamp = 0; + last_complete_timestamp = 0; + + for (c = 0; c < NR_OPQUADS; c++) + opquad_completion_timestamp[c] = 0; + next_opquad = 0; + + for (c = 0; c < NR_REGS; c++) + reg_available_timestamp[c] = 0; + for (c = 0; c < 8; c++) + fpu_st_timestamp[c] = 0; +} + +void codegen_timing_k6_start() +{ + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_K6) + { + units = k6_units; + nr_units = NR_K6_UNITS; + } + else + { + units = k6_2_units; + nr_units = NR_K6_2_UNITS; + } + last_prefix = 0; + prefixes = 0; +} + +void codegen_timing_k6_prefix(uint8_t prefix, uint32_t fetchdat) +{ + if (prefix != 0x0f) + decode_timestamp++; + + last_prefix = prefix; + prefixes++; +} + +void codegen_timing_k6_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +{ + const risc86_instruction_t **ins_table; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int old_last_complete_timestamp = last_complete_timestamp; + int bit8 = !(opcode & 1); + + switch (last_prefix) + { + case 0x0f: + if (opcode == 0x0f) + { + /*3DNow has the actual opcode after ModR/M, SIB and any offset*/ + uint32_t opcode_pc = op_pc + 1; /*Byte after ModR/M*/ + uint8_t modrm = fetchdat & 0xff; + uint8_t sib = (fetchdat >> 8) & 0xff; + + if ((modrm & 0xc0) != 0xc0) + { + if (op_32 & 0x200) + { + if ((modrm & 7) == 4) + { + /* Has SIB*/ + opcode_pc++; + if ((modrm & 0xc0) == 0x40) + opcode_pc++; + else if ((modrm & 0xc0) == 0x80) + opcode_pc += 4; + else if ((sib & 0x07) == 0x05) + opcode_pc += 4; + } + else + { + if ((modrm & 0xc0) == 0x40) + opcode_pc++; + else if ((modrm & 0xc0) == 0x80) + opcode_pc += 4; + else if ((modrm & 0xc7) == 0x05) + opcode_pc += 4; + } + } + else + { + if ((modrm & 0xc0) == 0x40) + opcode_pc++; + else if ((modrm & 0xc0) == 0x80) + opcode_pc += 2; + else if ((modrm & 0xc7) == 0x06) + opcode_pc += 2; + } + } + + opcode = fastreadb(cs + opcode_pc); + + ins_table = mod3 ? opcode_timings_0f0f_mod3 : opcode_timings_0f0f; + deps = mod3 ? opcode_deps_0f0f_mod3 : opcode_deps_0f0f; + } + else + { + ins_table = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; + } + break; + + case 0xd8: + ins_table = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + ins_table = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + ins_table = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + ins_table = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + ins_table = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + ins_table = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + ins_table = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + ins_table = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: + ins_table = mod3 ? opcode_timings_80_mod3 : opcode_timings_80; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x; + opcode = (fetchdat >> 3) & 7; + break; + case 0x81: case 0x83: + ins_table = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xd0: case 0xd2: + ins_table = mod3 ? opcode_timings_shift_b_mod3 : opcode_timings_shift_b; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc1: case 0xd1: case 0xd3: + ins_table = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + ins_table = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + ins_table = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + ins_table = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + ins_table = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + break; + } + } + + if (ins_table[opcode]) + decode_instruction(ins_table[opcode], deps[opcode], fetchdat, op_32, bit8); + else + decode_instruction(&vector_alu1_op, 0, fetchdat, op_32, bit8); + codegen_block_cycles += (last_complete_timestamp - old_last_complete_timestamp); +} + +void codegen_timing_k6_block_end() +{ + if (decode_buffer.nr_uops) + { + int old_last_complete_timestamp = last_complete_timestamp; + decode_flush(); + codegen_block_cycles += (last_complete_timestamp - old_last_complete_timestamp); + } +} + +int codegen_timing_k6_jump_cycles() +{ + if (decode_buffer.nr_uops) + return 1; + return 0; +} + +codegen_timing_t codegen_timing_k6 = +{ + codegen_timing_k6_start, + codegen_timing_k6_prefix, + codegen_timing_k6_opcode, + codegen_timing_k6_block_start, + codegen_timing_k6_block_end, + codegen_timing_k6_jump_cycles +}; diff --git a/src/cpu_new/codegen_timing_pentium.c b/src/cpu_new/codegen_timing_pentium.c new file mode 100644 index 000000000..ee893a361 --- /dev/null +++ b/src/cpu_new/codegen_timing_pentium.c @@ -0,0 +1,1327 @@ +/*Elements taken into account : + - U/V integer pairing + - FPU/FXCH pairing + - Prefix decode delay (including shadowing) + - FPU latencies + - AGI stalls + Elements not taken into account : + - Branch prediction (beyond most simplistic approximation) + - PMMX decode queue + - MMX latencies +*/ + +#include +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + + + +/*Instruction has different execution time for 16 and 32 bit data. Does not pair */ +#define CYCLES_HAS_MULTI (1 << 28) + +#define CYCLES_MULTI(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*Instruction lasts given number of cycles. Does not pair*/ +#define CYCLES(c) (c | PAIR_NP) + + +static int pair_timings[4][4] = +{ +/* Reg RM RMW Branch*/ +/*Reg*/ {1, 2, 3, 2}, +/*RM*/ {2, 2, 3, 3}, +/*RMW*/ {3, 4, 5, 4}, +/*Branch*/ {-1, -1, -1, -1} +}; + +/*Instruction follows either register timing, read-modify, or read-modify-write. + May be pairable*/ +#define CYCLES_REG (0ull << 0) +#define CYCLES_RM (1ull << 0) +#define CYCLES_RMW (2ull << 0) +#define CYCLES_BRANCH (3ull << 0) + +/*Instruction has immediate data. Can only be used with PAIR_U/PAIR_V/PAIR_UV*/ +#define CYCLES_HASIMM (3ull << 2) +#define CYCLES_IMM8 (1ull << 2) +#define CYCLES_IMM1632 (2ull << 2) + +#define CYCLES_MASK ((1ull << 7) - 1) + + +/*Instruction does not pair*/ +#define PAIR_NP (0ull << 29) +/*Instruction pairs in U pipe only*/ +#define PAIR_U (1ull << 29) +/*Instruction pairs in V pipe only*/ +#define PAIR_V (2ull << 29) +/*Instruction pairs in both U and V pipes*/ +#define PAIR_UV (3ull << 29) +/*Instruction pairs in U pipe only and only with FXCH*/ +#define PAIR_FX (5ull << 29) +/*Instruction is FXCH and only pairs in V pipe with FX pairable instruction*/ +#define PAIR_FXCH (6ull << 29) + +#define PAIR_FPU (4ull << 29) + +#define PAIR_MASK (7ull << 29) + + +/*comp_time = cycles until instruction complete + i_overlap = cycles that overlap with integer + f_overlap = cycles that overlap with subsequent FPU*/ +#define FPU_CYCLES(comp_time, i_overlap, f_overlap) ((uint64_t)comp_time) | ((uint64_t)i_overlap << 41) | ((uint64_t)f_overlap << 49) | PAIR_FPU + +#define FPU_COMP_TIME(timing) (timing & 0xff) +#define FPU_I_OVERLAP(timing) ((timing >> 41) & 0xff) +#define FPU_F_OVERLAP(timing) ((timing >> 49) & 0xff) + +#define FPU_I_LATENCY(timing) (FPU_COMP_TIME(timing) - FPU_I_OVERLAP(timing)) + +#define FPU_F_LATENCY(timing) (FPU_I_OVERLAP(timing) - FPU_F_OVERLAP(timing)) + +#define FPU_RESULT_LATENCY(timing) ((timing >> 41) & 0xff) + + +#define INVALID 0 + +static int u_pipe_full; +static uint32_t u_pipe_opcode; +static uint64_t *u_pipe_timings; +static uint32_t u_pipe_op_32; +static uint32_t u_pipe_regmask; +static uint32_t u_pipe_fetchdat; +static int u_pipe_decode_delay_offset; +static uint64_t *u_pipe_deps; + +static uint32_t regmask_modified; + +static uint32_t addr_regmask; + +static int fpu_latency; +static int fpu_st_latency[8]; + +static uint64_t opcode_timings[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* ADD ADD PUSH ES POP ES*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* OR OR PUSH CS */ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(1), INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, +/* ADC ADC PUSH SS POP SS*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, +/* SBB SBB PUSH DS POP DS*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* AND AND DAA*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), +/* SUB SUB SUB SUB*/ + PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* SUB SUB DAS*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* XOR XOR AAA*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), +/* CMP CMP CMP CMP*/ + PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* CMP CMP AAS*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(8), PAIR_NP | CYCLES(7), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(13), + +/* Jxx*/ +/*70*/ PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MOV MOV MOV MOV*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_NP | CYCLES(1), PAIR_UV | CYCLES_REG, CYCLES(3), PAIR_NP | CYCLES(3), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(1), +/* PUSHF POPF SAHF LAHF*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), + +/* MOV*/ +/*b0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_NP | CYCLES(15), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), +/* CALL JMP JMP JMP*/ + PAIR_V | CYCLES_REG, PAIR_V | CYCLES_REG, PAIR_NP | CYCLES(0), PAIR_V | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_RMW, INVALID +}; + +static uint64_t opcode_timings_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* OR OR PUSH CS */ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(1), INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* AND AND DAA*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), +/* SUB SUB SUB SUB*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* SUB SUB DAS*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* XOR XOR AAA*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), +/* CMP CMP CMP CMP*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* CMP CMP AAS*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(8), PAIR_NP | CYCLES(7), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(13), + +/* Jxx*/ +/*70*/ PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + +/*80*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* TEST TEST XCHG XCHG*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MOV MOV MOV MOV*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_NP | CYCLES(1), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(1), +/* PUSHF POPF SAHF LAHF*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), + +/* MOV*/ +/*b0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_NP | CYCLES(15), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), +/* CALL JMP JMP JMP*/ + PAIR_V | CYCLES_REG, PAIR_V | CYCLES_REG, PAIR_NP | CYCLES(0), PAIR_V | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_REG, INVALID +}; + +static uint64_t opcode_timings_0f[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + INVALID, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + +/*70*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_NP | CYCLES(100), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + +/*80*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/*90*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*a0*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(8), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), INVALID, INVALID, + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + INVALID, INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + +/*e0*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, + INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + +/*f0*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, +}; +static uint64_t opcode_timings_0f_mod3[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + INVALID, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/*70*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(100), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/*80*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/*90*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*a0*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(8), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), INVALID, INVALID, + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + INVALID, INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + INVALID, PAIR_UV | CYCLES_REG, INVALID, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + +/*e0*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, + INVALID, PAIR_UV | CYCLES_REG, INVALID, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + +/*f0*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + INVALID, PAIR_UV | CYCLES_REG, INVALID, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, +}; + +static uint64_t opcode_timings_shift[8] = +{ + PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, + PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, +}; +static uint64_t opcode_timings_shift_mod3[8] = +{ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, +}; + +static uint64_t opcode_timings_f6[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(17), PAIR_NP | CYCLES(22) +}; +static uint64_t opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(17), PAIR_NP | CYCLES(22) +}; +static uint64_t opcode_timings_f7[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(25,41), PAIR_NP | CYCLES_MULTI(30,46) +}; +static uint64_t opcode_timings_f7_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(25,41), PAIR_NP | CYCLES_MULTI(30,46) +}; +static uint64_t opcode_timings_ff[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), +/* JMP JMP far PUSH*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(2), INVALID +}; +static uint64_t opcode_timings_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), +/* JMP JMP far PUSH*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(2), INVALID +}; + +static uint64_t opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) +}; +static uint64_t opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) +}; + +static uint64_t opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + PAIR_FX | FPU_CYCLES(1,0,0), INVALID, PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(2,0,0), +/* FLDENV FLDCW FSTENV FSTCW*/ + PAIR_NP | FPU_CYCLES(32,0,0), PAIR_NP | FPU_CYCLES(8,0,0), PAIR_NP | FPU_CYCLES(48,0,0), PAIR_NP | FPU_CYCLES(2,0,0) +}; +static uint64_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), + PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), + /*FXCH*/ + PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), + PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), + /*FNOP*/ + PAIR_NP | FPU_CYCLES(3,0,0), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), +/* opFCHS opFABS*/ + PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), INVALID, INVALID, +/* opFTST opFXAM*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(21,4,0), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(5,2,2), PAIR_NP | FPU_CYCLES(5,2,2), PAIR_NP | FPU_CYCLES(5,2,2), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + PAIR_NP | FPU_CYCLES(5,2,2), PAIR_NP | FPU_CYCLES(5,2,2), PAIR_NP | FPU_CYCLES(2,0,0), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + PAIR_NP | FPU_CYCLES(53,2,2), PAIR_NP | FPU_CYCLES(103,2,2), PAIR_NP | FPU_CYCLES(120,36,0), PAIR_NP | FPU_CYCLES(112,2,2), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(2,0,0), +/* opFPREM opFSQRT opFSINCOS*/ + PAIR_NP | FPU_CYCLES(64,2,2), INVALID, PAIR_NP | FPU_CYCLES(70,69,2), PAIR_NP | FPU_CYCLES(89,2,2), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + PAIR_NP | FPU_CYCLES(9,0,0), PAIR_NP | FPU_CYCLES(20,5,0), PAIR_NP | FPU_CYCLES(65,2,2), PAIR_NP | FPU_CYCLES(65,2,2) +}; + +static uint64_t opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(4,0,0), PAIR_NP | FPU_CYCLES(4,0,0), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(42,38,2), PAIR_NP | FPU_CYCLES(42,38,2) +}; +static uint64_t opcode_timings_da_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FCOMPP*/ + INVALID, PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID +}; + + +static uint64_t opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + PAIR_NP | FPU_CYCLES(3,2,2), INVALID, PAIR_NP | FPU_CYCLES(6,0,0), PAIR_NP | FPU_CYCLES(6,0,0), +/* FLDe FSTPe*/ + INVALID, PAIR_NP | FPU_CYCLES(3,0,0), INVALID, PAIR_NP | FPU_CYCLES(3,0,0) +}; +static uint64_t opcode_timings_db_mod3[64] = +{ + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* opFNOP opFCLEX opFINIT*/ + INVALID, PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(7,0,0), PAIR_NP | FPU_CYCLES(17,0,0), +/* opFNOP opFNOP*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +}; + +static uint64_t opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) +}; +static uint64_t opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) +}; + +static uint64_t opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + PAIR_FX | FPU_CYCLES(1,0,0), INVALID, PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(2,0,0), +/* FRSTOR FSAVE FSTSW*/ + PAIR_NP | FPU_CYCLES(70,0,0), INVALID, PAIR_NP | FPU_CYCLES(127,0,0), PAIR_NP | FPU_CYCLES(6,0,0) +}; +static uint64_t opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + PAIR_NP | FPU_CYCLES(2,0,0), INVALID, PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), +/* FUCOM FUCOMP*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID +}; + +static uint64_t opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(4,0,0), PAIR_NP | FPU_CYCLES(4,0,0), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(42,38,2), PAIR_NP | FPU_CYCLES(42,38,2) +}; +static uint64_t opcode_timings_de_mod3[8] = +{ +/* FADDP FMULP FCOMPP*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), INVALID, PAIR_FX | FPU_CYCLES(1,0,0), +/* FSUBP FSUBRP FDIVP FDIVRP*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) +}; + +static uint64_t opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + PAIR_NP | FPU_CYCLES(3,2,2), INVALID, PAIR_NP | FPU_CYCLES(6,0,0), PAIR_NP | FPU_CYCLES(6,0,0), +/* FILDiq FBSTP FISTPiq*/ + INVALID, PAIR_NP | FPU_CYCLES(3,2,2), PAIR_NP | FPU_CYCLES(148,0,0), PAIR_NP | FPU_CYCLES(6,0,0) +}; +static uint64_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + PAIR_NP | FPU_CYCLES(6,0,0), INVALID, INVALID, INVALID +}; + +static uint64_t opcode_timings_81[8] = +{ + PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, + PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RM | CYCLES_IMM1632 +}; +static uint64_t opcode_timings_81_mod3[8] = +{ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG +}; +static uint64_t opcode_timings_8x[8] = +{ + PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, + PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RM | CYCLES_IMM8 +}; +static uint64_t opcode_timings_8x_mod3[8] = +{ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG +}; + +static int decode_delay, decode_delay_offset; +static uint8_t last_prefix; +static int prefixes; + +static inline int COUNT(uint64_t timings, uint64_t deps, int op_32) +{ + if ((timings & PAIR_FPU) && !(deps & FPU_FXCH)) + return FPU_I_LATENCY(timings); + if (timings & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return ((uintptr_t)timings >> 8) & 0xff; + return (uintptr_t)timings & 0xff; + } + if (!(timings & PAIR_MASK)) + return timings & 0xffff; + if ((timings & PAIR_MASK) == PAIR_FX) + return timings & 0xffff; + if ((timings & PAIR_MASK) == PAIR_FXCH) + return timings & 0xffff; + if ((timings & PAIR_UV) && !(timings & PAIR_FPU)) + timings &= 3; + switch (timings & CYCLES_MASK) + { + case CYCLES_REG: + return 1; + case CYCLES_RM: + return 2; + case CYCLES_RMW: + return 3; + case CYCLES_BRANCH: + return cpu_has_feature(CPU_FEATURE_MMX) ? 1 : 2; + } + + fatal("Illegal COUNT %016llx\n", timings); + + return timings; +} + +static int codegen_fpu_latencies(uint64_t deps, int reg) +{ + int latency = fpu_latency; + + if ((deps & FPU_RW_ST0) && fpu_st_latency[0] && fpu_st_latency[0] > latency) + latency = fpu_st_latency[0]; + if ((deps & FPU_RW_ST1) && fpu_st_latency[1] && fpu_st_latency[1] > latency) + latency = fpu_st_latency[1]; + if ((deps & FPU_RW_STREG) && fpu_st_latency[reg] && fpu_st_latency[reg] > latency) + latency = fpu_st_latency[reg]; + + return latency; +} + +#define SUB_AND_CLAMP(latency, count) \ + latency -= count; \ + if (latency < 0) \ + latency = 0 + +static void codegen_fpu_latency_clock(int count) +{ + SUB_AND_CLAMP(fpu_latency, count); + SUB_AND_CLAMP(fpu_st_latency[0], count); + SUB_AND_CLAMP(fpu_st_latency[1], count); + SUB_AND_CLAMP(fpu_st_latency[2], count); + SUB_AND_CLAMP(fpu_st_latency[3], count); + SUB_AND_CLAMP(fpu_st_latency[4], count); + SUB_AND_CLAMP(fpu_st_latency[5], count); + SUB_AND_CLAMP(fpu_st_latency[6], count); + SUB_AND_CLAMP(fpu_st_latency[7], count); +} + +static inline int codegen_timing_has_displacement(uint32_t fetchdat, int op_32) +{ + if (op_32 & 0x200) + { + if ((fetchdat & 7) == 4 && (fetchdat & 0xc0) != 0xc0) + { + /*Has SIB*/ + if ((fetchdat & 0xc0) == 0x40 || (fetchdat & 0xc0) == 0x80 || (fetchdat & 0x700) == 0x500) + return 1; + } + else + { + if ((fetchdat & 0xc0) == 0x40 || (fetchdat & 0xc0) == 0x80 || (fetchdat & 0xc7) == 0x05) + return 1; + } + } + else + { + if ((fetchdat & 0xc0) == 0x40 || (fetchdat & 0xc0) == 0x80 || (fetchdat & 0xc7) == 0x06) + return 1; + } + return 0; +} + +/*The instruction is only of interest here if it's longer than 7 bytes, as that's the + limit on Pentium MMX parallel decoding*/ +static inline int codegen_timing_instr_length(uint64_t timing, uint32_t fetchdat, int op_32) +{ + int len = prefixes; + if ((timing & CYCLES_MASK) == CYCLES_RM || (timing & CYCLES_MASK) == CYCLES_RMW) + { + len += 2; /*Opcode + ModR/M*/ + if ((timing & CYCLES_HASIMM) == CYCLES_IMM8) + len++; + if ((timing & CYCLES_HASIMM) == CYCLES_IMM1632) + len += (op_32 & 0x100) ? 4 : 2; + + if (op_32 & 0x200) + { + if ((fetchdat & 7) == 4 && (fetchdat & 0xc0) != 0xc0) + { + /* Has SIB*/ + len++; + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0x700) == 0x500) + len += 4; + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0xc7) == 0x05) + len += 4; + } + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 2; + else if ((fetchdat & 0xc7) == 0x06) + len += 2; + } + } + + return len; +} + +void codegen_timing_pentium_block_start() +{ + u_pipe_full = decode_delay = decode_delay_offset = 0; +} + +void codegen_timing_pentium_start() +{ +// decode_delay = 0; + last_prefix = 0; + prefixes = 0; +} + +void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat) +{ + prefixes++; + if ((prefix & 0xf8) == 0xd8) + { + last_prefix = prefix; + return; + } + if (cpu_has_feature(CPU_FEATURE_MMX) && prefix == 0x0f) + { + /*On Pentium MMX 0fh prefix is 'free'*/ + last_prefix = prefix; + return; + } + if (cpu_has_feature(CPU_FEATURE_MMX) && (prefix == 0x66 || prefix == 0x67)) + { + /*On Pentium MMX 66h and 67h prefixes take 2 clocks*/ + decode_delay_offset += 2; + last_prefix = prefix; + return; + } + if (prefix == 0x0f && (fetchdat & 0xf0) == 0x80) + { + /*On Pentium 0fh prefix is 'free' when used on conditional jumps*/ + last_prefix = prefix; + return; + } + /*On Pentium all prefixes take 1 cycle to decode. Decode may be shadowed + by execution of previous instructions*/ + decode_delay_offset++; + last_prefix = prefix; +} + +static int check_agi(uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int op_32) +{ + uint32_t addr_regmask = get_addr_regmask(deps[opcode], fetchdat, op_32); + + /*Instructions that use ESP implicitly (eg PUSH, POP, CALL etc) do not + cause AGIs with each other, but do with instructions that use it explicitly*/ + if ((addr_regmask & REGMASK_IMPL_ESP) && (regmask_modified & (1 << REG_ESP)) && !(regmask_modified & REGMASK_IMPL_ESP)) + addr_regmask |= (1 << REG_ESP); + + return (regmask_modified & addr_regmask) & ~REGMASK_IMPL_ESP; +} + +static void codegen_instruction(uint64_t *timings, uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int decode_delay_offset, int op_32, int exec_delay) +{ + int instr_cycles, latency = 0; + + if ((timings[opcode] & PAIR_FPU) && !(deps[opcode] & FPU_FXCH)) + instr_cycles = latency = codegen_fpu_latencies(deps[opcode], fetchdat & 7); + else + { +/* if (timings[opcode] & FPU_WRITE_ST0) + fatal("FPU_WRITE_ST0\n"); + if (timings[opcode] & FPU_WRITE_ST1) + fatal("FPU_WRITE_ST1\n"); + if (timings[opcode] & FPU_WRITE_STREG) + fatal("FPU_WRITE_STREG\n");*/ + instr_cycles = 0; + } + + if ((decode_delay + decode_delay_offset) > 0) + codegen_fpu_latency_clock(decode_delay + decode_delay_offset + instr_cycles); + else + codegen_fpu_latency_clock(instr_cycles); + instr_cycles += COUNT(timings[opcode], deps[opcode], op_32); + instr_cycles += exec_delay; + if ((decode_delay + decode_delay_offset) > 0) + codegen_block_cycles += instr_cycles + decode_delay + decode_delay_offset; + else + codegen_block_cycles += instr_cycles; + + decode_delay = (-instr_cycles) + 1; + + if (deps[opcode] & FPU_POP) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c] = fpu_st_latency[c+1]; + fpu_st_latency[7] = 0; + } + if (deps[opcode] & FPU_POP2) + { + int c; + + for (c = 0; c < 6; c++) + fpu_st_latency[c] = fpu_st_latency[c+2]; + fpu_st_latency[6] = fpu_st_latency[7] = 0; + } + if ((timings[opcode] & PAIR_FPU) && !(deps[opcode] & FPU_FXCH)) + { + /* if (fpu_latency) + fatal("Bad latency FPU\n");*/ + fpu_latency = FPU_F_LATENCY(timings[opcode]); + } + + if (deps[opcode] & FPU_PUSH) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c+1] = fpu_st_latency[c]; + fpu_st_latency[0] = 0; + } + if (deps[opcode] & FPU_WRITE_ST0) + { +/* if (fpu_st_latency[0]) + fatal("Bad latency ST0\n");*/ + fpu_st_latency[0] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (deps[opcode] & FPU_WRITE_ST1) + { +/* if (fpu_st_latency[1]) + fatal("Bad latency ST1\n");*/ + fpu_st_latency[1] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (deps[opcode] & FPU_WRITE_STREG) + { + int reg = fetchdat & 7; + if (deps[opcode] & FPU_POP) + reg--; + if (reg >= 0 && + !(reg == 0 && (deps[opcode] & FPU_WRITE_ST0)) && + !(reg == 1 && (deps[opcode] & FPU_WRITE_ST1))) + { + fpu_st_latency[reg] = FPU_RESULT_LATENCY(timings[opcode]); + } + } +} + +void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +{ + uint64_t *timings; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + int agi_stall = 0; + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_cl_mod3 : opcode_deps_shift_cl; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + break; + } + } + + if (u_pipe_full) + { + uint8_t regmask = get_srcdep_mask(deps[opcode], fetchdat, bit8, u_pipe_op_32); + + if ((u_pipe_timings[u_pipe_opcode] & PAIR_MASK) == PAIR_FX && + (timings[opcode] & PAIR_MASK) != PAIR_FXCH) + goto nopair; + + if ((timings[opcode] & PAIR_MASK) == PAIR_FXCH && + (u_pipe_timings[u_pipe_opcode] & PAIR_MASK) != PAIR_FX) + goto nopair; + + if ((u_pipe_timings[u_pipe_opcode] & PAIR_MASK) == PAIR_FX && + (timings[opcode] & PAIR_MASK) == PAIR_FXCH) + { + int temp; + + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + + codegen_instruction(u_pipe_timings, u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32, agi_stall); + + temp = fpu_st_latency[fetchdat & 7]; + fpu_st_latency[fetchdat & 7] = fpu_st_latency[0]; + fpu_st_latency[0] = temp; + + u_pipe_full = 0; + decode_delay_offset = 0; + regmask_modified = u_pipe_regmask; + addr_regmask = 0; + return; + } + + if ((timings[opcode] & PAIR_V) && !(u_pipe_regmask & regmask) && (decode_delay+decode_delay_offset+u_pipe_decode_delay_offset) <= 0) + { + int has_displacement; + + if (timings[opcode] & CYCLES_HASIMM) + has_displacement = codegen_timing_has_displacement(fetchdat, op_32); + else + has_displacement = 0; + + if (!has_displacement && (!cpu_has_feature(CPU_FEATURE_MMX) || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) + { + int t1 = u_pipe_timings[u_pipe_opcode] & CYCLES_MASK; + int t2 = timings[opcode] & CYCLES_MASK; + int t_pair; + uint64_t temp_timing; + uint64_t temp_deps = 0; + + if (!(u_pipe_timings[u_pipe_opcode] & PAIR_FPU)) + t1 &= 3; + if (!(timings[opcode] & PAIR_FPU)) + t2 &= 3; + + if (t1 < 0 || t2 < 0 || t1 > CYCLES_BRANCH || t2 > CYCLES_BRANCH) + fatal("Pair out of range\n"); + + t_pair = pair_timings[t1][t2]; + if (t_pair < 1) + fatal("Illegal pair timings : t1=%i t2=%i u_opcode=%02x v_opcode=%02x\n", t1, t2, u_pipe_opcode, opcode); + + /*Instruction can pair with previous*/ + temp_timing = t_pair; + if (check_agi(deps, opcode, fetchdat, op_32) || check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + codegen_instruction(&temp_timing, &temp_deps, 0, 0, 0, 0, agi_stall); + u_pipe_full = 0; + decode_delay_offset = 0; + + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8) | u_pipe_regmask; + addr_regmask = 0; + return; + } + } +nopair: + /*Instruction can not pair with previous*/ + /*Run previous now*/ + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + codegen_instruction(u_pipe_timings, u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32, agi_stall); + u_pipe_full = 0; + regmask_modified = u_pipe_regmask; + addr_regmask = 0; + } + + if ((timings[opcode] & PAIR_U) && (decode_delay + decode_delay_offset) <= 0) + { + int has_displacement; + + if (timings[opcode] & CYCLES_HASIMM) + has_displacement = codegen_timing_has_displacement(fetchdat, op_32); + else + has_displacement = 0; + + if ((!has_displacement || cpu_has_feature(CPU_FEATURE_MMX)) && (!cpu_has_feature(CPU_FEATURE_MMX) || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) + { + /*Instruction might pair with next*/ + u_pipe_full = 1; + u_pipe_opcode = opcode; + u_pipe_timings = timings; + u_pipe_op_32 = op_32; + u_pipe_regmask = get_dstdep_mask(deps[opcode], fetchdat, bit8); + u_pipe_fetchdat = fetchdat; + u_pipe_decode_delay_offset = decode_delay_offset; + u_pipe_deps = deps; + decode_delay_offset = 0; + return; + } + } + /*Instruction can not pair and must run now*/ + if (check_agi(deps, opcode, fetchdat, op_32)) + agi_stall = 1; + codegen_instruction(timings, deps, opcode, fetchdat, decode_delay_offset, op_32, agi_stall); + decode_delay_offset = 0; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); + addr_regmask = 0; +} + +void codegen_timing_pentium_block_end() +{ + if (u_pipe_full) + { + /*Run previous now*/ + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + codegen_block_cycles++; + codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_deps[u_pipe_opcode], u_pipe_op_32) + decode_delay + decode_delay_offset; + u_pipe_full = 0; + } +} + +int codegen_timing_pentium_jump_cycles() +{ + return 0; +} + +codegen_timing_t codegen_timing_pentium = +{ + codegen_timing_pentium_start, + codegen_timing_pentium_prefix, + codegen_timing_pentium_opcode, + codegen_timing_pentium_block_start, + codegen_timing_pentium_block_end, + codegen_timing_pentium_jump_cycles +}; diff --git a/src/cpu_new/codegen_timing_winchip.c b/src/cpu_new/codegen_timing_winchip.c new file mode 100644 index 000000000..90982349f --- /dev/null +++ b/src/cpu_new/codegen_timing_winchip.c @@ -0,0 +1,424 @@ +#include +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "../mem.h" + +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + +#define CYCLES(c) (int *)c +#define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8)) + +static int *opcode_timings[256] = +{ +/*00*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm, &timing_rm, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(5), CYCLES(6), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_mod3[256] = +{ +/*00*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(2), CYCLES(1), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, +/*70*/ NULL, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rm, &timing_rm, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*e0*/ NULL, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*f0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, +}; +static int *opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, +/*70*/ NULL, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rr, &timing_rr, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*e0*/ NULL, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*f0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, +}; + +static int *opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static int *opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static int *opcode_timings_f6[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f6_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f7[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_f7_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_ff[8] = +{ + &timing_mm, &timing_mm, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; +static int *opcode_timings_ff_mod3[8] = +{ + &timing_rr, &timing_rr, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; + +static int *opcode_timings_d8[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP FSUB FSUBR FDIV FDIVR*/ + CYCLES(4), CYCLES(6), CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs FLDENV FLDCW FSTENV FSTCW*/ + CYCLES(2), NULL, CYCLES(7), CYCLES(7), CYCLES(34), CYCLES(4), CYCLES(67), CYCLES(3) +}; +static int *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), + /*FXCH*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FNOP*/ + CYCLES(7), NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /*FSTP*/ + CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/* opFCHS opFABS opFTST opFXAM*/ + CYCLES(2), CYCLES(2), NULL, NULL, CYCLES(5), CYCLES(7), NULL, NULL, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI opFLDEG2 opFLDLN2 opFLDZ*/ + CYCLES(5), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(5), NULL, +/* opF2XM1 opFYL2X opFPTAN opFPATAN opFDECSTP opFINCSTP,*/ + CYCLES(300), CYCLES(58), CYCLES(676), CYCLES(355), NULL, NULL, CYCLES(3), CYCLES(3), +/* opFPREM opFSQRT opFSINCOS opFRNDINT opFSCALE opFSIN opFCOS*/ + CYCLES(70), NULL, CYCLES(72), CYCLES(292), CYCLES(21), CYCLES(30), CYCLES(474), CYCLES(474) +}; + +static int *opcode_timings_da[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_da_mod3[8] = +{ + NULL, NULL, NULL, NULL, NULL, CYCLES(5), NULL, NULL +}; + + +static int *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil FLDe FSTPe*/ + CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), NULL, CYCLES(8) +}; +static int *opcode_timings_db_mod3[64] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* opFNOP opFCLEX opFINIT opFNOP opFNOP*/ + NULL, CYCLES(7), CYCLES(18), CYCLES(27), CYCLES(7), CYCLES(7), NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static int *opcode_timings_dc[8] = +{ +/* opFADDd_a16 opFMULd_a16 opFCOMd_a16 opFCOMPd_a16 opFSUBd_a16 opFSUBRd_a16 opFDIVd_a16 opFDIVRd_a16*/ + CYCLES(6), CYCLES(8), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(74), CYCLES(74) +}; +static int *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + CYCLES(4), CYCLES(6), NULL, NULL, CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd FRSTOR FSAVE FSTSW*/ + CYCLES(2), NULL, CYCLES(8), CYCLES(8), CYCLES(131), NULL, CYCLES(154), CYCLES(5) +}; +static int *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL +}; + +static int *opcode_timings_de[8] = +{ +/* FADDiw FMULiw FCOMiw FCOMPiw FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP FSUB FSUBR FDIV FDIVR*/ + CYCLES(4), CYCLES(6), NULL, CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw FILDiq FBSTP FISTPiq*/ + CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), CYCLES(172), CYCLES(8) +}; +static int *opcode_timings_df_mod3[8] = +{ +/* FFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL +}; + +static int *opcode_timings_8x[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_8x_mod3[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_81[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_81_mod3[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; + +static int timing_count; +static uint8_t last_prefix; +static uint32_t regmask_modified; + +static inline int COUNT(int *c, int op_32) +{ + if ((uintptr_t)c <= 10000) + return (int)(uintptr_t)c; + if (((uintptr_t)c & ~0xffff) == (-1 & ~0xffff)) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + return *c; +} + +void codegen_timing_winchip_block_start() +{ + regmask_modified = 0; +} + +void codegen_timing_winchip_start() +{ + timing_count = 0; + last_prefix = 0; +} + +void codegen_timing_winchip_prefix(uint8_t prefix, uint32_t fetchdat) +{ + timing_count += COUNT(opcode_timings[prefix], 0); + last_prefix = prefix; +} + +void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +{ + int **timings; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + break; + } + } + + timing_count += COUNT(timings[opcode], op_32); + if (regmask_modified & get_addr_regmask(deps[opcode], fetchdat, op_32)) + timing_count++; /*AGI stall*/ + codegen_block_cycles += timing_count; + + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); +} + +void codegen_timing_winchip_block_end() +{ +} + +int codegen_timing_winchip_jump_cycles() +{ + return 0; +} + +codegen_timing_t codegen_timing_winchip = +{ + codegen_timing_winchip_start, + codegen_timing_winchip_prefix, + codegen_timing_winchip_opcode, + codegen_timing_winchip_block_start, + codegen_timing_winchip_block_end, + codegen_timing_winchip_jump_cycles +}; diff --git a/src/cpu_new/codegen_timing_winchip2.c b/src/cpu_new/codegen_timing_winchip2.c new file mode 100644 index 000000000..9da156b82 --- /dev/null +++ b/src/cpu_new/codegen_timing_winchip2.c @@ -0,0 +1,745 @@ +/*Since IDT/Centaur didn't document cycle timings in the WinChip datasheets, and + I don't currently own a WinChip 2 to test against, most of the timing here is + a guess. This code makes the current (probably wrong) assumptions : + - FPU uses same timings as a Pentium, except for FXCH (which doesn't pair) + - 3DNow! instructions perfectly pair + - MMX follows mostly Pentium rules - one pipeline has shift/pack, one has + multiply, and other instructions can execute in either pipeline + - Instructions with prefixes can pair if both instructions are fully decoded + when the first instruction starts execution.*/ +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" + +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + +/*Instruction has different execution time for 16 and 32 bit data. Does not pair */ +#define CYCLES_HAS_MULTI (1 << 31) + +#define CYCLES_FPU (1 << 30) + +#define CYCLES_IS_MMX_MUL (1 << 29) +#define CYCLES_IS_MMX_SHIFT (1 << 28) +#define CYCLES_IS_MMX_ANY (1 << 27) +#define CYCLES_IS_3DNOW (1 << 26) + +#define CYCLES_MMX_MUL(c) (CYCLES_IS_MMX_MUL | c) +#define CYCLES_MMX_SHIFT(c) (CYCLES_IS_MMX_SHIFT | c) +#define CYCLES_MMX_ANY(c) (CYCLES_IS_MMX_ANY | c) +#define CYCLES_3DNOW(c) (CYCLES_IS_3DNOW | c) + +#define CYCLES_IS_MMX (CYCLES_IS_MMX_MUL | CYCLES_IS_MMX_SHIFT | CYCLES_IS_MMX_ANY | CYCLES_IS_3DNOW) + +#define GET_CYCLES(c) (c & ~(CYCLES_HAS_MULTI | CYCLES_FPU | CYCLES_IS_MMX)) + +#define CYCLES(c) c +#define CYCLES2(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*comp_time = cycles until instruction complete + i_overlap = cycles that overlap with integer + f_overlap = cycles that overlap with subsequent FPU*/ +#define FPU_CYCLES(comp_time, i_overlap, f_overlap) (comp_time) | (i_overlap << 8) | (f_overlap << 16) | CYCLES_FPU + +#define FPU_COMP_TIME(timing) (timing & 0xff) +#define FPU_I_OVERLAP(timing) ((timing >> 8) & 0xff) +#define FPU_F_OVERLAP(timing) ((timing >> 16) & 0xff) + +#define FPU_I_LATENCY(timing) (FPU_COMP_TIME(timing) - FPU_I_OVERLAP(timing)) + +#define FPU_F_LATENCY(timing) (FPU_I_OVERLAP(timing) - FPU_F_OVERLAP(timing)) + +#define FPU_RESULT_LATENCY(timing) ((timing >> 8) & 0xff) + +#define INVALID 0 + +static uint32_t opcode_timings[256] = +{ +/*00*/ CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(2), INVALID, +/*10*/ CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), +/*20*/ CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), +/*30*/ CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), + +/*40*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), + +/*80*/ CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(5), CYCLES(6), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), INVALID, INVALID, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), INVALID +}; + +static uint32_t opcode_timings_mod3[256] = +{ +/*00*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), INVALID, +/*10*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), +/*20*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), +/*30*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), + +/*40*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), + +/*80*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(2), CYCLES(1), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), INVALID, INVALID, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), INVALID, +}; + +static uint32_t opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), INVALID, CYCLES(195), CYCLES(7), INVALID, CYCLES(1000), CYCLES(10000), INVALID, INVALID, INVALID, CYCLES_3DNOW(1), CYCLES(1), CYCLES_3DNOW(1), +/*10*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*50*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*60*/ CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), INVALID, INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), +/*70*/ INVALID, CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES(100), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), + +/*80*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), INVALID, INVALID, CYCLES(3), CYCLES(3), INVALID, CYCLES(13), CYCLES(3), CYCLES(3), INVALID, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), INVALID, INVALID, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), INVALID, INVALID, INVALID, INVALID, INVALID, CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ INVALID, CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), INVALID, CYCLES_MMX_MUL(2), INVALID, INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), INVALID, CYCLES_MMX_ANY(2), +/*e0*/ INVALID, CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), INVALID, INVALID, CYCLES_MMX_MUL(2), INVALID, INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), INVALID, CYCLES_MMX_ANY(2), +/*f0*/ INVALID, CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), INVALID, CYCLES_MMX_MUL(2), INVALID, INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), INVALID, +}; +static uint32_t opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), INVALID, CYCLES(195), CYCLES(7), INVALID, CYCLES(1000), CYCLES(10000), INVALID, INVALID, INVALID, CYCLES_3DNOW(1), CYCLES(1), CYCLES_3DNOW(1), +/*10*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*50*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*60*/ CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), +/*70*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES(100), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), + +/*80*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), INVALID, INVALID, CYCLES(3), CYCLES(3), INVALID, CYCLES(13), CYCLES(3), CYCLES(3), INVALID, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), INVALID, INVALID, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), INVALID, INVALID, INVALID, INVALID, INVALID, CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, CYCLES_MMX_MUL(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), +/*e0*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, INVALID, CYCLES_MMX_MUL(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), +/*f0*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, CYCLES_MMX_MUL(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, +}; + +static uint32_t opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static uint32_t opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static uint32_t opcode_timings_f6[8] = +{ + CYCLES(2), INVALID, CYCLES(2), CYCLES(2), CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static uint32_t opcode_timings_f6_mod3[8] = +{ + CYCLES(1), INVALID, CYCLES(1), CYCLES(1), CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static uint32_t opcode_timings_f7[8] = +{ + CYCLES(2), INVALID, CYCLES(2), CYCLES(2), CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static uint32_t opcode_timings_f7_mod3[8] = +{ + CYCLES(1), INVALID, CYCLES(1), CYCLES(1), CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static uint32_t opcode_timings_ff[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), INVALID +}; +static uint32_t opcode_timings_ff_mod3[8] = +{ + CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), INVALID +}; + +static uint32_t opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; +static uint32_t opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), +/* FSUB FSUBR FDIV FDIVR*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; + +static uint32_t opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + FPU_CYCLES(1,0,0), INVALID, FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* FLDENV FLDCW FSTENV FSTCW*/ + FPU_CYCLES(32,0,0), FPU_CYCLES(8,0,0), FPU_CYCLES(48,0,0), FPU_CYCLES(2,0,0) +}; +static uint32_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), + /*FXCH*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), + /*FNOP*/ + FPU_CYCLES(3,0,0), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), +/* opFCHS opFABS*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), INVALID, INVALID, +/* opFTST opFXAM*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(21,4,0), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + FPU_CYCLES(2,0,0), FPU_CYCLES(5,2,2), FPU_CYCLES(5,2,2), FPU_CYCLES(5,2,2), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + FPU_CYCLES(5,2,2), FPU_CYCLES(5,2,2), FPU_CYCLES(2,0,0), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + FPU_CYCLES(53,2,2), FPU_CYCLES(103,2,2),FPU_CYCLES(120,36,0),FPU_CYCLES(112,2,2), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* opFPREM opFSQRT opFSINCOS*/ + FPU_CYCLES(64,2,2), INVALID, FPU_CYCLES(70,69,2),FPU_CYCLES(89,2,2), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + FPU_CYCLES(9,0,0), FPU_CYCLES(20,5,0), FPU_CYCLES(65,2,2), FPU_CYCLES(65,2,2) +}; + +static uint32_t opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + FPU_CYCLES(6,2,2), FPU_CYCLES(6,2,2), FPU_CYCLES(4,0,0), FPU_CYCLES(4,0,0), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + FPU_CYCLES(6,2,2), FPU_CYCLES(6,2,2), FPU_CYCLES(42,38,2), FPU_CYCLES(42,38,2) +}; +static uint32_t opcode_timings_da_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FCOMPP*/ + INVALID, FPU_CYCLES(1,0,0), INVALID, INVALID +}; + + +static uint32_t opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + FPU_CYCLES(3,2,2), INVALID, FPU_CYCLES(6,0,0), FPU_CYCLES(6,0,0), +/* FLDe FSTPe*/ + INVALID, FPU_CYCLES(3,0,0), INVALID, FPU_CYCLES(3,0,0) +}; +static uint32_t opcode_timings_db_mod3[64] = +{ + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* opFNOP opFCLEX opFINIT*/ + INVALID, FPU_CYCLES(1,0,0), FPU_CYCLES(7,0,0), FPU_CYCLES(17,0,0), +/* opFNOP opFNOP*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +}; + +static uint32_t opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; +static uint32_t opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2),INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2),FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; + +static uint32_t opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + FPU_CYCLES(1,0,0), INVALID, FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* FRSTOR FSAVE FSTSW*/ + FPU_CYCLES(70,0,0), INVALID, FPU_CYCLES(127,0,0), FPU_CYCLES(6,0,0) +}; +static uint32_t opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + FPU_CYCLES(2,0,0), INVALID, FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), +/* FUCOM FUCOMP*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0),INVALID, INVALID +}; + +static uint32_t opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + FPU_CYCLES(6,2,2), FPU_CYCLES(6,2,2), FPU_CYCLES(4,0,0), FPU_CYCLES(4,0,0), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + FPU_CYCLES(6,2,2), FPU_CYCLES(6,2,2), FPU_CYCLES(42,38,2), FPU_CYCLES(42,38,2) +}; +static uint32_t opcode_timings_de_mod3[8] = +{ +/* FADDP FMULP FCOMPP*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), INVALID, FPU_CYCLES(1,0,0), +/* FSUBP FSUBRP FDIVP FDIVRP*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; + +static uint32_t opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + FPU_CYCLES(3,2,2), INVALID, FPU_CYCLES(6,0,0), FPU_CYCLES(6,0,0), +/* FILDiq FBSTP FISTPiq*/ + INVALID, FPU_CYCLES(3,2,2), FPU_CYCLES(148,0,0), FPU_CYCLES(6,0,0) +}; +static uint32_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + FPU_CYCLES(6,0,0), INVALID, INVALID, INVALID +}; + +static uint32_t opcode_timings_8x[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2) +}; +static uint32_t opcode_timings_8x_mod3[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2) +}; +static uint32_t opcode_timings_81[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2) +}; +static uint32_t opcode_timings_81_mod3[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2) +}; + +static int timing_count; +static uint8_t last_prefix; +static uint32_t regmask_modified; +static int decode_delay, decode_delay_offset; +static int fpu_latency; +static int fpu_st_latency[8]; + +static int u_pipe_full; +static uint32_t u_pipe_opcode; +static uint32_t *u_pipe_timings; +static uint32_t u_pipe_op_32; +static uint32_t u_pipe_regmask; +static uint32_t u_pipe_fetchdat; +static int u_pipe_decode_delay_offset; +static uint64_t *u_pipe_deps; + +int can_pair(uint32_t timing_a, uint32_t timing_b, uint8_t regmask_b) +{ + /*Only MMX/3DNow instructions can pair*/ + if (!(timing_b & CYCLES_IS_MMX)) + return 0; + /*Only one MMX multiply per cycle*/ + if ((timing_a & CYCLES_IS_MMX_MUL) && (timing_b & CYCLES_IS_MMX_MUL)) + return 0; + /*Only one MMX shift/pack per cycle*/ + if ((timing_a & CYCLES_IS_MMX_SHIFT) && (timing_b & CYCLES_IS_MMX_SHIFT)) + return 0; + /*Second instruction can not access registers written by first*/ + if (u_pipe_regmask & regmask_b) + return 0; + /*Must have had enough time to decode prefixes*/ + if ((decode_delay+decode_delay_offset+u_pipe_decode_delay_offset) > 0) + return 0; + + return 1; +} + +static inline int COUNT(uint32_t c, int op_32) +{ + if (c & CYCLES_FPU) + return FPU_I_LATENCY(c); + if (c & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return (c >> 8) & 0xff; + return c & 0xff; + } + return GET_CYCLES(c); +} + +static int check_agi(uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int op_32) +{ + uint32_t addr_regmask = get_addr_regmask(deps[opcode], fetchdat, op_32); + + /*Instructions that use ESP implicitly (eg PUSH, POP, CALL etc) do not + cause AGIs with each other, but do with instructions that use it explicitly*/ + if ((addr_regmask & REGMASK_IMPL_ESP) && (regmask_modified & (1 << REG_ESP)) && !(regmask_modified & REGMASK_IMPL_ESP)) + addr_regmask |= (1 << REG_ESP); + + return (regmask_modified & addr_regmask) & ~REGMASK_IMPL_ESP; +} + +static int codegen_fpu_latencies(uint64_t deps, int reg) +{ + int latency = fpu_latency; + + if ((deps & FPU_RW_ST0) && fpu_st_latency[0] && fpu_st_latency[0] > latency) + latency = fpu_st_latency[0]; + if ((deps & FPU_RW_ST1) && fpu_st_latency[1] && fpu_st_latency[1] > latency) + latency = fpu_st_latency[1]; + if ((deps & FPU_RW_STREG) && fpu_st_latency[reg] && fpu_st_latency[reg] > latency) + latency = fpu_st_latency[reg]; + + return latency; +} + +#define SUB_AND_CLAMP(latency, count) \ + latency -= count; \ + if (latency < 0) \ + latency = 0 + +static void codegen_fpu_latency_clock(int count) +{ + SUB_AND_CLAMP(fpu_latency, count); + SUB_AND_CLAMP(fpu_st_latency[0], count); + SUB_AND_CLAMP(fpu_st_latency[1], count); + SUB_AND_CLAMP(fpu_st_latency[2], count); + SUB_AND_CLAMP(fpu_st_latency[3], count); + SUB_AND_CLAMP(fpu_st_latency[4], count); + SUB_AND_CLAMP(fpu_st_latency[5], count); + SUB_AND_CLAMP(fpu_st_latency[6], count); + SUB_AND_CLAMP(fpu_st_latency[7], count); +} + +static void codegen_instruction(uint32_t *timings, uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int decode_delay_offset, int op_32, int exec_delay) +{ + int instr_cycles, latency = 0; + + if ((timings[opcode] & CYCLES_FPU) && !(deps[opcode] & FPU_FXCH)) + instr_cycles = latency = codegen_fpu_latencies(deps[opcode], fetchdat & 7); + else + instr_cycles = 0; + + if ((decode_delay + decode_delay_offset) > 0) + codegen_fpu_latency_clock(decode_delay + decode_delay_offset + instr_cycles); + else + codegen_fpu_latency_clock(instr_cycles); + instr_cycles += COUNT(timings[opcode], op_32); + instr_cycles += exec_delay; + if ((decode_delay + decode_delay_offset) > 0) + codegen_block_cycles += instr_cycles + decode_delay + decode_delay_offset; + else + codegen_block_cycles += instr_cycles; + decode_delay = (-instr_cycles) + 1; + + if (deps[opcode] & FPU_POP) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c] = fpu_st_latency[c+1]; + fpu_st_latency[7] = 0; + } + if (deps[opcode] & FPU_POP2) + { + int c; + + for (c = 0; c < 6; c++) + fpu_st_latency[c] = fpu_st_latency[c+2]; + fpu_st_latency[6] = fpu_st_latency[7] = 0; + } + if (timings[opcode] & CYCLES_FPU) + { + /* if (fpu_latency) + fatal("Bad latency FPU\n");*/ + fpu_latency = FPU_F_LATENCY(timings[opcode]); + } + + if (deps[opcode] & FPU_PUSH) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c+1] = fpu_st_latency[c]; + fpu_st_latency[0] = 0; + } + if (deps[opcode] & FPU_WRITE_ST0) + { +/* if (fpu_st_latency[0]) + fatal("Bad latency ST0\n");*/ + fpu_st_latency[0] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (deps[opcode] & FPU_WRITE_ST1) + { +/* if (fpu_st_latency[1]) + fatal("Bad latency ST1\n");*/ + fpu_st_latency[1] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (deps[opcode] & FPU_WRITE_STREG) + { + int reg = fetchdat & 7; + if (deps[opcode] & FPU_POP) + reg--; + if (reg >= 0 && + !(reg == 0 && (deps[opcode] & FPU_WRITE_ST0)) && + !(reg == 1 && (deps[opcode] & FPU_WRITE_ST1))) + { +/* if (fpu_st_latency[reg]) + fatal("Bad latency STREG %i %08x %i %016llx %02x\n",fpu_st_latency[reg], fetchdat, reg, timings[opcode], opcode);*/ + fpu_st_latency[reg] = FPU_RESULT_LATENCY(timings[opcode]); + } + } +} + +static void codegen_timing_winchip2_block_start() +{ + regmask_modified = 0; + decode_delay = decode_delay_offset = 0; + u_pipe_full = 0; +} + +static void codegen_timing_winchip2_start() +{ + timing_count = 0; + last_prefix = 0; +} + +static void codegen_timing_winchip2_prefix(uint8_t prefix, uint32_t fetchdat) +{ + if (prefix == 0x0f) + { + /*0fh prefix is 'free'*/ + last_prefix = prefix; + return; + } + /*On WinChip all prefixes take 1 cycle to decode. Decode may be shadowed + by execution of previous instructions*/ + decode_delay_offset++; + last_prefix = prefix; +} + +static void codegen_timing_winchip2_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +{ + uint32_t *timings; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + int agi_stall = 0; + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + break; + } + } + + if (u_pipe_full) + { + uint8_t regmask = get_srcdep_mask(deps[opcode], fetchdat, bit8, u_pipe_op_32); + + if (can_pair(u_pipe_timings[u_pipe_opcode], timings[opcode], regmask)) + { + int cycles_a = u_pipe_timings[u_pipe_opcode] & 0xff; + int cycles_b = timings[opcode] & 0xff; + uint32_t timing = (cycles_a > cycles_b) ? u_pipe_timings[u_pipe_opcode] : timings[opcode]; + uint64_t temp_deps = 0; + + if (check_agi(deps, opcode, fetchdat, op_32) || check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + + codegen_instruction(&timing, &temp_deps, 0, 0, 0, 0, agi_stall); + u_pipe_full = 0; + decode_delay_offset = 0; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8) | u_pipe_regmask; + return; + } + else + { + /*No pairing, run first instruction now*/ + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + codegen_instruction(u_pipe_timings, u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32, agi_stall); + u_pipe_full = 0; + regmask_modified = u_pipe_regmask; + } + } + if (timings[opcode] & CYCLES_IS_MMX) + { + /*Might pair with next instruction*/ + u_pipe_full = 1; + u_pipe_opcode = opcode; + u_pipe_timings = timings; + u_pipe_op_32 = op_32; + u_pipe_regmask = get_dstdep_mask(deps[opcode], fetchdat, bit8); + u_pipe_fetchdat = fetchdat; + u_pipe_decode_delay_offset = decode_delay_offset; + u_pipe_deps = deps; + decode_delay_offset = 0; + return; + } + + if (check_agi(deps, opcode, fetchdat, op_32)) + agi_stall = 1; + codegen_instruction(timings, deps, opcode, fetchdat, decode_delay_offset, op_32, agi_stall); + decode_delay_offset = 0; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); +} + +static void codegen_timing_winchip2_block_end() +{ + if (u_pipe_full) + { + int agi_stall = 0; + + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + codegen_instruction(u_pipe_timings, u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32, agi_stall); + u_pipe_full = 0; + } +} + +int codegen_timing_winchip2_jump_cycles() +{ + return 0; +} + +codegen_timing_t codegen_timing_winchip2 = +{ + codegen_timing_winchip2_start, + codegen_timing_winchip2_prefix, + codegen_timing_winchip2_opcode, + codegen_timing_winchip2_block_start, + codegen_timing_winchip2_block_end, + codegen_timing_winchip2_jump_cycles +}; diff --git a/src/cpu_new/cpu.c b/src/cpu_new/cpu.c new file mode 100644 index 000000000..4dde87a96 --- /dev/null +++ b/src/cpu_new/cpu.c @@ -0,0 +1,2688 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * CPU type handler. + * + * Version: @(#)cpu.c 1.0.6 2018/05/05 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * leilei, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../device.h" +#include "../machine/machine.h" +#include "../io.h" +#include "x86_ops.h" +#include "../mem.h" +#include "../nmi.h" +#include "../pic.h" +#include "../pci.h" +#ifdef USE_DYNAREC +# include "codegen.h" +#endif + + +static void cpu_write(uint16_t addr, uint8_t val, void *priv); +static uint8_t cpu_read(uint16_t addr, void *priv); + + +enum { + CPUID_FPU = (1 << 0), + CPUID_VME = (1 << 1), + CPUID_PSE = (1 << 3), + CPUID_TSC = (1 << 4), + CPUID_MSR = (1 << 5), + CPUID_CMPXCHG8B = (1 << 8), + CPUID_AMDSEP = (1 << 10), + CPUID_SEP = (1 << 11), + CPUID_CMOV = (1 << 15), + CPUID_MMX = (1 << 23), + CPUID_FXSR = (1 << 24) +}; + +/*Addition flags returned by CPUID function 0x80000001*/ +enum +{ + CPUID_3DNOW = (1 << 31) +}; + + +#ifdef USE_DYNAREC +const OpFn *x86_dynarec_opcodes; +const OpFn *x86_dynarec_opcodes_0f; +const OpFn *x86_dynarec_opcodes_d8_a16; +const OpFn *x86_dynarec_opcodes_d8_a32; +const OpFn *x86_dynarec_opcodes_d9_a16; +const OpFn *x86_dynarec_opcodes_d9_a32; +const OpFn *x86_dynarec_opcodes_da_a16; +const OpFn *x86_dynarec_opcodes_da_a32; +const OpFn *x86_dynarec_opcodes_db_a16; +const OpFn *x86_dynarec_opcodes_db_a32; +const OpFn *x86_dynarec_opcodes_dc_a16; +const OpFn *x86_dynarec_opcodes_dc_a32; +const OpFn *x86_dynarec_opcodes_dd_a16; +const OpFn *x86_dynarec_opcodes_dd_a32; +const OpFn *x86_dynarec_opcodes_de_a16; +const OpFn *x86_dynarec_opcodes_de_a32; +const OpFn *x86_dynarec_opcodes_df_a16; +const OpFn *x86_dynarec_opcodes_df_a32; +const OpFn *x86_dynarec_opcodes_REPE; +const OpFn *x86_dynarec_opcodes_REPNE; +const OpFn *x86_dynarec_opcodes_3DNOW; +#endif + +const OpFn *x86_opcodes; +const OpFn *x86_opcodes_0f; +const OpFn *x86_opcodes_d8_a16; +const OpFn *x86_opcodes_d8_a32; +const OpFn *x86_opcodes_d9_a16; +const OpFn *x86_opcodes_d9_a32; +const OpFn *x86_opcodes_da_a16; +const OpFn *x86_opcodes_da_a32; +const OpFn *x86_opcodes_db_a16; +const OpFn *x86_opcodes_db_a32; +const OpFn *x86_opcodes_dc_a16; +const OpFn *x86_opcodes_dc_a32; +const OpFn *x86_opcodes_dd_a16; +const OpFn *x86_opcodes_dd_a32; +const OpFn *x86_opcodes_de_a16; +const OpFn *x86_opcodes_de_a32; +const OpFn *x86_opcodes_df_a16; +const OpFn *x86_opcodes_df_a32; +const OpFn *x86_opcodes_REPE; +const OpFn *x86_opcodes_REPNE; +const OpFn *x86_opcodes_3DNOW; + +CPU *cpu_s; +int cpu_effective; +int cpu_multi; +int cpu_16bitbus; +int cpu_busspeed; +int cpu_cyrix_alignment; +int CPUID; +uint64_t cpu_CR4_mask; +int isa_cycles; +int cpu_cycles_read, cpu_cycles_read_l, + cpu_cycles_write, cpu_cycles_write_l; +int cpu_prefetch_cycles, cpu_prefetch_width, + cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles; +int cpu_waitstates; +int cpu_cache_int_enabled, cpu_cache_ext_enabled; +int cpu_pci_speed, cpu_alt_reset; + +uint32_t cpu_features; + +int is286, + is386, + is486 = 1, + cpu_iscyrix, + israpidcad, + is_pentium; + +int hasfpu; + + +uint64_t tsc = 0; +msr_t msr; +cr0_t CR0; +uint64_t pmc[2] = {0, 0}; + +uint16_t temp_seg_data[4] = {0, 0, 0, 0}; + +#if defined(DEV_BRANCH) && defined(USE_I686) +uint16_t cs_msr = 0; +uint32_t esp_msr = 0; +uint32_t eip_msr = 0; +uint64_t apic_base_msr = 0; +uint64_t mtrr_cap_msr = 0; +uint64_t mtrr_physbase_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t mtrr_physmask_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t mtrr_fix64k_8000_msr = 0; +uint64_t mtrr_fix16k_8000_msr = 0; +uint64_t mtrr_fix16k_a000_msr = 0; +uint64_t mtrr_fix4k_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t pat_msr = 0; +uint64_t mtrr_deftype_msr = 0; +uint64_t msr_ia32_pmc[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t ecx17_msr = 0; +uint64_t ecx79_msr = 0; +uint64_t ecx8x_msr[4] = {0, 0, 0, 0}; +uint64_t ecx116_msr = 0; +uint64_t ecx11x_msr[4] = {0, 0, 0, 0}; +uint64_t ecx11e_msr = 0; +uint64_t ecx186_msr = 0; +uint64_t ecx187_msr = 0; +uint64_t ecx1e0_msr = 0; +uint64_t ecx570_msr = 0; +#endif + +uint64_t ecx83_msr = 0; /* AMD K5 and K6 MSR's. */ +uint64_t star = 0; /* These are K6-only. */ +uint64_t sfmask = 0; + +int timing_rr; +int timing_mr, timing_mrl; +int timing_rm, timing_rml; +int timing_mm, timing_mml; +int timing_bt, timing_bnt; +int timing_int, timing_int_rm, timing_int_v86, timing_int_pm, + timing_int_pm_outer; +int timing_iret_rm, timing_iret_v86, timing_iret_pm, + timing_iret_pm_outer; +int timing_call_rm, timing_call_pm, timing_call_pm_gate, + timing_call_pm_gate_inner; +int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; +int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; +int timing_misaligned; + + +static uint8_t ccr0, ccr1, ccr2, ccr3, ccr4, ccr5, ccr6; + +int cpu_has_feature(int feature) +{ + return cpu_features & feature; +} + + +void +cpu_dynamic_switch(int new_cpu) +{ + if (cpu_effective == new_cpu) + return; + + int c = cpu; + cpu = new_cpu; + cpu_set(); + pc_speed_changed(); + cpu = c; +} + + +void +cpu_set_edx(void) +{ + EDX = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].edx_reset; +} + + +void +cpu_set(void) +{ + if (!machines[machine].cpu[cpu_manufacturer].cpus) + { + /*CPU is invalid, set to default*/ + cpu_manufacturer = 0; + cpu = 0; + } + + cpu_effective = cpu; + cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective]; + + cpu_alt_reset = 0; + + CPUID = cpu_s->cpuid_model; + is8086 = (cpu_s->cpu_type > CPU_8088); + is286 = (cpu_s->cpu_type >= CPU_286); + is386 = (cpu_s->cpu_type >= CPU_386SX); + israpidcad = (cpu_s->cpu_type == CPU_RAPIDCAD); + is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_RAPIDCAD); + is_pentium = (cpu_s->cpu_type >= CPU_WINCHIP); + 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); + 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; + ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = 0; + + if ((cpu_s->cpu_type == CPU_8088) || (cpu_s->cpu_type == CPU_8086) || + (cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) || + (cpu_s->cpu_type == CPU_386DX) || (cpu_s->cpu_type == CPU_i486SX)) { + hasfpu = !!enable_external_fpu; + } + + cpu_update_waitstates(); + + isa_cycles = cpu_s->atclk_div; + + if (cpu_s->rspeed <= 8000000) + cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; + else + cpu_rom_prefetch_cycles = cpu_s->rspeed / 1000000; + + if (cpu_s->pci_speed) + { + pci_nonburst_time = 4*cpu_s->rspeed / cpu_s->pci_speed; + pci_burst_time = cpu_s->rspeed / cpu_s->pci_speed; + } + else + { + pci_nonburst_time = 4; + pci_burst_time = 1; + } + + if (cpu_iscyrix) + io_sethandler(0x0022, 0x0002, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + else + io_removehandler(0x0022, 0x0002, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + + if (hasfpu) + io_sethandler(0x00f0, 0x000f, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + else + io_removehandler(0x00f0, 0x000f, cpu_read, NULL, NULL, cpu_write, NULL, NULL, NULL); + +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_386_0f, dynarec_ops_386, dynarec_ops_386_0f); +#else + x86_setopcodes(ops_386, ops_386_0f); +#endif + x86_opcodes_REPE = ops_REPE; + x86_opcodes_REPNE = ops_REPNE; + x86_opcodes_3DNOW = ops_3DNOW; +#ifdef USE_DYNAREC + x86_dynarec_opcodes_REPE = dynarec_ops_REPE; + x86_dynarec_opcodes_REPNE = dynarec_ops_REPNE; + x86_dynarec_opcodes_3DNOW = dynarec_ops_3DNOW; +#endif + +#ifdef USE_DYNAREC + if (hasfpu) + { + x86_dynarec_opcodes_d8_a16 = dynarec_ops_fpu_d8_a16; + x86_dynarec_opcodes_d8_a32 = dynarec_ops_fpu_d8_a32; + x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_d9_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_d9_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_db_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_dc_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_dc_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_dd_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_dd_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_de_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_de_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_df_a32; + } + else + { + x86_dynarec_opcodes_d8_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_d8_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_d9_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_nofpu_a32; + } + codegen_timing_set(&codegen_timing_486); +#endif + + if (hasfpu) + { + x86_opcodes_d8_a16 = ops_fpu_d8_a16; + x86_opcodes_d8_a32 = ops_fpu_d8_a32; + x86_opcodes_d9_a16 = ops_fpu_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_d9_a32; + x86_opcodes_da_a16 = ops_fpu_da_a16; + x86_opcodes_da_a32 = ops_fpu_da_a32; + x86_opcodes_db_a16 = ops_fpu_db_a16; + x86_opcodes_db_a32 = ops_fpu_db_a32; + x86_opcodes_dc_a16 = ops_fpu_dc_a16; + x86_opcodes_dc_a32 = ops_fpu_dc_a32; + x86_opcodes_dd_a16 = ops_fpu_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_dd_a32; + x86_opcodes_de_a16 = ops_fpu_de_a16; + x86_opcodes_de_a32 = ops_fpu_de_a32; + x86_opcodes_df_a16 = ops_fpu_df_a16; + x86_opcodes_df_a32 = ops_fpu_df_a32; + } + else + { + x86_opcodes_d8_a16 = ops_nofpu_a16; + x86_opcodes_d8_a32 = ops_nofpu_a32; + x86_opcodes_d9_a16 = ops_nofpu_a16; + x86_opcodes_d9_a32 = ops_nofpu_a32; + x86_opcodes_da_a16 = ops_nofpu_a16; + x86_opcodes_da_a32 = ops_nofpu_a32; + x86_opcodes_db_a16 = ops_nofpu_a16; + x86_opcodes_db_a32 = ops_nofpu_a32; + x86_opcodes_dc_a16 = ops_nofpu_a16; + x86_opcodes_dc_a32 = ops_nofpu_a32; + x86_opcodes_dd_a16 = ops_nofpu_a16; + x86_opcodes_dd_a32 = ops_nofpu_a32; + x86_opcodes_de_a16 = ops_nofpu_a16; + x86_opcodes_de_a32 = ops_nofpu_a32; + x86_opcodes_df_a16 = ops_nofpu_a16; + x86_opcodes_df_a32 = ops_nofpu_a32; + } + + memset(&msr, 0, sizeof(msr)); + + timing_misaligned = 0; + cpu_cyrix_alignment = 0; + + switch (cpu_s->cpu_type) + { + case CPU_8088: + case CPU_8086: + break; + + case CPU_286: +#ifdef USE_DYNAREC + x86_setopcodes(ops_286, ops_286_0f, dynarec_ops_286, dynarec_ops_286_0f); +#else + x86_setopcodes(ops_286, ops_286_0f); +#endif + if (enable_external_fpu) + { +#ifdef USE_DYNAREC + x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_287_d9_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_287_d9_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_287_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_287_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_287_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_287_db_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_287_dc_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_287_dc_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_287_dd_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_287_dd_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_287_de_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_287_de_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_287_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_287_df_a32; +#endif + x86_opcodes_d9_a16 = ops_fpu_287_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_287_d9_a32; + x86_opcodes_da_a16 = ops_fpu_287_da_a16; + x86_opcodes_da_a32 = ops_fpu_287_da_a32; + x86_opcodes_db_a16 = ops_fpu_287_db_a16; + x86_opcodes_db_a32 = ops_fpu_287_db_a32; + x86_opcodes_dc_a16 = ops_fpu_287_dc_a16; + x86_opcodes_dc_a32 = ops_fpu_287_dc_a32; + x86_opcodes_dd_a16 = ops_fpu_287_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_287_dd_a32; + x86_opcodes_de_a16 = ops_fpu_287_de_a16; + x86_opcodes_de_a32 = ops_fpu_287_de_a32; + x86_opcodes_df_a16 = ops_fpu_287_df_a16; + x86_opcodes_df_a32 = ops_fpu_287_df_a32; + } + timing_rr = 2; /*register dest - register src*/ + timing_rm = 7; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 7; /*memory dest - memory src*/ + timing_rml = 9; /*register dest - memory src long*/ + timing_mrl = 11; /*memory dest - register src long*/ + timing_mml = 11; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 23; + timing_int_v86 = 0; + timing_int_pm = 40; + timing_int_pm_outer = 78; + timing_iret_rm = 17; + timing_iret_v86 = 0; + timing_iret_pm = 31; + timing_iret_pm_outer = 55; + timing_call_rm = 13; + timing_call_pm = 26; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 82; + timing_retf_rm = 15; + timing_retf_pm = 25; + timing_retf_pm_outer = 55; + timing_jmp_rm = 11; + timing_jmp_pm = 23; + timing_jmp_pm_gate = 38; + break; + + case CPU_386SX: + timing_rr = 2; /*register dest - register src*/ + timing_rm = 6; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 6; /*memory dest - memory src*/ + timing_rml = 8; /*register dest - memory src long*/ + timing_mrl = 11; /*memory dest - register src long*/ + timing_mml = 10; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 37; + timing_int_v86 = 59; + timing_int_pm = 99; + timing_int_pm_outer = 119; + timing_iret_rm = 22; + timing_iret_v86 = 60; + timing_iret_pm = 38; + timing_iret_pm_outer = 82; + timing_call_rm = 17; + timing_call_pm = 34; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 86; + timing_retf_rm = 18; + timing_retf_pm = 32; + timing_retf_pm_outer = 68; + timing_jmp_rm = 12; + timing_jmp_pm = 27; + timing_jmp_pm_gate = 45; + break; + + case CPU_386DX: + timing_rr = 2; /*register dest - register src*/ + timing_rm = 6; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 6; /*memory dest - memory src*/ + timing_rml = 6; /*register dest - memory src long*/ + timing_mrl = 7; /*memory dest - register src long*/ + timing_mml = 6; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 37; + timing_int_v86 = 59; + timing_int_pm = 99; + timing_int_pm_outer = 119; + timing_iret_rm = 22; + timing_iret_v86 = 60; + timing_iret_pm = 38; + timing_iret_pm_outer = 82; + timing_call_rm = 17; + timing_call_pm = 34; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 86; + timing_retf_rm = 18; + timing_retf_pm = 32; + timing_retf_pm_outer = 68; + timing_jmp_rm = 12; + timing_jmp_pm = 27; + timing_jmp_pm_gate = 45; + break; + + case CPU_RAPIDCAD: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + timing_misaligned = 3; + break; + + case CPU_486SLC: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 5; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 5; /*register dest - memory src long*/ + timing_mrl = 7; /*memory dest - register src long*/ + timing_mml = 7; + timing_bt = 6-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + /*unknown*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + timing_misaligned = 3; + break; + + case CPU_486DLC: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 3; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 6-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + /*unknown*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + timing_misaligned = 3; + break; + + case CPU_iDX4: + cpu_features = CPU_FEATURE_CR4 | CPU_FEATURE_VME; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_VME; + case CPU_i486SX: + case CPU_i486DX: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + timing_misaligned = 3; + break; + + case CPU_Am486SX: + case CPU_Am486DX: + /*AMD timing identical to Intel*/ +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + timing_misaligned = 3; + break; + + case CPU_Cx486S: + case CPU_Cx486DX: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 3; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 4-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; /*unknown*/ + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + timing_misaligned = 3; + break; + + case CPU_Cx5x86: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 5-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 9; + timing_int_v86 = 82; /*unknown*/ + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + break; + + case CPU_WINCHIP: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_winchip_0f, dynarec_ops_386, dynarec_ops_winchip_0f); +#else + x86_setopcodes(ops_386, ops_winchip_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + /*unknown*/ + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_winchip); +#endif + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + break; + + case CPU_WINCHIP2: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f); +#else + x86_setopcodes(ops_386, ops_winchip2_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_3DNOW; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21); + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + /*unknown*/ + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + codegen_timing_set(&codegen_timing_winchip2); + break; + + case CPU_PENTIUM: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); +#else + x86_setopcodes(ops_386, ops_pentium_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + timing_misaligned = 3; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_pentium); +#endif + break; + + case CPU_PENTIUMMMX: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); +#else + x86_setopcodes(ops_386, ops_pentiummmx_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + timing_misaligned = 3; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_pentium); +#endif + break; + + case CPU_Cx6x86: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); +#else + x86_setopcodes(ops_386, ops_pentium_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + cpu_features = CPU_FEATURE_RDTSC; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + CPUID = 0; /*Disabled on powerup by default*/ + break; + + case CPU_Cx6x86L: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); +#else + x86_setopcodes(ops_386, ops_pentium_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + cpu_features = CPU_FEATURE_RDTSC; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + ccr4 = 0x80; + break; + + + case CPU_CxGX1: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); +#else + x86_setopcodes(ops_386, ops_pentium_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 5-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + break; + + + case CPU_Cx6x86MX: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_c6x86mx_0f, dynarec_ops_386, dynarec_ops_c6x86mx_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; +#else + x86_setopcodes(ops_386, ops_c6x86mx_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_MMX; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + ccr4 = 0x80; + break; + + case CPU_K5: + case CPU_5K86: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); +#else + x86_setopcodes(ops_386, ops_k6_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + timing_misaligned = 3; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_k6); +#endif + break; + + case CPU_K6: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); +#else + x86_setopcodes(ops_386, ops_k6_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + timing_misaligned = 3; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_k6); +#endif + break; + + case CPU_K6_2: + case CPU_K6_3: + case CPU_K6_2P: + case CPU_K6_3P: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_k62_0f, dynarec_ops_386, dynarec_ops_k62_0f); +#else + x86_setopcodes(ops_386, ops_k62_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + timing_misaligned = 3; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX | CPU_FEATURE_3DNOW; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE; + codegen_timing_set(&codegen_timing_k6); + break; + +#if defined(DEV_BRANCH) && defined(USE_I686) + case CPU_PENTIUMPRO: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentiumpro_0f, dynarec_ops_386, dynarec_ops_pentiumpro_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; +#else + x86_setopcodes(ops_386, ops_pentiumpro_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + timing_misaligned = 2; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + break; + +#if 0 + case CPU_PENTIUM2: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium2_0f, dynarec_ops_386, dynarec_ops_pentium2_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; +#else + x86_setopcodes(ops_386, ops_pentium2_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + timing_misaligned = 2; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + break; +#endif + + case CPU_PENTIUM2D: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium2d_0f, dynarec_ops_386, dynarec_ops_pentium2d_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; +#else + x86_setopcodes(ops_386, ops_pentium2d_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + timing_misaligned = 2; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE | CR4_OSFXSR; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + break; +#endif + + default: + fatal("cpu_set : unknown CPU type %i\n", cpu_s->cpu_type); + } +} + + +char * +cpu_current_pc(char *bufp) +{ + static char buff[10]; + + if (bufp == NULL) + bufp = buff; + + sprintf(bufp, "%04X:%04X", CS, cpu_state.pc); + + return(bufp); +} + + +void +cpu_CPUID(void) +{ + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) + { + case CPU_RAPIDCAD: + case CPU_i486DX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; /*FPU*/ + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_iDX4: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_Am486SX: + if (!EAX) + { + EAX = 1; + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = EDX = 0; /*No FPU*/ + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_Am486DX: + if (!EAX) + { + EAX = 1; + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; /*FPU*/ + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_WINCHIP: + if (!EAX) + { + EAX = 1; + if (msr.fcr2 & (1 << 14)) + { + EBX = msr.fcr3 >> 32; + ECX = msr.fcr3 & 0xffffffff; + EDX = msr.fcr2 >> 32; + } + else + { + EBX = 0x746e6543; /*CentaurHauls*/ + ECX = 0x736c7561; + EDX = 0x48727561; + } + } + else if (EAX == 1) + { + EAX = 0x540; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_WINCHIP2: + switch (EAX) + { + case 0: + EAX = 1; + if (msr.fcr2 & (1 << 14)) + { + EBX = msr.fcr3 >> 32; + ECX = msr.fcr3 & 0xffffffff; + EDX = msr.fcr2 >> 32; + } + else + { + EBX = 0x746e6543; /*CentaurHauls*/ + ECX = 0x736c7561; + EDX = 0x48727561; + } + break; + case 1: + EAX = 0x580; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000005; + break; + case 0x80000001: + EAX = 0x580; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + if (cpu_has_feature(CPU_FEATURE_3DNOW)) + EDX |= CPUID_3DNOW; + break; + + case 0x80000002: /*Processor name string*/ + EAX = 0x20544449; /*IDT WinChip 2-3D*/ + EBX = 0x436e6957; + ECX = 0x20706968; + EDX = 0x44332d32; + break; + + case 0x80000005: /*Cache information*/ + EBX = 0x08800880; /*TLBs*/ + ECX = 0x20040120; /*L1 data cache*/ + EDX = 0x20020120; /*L1 instruction cache*/ + break; + + default: + EAX = EBX = ECX = EDX = 0; + break; + } + break; + + case CPU_PENTIUM: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_K5: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_5K86: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000000) + { + EAX = 0x80000005; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000001) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000002) + { + EAX = 0x2D444D41; + EBX = 0x7428354B; + ECX = 0x5020296D; + EDX = 0x65636F72; + } + else if (EAX == 0x80000003) + { + EAX = 0x726F7373; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000004) + { + EAX = EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000005) + { + EAX = 0; + EBX = 0x04800000; + ECX = 0x08040120; + EDX = 0x10040120; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_K6: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + } + else if (EAX == 0x80000000) + { + EAX = 0x80000005; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000001) + { + EAX = CPUID + 0x100; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_AMDSEP | CPUID_MMX; + } + else if (EAX == 0x80000002) + { + EAX = 0x2D444D41; + EBX = 0x6D74364B; + ECX = 0x202F7720; + EDX = 0x746C756D; + } + else if (EAX == 0x80000003) + { + EAX = 0x64656D69; + EBX = 0x65206169; + ECX = 0x6E657478; + EDX = 0x6E6F6973; + } + else if (EAX == 0x80000004) + { + EAX = 0x73; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000005) + { + EAX = 0; + EBX = 0x02800140; + ECX = 0x20020220; + EDX = 0x20020220; + } + else if (EAX == 0x8FFFFFFF) + { + EAX = 0x4778654E; + EBX = 0x72656E65; + ECX = 0x6F697461; + EDX = 0x444D416E; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_K6_2: + switch (EAX) + { + case 0: + EAX = 1; + EBX = 0x68747541; /*AuthenticAMD*/ + ECX = 0x444d4163; + EDX = 0x69746e65; + break; + case 1: + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000005; + break; + case 0x80000001: + EAX = CPUID+0x100; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_3DNOW; + break; + + case 0x80000002: /*Processor name string*/ + EAX = 0x2d444d41; /*AMD-K6(tm) 3D pr*/ + EBX = 0x7428364b; + ECX = 0x3320296d; + EDX = 0x72702044; + break; + + case 0x80000003: /*Processor name string*/ + EAX = 0x7365636f; /*ocessor*/ + EBX = 0x00726f73; + ECX = 0x00000000; + EDX = 0x00000000; + break; + + case 0x80000005: /*Cache information*/ + EBX = 0x02800140; /*TLBs*/ + ECX = 0x20020220; /*L1 data cache*/ + EDX = 0x20020220; /*L1 instruction cache*/ + break; + + default: + EAX = EBX = ECX = EDX = 0; + break; + } + break; + + case CPU_K6_3: + switch (EAX) + { + case 0: + EAX = 1; + EBX = 0x68747541; /*AuthenticAMD*/ + ECX = 0x444d4163; + EDX = 0x69746e65; + break; + case 1: + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000006; + break; + case 0x80000001: + EAX = CPUID+0x100; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_3DNOW; + break; + + case 0x80000002: /*Processor name string*/ + EAX = 0x2d444d41; /*AMD-K6(tm) 3D+ P*/ + EBX = 0x7428364b; + ECX = 0x3320296d; + EDX = 0x50202b44; + break; + + case 0x80000003: /*Processor name string*/ + EAX = 0x65636f72; /*rocessor*/ + EBX = 0x726f7373; + ECX = 0x00000000; + EDX = 0x00000000; + break; + + case 0x80000005: /*Cache information*/ + EBX = 0x02800140; /*TLBs*/ + ECX = 0x20020220; /*L1 data cache*/ + EDX = 0x20020220; /*L1 instruction cache*/ + break; + + case 0x80000006: /*L2 Cache information*/ + ECX = 0x01004220; + break; + + default: + EAX = EBX = ECX = EDX = 0; + break; + } + break; + + case CPU_K6_2P: + case CPU_K6_3P: + switch (EAX) + { + case 0: + EAX = 1; + EBX = 0x68747541; /*AuthenticAMD*/ + ECX = 0x444d4163; + EDX = 0x69746e65; + break; + case 1: + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000007; + break; + case 0x80000001: + EAX = CPUID+0x100; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_3DNOW; + break; + + case 0x80000002: /*Processor name string*/ + EAX = 0x2d444d41; /*AMD-K6(tm)-III P*/ + EBX = 0x7428364b; + ECX = 0x492d296d; + EDX = 0x50204949; + break; + + case 0x80000003: /*Processor name string*/ + EAX = 0x65636f72; /*rocessor*/ + EBX = 0x726f7373; + ECX = 0x00000000; + EDX = 0x00000000; + break; + + case 0x80000005: /*Cache information*/ + EBX = 0x02800140; /*TLBs*/ + ECX = 0x20020220; /*L1 data cache*/ + EDX = 0x20020220; /*L1 instruction cache*/ + break; + + case 0x80000006: /*L2 Cache information*/ + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_K6_3P) + ECX = 0x01004220; + else + ECX = 0x00804220; + break; + + case 0x80000007: /*PowerNow information*/ + EDX = 7; + break; + + default: + EAX = EBX = ECX = EDX = 0; + break; + } + break; + + case CPU_PENTIUMMMX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + + case CPU_Cx6x86: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + + case CPU_Cx6x86L: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_CMPXCHG8B; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + + case CPU_CxGX1: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + + + case CPU_Cx6x86MX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX; + } + else + EAX = EBX = ECX = EDX = 0; + break; + +#ifdef DEV_BRANCH +#ifdef USE_I686 + case CPU_PENTIUMPRO: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_SEP | CPUID_CMOV; + } + else if (EAX == 2) + { + } + else + EAX = EBX = ECX = EDX = 0; + break; + + /* case CPU_PENTIUM2: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_CMOV; + } + else if (EAX == 2) + { + EAX = 0x03020101; + EBX = ECX = 0; + EDX = 0x0C040843; + } + else + EAX = EBX = ECX = EDX = 0; + break; */ + + case CPU_PENTIUM2D: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_FXSR | CPUID_CMOV; + } + else if (EAX == 2) + { + EAX = 0x03020101; + EBX = ECX = 0; + EDX = 0x0C040844; + } + else + EAX = EBX = ECX = EDX = 0; + break; +#endif +#endif + + } +} + +void cpu_RDMSR() +{ + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) + { + case CPU_WINCHIP: + case CPU_WINCHIP2: + EAX = EDX = 0; + switch (ECX) + { + case 0x02: + EAX = msr.tr1; + break; + case 0x0e: + EAX = msr.tr12; + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x11: + EAX = msr.cesr; + break; + case 0x107: + EAX = msr.fcr; + break; + case 0x108: + EAX = msr.fcr2 & 0xffffffff; + EDX = msr.fcr2 >> 32; + break; + case 0x10a: + EAX = cpu_multi & 3; + break; + } + break; + + case CPU_K5: + case CPU_5K86: + case CPU_K6: + case CPU_K6_2: + case CPU_K6_3: + case CPU_K6_2P: + case CPU_K6_3P: + EAX = EDX = 0; + switch (ECX) + { + case 0x0e: + EAX = msr.tr12; + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x83: + EAX = ecx83_msr & 0xffffffff; + EDX = ecx83_msr >> 32; + break; + case 0xC0000081: + EAX = star & 0xffffffff; + EDX = star >> 32; + break; + case 0xC0000084: + EAX = sfmask & 0xffffffff; + EDX = sfmask >> 32; + break; + default: + x86gpf(NULL, 0); + break; + } + break; + + case CPU_PENTIUM: + case CPU_PENTIUMMMX: + EAX = EDX = 0; + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + } + break; + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + } + break; + +#ifdef DEV_BRANCH +#ifdef USE_I686 + case CPU_PENTIUMPRO: + case CPU_PENTIUM2D: + EAX = EDX = 0; + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x17: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type != CPU_PENTIUM2D) goto i686_invalid_rdmsr; + EAX = ecx17_msr & 0xffffffff; + EDX = ecx17_msr >> 32; + break; + case 0x1B: + EAX = apic_base_msr & 0xffffffff; + EDX = apic_base_msr >> 32; + break; + case 0x2A: + EAX = 0xC5800000; + EDX = 0; + break; + case 0x79: + EAX = ecx79_msr & 0xffffffff; + EDX = ecx79_msr >> 32; + break; + case 0x88: case 0x89: case 0x8A: case 0x8B: + EAX = ecx8x_msr[ECX - 0x88] & 0xffffffff; + EDX = ecx8x_msr[ECX - 0x88] >> 32; + break; + case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: + EAX = msr_ia32_pmc[ECX - 0xC1] & 0xffffffff; + EDX = msr_ia32_pmc[ECX - 0xC1] >> 32; + break; + case 0xFE: + EAX = mtrr_cap_msr & 0xffffffff; + EDX = mtrr_cap_msr >> 32; + break; + case 0x116: + EAX = ecx116_msr & 0xffffffff; + EDX = ecx116_msr >> 32; + break; + case 0x118: case 0x119: case 0x11A: case 0x11B: + EAX = ecx11x_msr[ECX - 0x118] & 0xffffffff; + EDX = ecx11x_msr[ECX - 0x118] >> 32; + break; + case 0x11E: + EAX = ecx11e_msr & 0xffffffff; + EDX = ecx11e_msr >> 32; + break; + case 0x174: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX &= 0xFFFF0000; + EAX |= cs_msr; + break; + case 0x175: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX = esp_msr; + break; + case 0x176: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX = eip_msr; + break; + case 0x186: + EAX = ecx186_msr & 0xffffffff; + EDX = ecx186_msr >> 32; + break; + case 0x187: + EAX = ecx187_msr & 0xffffffff; + EDX = ecx187_msr >> 32; + break; + case 0x1E0: + EAX = ecx1e0_msr & 0xffffffff; + EDX = ecx1e0_msr >> 32; + break; + case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F: + if (ECX & 1) + { + EAX = mtrr_physmask_msr[(ECX - 0x200) >> 1] & 0xffffffff; + EDX = mtrr_physmask_msr[(ECX - 0x200) >> 1] >> 32; + } + else + { + EAX = mtrr_physbase_msr[(ECX - 0x200) >> 1] & 0xffffffff; + EDX = mtrr_physbase_msr[(ECX - 0x200) >> 1] >> 32; + } + break; + case 0x250: + EAX = mtrr_fix64k_8000_msr & 0xffffffff; + EDX = mtrr_fix64k_8000_msr >> 32; + break; + case 0x258: + EAX = mtrr_fix16k_8000_msr & 0xffffffff; + EDX = mtrr_fix16k_8000_msr >> 32; + break; + case 0x259: + EAX = mtrr_fix16k_a000_msr & 0xffffffff; + EDX = mtrr_fix16k_a000_msr >> 32; + break; + case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F: + EAX = mtrr_fix4k_msr[ECX - 0x268] & 0xffffffff; + EDX = mtrr_fix4k_msr[ECX - 0x268] >> 32; + break; + case 0x277: + EAX = pat_msr & 0xffffffff; + EDX = pat_msr >> 32; + break; + case 0x2FF: + EAX = mtrr_deftype_msr & 0xffffffff; + EDX = mtrr_deftype_msr >> 32; + break; + case 0x570: + EAX = ecx570_msr & 0xffffffff; + EDX = ecx570_msr >> 32; + break; + default: +i686_invalid_rdmsr: + x86gpf(NULL, 0); + break; + } + break; +#endif +#endif + } +} + +void cpu_WRMSR() +{ + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) + { + case CPU_WINCHIP: + case CPU_WINCHIP2: + switch (ECX) + { + case 0x02: + msr.tr1 = EAX & 2; + break; + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x11: + msr.cesr = EAX & 0xff00ff; + break; + case 0x107: + msr.fcr = EAX; + if (EAX & (1 << 9)) + cpu_features |= CPU_FEATURE_MMX; + else + cpu_features &= ~CPU_FEATURE_MMX; + if (EAX & (1 << 1)) + cpu_features |= CPU_FEATURE_CX8; + else + cpu_features &= ~CPU_FEATURE_CX8; + if ((EAX & (1 << 20)) && machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type >= CPU_WINCHIP2) + cpu_features |= CPU_FEATURE_3DNOW; + else + cpu_features &= ~CPU_FEATURE_3DNOW; + if (EAX & (1 << 29)) + CPUID = 0; + else + CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpuid_model; + break; + case 0x108: + msr.fcr2 = EAX | ((uint64_t)EDX << 32); + break; + case 0x109: + msr.fcr3 = EAX | ((uint64_t)EDX << 32); + break; + } + break; + + case CPU_K5: + case CPU_5K86: + case CPU_K6: + case CPU_K6_2: + case CPU_K6_3: + case CPU_K6_2P: + case CPU_K6_3P: + switch (ECX) + { + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x83: + ecx83_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000081: + star = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000084: + sfmask = EAX | ((uint64_t)EDX << 32); + break; + } + break; + + case CPU_PENTIUM: + case CPU_PENTIUMMMX: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + } + break; + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + } + break; + +#ifdef DEV_BRANCH +#ifdef USE_I686 + case CPU_PENTIUMPRO: + case CPU_PENTIUM2D: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x17: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type != CPU_PENTIUM2D) goto i686_invalid_wrmsr; + ecx17_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x1B: + apic_base_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x79: + ecx79_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x88: case 0x89: case 0x8A: case 0x8B: + ecx8x_msr[ECX - 0x88] = EAX | ((uint64_t)EDX << 32); + break; + case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: + msr_ia32_pmc[ECX - 0xC1] = EAX | ((uint64_t)EDX << 32); + break; + case 0xFE: + mtrr_cap_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x116: + ecx116_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x118: case 0x119: case 0x11A: case 0x11B: + ecx11x_msr[ECX - 0x118] = EAX | ((uint64_t)EDX << 32); + break; + case 0x11E: + ecx11e_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x174: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + cs_msr = EAX & 0xFFFF; + break; + case 0x175: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + esp_msr = EAX; + break; + case 0x176: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + eip_msr = EAX; + break; + case 0x186: + ecx186_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x187: + ecx187_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x1E0: + ecx1e0_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F: + if (ECX & 1) + mtrr_physmask_msr[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); + else + mtrr_physbase_msr[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); + break; + case 0x250: + mtrr_fix64k_8000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x258: + mtrr_fix16k_8000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x259: + mtrr_fix16k_a000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F: + mtrr_fix4k_msr[ECX - 0x268] = EAX | ((uint64_t)EDX << 32); + break; + case 0x277: + pat_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x2FF: + mtrr_deftype_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x570: + ecx570_msr = EAX | ((uint64_t)EDX << 32); + break; + default: +i686_invalid_wrmsr: + x86gpf(NULL, 0); + break; + } + break; +#endif +#endif + } +} + +static int cyrix_addr; + +static void cpu_write(uint16_t addr, uint8_t val, void *priv) +{ + if (addr == 0xf0) { + /* Writes to F0 clear FPU error and deassert the interrupt. */ + if (is286) + picintc(1 << 13); + else + nmi = 0; + return; + } else if (addr >= 0xf1) + return; /* FPU stuff */ + + if (!(addr & 1)) + cyrix_addr = val; + else switch (cyrix_addr) + { + case 0xc0: /*CCR0*/ + ccr0 = val; + break; + case 0xc1: /*CCR1*/ + ccr1 = val; + break; + case 0xc2: /*CCR2*/ + ccr2 = val; + break; + case 0xc3: /*CCR3*/ + ccr3 = val; + break; + case 0xe8: /*CCR4*/ + if ((ccr3 & 0xf0) == 0x10) + { + ccr4 = val; + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_Cx6x86) + { + if (val & 0x80) + CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpuid_model; + else + CPUID = 0; + } + } + break; + case 0xe9: /*CCR5*/ + if ((ccr3 & 0xf0) == 0x10) + ccr5 = val; + break; + case 0xea: /*CCR6*/ + if ((ccr3 & 0xf0) == 0x10) + ccr6 = val; + break; + } +} + +static uint8_t cpu_read(uint16_t addr, void *priv) +{ + if (addr >= 0xf0) + return 0xff; /* FPU stuff */ + + if (addr & 1) + { + switch (cyrix_addr) + { + case 0xc0: return ccr0; + case 0xc1: return ccr1; + case 0xc2: return ccr2; + case 0xc3: return ccr3; + case 0xe8: return ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; + case 0xe9: return ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; + case 0xea: return ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; + case 0xfe: return machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cyrix_id & 0xff; + case 0xff: return machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cyrix_id >> 8; + } + if ((cyrix_addr & 0xf0) == 0xc0) return 0xff; + if (cyrix_addr == 0x20 && machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_Cx5x86) return 0xff; + } + return 0xff; +} + + +void +#ifdef USE_DYNAREC +x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f, + const OpFn *dynarec_opcodes, const OpFn *dynarec_opcodes_0f) +{ + x86_opcodes = opcodes; + x86_opcodes_0f = opcodes_0f; + x86_dynarec_opcodes = dynarec_opcodes; + x86_dynarec_opcodes_0f = dynarec_opcodes_0f; +} +#else +x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f) +{ + x86_opcodes = opcodes; + x86_opcodes_0f = opcodes_0f; +} +#endif + + +void +cpu_update_waitstates(void) +{ + cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective]; + + if (is486) + cpu_prefetch_width = 16; + else + cpu_prefetch_width = cpu_16bitbus ? 2 : 4; + + if (cpu_cache_int_enabled) + { + /* Disable prefetch emulation */ + cpu_prefetch_cycles = 0; + } + else if (cpu_waitstates && (cpu_s->cpu_type >= CPU_286 && cpu_s->cpu_type <= CPU_386DX)) + { + /* Waitstates override */ + cpu_prefetch_cycles = cpu_waitstates+1; + cpu_cycles_read = cpu_waitstates+1; + cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * (cpu_waitstates+1); + cpu_cycles_write = cpu_waitstates+1; + cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * (cpu_waitstates+1); + } + else if (cpu_cache_ext_enabled) + { + /* Use cache timings */ + cpu_prefetch_cycles = cpu_s->cache_read_cycles; + cpu_cycles_read = cpu_s->cache_read_cycles; + cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * cpu_s->cache_read_cycles; + cpu_cycles_write = cpu_s->cache_write_cycles; + cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->cache_write_cycles; + } + else + { + /* Use memory timings */ + cpu_prefetch_cycles = cpu_s->mem_read_cycles; + cpu_cycles_read = cpu_s->mem_read_cycles; + cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_read_cycles; + cpu_cycles_write = cpu_s->mem_write_cycles; + cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_write_cycles; + } + if (is486) + cpu_prefetch_cycles = (cpu_prefetch_cycles * 11) / 16; + cpu_mem_prefetch_cycles = cpu_prefetch_cycles; + if (cpu_s->rspeed <= 8000000) + cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; +} diff --git a/src/cpu_new/cpu.h b/src/cpu_new/cpu.h new file mode 100644 index 000000000..953f0bee1 --- /dev/null +++ b/src/cpu_new/cpu.h @@ -0,0 +1,486 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * CPU type handler. + * + * Version: @(#)cpu.h 1.0.13 2018/11/14 + * + * Authors: Sarah Walker, + * leilei, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016,2018 Miran Grca. + */ +#ifndef EMU_CPU_H +# define EMU_CPU_H + + +#define CPU_8088 0 /* 808x class CPUs */ +#define CPU_8086 1 +#define CPU_286 2 /* 286 class CPUs */ +#define CPU_386SX 3 /* 386 class CPUs */ +#define CPU_386DX 4 +#define CPU_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 MANU_INTEL 0 +#define MANU_AMD 1 +#define MANU_CYRIX 2 +#define MANU_IDT 3 + +#define CPU_SUPPORTS_DYNAREC 1 +#define CPU_REQUIRES_DYNAREC 2 +#define CPU_ALTERNATE_XTAL 4 + + +typedef struct { + const char *name; + int cpu_type; + int rspeed; + 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; +} CPU; + +extern CPU cpus_8088[]; +extern CPU cpus_8086[]; +extern CPU cpus_286[]; +extern CPU cpus_i386SX[]; +extern CPU cpus_i386DX[]; +extern CPU cpus_Am386SX[]; +extern CPU cpus_Am386DX[]; +extern CPU cpus_486SLC[]; +extern CPU cpus_486DLC[]; +extern CPU cpus_i486[]; +extern CPU cpus_Am486[]; +extern CPU cpus_Cx486[]; +extern CPU cpus_WinChip[]; +extern CPU cpus_WinChip_SS7[]; +extern CPU cpus_Pentium5V[]; +extern CPU cpus_Pentium5V50[]; +extern CPU cpus_PentiumS5[]; +extern CPU cpus_K5[]; +extern CPU cpus_K56[]; +extern CPU cpus_K56_SS7[]; +extern CPU cpus_Pentium[]; +extern CPU cpus_6x86[]; +#ifdef DEV_BRANCH +#ifdef USE_I686 +extern CPU cpus_PentiumPro[]; +extern CPU cpus_Pentium2[]; +extern CPU cpus_Pentium2D[]; +#endif +#endif + + +#define C_FLAG 0x0001 +#define P_FLAG 0x0004 +#define A_FLAG 0x0010 +#define Z_FLAG 0x0040 +#define N_FLAG 0x0080 +#define T_FLAG 0x0100 +#define I_FLAG 0x0200 +#define D_FLAG 0x0400 +#define V_FLAG 0x0800 +#define NT_FLAG 0x4000 + +#define VM_FLAG 0x0002 /* in EFLAGS */ +#define VIF_FLAG 0x0008 /* in EFLAGS */ +#define VIP_FLAG 0x0010 /* in EFLAGS */ + +#define WP_FLAG 0x10000 /* in CR0 */ +#define CR4_VME (1 << 0) +#define CR4_PVI (1 << 1) +#define CR4_PSE (1 << 4) + +#define CPL ((cpu_state.seg_cs.access>>5)&3) + +#define IOPL ((cpu_state.flags>>12)&3) + +#define IOPLp ((!(msw&1)) || (CPL<=IOPL)) + + +typedef union { + uint32_t l; + uint16_t w; + struct { + uint8_t l, + h; + } b; +} x86reg; + +typedef struct { + uint32_t base; + uint32_t limit; + uint8_t access; + uint16_t seg; + uint32_t limit_low, + limit_high; + int checked; /*Non-zero if selector is known to be valid*/ +} x86seg; + +typedef union { + uint64_t q; + int64_t sq; + uint32_t l[2]; + int32_t sl[2]; + uint16_t w[4]; + int16_t sw[4]; + uint8_t b[8]; + int8_t sb[8]; + float f[2]; +} MMX_REG; + +typedef struct { + uint32_t tr1, tr12; + uint32_t cesr; + uint32_t fcr; + uint64_t fcr2, fcr3; +} msr_t; + +typedef union { + uint32_t l; + uint16_t w; +} cr0_t; + + +struct _cpustate_ { + x86reg regs[8]; + + uint8_t tag[8]; + + x86seg *ea_seg; + uint32_t eaaddr; + + int flags_op; + uint32_t flags_res; + uint32_t flags_op1, + flags_op2; + + uint32_t pc; + uint32_t oldpc; + uint32_t op32; + + int TOP; + + union { + struct { + int8_t rm, + mod, + reg; + } rm_mod_reg; + int32_t rm_mod_reg_data; + } rm_data; + + int8_t ssegs; + int8_t ismmx; + int8_t abrt; + + int _cycles; + int cpu_recomp_ins; + + uint16_t npxs, + npxc; + + double ST[8]; + + uint16_t MM_w4[8]; + + MMX_REG MM[8]; + + uint16_t old_npxc, + new_npxc; + uint32_t last_ea; + + uint32_t old_fp_control, new_fp_control; +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ + uint16_t old_fp_control2, new_fp_control2; +#endif +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined __amd64__ + uint32_t trunc_fp_control; +#endif + + x86seg seg_cs, + seg_ds, + seg_es, + seg_ss, + seg_fs, + seg_gs; + + uint16_t flags, eflags; +} cpu_state; + +/*The cpu_state.flags below must match in both cpu_cur_status and block->status for a block + to be valid*/ +#define CPU_STATUS_USE32 (1 << 0) +#define CPU_STATUS_STACK32 (1 << 1) +#define CPU_STATUS_PMODE (1 << 2) +#define CPU_STATUS_V86 (1 << 3) +#define CPU_STATUS_FLAGS 0xffff + +/*If the cpu_state.flags below are set in cpu_cur_status, they must be set in block->status. + Otherwise they are ignored*/ +#define CPU_STATUS_NOTFLATDS (1 << 8) +#define CPU_STATUS_NOTFLATSS (1 << 9) +#define CPU_STATUS_MASK 0xff00 + +#ifdef __MSC__ +# define COMPILE_TIME_ASSERT(expr) /*nada*/ +#else +# ifdef EXTREME_DEBUG +# define COMPILE_TIME_ASSERT(expr) typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0]; +# else +# define COMPILE_TIME_ASSERT(expr) /*nada*/ +# endif +#endif + +COMPILE_TIME_ASSERT(sizeof(cpu_state) <= 128) + +#define cpu_state_offset(MEMBER) ((uint8_t)((uintptr_t)&cpu_state.MEMBER - (uintptr_t)&cpu_state - 128)) + +#define EAX cpu_state.regs[0].l +#define AX cpu_state.regs[0].w +#define AL cpu_state.regs[0].b.l +#define AH cpu_state.regs[0].b.h +#define ECX cpu_state.regs[1].l +#define CX cpu_state.regs[1].w +#define CL cpu_state.regs[1].b.l +#define CH cpu_state.regs[1].b.h +#define EDX cpu_state.regs[2].l +#define DX cpu_state.regs[2].w +#define DL cpu_state.regs[2].b.l +#define DH cpu_state.regs[2].b.h +#define EBX cpu_state.regs[3].l +#define BX cpu_state.regs[3].w +#define BL cpu_state.regs[3].b.l +#define BH cpu_state.regs[3].b.h +#define ESP cpu_state.regs[4].l +#define EBP cpu_state.regs[5].l +#define ESI cpu_state.regs[6].l +#define EDI cpu_state.regs[7].l +#define SP cpu_state.regs[4].w +#define BP cpu_state.regs[5].w +#define SI cpu_state.regs[6].w +#define DI cpu_state.regs[7].w + +#define cycles cpu_state._cycles + +#define cpu_rm cpu_state.rm_data.rm_mod_reg.rm +#define cpu_mod cpu_state.rm_data.rm_mod_reg.mod +#define cpu_reg cpu_state.rm_data.rm_mod_reg.reg + +#define CR4_TSD (1 << 2) +#define CR4_DE (1 << 3) +#define CR4_MCE (1 << 6) +#define CR4_PCE (1 << 8) +#define CR4_OSFXSR (1 << 9) + + +/* Global variables. */ +extern int cpu_iscyrix; +extern int cpu_16bitbus; +extern int cpu_busspeed; +extern int cpu_multi; +extern int cpu_cyrix_alignment; /*Cyrix 5x86/6x86 only has data misalignment + penalties when crossing 8-byte boundaries*/ + +extern int is8086, is286, is386, is486; +extern int is_rapidcad; +extern int hasfpu; +#define CPU_FEATURE_RDTSC (1 << 0) +#define CPU_FEATURE_MSR (1 << 1) +#define CPU_FEATURE_MMX (1 << 2) +#define CPU_FEATURE_CR4 (1 << 3) +#define CPU_FEATURE_VME (1 << 4) +#define CPU_FEATURE_CX8 (1 << 5) +#define CPU_FEATURE_3DNOW (1 << 6) + +extern uint32_t cpu_features; + +extern uint16_t cpu_cur_status; +extern uint64_t cpu_CR4_mask; +extern uint64_t tsc; +extern msr_t msr; +extern uint8_t opcode; +extern int insc; +extern int fpucount; +extern float mips,flops; +extern int clockrate; +extern int cgate16; +extern int cpl_override; +extern int CPUID; +extern uint64_t xt_cpu_multi; +extern int isa_cycles; +extern uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; +extern int ins,output; +extern uint32_t pccache; +extern uint8_t *pccache2; + +extern double bus_timing; +extern uint64_t pmc[2]; +extern uint16_t temp_seg_data[4]; +extern uint16_t cs_msr; +extern uint32_t esp_msr; +extern uint32_t eip_msr; + +/* For the AMD K6. */ +extern uint64_t star; + +#define FPU_CW_Reserved_Bits (0xe0c0) + +extern cr0_t CR0; +#define cr0 CR0.l +#define msw CR0.w +extern uint32_t cr2, cr3, cr4; +extern uint32_t dr[8]; + + +/*Segments - + _cs,_ds,_es,_ss are the segment structures + CS,DS,ES,SS is the 16-bit data + cs,ds,es,ss are defines to the bases*/ +extern x86seg gdt,ldt,idt,tr; +extern x86seg _oldds; +#define CS cpu_state.seg_cs.seg +#define DS cpu_state.seg_ds.seg +#define ES cpu_state.seg_es.seg +#define SS cpu_state.seg_ss.seg +#define FS cpu_state.seg_fs.seg +#define GS cpu_state.seg_gs.seg +#define cs cpu_state.seg_cs.base +#define ds cpu_state.seg_ds.base +#define es cpu_state.seg_es.base +#define ss cpu_state.seg_ss.base +#define fs_seg cpu_state.seg_fs.base +#define gs cpu_state.seg_gs.base + + +#define ISA_CYCLES(x) (x * isa_cycles) + +extern int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l; +extern int cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles; +extern int cpu_waitstates; +extern int cpu_cache_int_enabled, cpu_cache_ext_enabled; +extern int cpu_pci_speed; + +extern int timing_rr; +extern int timing_mr, timing_mrl; +extern int timing_rm, timing_rml; +extern int timing_mm, timing_mml; +extern int timing_bt, timing_bnt; +extern int timing_int, timing_int_rm, timing_int_v86, timing_int_pm; +extern int timing_int_pm_outer, timing_iret_rm, timing_iret_v86, timing_iret_pm; +extern int timing_iret_pm_outer, timing_call_rm, timing_call_pm; +extern int timing_call_pm_gate, timing_call_pm_gate_inner; +extern int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; +extern int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; +extern int timing_misaligned; + + +extern CPU cpus_pcjr[]; // FIXME: should be in machine file! +extern CPU cpus_europc[]; // FIXME: should be in machine file! +extern CPU cpus_pc1512[]; // FIXME: should be in machine file! +extern CPU cpus_ibmat[]; // FIXME: should be in machine file! +extern CPU cpus_ibmxt286[]; // FIXME: should be in machine file! +extern CPU cpus_ps1_m2011[]; // FIXME: should be in machine file! +extern CPU cpus_ps2_m30_286[]; // FIXME: should be in machine file! +#if 0 +extern CPU cpus_acer[]; // FIXME: should be in machine file! +#endif + + +/* Functions. */ +extern int cpu_has_feature(int feature); + +int loadseg(uint16_t seg, x86seg *s); +void loadseg_dynarec(uint16_t seg, x86seg *s); +void loadcs(uint16_t seg); + +extern char *cpu_current_pc(char *bufp); + +extern void cpu_update_waitstates(void); +extern void cpu_set(void); + +extern void cpu_CPUID(void); +extern void cpu_RDMSR(void); +extern void cpu_WRMSR(void); + +extern int checkio(int port); +extern void codegen_block_end(void); +extern void codegen_reset(void); +extern void cpu_set_edx(void); +extern int divl(uint32_t val); +extern void execx86(int cycs); +extern void exec386(int cycs); +extern void exec386_dynarec(int cycs); +extern int idivl(int32_t val); +void pmodeint(int num, int soft); +int loadseg(uint16_t seg, x86seg *s); +void loadcs(uint16_t seg); +void loadcscall(uint16_t seg, uint32_t old_pc); +void loadcsjmp(uint16_t seg, uint32_t old_pc); +void pmoderetf(int is32, uint16_t off); +void pmodeiret(int is32); +extern void resetmcr(void); +extern void resetx86(void); +extern void refreshread(void); +extern void resetreadlookup(void); +extern void softresetx86(void); +extern void x86_int(int num); +extern void x86_int_sw(int num); +extern int x86_int_sw_rm(int num); +extern void x86gpf(char *s, uint16_t error); +extern void x86np(char *s, uint16_t error); +extern void x86ss(char *s, uint16_t error); +extern void x86ts(char *s, uint16_t error); + +#ifdef ENABLE_808X_LOG +extern void dumpregs(int __force); +extern void x87_dumpregs(void); +extern void x87_reset(void); +#endif + +extern int cpu_effective, cpu_alt_reset; +extern void cpu_dynamic_switch(int new_cpu); + + +#endif /*EMU_CPU_H*/ diff --git a/src/cpu_new/cpu_table.c b/src/cpu_new/cpu_table.c new file mode 100644 index 000000000..4d02396ff --- /dev/null +++ b/src/cpu_new/cpu_table.c @@ -0,0 +1,523 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Define all known processor types. + * + * Available cpuspeeds: + * + * 0 = 16 MHz + * 1 = 20 MHz + * 2 = 25 MHz + * 3 = 33 MHz + * 4 = 40 MHz + * 5 = 50 MHz + * 6 = 66 MHz + * 7 = 75 MHz + * 8 = 80 MHz + * 9 = 90 MHz + * 10 = 100 MHz + * 11 = 120 MHz + * 12 = 133 MHz + * 13 = 150 MHz + * 14 = 160 MHz + * 15 = 166 MHz + * 16 = 180 MHz + * 17 = 200 MHz + * + * Version: @(#)cpu_table.c 1.0.6 2018/07/24 + * + * Authors: Sarah Walker, + * leilei, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../machine/machine.h" + + +CPU cpus_8088[] = { + /*8088 standard*/ + {"8088/4.77", CPU_8088, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/7.16", CPU_8088, 7159092, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/8", CPU_8088, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/10", CPU_8088, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/12", CPU_8088, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/16", CPU_8088, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"i386SX/16", CPU_386SX, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"i386DX/16", CPU_386DX, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3, 2}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_pcjr[] = { + /*8088 PCjr*/ + {"8088/4.77", CPU_8088, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_europc[] = { + /*8088 EuroPC*/ + {"8088/4.77", CPU_8088, 4772728, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8088/7.16", CPU_8088, 7159092, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8088/9.54", CPU_8088, 9545456, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_8086[] = { + /*8086 standard*/ + {"8086/7.16", CPU_8086, 7159092, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8086/8", CPU_8086, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/9.54", CPU_8086, 9545456, 1, 0, 0, 0, 0, CPU_ALTERNATE_XTAL, 0,0,0,0, 1}, + {"8086/10", CPU_8086, 10000000, 2, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/12", CPU_8086, 12000000, 3, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/16", CPU_8086, 16000000, 4, 0, 0, 0, 0, 0, 0,0,0,0, 2}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_pc1512[] = { + /*8086 Amstrad*/ + {"8086/8", CPU_8086, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_286[] = { + /*286*/ + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/8", CPU_286, 8000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/10", CPU_286, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/12", CPU_286, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/16", CPU_286, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/20", CPU_286, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"286/25", CPU_286, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_ibmat[] = { + /*286*/ + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"286/8", CPU_286, 8000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_ibmxt286[] = { + /*286*/ + {"286/6", CPU_286, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_ps1_m2011[] = { + /*286*/ + {"286/10", CPU_286, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 9} +}; + +CPU cpus_ps2_m30_286[] = { + /*286*/ + {"286/10", CPU_286, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/12", CPU_286, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/16", CPU_286, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/20", CPU_286, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"286/25", CPU_286, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_i386SX[] = { + /*i386SX*/ + {"i386SX/16", CPU_386SX, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"i386SX/20", CPU_386SX, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"i386SX/25", CPU_386SX, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"i386SX/33", CPU_386SX, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"i386SX/40", CPU_386SX, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_i386DX[] = { + /*i386DX*/ + {"i386DX/16", CPU_386DX, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3, 2}, + {"i386DX/20", CPU_386DX, 20000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"i386DX/25", CPU_386DX, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"i386DX/33", CPU_386DX, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"i386DX/40", CPU_386DX, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"RapidCAD/25", CPU_RAPIDCAD, 25000000, 1, 0, 0x0430, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, + {"RapidCAD/33", CPU_RAPIDCAD, 33333333, 1, 0, 0x0430, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"RapidCAD/40", CPU_RAPIDCAD, 40000000, 1, 0, 0x0430, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, + {"i486DX/33", CPU_i486DX, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6, 6,3,3, 4}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_Am386SX[] = { + /*Am386*/ + {"Am386SX/16", CPU_386SX, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"Am386SX/20", CPU_386SX, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386SX/25", CPU_386SX, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386SX/33", CPU_386SX, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"Am386SX/40", CPU_386SX, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_Am386DX[] = { + /*Am386*/ + {"Am386DX/25", CPU_386DX, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386DX/33", CPU_386DX, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"Am386DX/40", CPU_386DX, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_486SLC[] = { + /*Cx486SLC*/ + {"Cx486SLC/20", CPU_486SLC, 20000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"Cx486SLC/25", CPU_486SLC, 25000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"Cx486SLC/33", CPU_486SLC, 33333333, 1, 0, 0x400, 0, 0x0000, 0, 6,6,3,3, 4}, + {"Cx486SRx2/32", CPU_486SLC, 32000000, 2, 0, 0x406, 0, 0x0006, 0, 6,6,6,6, 4}, + {"Cx486SRx2/40", CPU_486SLC, 40000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, + {"Cx486SRx2/50", CPU_486SLC, 50000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0, 0} +}; + +CPU cpus_486DLC[] = { + /*Cx486DLC*/ + {"Cx486DLC/25", CPU_486DLC, 25000000, 1, 0, 0x401, 0, 0x0001, 0, 4, 4,3,3, 3}, + {"Cx486DLC/33", CPU_486DLC, 33333333, 1, 0, 0x401, 0, 0x0001, 0, 6, 6,3,3, 4}, + {"Cx486DLC/40", CPU_486DLC, 40000000, 1, 0, 0x401, 0, 0x0001, 0, 7, 7,3,3, 5}, + {"Cx486DRx2/32", CPU_486DLC, 32000000, 2, 0, 0x407, 0, 0x0007, 0, 6, 6,6,6, 4}, + {"Cx486DRx2/40", CPU_486DLC, 40000000, 2, 0, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6}, + {"Cx486DRx2/50", CPU_486DLC, 50000000, 2, 0, 0x407, 0, 0x0007, 0, 8, 8,6,6, 6}, + {"Cx486DRx2/66", CPU_486DLC, 66666666, 2, 0, 0x407, 0, 0x0007, 0, 12,12,6,6, 8}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; + +CPU cpus_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, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8, 8,6,6, 6}, + {"i486SX2/66 (Q0569)", CPU_i486SX, 66666666, 2, 33333333, 0x45b, 0x45b, 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}, + {"", -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}, + {"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}, + {"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}, + {"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}, + {"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}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +CPU cpus_Cx486[] = { + /*Cx486/5x86*/ + {"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}, + {"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}, + {"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}, + {"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}, + {"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/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_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}, + + /*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}, + + /*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}, + {"", -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}, + {"", -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}, + {"", -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 OverDrive 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Pentium OverDrive 133", CPU_PENTIUM, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; + +CPU cpus_Pentium5V50[] = { + /*Intel Pentium (5V, socket 4, including 50 MHz FSB)*/ + {"Pentium 50 (Q0399)", CPU_PENTIUM, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4, 4,3,3, 6}, + {"Pentium 60", CPU_PENTIUM, 60000000, 1, 30000000, 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 OverDrive 100", CPU_PENTIUM, 100000000, 2, 25000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8, 8,6,6, 12}, + {"Pentium OverDrive 120", CPU_PENTIUM, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Pentium OverDrive 133", CPU_PENTIUM, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0, 0} +}; + +CPU cpus_PentiumS5[] = { + /*Intel Pentium (Socket 5)*/ + {"Pentium 75", CPU_PENTIUM, 75000000, 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}, + {"", -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}, + {"", -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}, + {"", -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}, + {"", -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}, + {"", -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}, + {"Pentium II 75", CPU_PENTIUM2D, 75000000, 2, 25000000, 0x654, 0x654, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7, 7, 4, 4, 9}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; +#endif +#endif diff --git a/src/cpu_new/x86.h b/src/cpu_new/x86.h new file mode 100644 index 000000000..e3505a2e2 --- /dev/null +++ b/src/cpu_new/x86.h @@ -0,0 +1,70 @@ +extern uint8_t opcode, opcode2; +extern uint8_t flags_p; +extern uint8_t znptable8[256]; + +extern uint16_t zero, oldcs; +extern uint16_t lastcs, lastpc; +extern uint16_t *mod1add[2][8]; +extern uint16_t znptable16[65536]; + +extern int x86_was_reset, trap; +extern int codegen_flat_ss, codegen_flat_ds; +extern int timetolive, keyboardtimer, trap; +extern int optype, stack32; +extern int oldcpl, cgate32, cpl_override, fpucount; +extern int nmi_enable; +extern int oddeven, inttype; + +extern uint32_t use32; +extern uint32_t rmdat, easeg; +extern uint32_t oxpc, flags_zn; +extern uint32_t abrt_error; +extern uint32_t backupregs[16]; +extern uint32_t *mod1seg[8]; +extern uint32_t *eal_r, *eal_w; + +#define fetchdat rmdat + +#define setznp168 setznp16 + +#define getr8(r) ((r&4)?cpu_state.regs[r&3].b.h:cpu_state.regs[r&3].b.l) +#define getr16(r) cpu_state.regs[r].w +#define getr32(r) cpu_state.regs[r].l + +#define setr8(r,v) if (r&4) cpu_state.regs[r&3].b.h=v; \ + else cpu_state.regs[r&3].b.l=v; +#define setr16(r,v) cpu_state.regs[r].w=v +#define setr32(r,v) cpu_state.regs[r].l=v + +#define fetchea() { \ + rmdat = readmemb(cs + pc); \ + pc++; \ + reg = (rmdat >> 3) & 7; \ + mod = (rmdat >> 6) & 3; \ + rm = rmdat & 7; \ + if (mod!=3) \ + fetcheal(); \ + } + +#define JMP 1 +#define CALL 2 +#define IRET 3 +#define OPTYPE_INT 4 + + +enum +{ + ABRT_NONE = 0, + ABRT_GEN, + ABRT_TS = 0xA, + ABRT_NP = 0xB, + ABRT_SS = 0xC, + ABRT_GPF = 0xD, + ABRT_PF = 0xE +}; + + +extern void x86_doabrt(int x86_abrt); +extern void x86illegal(); +extern void x86seg_reset(); +extern void x86gpf(char *s, uint16_t error); diff --git a/src/cpu_new/x86_flags.h b/src/cpu_new/x86_flags.h new file mode 100644 index 000000000..9a9983926 --- /dev/null +++ b/src/cpu_new/x86_flags.h @@ -0,0 +1,630 @@ +extern int tempc; + +enum +{ + FLAGS_UNKNOWN, + + FLAGS_ZN8, + FLAGS_ZN16, + FLAGS_ZN32, + + FLAGS_ADD8, + FLAGS_ADD16, + FLAGS_ADD32, + + FLAGS_SUB8, + FLAGS_SUB16, + FLAGS_SUB32, + + FLAGS_SHL8, + FLAGS_SHL16, + FLAGS_SHL32, + + FLAGS_SHR8, + FLAGS_SHR16, + FLAGS_SHR32, + + FLAGS_SAR8, + FLAGS_SAR16, + FLAGS_SAR32, + + FLAGS_ROL8, + FLAGS_ROL16, + FLAGS_ROL32, + + FLAGS_ROR8, + FLAGS_ROR16, + FLAGS_ROR32, + + FLAGS_INC8, + FLAGS_INC16, + FLAGS_INC32, + + FLAGS_DEC8, + FLAGS_DEC16, + FLAGS_DEC32, + + FLAGS_ADC8, + FLAGS_ADC16, + FLAGS_ADC32, + + FLAGS_SBC8, + FLAGS_SBC16, + FLAGS_SBC32 +}; + +static inline int ZF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + case FLAGS_ADC8: + case FLAGS_ADC16: + case FLAGS_ADC32: + case FLAGS_SBC8: + case FLAGS_SBC16: + case FLAGS_SBC32: + return !cpu_state.flags_res; + + case FLAGS_ROL8: + case FLAGS_ROL16: + case FLAGS_ROL32: + case FLAGS_ROR8: + case FLAGS_ROR16: + case FLAGS_ROR32: + case FLAGS_UNKNOWN: + return cpu_state.flags & Z_FLAG; + } + return 0; +} + +static inline int NF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ADD8: + case FLAGS_SUB8: + case FLAGS_SHL8: + case FLAGS_SHR8: + case FLAGS_SAR8: + case FLAGS_INC8: + case FLAGS_DEC8: + case FLAGS_ADC8: + case FLAGS_SBC8: + return cpu_state.flags_res & 0x80; + + case FLAGS_ZN16: + case FLAGS_ADD16: + case FLAGS_SUB16: + case FLAGS_SHL16: + case FLAGS_SHR16: + case FLAGS_SAR16: + case FLAGS_INC16: + case FLAGS_DEC16: + case FLAGS_ADC16: + case FLAGS_SBC16: + return cpu_state.flags_res & 0x8000; + + case FLAGS_ZN32: + case FLAGS_ADD32: + case FLAGS_SUB32: + case FLAGS_SHL32: + case FLAGS_SHR32: + case FLAGS_SAR32: + case FLAGS_INC32: + case FLAGS_DEC32: + case FLAGS_ADC32: + case FLAGS_SBC32: + return cpu_state.flags_res & 0x80000000; + + case FLAGS_ROL8: + case FLAGS_ROL16: + case FLAGS_ROL32: + case FLAGS_ROR8: + case FLAGS_ROR16: + case FLAGS_ROR32: + case FLAGS_UNKNOWN: + return cpu_state.flags & N_FLAG; + } + return 0; +} + +static inline int PF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + case FLAGS_ADC8: + case FLAGS_ADC16: + case FLAGS_ADC32: + case FLAGS_SBC8: + case FLAGS_SBC16: + case FLAGS_SBC32: + return znptable8[cpu_state.flags_res & 0xff] & P_FLAG; + + case FLAGS_ROL8: + case FLAGS_ROL16: + case FLAGS_ROL32: + case FLAGS_ROR8: + case FLAGS_ROR16: + case FLAGS_ROR32: + case FLAGS_UNKNOWN: + return cpu_state.flags & P_FLAG; + } + return 0; +} + +static inline int VF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADC8: + case FLAGS_ADD8: + case FLAGS_INC8: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); + case FLAGS_ADC16: + case FLAGS_ADD16: + case FLAGS_INC16: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x8000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); + case FLAGS_ADC32: + case FLAGS_ADD32: + case FLAGS_INC32: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80000000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); + + case FLAGS_SBC8: + case FLAGS_SUB8: + case FLAGS_DEC8: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); + case FLAGS_SBC16: + case FLAGS_SUB16: + case FLAGS_DEC16: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); + case FLAGS_SBC32: + case FLAGS_SUB32: + case FLAGS_DEC32: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); + + case FLAGS_SHL8: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80); + case FLAGS_SHL16: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x8000); + case FLAGS_SHL32: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80000000); + + case FLAGS_SHR8: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80)); + case FLAGS_SHR16: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x8000)); + case FLAGS_SHR32: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80000000)); + + case FLAGS_ROL8: + return (cpu_state.flags_res ^ (cpu_state.flags_res >> 7)) & 1; + case FLAGS_ROL16: + return (cpu_state.flags_res ^ (cpu_state.flags_res >> 15)) & 1; + case FLAGS_ROL32: + return (cpu_state.flags_res ^ (cpu_state.flags_res >> 31)) & 1; + + case FLAGS_ROR8: + return (cpu_state.flags_res ^ (cpu_state.flags_res >> 1)) & 0x40; + case FLAGS_ROR16: + return (cpu_state.flags_res ^ (cpu_state.flags_res >> 1)) & 0x4000; + case FLAGS_ROR32: + return (cpu_state.flags_res ^ (cpu_state.flags_res >> 1)) & 0x40000000; + + case FLAGS_UNKNOWN: + return cpu_state.flags & V_FLAG; + } + return 0; +} + +static inline int AF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + return ((cpu_state.flags_op1 & 0xF) + (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_ADC8: + return ((cpu_state.flags_res & 0xf) < (cpu_state.flags_op1 & 0xf)) || + ((cpu_state.flags_res & 0xf) == (cpu_state.flags_op1 & 0xf) && cpu_state.flags_op2 == 0xff); + case FLAGS_ADC16: + return ((cpu_state.flags_res & 0xf) < (cpu_state.flags_op1 & 0xf)) || + ((cpu_state.flags_res & 0xf) == (cpu_state.flags_op1 & 0xf) && cpu_state.flags_op2 == 0xffff); + case FLAGS_ADC32: + return ((cpu_state.flags_res & 0xf) < (cpu_state.flags_op1 & 0xf)) || + ((cpu_state.flags_res & 0xf) == (cpu_state.flags_op1 & 0xf) && cpu_state.flags_op2 == 0xffffffff); + + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return ((cpu_state.flags_op1 & 0xF) - (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_SBC8: + case FLAGS_SBC16: + case FLAGS_SBC32: + return ((cpu_state.flags_op1 & 0xf) < (cpu_state.flags_op2 & 0xf)) || + ((cpu_state.flags_op1 & 0xf) == (cpu_state.flags_op2 & 0xf) && (cpu_state.flags_res & 0xf) != 0); + + case FLAGS_ROL8: + case FLAGS_ROL16: + case FLAGS_ROL32: + case FLAGS_ROR8: + case FLAGS_ROR16: + case FLAGS_ROR32: + case FLAGS_UNKNOWN: + return cpu_state.flags & A_FLAG; + } + return 0; +} + +static inline int CF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ADD8: + return ((cpu_state.flags_op1 + cpu_state.flags_op2) & 0x100) ? 1 : 0; + case FLAGS_ADD16: + return ((cpu_state.flags_op1 + cpu_state.flags_op2) & 0x10000) ? 1 : 0; + case FLAGS_ADD32: + return (cpu_state.flags_res < cpu_state.flags_op1); + + case FLAGS_ADC8: + return (cpu_state.flags_res < cpu_state.flags_op1) || + (cpu_state.flags_res == cpu_state.flags_op1 && cpu_state.flags_op2 == 0xff); + case FLAGS_ADC16: + return (cpu_state.flags_res < cpu_state.flags_op1) || + (cpu_state.flags_res == cpu_state.flags_op1 && cpu_state.flags_op2 == 0xffff); + case FLAGS_ADC32: + return (cpu_state.flags_res < cpu_state.flags_op1) || + (cpu_state.flags_res == cpu_state.flags_op1 && cpu_state.flags_op2 == 0xffffffff); + + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + return (cpu_state.flags_op1 < cpu_state.flags_op2); + + case FLAGS_SBC8: + case FLAGS_SBC16: + case FLAGS_SBC32: + return (cpu_state.flags_op1 < cpu_state.flags_op2) || + (cpu_state.flags_op1 == cpu_state.flags_op2 && cpu_state.flags_res != 0); + + case FLAGS_SHL8: + return ((cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80) ? 1 : 0; + case FLAGS_SHL16: + return ((cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x8000) ? 1 : 0; + case FLAGS_SHL32: + return ((cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80000000) ? 1 : 0; + + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + return (cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_SAR8: + return ((int8_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR16: + return ((int16_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR32: + return ((int32_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + return 0; + + case FLAGS_ROL8: + case FLAGS_ROL16: + case FLAGS_ROL32: + return cpu_state.flags_res & 1; + + case FLAGS_ROR8: + return (cpu_state.flags_res & 0x80) ? 1 : 0; + case FLAGS_ROR16: + return (cpu_state.flags_res & 0x8000) ? 1 :0; + case FLAGS_ROR32: + return (cpu_state.flags_res & 0x80000000) ? 1 : 0; + + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_UNKNOWN: + return cpu_state.flags & C_FLAG; + } + return 0; +} + +//#define ZF_SET() (flags & Z_FLAG) +//#define NF_SET() (flags & N_FLAG) +//#define PF_SET() (flags & P_FLAG) +//#define VF_SET() (flags & V_FLAG) +//#define CF_SET() (flags & C_FLAG) +//#define AF_SET() (flags & A_FLAG) + +static inline void flags_rebuild() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + uint16_t tempf = 0; + if (CF_SET()) tempf |= C_FLAG; + if (PF_SET()) tempf |= P_FLAG; + if (AF_SET()) tempf |= A_FLAG; + if (ZF_SET()) tempf |= Z_FLAG; + if (NF_SET()) tempf |= N_FLAG; + if (VF_SET()) tempf |= V_FLAG; + cpu_state.flags = (cpu_state.flags & ~0x8d5) | tempf; + cpu_state.flags_op = FLAGS_UNKNOWN; + } +} + +static inline void flags_extract() +{ + cpu_state.flags_op = FLAGS_UNKNOWN; +} + +static inline void flags_rebuild_c() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + if (CF_SET()) + cpu_state.flags |= C_FLAG; + else + cpu_state.flags &= ~C_FLAG; + } +} + +static inline int flags_res_valid() +{ + if (cpu_state.flags_op == FLAGS_UNKNOWN || + (cpu_state.flags_op >= FLAGS_ROL8 && cpu_state.flags_op <= FLAGS_ROR32)) + return 0; + + return 1; +} + +static inline void setznp8(uint8_t val) +{ + cpu_state.flags_op = FLAGS_ZN8; + cpu_state.flags_res = val; +} +static inline void setznp16(uint16_t val) +{ + cpu_state.flags_op = FLAGS_ZN16; + cpu_state.flags_res = val; +} +static inline void setznp32(uint32_t val) +{ + cpu_state.flags_op = FLAGS_ZN32; + cpu_state.flags_res = val; +} + +#define set_flags_shift(op, orig, shift, res) \ + cpu_state.flags_op = op; \ + cpu_state.flags_res = res; \ + cpu_state.flags_op1 = orig; \ + cpu_state.flags_op2 = shift; + +#define set_flags_rotate(op, res) \ + cpu_state.flags_op = op; \ + cpu_state.flags_res = res; + +static inline void setadd8(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_ADD8; +} +static inline void setadd16(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_ADD16; +} +static inline void setadd32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_ADD32; +} +static inline void setadd8nc(uint8_t a, uint8_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_INC8; +} +static inline void setadd16nc(uint16_t a, uint16_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_INC16; +} +static inline void setadd32nc(uint32_t a, uint32_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_INC32; +} + +static inline void setsub8(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_SUB8; +} +static inline void setsub16(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_SUB16; +} +static inline void setsub32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_SUB32; +} + +static inline void setsub8nc(uint8_t a, uint8_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_DEC8; +} +static inline void setsub16nc(uint16_t a, uint16_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_DEC16; +} +static inline void setsub32nc(uint32_t a, uint32_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_DEC32; +} + +static inline void setadc8(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b + tempc) & 0xff; + cpu_state.flags_op = FLAGS_ADC8; +} +static inline void setadc16(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b + tempc) & 0xffff; + cpu_state.flags_op = FLAGS_ADC16; +} +static inline void setadc32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b + tempc; + cpu_state.flags_op = FLAGS_ADC32; +} + +static inline void setsbc8(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - (b + tempc)) & 0xff; + cpu_state.flags_op = FLAGS_SBC8; +} +static inline void setsbc16(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - (b + tempc)) & 0xffff; + cpu_state.flags_op = FLAGS_SBC16; +} +static inline void setsbc32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - (b + tempc); + cpu_state.flags_op = FLAGS_SBC32; +} + +extern void cpu_386_flags_extract(); +extern void cpu_386_flags_rebuild(); diff --git a/src/cpu_new/x86_flags_dynarec.h b/src/cpu_new/x86_flags_dynarec.h new file mode 100644 index 000000000..2a5212afa --- /dev/null +++ b/src/cpu_new/x86_flags_dynarec.h @@ -0,0 +1,528 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +/* This file is needed so that the dynarec can use the old flags + functions, while the interpreter can use the new ones. */ +extern int tempc; + +enum +{ + FLAGS_UNKNOWN, + + FLAGS_ZN8, + FLAGS_ZN16, + FLAGS_ZN32, + + FLAGS_ADD8, + FLAGS_ADD16, + FLAGS_ADD32, + + FLAGS_SUB8, + FLAGS_SUB16, + FLAGS_SUB32, + + FLAGS_SHL8, + FLAGS_SHL16, + FLAGS_SHL32, + + FLAGS_SHR8, + FLAGS_SHR16, + FLAGS_SHR32, + + FLAGS_SAR8, + FLAGS_SAR16, + FLAGS_SAR32, + + FLAGS_INC8, + FLAGS_INC16, + FLAGS_INC32, + + FLAGS_DEC8, + FLAGS_DEC16, + FLAGS_DEC32 +}; + +static __inline int ZF_SET_dynarec() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return !cpu_state.flags_res; + + case FLAGS_UNKNOWN: + return cpu_state.flags & Z_FLAG; + + default: + return 0; + } +} + +static __inline int NF_SET_dynarec() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ADD8: + case FLAGS_SUB8: + case FLAGS_SHL8: + case FLAGS_SHR8: + case FLAGS_SAR8: + case FLAGS_INC8: + case FLAGS_DEC8: + return cpu_state.flags_res & 0x80; + + case FLAGS_ZN16: + case FLAGS_ADD16: + case FLAGS_SUB16: + case FLAGS_SHL16: + case FLAGS_SHR16: + case FLAGS_SAR16: + case FLAGS_INC16: + case FLAGS_DEC16: + return cpu_state.flags_res & 0x8000; + + case FLAGS_ZN32: + case FLAGS_ADD32: + case FLAGS_SUB32: + case FLAGS_SHL32: + case FLAGS_SHR32: + case FLAGS_SAR32: + case FLAGS_INC32: + case FLAGS_DEC32: + return cpu_state.flags_res & 0x80000000; + + case FLAGS_UNKNOWN: + return cpu_state.flags & N_FLAG; + + default: + return 0; + } +} + +static __inline int PF_SET_dynarec() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return znptable8[cpu_state.flags_res & 0xff] & P_FLAG; + + case FLAGS_UNKNOWN: + return cpu_state.flags & P_FLAG; + + default: + return 0; + } +} + +static __inline int VF_SET_dynarec() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADD8: + case FLAGS_INC8: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); + case FLAGS_ADD16: + case FLAGS_INC16: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x8000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); + case FLAGS_ADD32: + case FLAGS_INC32: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80000000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); + + case FLAGS_SUB8: + case FLAGS_DEC8: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); + case FLAGS_SUB16: + case FLAGS_DEC16: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); + case FLAGS_SUB32: + case FLAGS_DEC32: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); + + case FLAGS_SHL8: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80); + case FLAGS_SHL16: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x8000); + case FLAGS_SHL32: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80000000); + + case FLAGS_SHR8: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80)); + case FLAGS_SHR16: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x8000)); + case FLAGS_SHR32: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80000000)); + + case FLAGS_UNKNOWN: + return cpu_state.flags & V_FLAG; + + default: + return 0; + } +} + +static __inline int AF_SET_dynarec() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + return ((cpu_state.flags_op1 & 0xF) + (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return ((cpu_state.flags_op1 & 0xF) - (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_UNKNOWN: + return cpu_state.flags & A_FLAG; + + default: + return 0; + } +} + +static __inline int CF_SET_dynarec() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ADD8: + return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x100; + case FLAGS_ADD16: + return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x10000; + case FLAGS_ADD32: + return (cpu_state.flags_res < cpu_state.flags_op1); + + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + return (cpu_state.flags_op1 < cpu_state.flags_op2); + + case FLAGS_SHL8: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80; + case FLAGS_SHL16: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x8000; + case FLAGS_SHL32: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80000000; + + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + return (cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_SAR8: + return ((int8_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR16: + return ((int16_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR32: + return ((int32_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + return 0; + + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_UNKNOWN: + return cpu_state.flags & C_FLAG; + + default: + return 0; + } +} + +static __inline void flags_rebuild_dynarec() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + uint16_t tempf = 0; + if (CF_SET_dynarec()) tempf |= C_FLAG; + if (PF_SET_dynarec()) tempf |= P_FLAG; + if (AF_SET_dynarec()) tempf |= A_FLAG; + if (ZF_SET_dynarec()) tempf |= Z_FLAG; + if (NF_SET_dynarec()) tempf |= N_FLAG; + if (VF_SET_dynarec()) tempf |= V_FLAG; + cpu_state.flags = (cpu_state.flags & ~0x8d5) | tempf; + cpu_state.flags_op = FLAGS_UNKNOWN; + } +} + +static __inline void flags_extract_dynarec() +{ + cpu_state.flags_op = FLAGS_UNKNOWN; +} + +static __inline void flags_rebuild_c_dynarec() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + if (CF_SET_dynarec()) + cpu_state.flags |= C_FLAG; + else + cpu_state.flags &= ~C_FLAG; + } +} + +static __inline void setznp8_dynarec(uint8_t val) +{ + cpu_state.flags_op = FLAGS_ZN8; + cpu_state.flags_res = val; +} +static __inline void setznp16_dynarec(uint16_t val) +{ + cpu_state.flags_op = FLAGS_ZN16; + cpu_state.flags_res = val; +} +static __inline void setznp32_dynarec(uint32_t val) +{ + cpu_state.flags_op = FLAGS_ZN32; + cpu_state.flags_res = val; +} + +#define set_flags_shift_dynarec(op, orig, shift, res) \ + cpu_state.flags_op = op; \ + cpu_state.flags_res = res; \ + cpu_state.flags_op1 = orig; \ + cpu_state.flags_op2 = shift; + +static __inline void setadd8_dynarec(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_ADD8; +} +static __inline void setadd16_dynarec(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_ADD16; +} +static __inline void setadd32_dynarec(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_ADD32; +} +static __inline void setadd8nc_dynarec(uint8_t a, uint8_t b) +{ + flags_rebuild_c_dynarec(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_INC8; +} +static __inline void setadd16nc_dynarec(uint16_t a, uint16_t b) +{ + flags_rebuild_c_dynarec(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_INC16; +} +static __inline void setadd32nc_dynarec(uint32_t a, uint32_t b) +{ + flags_rebuild_c_dynarec(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_INC32; +} + +static __inline void setsub8_dynarec(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_SUB8; +} +static __inline void setsub16_dynarec(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_SUB16; +} +static __inline void setsub32_dynarec(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_SUB32; +} + +static __inline void setsub8nc_dynarec(uint8_t a, uint8_t b) +{ + flags_rebuild_c_dynarec(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_DEC8; +} +static __inline void setsub16nc_dynarec(uint16_t a, uint16_t b) +{ + flags_rebuild_c_dynarec(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_DEC16; +} +static __inline void setsub32nc_dynarec(uint32_t a, uint32_t b) +{ + flags_rebuild_c_dynarec(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_DEC32; +} + +static __inline void setadc8_dynarec(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + cpu_state.flags&=~0x8D5; + cpu_state.flags|=znptable8[c&0xFF]; + if (c&0x100) cpu_state.flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) cpu_state.flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) cpu_state.flags|=A_FLAG; +} +static __inline void setadc16_dynarec(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + cpu_state.flags&=~0x8D5; + cpu_state.flags|=znptable16[c&0xFFFF]; + if (c&0x10000) cpu_state.flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) cpu_state.flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) cpu_state.flags|=A_FLAG; +} +static __inline void setadc32_dynarec(uint32_t a, uint32_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + cpu_state.flags&=~0x8D5; + cpu_state.flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + cpu_state.flags|=(znptable8[c&0xFF]&P_FLAG); + if ((ca) || (c==a && tempc)) cpu_state.flags|=C_FLAG; + if ((a^b)&(a^c)&0x80000000) cpu_state.flags|=V_FLAG; + if (((a&0xF)-((b&0xF)+tempc))&0x10) cpu_state.flags|=A_FLAG; +} + +extern void cpu_386_flags_extract(); +extern void cpu_386_flags_rebuild(); \ No newline at end of file diff --git a/src/cpu_new/x86_ops.h b/src/cpu_new/x86_ops.h new file mode 100644 index 000000000..0de3b3252 --- /dev/null +++ b/src/cpu_new/x86_ops.h @@ -0,0 +1,242 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Miscellaneous x86 CPU Instructions. + * + * Version: @(#)x86_ops.h 1.0.2 2018/05/05 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef _X86_OPS_H +#define _X86_OPS_H + + +#define UN_USED(x) (void)(x) + + +typedef int (*OpFn)(uint32_t fetchdat); + +#ifdef USE_DYNAREC +void x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f, + const OpFn *dynarec_opcodes, + const OpFn *dynarec_opcodes_0f); + +extern const OpFn *x86_dynarec_opcodes; +extern const OpFn *x86_dynarec_opcodes_0f; +extern const OpFn *x86_dynarec_opcodes_d8_a16; +extern const OpFn *x86_dynarec_opcodes_d8_a32; +extern const OpFn *x86_dynarec_opcodes_d9_a16; +extern const OpFn *x86_dynarec_opcodes_d9_a32; +extern const OpFn *x86_dynarec_opcodes_da_a16; +extern const OpFn *x86_dynarec_opcodes_da_a32; +extern const OpFn *x86_dynarec_opcodes_db_a16; +extern const OpFn *x86_dynarec_opcodes_db_a32; +extern const OpFn *x86_dynarec_opcodes_dc_a16; +extern const OpFn *x86_dynarec_opcodes_dc_a32; +extern const OpFn *x86_dynarec_opcodes_dd_a16; +extern const OpFn *x86_dynarec_opcodes_dd_a32; +extern const OpFn *x86_dynarec_opcodes_de_a16; +extern const OpFn *x86_dynarec_opcodes_de_a32; +extern const OpFn *x86_dynarec_opcodes_df_a16; +extern const OpFn *x86_dynarec_opcodes_df_a32; +extern const OpFn *x86_dynarec_opcodes_REPE; +extern const OpFn *x86_dynarec_opcodes_REPNE; +extern const OpFn *x86_dynarec_opcodes_3DNOW; + +extern const OpFn dynarec_ops_286[1024]; +extern const OpFn dynarec_ops_286_0f[1024]; + +extern const OpFn dynarec_ops_386[1024]; +extern const OpFn dynarec_ops_386_0f[1024]; + +extern const OpFn dynarec_ops_486_0f[1024]; + +extern const OpFn dynarec_ops_winchip_0f[1024]; +extern const OpFn dynarec_ops_winchip2_0f[1024]; + +extern const OpFn dynarec_ops_pentium_0f[1024]; +extern const OpFn dynarec_ops_pentiummmx_0f[1024]; +extern const OpFn dynarec_ops_c6x86mx_0f[1024]; + +extern const OpFn dynarec_ops_k6_0f[1024]; +extern const OpFn dynarec_ops_k62_0f[1024]; + +#if defined(DEV_BRANCH) && defined(USE_I686) +extern const OpFn dynarec_ops_pentiumpro_0f[1024]; +extern const OpFn dynarec_ops_pentium2d_0f[1024]; +#endif + +extern const OpFn dynarec_ops_fpu_287_d9_a16[256]; +extern const OpFn dynarec_ops_fpu_287_d9_a32[256]; +extern const OpFn dynarec_ops_fpu_287_da_a16[256]; +extern const OpFn dynarec_ops_fpu_287_da_a32[256]; +extern const OpFn dynarec_ops_fpu_287_db_a16[256]; +extern const OpFn dynarec_ops_fpu_287_db_a32[256]; +extern const OpFn dynarec_ops_fpu_287_dc_a16[32]; +extern const OpFn dynarec_ops_fpu_287_dc_a32[32]; +extern const OpFn dynarec_ops_fpu_287_dd_a16[256]; +extern const OpFn dynarec_ops_fpu_287_dd_a32[256]; +extern const OpFn dynarec_ops_fpu_287_de_a16[256]; +extern const OpFn dynarec_ops_fpu_287_de_a32[256]; +extern const OpFn dynarec_ops_fpu_287_df_a16[256]; +extern const OpFn dynarec_ops_fpu_287_df_a32[256]; + +extern const OpFn dynarec_ops_fpu_d8_a16[32]; +extern const OpFn dynarec_ops_fpu_d8_a32[32]; +extern const OpFn dynarec_ops_fpu_d9_a16[256]; +extern const OpFn dynarec_ops_fpu_d9_a32[256]; +extern const OpFn dynarec_ops_fpu_da_a16[256]; +extern const OpFn dynarec_ops_fpu_da_a32[256]; +extern const OpFn dynarec_ops_fpu_db_a16[256]; +extern const OpFn dynarec_ops_fpu_db_a32[256]; +extern const OpFn dynarec_ops_fpu_dc_a16[32]; +extern const OpFn dynarec_ops_fpu_dc_a32[32]; +extern const OpFn dynarec_ops_fpu_dd_a16[256]; +extern const OpFn dynarec_ops_fpu_dd_a32[256]; +extern const OpFn dynarec_ops_fpu_de_a16[256]; +extern const OpFn dynarec_ops_fpu_de_a32[256]; +extern const OpFn dynarec_ops_fpu_df_a16[256]; +extern const OpFn dynarec_ops_fpu_df_a32[256]; +extern const OpFn dynarec_ops_nofpu_a16[256]; +extern const OpFn dynarec_ops_nofpu_a32[256]; + +extern const OpFn dynarec_ops_fpu_686_da_a16[256]; +extern const OpFn dynarec_ops_fpu_686_da_a32[256]; +extern const OpFn dynarec_ops_fpu_686_db_a16[256]; +extern const OpFn dynarec_ops_fpu_686_db_a32[256]; +extern const OpFn dynarec_ops_fpu_686_df_a16[256]; +extern const OpFn dynarec_ops_fpu_686_df_a32[256]; + +extern const OpFn dynarec_ops_REPE[1024]; +extern const OpFn dynarec_ops_REPNE[1024]; +extern const OpFn dynarec_ops_3DNOW[256]; +#else +void x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f); +#endif + +extern const OpFn *x86_opcodes; +extern const OpFn *x86_opcodes_0f; +extern const OpFn *x86_opcodes_d8_a16; +extern const OpFn *x86_opcodes_d8_a32; +extern const OpFn *x86_opcodes_d9_a16; +extern const OpFn *x86_opcodes_d9_a32; +extern const OpFn *x86_opcodes_da_a16; +extern const OpFn *x86_opcodes_da_a32; +extern const OpFn *x86_opcodes_db_a16; +extern const OpFn *x86_opcodes_db_a32; +extern const OpFn *x86_opcodes_dc_a16; +extern const OpFn *x86_opcodes_dc_a32; +extern const OpFn *x86_opcodes_dd_a16; +extern const OpFn *x86_opcodes_dd_a32; +extern const OpFn *x86_opcodes_de_a16; +extern const OpFn *x86_opcodes_de_a32; +extern const OpFn *x86_opcodes_df_a16; +extern const OpFn *x86_opcodes_df_a32; +extern const OpFn *x86_opcodes_REPE; +extern const OpFn *x86_opcodes_REPNE; +extern const OpFn *x86_opcodes_3DNOW; + +extern const OpFn ops_286[1024]; +extern const OpFn ops_286_0f[1024]; + +extern const OpFn ops_386[1024]; +extern const OpFn ops_386_0f[1024]; + +extern const OpFn ops_486_0f[1024]; + +extern const OpFn ops_winchip_0f[1024]; +extern const OpFn ops_winchip2_0f[1024]; + +extern const OpFn ops_pentium_0f[1024]; +extern const OpFn ops_pentiummmx_0f[1024]; + +extern const OpFn ops_c6x86mx_0f[1024]; + +extern const OpFn ops_k6_0f[1024]; +extern const OpFn ops_k62_0f[1024]; + +#if defined(DEV_BRANCH) && defined(USE_I686) +extern const OpFn ops_pentiumpro_0f[1024]; +extern const OpFn ops_pentium2d_0f[1024]; +#endif + +extern const OpFn ops_fpu_287_d9_a16[256]; +extern const OpFn ops_fpu_287_d9_a32[256]; +extern const OpFn ops_fpu_287_da_a16[256]; +extern const OpFn ops_fpu_287_da_a32[256]; +extern const OpFn ops_fpu_287_db_a16[256]; +extern const OpFn ops_fpu_287_db_a32[256]; +extern const OpFn ops_fpu_287_dc_a16[32]; +extern const OpFn ops_fpu_287_dc_a32[32]; +extern const OpFn ops_fpu_287_dd_a16[256]; +extern const OpFn ops_fpu_287_dd_a32[256]; +extern const OpFn ops_fpu_287_de_a16[256]; +extern const OpFn ops_fpu_287_de_a32[256]; +extern const OpFn ops_fpu_287_df_a16[256]; +extern const OpFn ops_fpu_287_df_a32[256]; + +extern const OpFn ops_fpu_d8_a16[32]; +extern const OpFn ops_fpu_d8_a32[32]; +extern const OpFn ops_fpu_d9_a16[256]; +extern const OpFn ops_fpu_d9_a32[256]; +extern const OpFn ops_fpu_da_a16[256]; +extern const OpFn ops_fpu_da_a32[256]; +extern const OpFn ops_fpu_db_a16[256]; +extern const OpFn ops_fpu_db_a32[256]; +extern const OpFn ops_fpu_dc_a16[32]; +extern const OpFn ops_fpu_dc_a32[32]; +extern const OpFn ops_fpu_dd_a16[256]; +extern const OpFn ops_fpu_dd_a32[256]; +extern const OpFn ops_fpu_de_a16[256]; +extern const OpFn ops_fpu_de_a32[256]; +extern const OpFn ops_fpu_df_a16[256]; +extern const OpFn ops_fpu_df_a32[256]; +extern const OpFn ops_nofpu_a16[256]; +extern const OpFn ops_nofpu_a32[256]; + +extern const OpFn ops_fpu_686_da_a16[256]; +extern const OpFn ops_fpu_686_da_a32[256]; +extern const OpFn ops_fpu_686_db_a16[256]; +extern const OpFn ops_fpu_686_db_a32[256]; +extern const OpFn ops_fpu_686_df_a16[256]; +extern const OpFn ops_fpu_686_df_a32[256]; + +extern const OpFn ops_REPE[1024]; +extern const OpFn ops_REPNE[1024]; +extern const OpFn ops_3DNOW[256]; + +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +#endif /*_X86_OPS_H*/ diff --git a/src/cpu_new/x86_ops_3dnow.h b/src/cpu_new/x86_ops_3dnow.h new file mode 100644 index 000000000..c578c400a --- /dev/null +++ b/src/cpu_new/x86_ops_3dnow.h @@ -0,0 +1,346 @@ +#include + +static int opPREFETCH_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + + CLOCK_CYCLES(1); + return 0; +} +static int opPREFETCH_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + + CLOCK_CYCLES(1); + return 0; +} + +static int opFEMMS(uint32_t fetchdat) +{ + ILLEGAL_ON(!cpu_has_feature(CPU_FEATURE_MMX)); + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + x87_emms(); + CLOCK_CYCLES(1); + return 0; +} + +static int opPAVGUSB(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].b[0] + src.b[0] + 1) >> 1; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].b[1] + src.b[1] + 1) >> 1; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].b[2] + src.b[2] + 1) >> 1; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].b[3] + src.b[3] + 1) >> 1; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].b[4] + src.b[4] + 1) >> 1; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].b[5] + src.b[5] + 1) >> 1; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].b[6] + src.b[6] + 1) >> 1; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].b[7] + src.b[7] + 1) >> 1; + + return 0; +} +static int opPF2ID(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sl[0] = (int32_t)src.f[0]; + cpu_state.MM[cpu_reg].sl[1] = (int32_t)src.f[1]; + + return 0; +} +static int opPFACC(uint32_t fetchdat) +{ + MMX_REG src; + float tempf; + + MMX_GETSRC(); + + tempf = cpu_state.MM[cpu_reg].f[0] + cpu_state.MM[cpu_reg].f[1]; + cpu_state.MM[cpu_reg].f[1] = src.f[0] + src.f[1]; + cpu_state.MM[cpu_reg].f[0] = tempf; + + return 0; +} +static int opPFADD(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] += src.f[0]; + cpu_state.MM[cpu_reg].f[1] += src.f[1]; + + return 0; +} +static int opPFCMPEQ(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].f[0] == src.f[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].f[1] == src.f[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPFCMPGE(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].f[0] >= src.f[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].f[1] >= src.f[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPFCMPGT(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].f[0] > src.f[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].f[1] > src.f[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPFMAX(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + if (src.f[0] > cpu_state.MM[cpu_reg].f[0]) + cpu_state.MM[cpu_reg].f[0] = src.f[0]; + if (src.f[1] > cpu_state.MM[cpu_reg].f[1]) + cpu_state.MM[cpu_reg].f[1] = src.f[1]; + + return 0; +} +static int opPFMIN(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + if (src.f[0] < cpu_state.MM[cpu_reg].f[0]) + cpu_state.MM[cpu_reg].f[0] = src.f[0]; + if (src.f[1] < cpu_state.MM[cpu_reg].f[1]) + cpu_state.MM[cpu_reg].f[1] = src.f[1]; + + return 0; +} +static int opPFMUL(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] *= src.f[0]; + cpu_state.MM[cpu_reg].f[1] *= src.f[1]; + + return 0; +} +static int opPFRCP(uint32_t fetchdat) +{ + union + { + uint32_t i; + float f; + } src; + + if (cpu_mod == 3) + { + src.f = cpu_state.MM[cpu_rm].f[0]; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_READ(cpu_state.ea_seg); + src.i = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + + cpu_state.MM[cpu_reg].f[0] = 1.0/src.f; + cpu_state.MM[cpu_reg].f[1] = cpu_state.MM[cpu_reg].f[0]; + + return 0; +} +/*Since opPFRCP() calculates a full precision reciprocal, treat the followup iterations as MOVs*/ +static int opPFRCPIT1(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] = src.f[0]; + cpu_state.MM[cpu_reg].f[1] = src.f[1]; + + return 0; +} +static int opPFRCPIT2(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] = src.f[0]; + cpu_state.MM[cpu_reg].f[1] = src.f[1]; + + return 0; +} +static int opPFRSQRT(uint32_t fetchdat) +{ + union + { + uint32_t i; + float f; + } src; + + if (cpu_mod == 3) + { + src.f = cpu_state.MM[cpu_rm].f[0]; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_READ(cpu_state.ea_seg); + src.i = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + + cpu_state.MM[cpu_reg].f[0] = 1.0/sqrt(src.f); + cpu_state.MM[cpu_reg].f[1] = cpu_state.MM[cpu_reg].f[0]; + + return 0; +} +/*Since opPFRSQRT() calculates a full precision inverse square root, treat the followup iteration as a NOP*/ +static int opPFRSQIT1(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + UN_USED(src); + + return 0; +} +static int opPFSUB(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] -= src.f[0]; + cpu_state.MM[cpu_reg].f[1] -= src.f[1]; + + return 0; +} +static int opPFSUBR(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] = src.f[0] - cpu_state.MM[cpu_reg].f[0]; + cpu_state.MM[cpu_reg].f[1] = src.f[1] - cpu_state.MM[cpu_reg].f[1]; + + return 0; +} +static int opPI2FD(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] = (float)src.sl[0]; + cpu_state.MM[cpu_reg].f[1] = (float)src.sl[1]; + + return 0; +} +static int opPMULHRW(uint32_t fetchdat) +{ + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].w[0] = (((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)cpu_state.MM[cpu_rm].sw[0]) + 0x8000) >> 16; + cpu_state.MM[cpu_reg].w[1] = (((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)cpu_state.MM[cpu_rm].sw[1]) + 0x8000) >> 16; + cpu_state.MM[cpu_reg].w[2] = (((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)cpu_state.MM[cpu_rm].sw[2]) + 0x8000) >> 16; + cpu_state.MM[cpu_reg].w[3] = (((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)cpu_state.MM[cpu_rm].sw[3]) + 0x8000) >> 16; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + SEG_CHECK_READ(cpu_state.ea_seg); + src.l[0] = readmeml(easeg, cpu_state.eaaddr); + src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].w[0] = ((int32_t)(cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) + 0x8000) >> 16; + cpu_state.MM[cpu_reg].w[1] = ((int32_t)(cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]) + 0x8000) >> 16; + cpu_state.MM[cpu_reg].w[2] = ((int32_t)(cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) + 0x8000) >> 16; + cpu_state.MM[cpu_reg].w[3] = ((int32_t)(cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]) + 0x8000) >> 16; + CLOCK_CYCLES(2); + } + return 0; +} + +const OpFn OP_TABLE(3DNOW)[256] = +{ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPI2FD, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPF2ID, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ opPFCMPGE, ILLEGAL, ILLEGAL, ILLEGAL, opPFMIN, ILLEGAL, opPFRCP, opPFRSQRT, ILLEGAL, ILLEGAL, opPFSUB, ILLEGAL, ILLEGAL, ILLEGAL, opPFADD, ILLEGAL, +/*a0*/ opPFCMPGT, ILLEGAL, ILLEGAL, ILLEGAL, opPFMAX, ILLEGAL, opPFRCPIT1, opPFRSQIT1, ILLEGAL, ILLEGAL, opPFSUBR, ILLEGAL, ILLEGAL, ILLEGAL, opPFACC, ILLEGAL, +/*b0*/ opPFCMPEQ, ILLEGAL, ILLEGAL, ILLEGAL, opPFMUL, ILLEGAL, opPFRCPIT2, opPMULHRW, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPAVGUSB, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +static int op3DNOW_a16(uint32_t fetchdat) +{ + uint8_t opcode; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + opcode = fastreadb(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + return x86_opcodes_3DNOW[opcode](0); +} +static int op3DNOW_a32(uint32_t fetchdat) +{ + uint8_t opcode; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + opcode = fastreadb(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + return x86_opcodes_3DNOW[opcode](0); +} diff --git a/src/cpu_new/x86_ops_amd.h b/src/cpu_new/x86_ops_amd.h new file mode 100644 index 000000000..8f003e1fb --- /dev/null +++ b/src/cpu_new/x86_ops_amd.h @@ -0,0 +1,192 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * AMD SYSCALL and SYSRET CPU Instructions. + * + * Version: @(#)x86_ops_amd.h 1.0.4 2018/10/17 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ + +/* 0 = Limit 0-15 + 1 = Base 0-15 + 2 = Base 16-23 (bits 0-7), Access rights + 8-11 Type + 12 S + 13, 14 DPL + 15 P + 3 = Limit 16-19 (bits 0-3), Base 24-31 (bits 8-15), granularity, etc. + 4 A + 6 DB + 7 G */ + +#define AMD_SYSCALL_EIP (star & 0xFFFFFFFF) +#define AMD_SYSCALL_SB ((star >> 32) & 0xFFFF) +#define AMD_SYSRET_SB ((star >> 48) & 0xFFFF) + +/* 0F 05 */ +static int opSYSCALL(uint32_t fetchdat) +{ + uint16_t syscall_cs_seg_data[4] = {0, 0, 0, 0}; + uint16_t syscall_ss_seg_data[4] = {0, 0, 0, 0}; + + if (!(cr0 & 1)) return internal_illegal("SYSCALL: CPU not in protected mode"); + if (!AMD_SYSCALL_SB) return internal_illegal("SYSCALL: AMD SYSCALL SB MSR is zero"); + + /* Set VM, IF, RF to 0. */ + /* cpu_state.eflags &= ~0x00030200; + cpu_state.flags &= ~0x0200; */ + + /* Let's do this by the AMD spec. */ + ECX = cpu_state.pc; + + cpu_state.eflags &= ~0x0002; + cpu_state.flags &= ~0x0200; + + /* CS */ + cpu_state.seg_cs.seg = AMD_SYSCALL_SB & ~7; + if (AMD_SYSCALL_SB & 4) + { + if (cpu_state.seg_cs.seg >= ldt.limit) + { + x386_dynarec_log("Bigger than LDT limit %04X %04X CS\n",AMD_SYSCALL_SB,ldt.limit); + x86gpf(NULL, AMD_SYSCALL_SB & ~3); + return 1; + } + cpu_state.seg_cs.seg +=ldt.base; + } + else + { + if (cpu_state.seg_cs.seg >= gdt.limit) + { + x386_dynarec_log("Bigger than GDT limit %04X %04X CS\n",AMD_SYSCALL_SB,gdt.limit); + x86gpf(NULL, AMD_SYSCALL_SB & ~3); + return 1; + } + cpu_state.seg_cs.seg += gdt.base; + } + cpl_override = 1; + + syscall_cs_seg_data[0] = 0xFFFF; + syscall_cs_seg_data[1] = 0; + syscall_cs_seg_data[2] = 0x9B00; + syscall_cs_seg_data[3] = 0xC0; + + cpl_override = 0; + + use32 = 0x300; + CS = (AMD_SYSCALL_SB & ~3) | 0; + + do_seg_load(&cpu_state.seg_cs, syscall_cs_seg_data); + use32 = 0x300; + + CS = (CS & 0xFFFC) | 0; + + cpu_state.seg_cs.limit = 0xFFFFFFFF; + cpu_state.seg_cs.limit_high = 0xFFFFFFFF; + + /* SS */ + syscall_ss_seg_data[0] = 0xFFFF; + syscall_ss_seg_data[1] = 0; + syscall_ss_seg_data[2] = 0x9300; + syscall_ss_seg_data[3] = 0xC0; + do_seg_load(&cpu_state.seg_ss, syscall_ss_seg_data); + cpu_state.seg_ss.seg = (AMD_SYSCALL_SB + 8) & 0xFFFC; + stack32 = 1; + + cpu_state.seg_ss.limit = 0xFFFFFFFF; + cpu_state.seg_ss.limit_high = 0xFFFFFFFF; + + cpu_state.seg_ss.checked = 0; + + cpu_state.pc = AMD_SYSCALL_EIP; + + CLOCK_CYCLES(20); + + CPU_BLOCK_END(); + + return 0; +} + +/* 0F 07 */ +static int opSYSRET(uint32_t fetchdat) +{ + uint16_t sysret_cs_seg_data[4] = {0, 0, 0, 0}; + uint16_t sysret_ss_seg_data[4] = {0, 0, 0, 0}; + + if (!AMD_SYSRET_SB) return internal_illegal("SYSRET: CS MSR is zero"); + if (!(cr0 & 1)) return internal_illegal("SYSRET: CPU not in protected mode"); + + cpu_state.pc = ECX; + + cpu_state.eflags |= (1 << 1); + + /* CS */ + cpu_state.seg_cs.seg = AMD_SYSRET_SB & ~7; + if (AMD_SYSRET_SB & 4) + { + if (cpu_state.seg_cs.seg >= ldt.limit) + { + x386_dynarec_log("Bigger than LDT limit %04X %04X CS\n",AMD_SYSRET_SB,ldt.limit); + x86gpf(NULL, AMD_SYSRET_SB & ~3); + return 1; + } + cpu_state.seg_cs.seg +=ldt.base; + } + else + { + if (cpu_state.seg_cs.seg >= gdt.limit) + { + x386_dynarec_log("Bigger than GDT limit %04X %04X CS\n",AMD_SYSRET_SB,gdt.limit); + x86gpf(NULL, AMD_SYSRET_SB & ~3); + return 1; + } + cpu_state.seg_cs.seg += gdt.base; + } + cpl_override = 1; + + sysret_cs_seg_data[0] = 0xFFFF; + sysret_cs_seg_data[1] = 0; + sysret_cs_seg_data[2] = 0xFB00; + sysret_cs_seg_data[3] = 0xC0; + + cpl_override = 0; + + use32 = 0x300; + CS = (AMD_SYSRET_SB & ~3) | 3; + + do_seg_load(&cpu_state.seg_cs, sysret_cs_seg_data); + flushmmucache_cr3(); + use32 = 0x300; + + CS = (CS & 0xFFFC) | 3; + + cpu_state.seg_cs.limit = 0xFFFFFFFF; + cpu_state.seg_cs.limit_high = 0xFFFFFFFF; + + /* SS */ + sysret_ss_seg_data[0] = 0xFFFF; + sysret_ss_seg_data[1] = 0; + sysret_ss_seg_data[2] = 0xF300; + sysret_ss_seg_data[3] = 0xC0; + do_seg_load(&cpu_state.seg_ss, sysret_ss_seg_data); + cpu_state.seg_ss.seg = ((AMD_SYSRET_SB + 8) & 0xFFFC) | 3; + stack32 = 1; + + cpu_state.seg_ss.limit = 0xFFFFFFFF; + cpu_state.seg_ss.limit_high = 0xFFFFFFFF; + + cpu_state.seg_ss.checked = 0; + + CLOCK_CYCLES(20); + + CPU_BLOCK_END(); + + return 0; +} diff --git a/src/cpu_new/x86_ops_arith.h b/src/cpu_new/x86_ops_arith.h new file mode 100644 index 000000000..489fd5e57 --- /dev/null +++ b/src/cpu_new/x86_ops_arith.h @@ -0,0 +1,818 @@ +#define OP_ARITH(name, operation, setflags, flagops, gettempc) \ + static int op ## name ## _b_rmw_a16(uint32_t fetchdat) \ + { \ + uint8_t dst; \ + uint8_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = getr8(cpu_rm); \ + src = getr8(cpu_reg); \ + setflags ## 8 flagops; \ + setr8(cpu_rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteab(); if (cpu_state.abrt) return 1; \ + src = getr8(cpu_reg); \ + seteab(operation); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_mr, 2, rmdat, 1,0,1,0, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _b_rmw_a32(uint32_t fetchdat) \ + { \ + uint8_t dst; \ + uint8_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = getr8(cpu_rm); \ + src = getr8(cpu_reg); \ + setflags ## 8 flagops; \ + setr8(cpu_rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteab(); if (cpu_state.abrt) return 1; \ + src = getr8(cpu_reg); \ + seteab(operation); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_mr, 2, rmdat, 1,0,1,0, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _w_rmw_a16(uint32_t fetchdat) \ + { \ + uint16_t dst; \ + uint16_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].w; \ + src = cpu_state.regs[cpu_reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].w; \ + seteaw(operation); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 1,0,1,0, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _w_rmw_a32(uint32_t fetchdat) \ + { \ + uint16_t dst; \ + uint16_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].w; \ + src = cpu_state.regs[cpu_reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].w; \ + seteaw(operation); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 1,0,1,0, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _l_rmw_a16(uint32_t fetchdat) \ + { \ + uint32_t dst; \ + uint32_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].l; \ + src = cpu_state.regs[cpu_reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteal(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].l; \ + seteal(operation); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,1,0,1, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _l_rmw_a32(uint32_t fetchdat) \ + { \ + uint32_t dst; \ + uint32_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].l; \ + src = cpu_state.regs[cpu_reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteal(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].l; \ + seteal(operation); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,1,0,1, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _b_rm_a16(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + dst = getr8(cpu_reg); \ + src = geteab(); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + setr8(cpu_reg, operation); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); \ + return 0; \ + } \ + static int op ## name ## _b_rm_a32(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + dst = getr8(cpu_reg); \ + src = geteab(); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + setr8(cpu_reg, operation); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); \ + return 0; \ + } \ + \ + static int op ## name ## _w_rm_a16(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + dst = cpu_state.regs[cpu_reg].w; \ + src = geteaw(); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_reg].w = operation; \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); \ + return 0; \ + } \ + static int op ## name ## _w_rm_a32(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + dst = cpu_state.regs[cpu_reg].w; \ + src = geteaw(); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_reg].w = operation; \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); \ + return 0; \ + } \ + \ + static int op ## name ## _l_rm_a16(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + dst = cpu_state.regs[cpu_reg].l; \ + src = geteal(); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_reg].l = operation; \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); \ + return 0; \ + } \ + static int op ## name ## _l_rm_a32(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + dst = cpu_state.regs[cpu_reg].l; \ + src = geteal(); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_reg].l = operation; \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); \ + return 0; \ + } \ + \ + static int op ## name ## _AL_imm(uint32_t fetchdat) \ + { \ + uint8_t dst = AL; \ + uint8_t src = getbytef(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 8 flagops; \ + AL = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int op ## name ## _AX_imm(uint32_t fetchdat) \ + { \ + uint16_t dst = AX; \ + uint16_t src = getwordf(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 16 flagops; \ + AX = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int op ## name ## _EAX_imm(uint32_t fetchdat) \ + { \ + uint32_t dst = EAX; \ + uint32_t src = getlong(); if (cpu_state.abrt) return 1; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 32 flagops; \ + EAX = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); \ + return 0; \ + } + +OP_ARITH(ADD, dst + src, setadd, (dst, src), 0) +OP_ARITH(ADC, dst + src + tempc, setadc, (dst, src), 1) +OP_ARITH(SUB, dst - src, setsub, (dst, src), 0) +OP_ARITH(SBB, dst - (src + tempc), setsbc, (dst, src), 1) +OP_ARITH(OR, dst | src, setznp, (dst | src), 0) +OP_ARITH(AND, dst & src, setznp, (dst & src), 0) +OP_ARITH(XOR, dst ^ src, setznp, (dst ^ src), 0) + +static int opCMP_b_rmw_a16(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + dst = geteab(); if (cpu_state.abrt) return 1; + setsub8(dst, getr8(cpu_reg)); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_b_rmw_a32(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + dst = geteab(); if (cpu_state.abrt) return 1; + setsub8(dst, getr8(cpu_reg)); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_w_rmw_a16(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + dst = geteaw(); if (cpu_state.abrt) return 1; + setsub16(dst, cpu_state.regs[cpu_reg].w); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_w_rmw_a32(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + dst = geteaw(); if (cpu_state.abrt) return 1; + setsub16(dst, cpu_state.regs[cpu_reg].w); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_l_rmw_a16(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + dst = geteal(); if (cpu_state.abrt) return 1; + setsub32(dst, cpu_state.regs[cpu_reg].l); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +static int opCMP_l_rmw_a32(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + dst = geteal(); if (cpu_state.abrt) return 1; + setsub32(dst, cpu_state.regs[cpu_reg].l); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opCMP_b_rm_a16(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteab(); if (cpu_state.abrt) return 1; + setsub8(getr8(cpu_reg), src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_b_rm_a32(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteab(); if (cpu_state.abrt) return 1; + setsub8(getr8(cpu_reg), src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_w_rm_a16(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteaw(); if (cpu_state.abrt) return 1; + setsub16(cpu_state.regs[cpu_reg].w, src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_w_rm_a32(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteaw(); if (cpu_state.abrt) return 1; + setsub16(cpu_state.regs[cpu_reg].w, src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_l_rm_a16(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteal(); if (cpu_state.abrt) return 1; + setsub32(cpu_state.regs[cpu_reg].l, src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +static int opCMP_l_rm_a32(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteal(); if (cpu_state.abrt) return 1; + setsub32(cpu_state.regs[cpu_reg].l, src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opCMP_AL_imm(uint32_t fetchdat) +{ + uint8_t src = getbytef(); + setsub8(AL, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opCMP_AX_imm(uint32_t fetchdat) +{ + uint16_t src = getwordf(); + setsub16(AX, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} + +static int opCMP_EAX_imm(uint32_t fetchdat) +{ + uint32_t src = getlong(); if (cpu_state.abrt) return 1; + setsub32(EAX, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + +static int opTEST_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + temp2 = getr8(cpu_reg); + setznp8(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opTEST_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + temp2 = getr8(cpu_reg); + setznp8(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opTEST_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].w; + setznp16(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opTEST_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].w; + setznp16(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opTEST_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].l; + setznp32(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0,(cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +static int opTEST_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].l; + setznp32(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0,(cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opTEST_AL(uint32_t fetchdat) +{ + uint8_t temp = getbytef(); + setznp8(AL & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opTEST_AX(uint32_t fetchdat) +{ + uint16_t temp = getwordf(); + setznp16(AX & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opTEST_EAX(uint32_t fetchdat) +{ + uint32_t temp = getlong(); if (cpu_state.abrt) return 1; + setznp32(EAX & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + + +#define ARITH_MULTI(ea_width, flag_width) \ + dst = getea ## ea_width(); if (cpu_state.abrt) return 1; \ + switch (rmdat&0x38) \ + { \ + case 0x00: /*ADD ea, #*/ \ + setea ## ea_width(dst + src); if (cpu_state.abrt) return 1; \ + setadd ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x08: /*OR ea, #*/ \ + dst |= src; \ + setea ## ea_width(dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x10: /*ADC ea, #*/ \ + tempc = CF_SET() ? 1 : 0; \ + setea ## ea_width(dst + src + tempc); if (cpu_state.abrt) return 1; \ + setadc ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x18: /*SBB ea, #*/ \ + tempc = CF_SET() ? 1 : 0; \ + setea ## ea_width(dst - (src + tempc)); if (cpu_state.abrt) return 1; \ + setsbc ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x20: /*AND ea, #*/ \ + dst &= src; \ + setea ## ea_width(dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x28: /*SUB ea, #*/ \ + setea ## ea_width(dst - src); if (cpu_state.abrt) return 1; \ + setsub ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x30: /*XOR ea, #*/ \ + dst ^= src; \ + setea ## ea_width(dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x38: /*CMP ea, #*/ \ + setsub ## flag_width(dst, src); \ + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); \ + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 7); \ + break; \ + } + + +static int op80_a16(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + src = getbyte(); if (cpu_state.abrt) return 1; + ARITH_MULTI(b, 8); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +static int op80_a32(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + src = getbyte(); if (cpu_state.abrt) return 1; + ARITH_MULTI(b, 8); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} +static int op81_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + src = getword(); if (cpu_state.abrt) return 1; + ARITH_MULTI(w, 16); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 4, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +static int op81_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + src = getword(); if (cpu_state.abrt) return 1; + ARITH_MULTI(w, 16); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 4, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} +static int op81_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + src = getlong(); if (cpu_state.abrt) return 1; + ARITH_MULTI(l, 32); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + + return 0; +} +static int op81_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + src = getlong(); if (cpu_state.abrt) return 1; + ARITH_MULTI(l, 32); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + + return 0; +} + +static int op83_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(w, 16); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +static int op83_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(w, 16); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} + +static int op83_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(l, 32); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + + return 0; +} +static int op83_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(l, 32); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + + return 0; +} + diff --git a/src/cpu_new/x86_ops_atomic.h b/src/cpu_new/x86_ops_atomic.h new file mode 100644 index 000000000..4011a0aa4 --- /dev/null +++ b/src/cpu_new/x86_ops_atomic.h @@ -0,0 +1,292 @@ +static int opCMPXCHG_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2 = AL; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + if (AL == temp) seteab(getr8(cpu_reg)); + else AL = temp; + if (cpu_state.abrt) return 1; + setsub8(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2 = AL; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + if (AL == temp) seteab(getr8(cpu_reg)); + else AL = temp; + if (cpu_state.abrt) return 1; + setsub8(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2 = AX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + if (AX == temp) seteaw(cpu_state.regs[cpu_reg].w); + else AX = temp; + if (cpu_state.abrt) return 1; + setsub16(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2 = AX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + if (AX == temp) seteaw(cpu_state.regs[cpu_reg].w); + else AX = temp; + if (cpu_state.abrt) return 1; + setsub16(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2 = EAX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + if (EAX == temp) seteal(cpu_state.regs[cpu_reg].l); + else EAX = temp; + if (cpu_state.abrt) return 1; + setsub32(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2 = EAX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + if (EAX == temp) seteal(cpu_state.regs[cpu_reg].l); + else EAX = temp; + if (cpu_state.abrt) return 1; + setsub32(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG8B_a16(uint32_t fetchdat) +{ + uint32_t temp, temp_hi, temp2 = EAX, temp2_hi = EDX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); + temp_hi = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + if (EAX == temp && EDX == temp_hi) + { + seteal(EBX); + writememl(easeg, cpu_state.eaaddr+4, ECX); + } + else + { + EAX = temp; + EDX = temp_hi; + } + if (cpu_state.abrt) return 0; + flags_rebuild(); + if (temp == temp2 && temp_hi == temp2_hi) + cpu_state.flags |= Z_FLAG; + else + cpu_state.flags &= ~Z_FLAG; + cycles -= (cpu_mod == 3) ? 6 : 10; + return 0; +} +static int opCMPXCHG8B_a32(uint32_t fetchdat) +{ + uint32_t temp, temp_hi, temp2 = EAX, temp2_hi = EDX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); + temp_hi = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + if (EAX == temp && EDX == temp_hi) + { + seteal(EBX); + writememl(easeg, cpu_state.eaaddr+4, ECX); + } + else + { + EAX = temp; + EDX = temp_hi; + } + if (cpu_state.abrt) return 0; + flags_rebuild(); + if (temp == temp2 && temp_hi == temp2_hi) + cpu_state.flags |= Z_FLAG; + else + cpu_state.flags &= ~Z_FLAG; + cycles -= (cpu_mod == 3) ? 6 : 10; + return 0; +} + +static int opXADD_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + seteab(temp + getr8(cpu_reg)); if (cpu_state.abrt) return 1; + setadd8(temp, getr8(cpu_reg)); + setr8(cpu_reg, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + seteab(temp + getr8(cpu_reg)); if (cpu_state.abrt) return 1; + setadd8(temp, getr8(cpu_reg)); + setr8(cpu_reg, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} + +static int opXADD_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(temp + cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; + setadd16(temp, cpu_state.regs[cpu_reg].w); + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(temp + cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; + setadd16(temp, cpu_state.regs[cpu_reg].w); + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} + +static int opXADD_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(temp + cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; + setadd32(temp, cpu_state.regs[cpu_reg].l); + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(temp + cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; + setadd32(temp, cpu_state.regs[cpu_reg].l); + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} diff --git a/src/cpu_new/x86_ops_bcd.h b/src/cpu_new/x86_ops_bcd.h new file mode 100644 index 000000000..cd29b1405 --- /dev/null +++ b/src/cpu_new/x86_ops_bcd.h @@ -0,0 +1,113 @@ +static int opAAA(uint32_t fetchdat) +{ + flags_rebuild(); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) + { + AL += 6; + AH++; + cpu_state.flags |= (A_FLAG | C_FLAG); + } + else + cpu_state.flags &= ~(A_FLAG | C_FLAG); + AL &= 0xF; + CLOCK_CYCLES(is486 ? 3 : 4); + PREFETCH_RUN(is486 ? 3 : 4, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opAAD(uint32_t fetchdat) +{ + int base = getbytef(); + if (cpu_manufacturer != MANU_INTEL) base = 10; + AL = (AH * base) + AL; + AH = 0; + setznp16(AX); + CLOCK_CYCLES((is486) ? 14 : 19); + PREFETCH_RUN(is486 ? 14 : 19, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opAAM(uint32_t fetchdat) +{ + int base = getbytef(); + if (!base || cpu_manufacturer != MANU_INTEL) base = 10; + AH = AL / base; + AL %= base; + setznp16(AX); + CLOCK_CYCLES((is486) ? 15 : 17); + PREFETCH_RUN(is486 ? 15 : 17, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opAAS(uint32_t fetchdat) +{ + flags_rebuild(); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) + { + AL -= 6; + AH--; + cpu_state.flags |= (A_FLAG | C_FLAG); + } + else + cpu_state.flags &= ~(A_FLAG | C_FLAG); + AL &= 0xF; + CLOCK_CYCLES(is486 ? 3 : 4); + PREFETCH_RUN(is486 ? 3 : 4, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opDAA(uint32_t fetchdat) +{ + uint16_t tempw; + + flags_rebuild(); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) + { + int tempi = ((uint16_t)AL) + 6; + AL += 6; + cpu_state.flags |= A_FLAG; + if (tempi & 0x100) cpu_state.flags |= C_FLAG; + } + if ((cpu_state.flags & C_FLAG) || (AL > 0x9f)) + { + AL += 0x60; + cpu_state.flags |= C_FLAG; + } + + tempw = cpu_state.flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags_rebuild(); + cpu_state.flags |= tempw; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0); + + return 0; +} + +static int opDAS(uint32_t fetchdat) +{ + uint16_t tempw; + + flags_rebuild(); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) + { + int tempi = ((uint16_t)AL) - 6; + AL -= 6; + cpu_state.flags |= A_FLAG; + if (tempi & 0x100) cpu_state.flags |= C_FLAG; + } + if ((cpu_state.flags & C_FLAG) || (AL > 0x9f)) + { + AL -= 0x60; + cpu_state.flags |= C_FLAG; + } + + tempw = cpu_state.flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags_rebuild(); + cpu_state.flags |= tempw; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0); + + return 0; +} diff --git a/src/cpu_new/x86_ops_bit.h b/src/cpu_new/x86_ops_bit.h new file mode 100644 index 000000000..df2d48619 --- /dev/null +++ b/src/cpu_new/x86_ops_bit.h @@ -0,0 +1,328 @@ +static int opBT_w_r_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = 0; + temp = geteaw(); if (cpu_state.abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 0); + return 0; +} +static int opBT_w_r_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = 0; + temp = geteaw(); if (cpu_state.abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 1); + return 0; +} +static int opBT_l_r_a16(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = 0; + temp = geteal(); if (cpu_state.abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 0); + return 0; +} +static int opBT_l_r_a32(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = 0; + temp = geteal(); if (cpu_state.abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 1); + return 0; +} + +#define opBT(name, operation) \ + static int opBT ## name ## _w_r_a16(uint32_t fetchdat) \ + { \ + int tempc; \ + uint16_t temp; \ + \ + fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = eal_w = 0; \ + temp = geteaw(); if (cpu_state.abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[cpu_reg].w & 15)); \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + flags_rebuild(); \ + if (tempc) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + PREFETCH_RUN(6, 2, rmdat, 1,0,1,0, 0); \ + return 0; \ + } \ + static int opBT ## name ## _w_r_a32(uint32_t fetchdat) \ + { \ + int tempc; \ + uint16_t temp; \ + \ + fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = eal_w = 0; \ + temp = geteaw(); if (cpu_state.abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[cpu_reg].w & 15)); \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + flags_rebuild(); \ + if (tempc) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + PREFETCH_RUN(6, 2, rmdat, 1,0,1,0, 1); \ + return 0; \ + } \ + static int opBT ## name ## _l_r_a16(uint32_t fetchdat) \ + { \ + int tempc; \ + uint32_t temp; \ + \ + fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = eal_w = 0; \ + temp = geteal(); if (cpu_state.abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[cpu_reg].l & 31)); \ + seteal(temp); if (cpu_state.abrt) return 1; \ + flags_rebuild(); \ + if (tempc) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + PREFETCH_RUN(6, 2, rmdat, 0,1,0,1, 0); \ + return 0; \ + } \ + static int opBT ## name ## _l_r_a32(uint32_t fetchdat) \ + { \ + int tempc; \ + uint32_t temp; \ + \ + fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = eal_w = 0; \ + temp = geteal(); if (cpu_state.abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[cpu_reg].l & 31)); \ + seteal(temp); if (cpu_state.abrt) return 1; \ + flags_rebuild(); \ + if (tempc) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + PREFETCH_RUN(6, 2, rmdat, 0,1,0,1, 1); \ + return 0; \ + } + +opBT(C, ^=) +opBT(R, &=~) +opBT(S, |=) + +static int opBA_w_a16(uint32_t fetchdat) +{ + int tempc, count; + uint16_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + + temp = geteaw(); + count = getbyte(); if (cpu_state.abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + seteaw(temp); if (cpu_state.abrt) return 1; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + return 0; +} +static int opBA_w_a32(uint32_t fetchdat) +{ + int tempc, count; + uint16_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + + temp = geteaw(); + count = getbyte(); if (cpu_state.abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + seteaw(temp); if (cpu_state.abrt) return 1; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + return 0; +} + +static int opBA_l_a16(uint32_t fetchdat) +{ + int tempc, count; + uint32_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + + temp = geteal(); + count = getbyte(); if (cpu_state.abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + seteal(temp); if (cpu_state.abrt) return 1; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + return 0; +} +static int opBA_l_a32(uint32_t fetchdat) +{ + int tempc, count; + uint32_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + + temp = geteal(); + count = getbyte(); if (cpu_state.abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + seteal(temp); if (cpu_state.abrt) return 1; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + return 0; +} diff --git a/src/cpu_new/x86_ops_bitscan.h b/src/cpu_new/x86_ops_bitscan.h new file mode 100644 index 000000000..01d9c5795 --- /dev/null +++ b/src/cpu_new/x86_ops_bitscan.h @@ -0,0 +1,159 @@ +#define BS_common(start, end, dir, dest, time) \ + flags_rebuild(); \ + instr_cycles = 0; \ + if (temp) \ + { \ + int c; \ + cpu_state.flags &= ~Z_FLAG; \ + for (c = start; c != end; c += dir) \ + { \ + CLOCK_CYCLES(time); \ + instr_cycles += time; \ + if (temp & (1 << c)) \ + { \ + dest = c; \ + break; \ + } \ + } \ + } \ + else \ + cpu_state.flags |= Z_FLAG; + +static int opBSF_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + int instr_cycles = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + + BS_common(0, 16, 1, cpu_state.regs[cpu_reg].w, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opBSF_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + int instr_cycles = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + + BS_common(0, 16, 1, cpu_state.regs[cpu_reg].w, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opBSF_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + int instr_cycles = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + + BS_common(0, 32, 1, cpu_state.regs[cpu_reg].l, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return 0; +} +static int opBSF_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + int instr_cycles = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + + BS_common(0, 32, 1, cpu_state.regs[cpu_reg].l, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return 0; +} + +static int opBSR_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + int instr_cycles = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + + BS_common(15, -1, -1, cpu_state.regs[cpu_reg].w, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opBSR_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + int instr_cycles = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + + BS_common(15, -1, -1, cpu_state.regs[cpu_reg].w, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opBSR_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + int instr_cycles = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + + BS_common(31, -1, -1, cpu_state.regs[cpu_reg].l, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return 0; +} +static int opBSR_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + int instr_cycles = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + + BS_common(31, -1, -1, cpu_state.regs[cpu_reg].l, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return 0; +} + diff --git a/src/cpu_new/x86_ops_call.h b/src/cpu_new/x86_ops_call.h new file mode 100644 index 000000000..a11bc9c97 --- /dev/null +++ b/src/cpu_new/x86_ops_call.h @@ -0,0 +1,455 @@ +#define CALL_FAR_w(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = cpu_state.pc; \ + cpu_state.pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg, old_pc); \ + else \ + { \ + loadcs(new_seg); \ + cycles -= timing_call_rm; \ + } \ + optype = 0; \ + if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + oldss = ss; \ + if (cgate32) \ + { \ + uint32_t old_esp = ESP; \ + PUSH_L(old_cs); if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \ + } \ + else \ + { \ + uint32_t old_esp = ESP; \ + PUSH_W(old_cs); if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; } \ + PUSH_W(old_pc); if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \ + } + +#define CALL_FAR_l(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = cpu_state.pc; \ + cpu_state.pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg, old_pc); \ + else \ + { \ + loadcs(new_seg); \ + cycles -= timing_call_rm; \ + } \ + optype = 0; \ + if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + oldss = ss; \ + if (cgate16) \ + { \ + uint32_t old_esp = ESP; \ + PUSH_W(old_cs); if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; } \ + PUSH_W(old_pc); if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \ + } \ + else \ + { \ + uint32_t old_esp = ESP; \ + PUSH_L(old_cs); if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \ + } + + +static int opCALL_far_w(uint32_t fetchdat) +{ + uint32_t old_cs, old_pc; + uint16_t new_cs, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + new_pc = getwordf(); + new_cs = getword(); if (cpu_state.abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 5, -1, 0,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); + PREFETCH_FLUSH(); + + return 0; +} +static int opCALL_far_l(uint32_t fetchdat) +{ + uint32_t old_cs, old_pc; + uint32_t new_cs, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + new_pc = getlong(); + new_cs = getword(); if (cpu_state.abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 7, -1, 0,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); + PREFETCH_FLUSH(); + + return 0; +} + + +static int opFF_w_a16(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + uint16_t temp; + + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(temp + 1); if (cpu_state.abrt) return 1; + setadd16nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + break; + case 0x08: /*DEC w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(temp - 1); if (cpu_state.abrt) return 1; + setsub16nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + break; + case 0x10: /*CALL*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_pc = geteaw(); if (cpu_state.abrt) return 1; + PUSH_W(cpu_state.pc); + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 0); + PREFETCH_FLUSH(); + break; + case 0x18: /*CALL far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_pc = readmemw(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); + PREFETCH_FLUSH(); + break; + case 0x20: /*JMP*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_pc = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + PREFETCH_FLUSH(); + break; + case 0x28: /*JMP far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + old_pc = cpu_state.pc; + new_pc = readmemw(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,0,0, 0); + PREFETCH_FLUSH(); + break; + case 0x30: /*PUSH w*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + PUSH_W(temp); + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 0); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return cpu_state.abrt; +} +static int opFF_w_a32(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + uint16_t temp; + + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(temp + 1); if (cpu_state.abrt) return 1; + setadd16nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + break; + case 0x08: /*DEC w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(temp - 1); if (cpu_state.abrt) return 1; + setsub16nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + break; + case 0x10: /*CALL*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_pc = geteaw(); if (cpu_state.abrt) return 1; + PUSH_W(cpu_state.pc); + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 1); + PREFETCH_FLUSH(); + break; + case 0x18: /*CALL far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_pc = readmemw(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,cgate16 ? 2:0,cgate16 ? 0:2, 1); + PREFETCH_FLUSH(); + break; + case 0x20: /*JMP*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_pc = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,0,0,0, 1); + PREFETCH_FLUSH(); + break; + case 0x28: /*JMP far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + old_pc = cpu_state.pc; + new_pc = readmemw(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,0,0, 1); + PREFETCH_FLUSH(); + break; + case 0x30: /*PUSH w*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + PUSH_W(temp); + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 1); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return cpu_state.abrt; +} + +static int opFF_l_a16(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + uint32_t temp; + + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(temp + 1); if (cpu_state.abrt) return 1; + setadd32nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + break; + case 0x08: /*DEC l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(temp - 1); if (cpu_state.abrt) return 1; + setsub32nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + break; + case 0x10: /*CALL*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_pc = geteal(); if (cpu_state.abrt) return 1; + PUSH_L(cpu_state.pc); + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 0); + PREFETCH_FLUSH(); + break; + case 0x18: /*CALL far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_pc = readmeml(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,cgate16 ? 2:0,cgate16 ? 0:2, 0); + PREFETCH_FLUSH(); + break; + case 0x20: /*JMP*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_pc = geteal(); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 0,1,0,0, 0); + PREFETCH_FLUSH(); + break; + case 0x28: /*JMP far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + old_pc = cpu_state.pc; + new_pc = readmeml(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 0); + PREFETCH_FLUSH(); + break; + case 0x30: /*PUSH l*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + PUSH_L(temp); + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 0); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return cpu_state.abrt; +} +static int opFF_l_a32(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + uint32_t temp; + + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(temp + 1); if (cpu_state.abrt) return 1; + setadd32nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + break; + case 0x08: /*DEC l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(temp - 1); if (cpu_state.abrt) return 1; + setsub32nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + break; + case 0x10: /*CALL*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_pc = geteal(); if (cpu_state.abrt) return 1; + PUSH_L(cpu_state.pc); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 1); + PREFETCH_FLUSH(); + break; + case 0x18: /*CALL far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_pc = readmeml(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,cgate16 ? 2:0,cgate16 ? 0:2, 1); + PREFETCH_FLUSH(); + break; + case 0x20: /*JMP*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_pc = geteal(); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 1); + PREFETCH_FLUSH(); + break; + case 0x28: /*JMP far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + old_pc = cpu_state.pc; + new_pc = readmeml(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 1); + PREFETCH_FLUSH(); + break; + case 0x30: /*PUSH l*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + PUSH_L(temp); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 1); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return cpu_state.abrt; +} diff --git a/src/cpu_new/x86_ops_flag.h b/src/cpu_new/x86_ops_flag.h new file mode 100644 index 000000000..d21408c8b --- /dev/null +++ b/src/cpu_new/x86_ops_flag.h @@ -0,0 +1,275 @@ +static int opCMC(uint32_t fetchdat) +{ + flags_rebuild(); + cpu_state.flags ^= C_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} + + +static int opCLC(uint32_t fetchdat) +{ + flags_rebuild(); + cpu_state.flags &= ~C_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCLD(uint32_t fetchdat) +{ + cpu_state.flags &= ~D_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCLI(uint32_t fetchdat) +{ + if (!IOPLp) + { + if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) + { + cpu_state.eflags &= ~VIF_FLAG; + } + else + { + x86gpf(NULL,0); + return 1; + } + } + else + cpu_state.flags &= ~I_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opSTC(uint32_t fetchdat) +{ + flags_rebuild(); + cpu_state.flags |= C_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opSTD(uint32_t fetchdat) +{ + cpu_state.flags |= D_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opSTI(uint32_t fetchdat) +{ + if (!IOPLp) + { + if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) + { + if (cpu_state.eflags & VIP_FLAG) + { + x86gpf(NULL,0); + return 1; + } + else + cpu_state.eflags |= VIF_FLAG; + } + else + { + x86gpf(NULL,0); + return 1; + } + } + else + cpu_state.flags |= I_FLAG; + + CPU_BLOCK_END(); + + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opSAHF(uint32_t fetchdat) +{ + flags_rebuild(); + cpu_state.flags = (cpu_state.flags & 0xff00) | (AH & 0xd5) | 2; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + + codegen_flags_changed = 0; + + return 0; +} +static int opLAHF(uint32_t fetchdat) +{ + flags_rebuild(); + AH = cpu_state.flags & 0xff; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opPUSHF(uint32_t fetchdat) +{ + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + { + if (cr4 & CR4_VME) + { + uint16_t temp; + + flags_rebuild(); + temp = (cpu_state.flags & ~I_FLAG) | 0x3000; + if (cpu_state.eflags & VIF_FLAG) + temp |= I_FLAG; + PUSH_W(temp); + } + else + { + x86gpf(NULL,0); + return 1; + } + } + else + { + flags_rebuild(); + PUSH_W(cpu_state.flags); + } + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opPUSHFD(uint32_t fetchdat) +{ + uint16_t tempw; + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + if (cpu_CR4_mask & CR4_VME) tempw = cpu_state.eflags & 0x3c; + else if (CPUID) tempw = cpu_state.eflags & 0x24; + else tempw = cpu_state.eflags & 4; + flags_rebuild(); + PUSH_L(cpu_state.flags | (tempw << 16)); + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,1, 0); + return cpu_state.abrt; +} + +static int opPOPF_286(uint32_t fetchdat) +{ + uint16_t tempw; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + tempw = POP_W(); if (cpu_state.abrt) return 1; + + if (!(msw & 1)) cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2; + else if (!(CPL)) cpu_state.flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2; + else cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; + flags_extract(); + + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + + codegen_flags_changed = 0; + + return 0; +} +static int opPOPF(uint32_t fetchdat) +{ + uint16_t tempw; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + { + if (cr4 & CR4_VME) + { + uint32_t old_esp = ESP; + + tempw = POP_W(); + if (cpu_state.abrt) + { + ESP = old_esp; + return 1; + } + + if ((tempw & T_FLAG) || ((tempw & I_FLAG) && (cpu_state.eflags & VIP_FLAG))) + { + ESP = old_esp; + x86gpf(NULL, 0); + return 1; + } + if (tempw & I_FLAG) + cpu_state.eflags |= VIF_FLAG; + else + cpu_state.eflags &= ~VIF_FLAG; + cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; + } + else + { + x86gpf(NULL, 0); + return 1; + } + } + else + { + tempw = POP_W(); + if (cpu_state.abrt) + return 1; + + if (!(CPL) || !(msw & 1)) + cpu_state.flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) + cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2; + else + cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; + } + flags_extract(); + + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + + codegen_flags_changed = 0; + + return 0; +} +static int opPOPFD(uint32_t fetchdat) +{ + uint32_t templ; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + templ = POP_L(); if (cpu_state.abrt) return 1; + + if (!(CPL) || !(msw & 1)) cpu_state.flags = (templ & 0x7fd5) | 2; + else if (IOPLp) cpu_state.flags = (cpu_state.flags & 0x3000) | (templ & 0x4fd5) | 2; + else cpu_state.flags = (cpu_state.flags & 0x3200) | (templ & 0x4dd5) | 2; + + templ &= is486 ? 0x3c0000 : 0; + templ |= ((cpu_state.eflags&3) << 16); + if (cpu_CR4_mask & CR4_VME) cpu_state.eflags = (templ >> 16) & 0x3f; + else if (CPUID) cpu_state.eflags = (templ >> 16) & 0x27; + else if (is486) cpu_state.eflags = (templ >> 16) & 7; + else cpu_state.eflags = (templ >> 16) & 3; + + flags_extract(); + + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 0,1,0,0, 0); + + codegen_flags_changed = 0; + + return 0; +} diff --git a/src/cpu_new/x86_ops_fpu.h b/src/cpu_new/x86_ops_fpu.h new file mode 100644 index 000000000..8c264374f --- /dev/null +++ b/src/cpu_new/x86_ops_fpu.h @@ -0,0 +1,82 @@ +static int opESCAPE_d8_a16(uint32_t fetchdat) +{ + return x86_opcodes_d8_a16[(fetchdat >> 3) & 0x1f](fetchdat); +} +static int opESCAPE_d8_a32(uint32_t fetchdat) +{ + return x86_opcodes_d8_a32[(fetchdat >> 3) & 0x1f](fetchdat); +} + +static int opESCAPE_d9_a16(uint32_t fetchdat) +{ + return x86_opcodes_d9_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_d9_a32(uint32_t fetchdat) +{ + return x86_opcodes_d9_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_da_a16(uint32_t fetchdat) +{ + return x86_opcodes_da_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_da_a32(uint32_t fetchdat) +{ + return x86_opcodes_da_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_db_a16(uint32_t fetchdat) +{ + return x86_opcodes_db_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_db_a32(uint32_t fetchdat) +{ + return x86_opcodes_db_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_dc_a16(uint32_t fetchdat) +{ + return x86_opcodes_dc_a16[(fetchdat >> 3) & 0x1f](fetchdat); +} +static int opESCAPE_dc_a32(uint32_t fetchdat) +{ + return x86_opcodes_dc_a32[(fetchdat >> 3) & 0x1f](fetchdat); +} + +static int opESCAPE_dd_a16(uint32_t fetchdat) +{ + return x86_opcodes_dd_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_dd_a32(uint32_t fetchdat) +{ + return x86_opcodes_dd_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_de_a16(uint32_t fetchdat) +{ + return x86_opcodes_de_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_de_a32(uint32_t fetchdat) +{ + return x86_opcodes_de_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_df_a16(uint32_t fetchdat) +{ + return x86_opcodes_df_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_df_a32(uint32_t fetchdat) +{ + return x86_opcodes_df_a32[fetchdat & 0xff](fetchdat); +} + +static int opWAIT(uint32_t fetchdat) +{ + if ((cr0 & 0xa) == 0xa) + { + x86_int(7); + return 1; + } + CLOCK_CYCLES(4); + return 0; +} diff --git a/src/cpu_new/x86_ops_i686.h b/src/cpu_new/x86_ops_i686.h new file mode 100644 index 000000000..b4c1ed7ff --- /dev/null +++ b/src/cpu_new/x86_ops_i686.h @@ -0,0 +1,514 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * x86 i686 (Pentium Pro/Pentium II) CPU Instructions. + * + * Version: @(#)x86_ops_i686.h 1.0.5 2018/10/17 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ + +/* 0 = Limit 0-15 + 1 = Base 0-15 + 2 = Base 16-23 (bits 0-7), Access rights + 8-11 Type + 12 S + 13, 14 DPL + 15 P + 3 = Limit 16-19 (bits 0-3), Base 24-31 (bits 8-15), granularity, etc. + 4 A + 6 DB + 7 G */ + +static void make_seg_data(uint16_t *seg_data, uint32_t base, uint32_t limit, uint8_t type, uint8_t s, uint8_t dpl, uint8_t p, uint8_t g, uint8_t db, uint8_t a) +{ + seg_data[0] = limit & 0xFFFF; + seg_data[1] = base & 0xFFFF; + seg_data[2] = ((base >> 16) & 0xFF) | (type << 8) | (p << 15) | (dpl << 13) | (s << 12); + seg_data[3] = ((limit >> 16) & 0xF) | (a << 4) | (db << 6) | (g << 7) | ((base >> 16) & 0xFF00); +} + +static int opSYSENTER(uint32_t fetchdat) +{ + uint16_t sysenter_cs_seg_data[4]; + uint16_t sysenter_ss_seg_data[4]; + +#ifdef SYSENTER_LOG + x386_dynarec_log("SYSENTER called\n"); +#endif + + if (!(msw & 1)) return internal_illegal("SYSENTER: CPU not in protected mode"); + if (!(cs_msr & 0xFFFC)) return internal_illegal("SYSENTER: CS MSR is zero"); + +#ifdef SYSENTER_LOG + x386_dynarec_log("SYSENTER started:\n"); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); + x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32); +#endif + + if (cpu_state.abrt) return 1; + + ESP = esp_msr; + cpu_state.pc = eip_msr; + + optype = CALL; \ + cgate16 = cgate32 = 0; \ + + /* Set VM, RF, and IF to 0. */ + cpu_state.eflags &= ~0x0003; + cpu_state.flags &= ~0x0200; + + CS = (cs_msr & 0xFFFC); + make_seg_data(sysenter_cs_seg_data, 0, 0xFFFFF, 11, 1, 0, 1, 1, 1, 0); + do_seg_load(&cpu_state.seg_cs, sysenter_cs_seg_data); + use32 = 0x300; + + SS = ((cs_msr + 8) & 0xFFFC); + make_seg_data(sysenter_ss_seg_data, 0, 0xFFFFF, 3, 1, 0, 1, 1, 1, 0); + do_seg_load(&cpu_state.seg_ss, sysenter_ss_seg_data); + stack32 = 1; + + cycles -= timing_call_pm; + + optype = 0; + + CPU_BLOCK_END(); + +#ifdef SYSENTER_LOG + x386_dynarec_log("SYSENTER completed:\n"); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); + x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32); +#endif + + return 0; +} + +static int opSYSEXIT(uint32_t fetchdat) +{ + uint16_t sysexit_cs_seg_data[4]; + uint16_t sysexit_ss_seg_data[4]; + +#ifdef SYSEXIT_LOG + x386_dynarec_log("SYSEXIT called\n"); +#endif + + if (!(cs_msr & 0xFFFC)) return internal_illegal("SYSEXIT: CS MSR is zero"); + if (!(msw & 1)) return internal_illegal("SYSEXIT: CPU not in protected mode"); + if (CPL) return internal_illegal("SYSEXIT: CPL not 0"); + +#ifdef SYSEXIT_LOG + x386_dynarec_log("SYSEXIT start:\n"); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); + x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32, ECX, EDX); +#endif + + if (cpu_state.abrt) return 1; + + ESP = ECX; + cpu_state.pc = EDX; + + optype = CALL; \ + cgate16 = cgate32 = 0; \ + + CS = ((cs_msr + 16) & 0xFFFC) | 3; + make_seg_data(sysexit_cs_seg_data, 0, 0xFFFFF, 11, 1, 3, 1, 1, 1, 0); + do_seg_load(&cpu_state.seg_cs, sysexit_cs_seg_data); + use32 = 0x300; + + SS = CS + 8; + make_seg_data(sysexit_ss_seg_data, 0, 0xFFFFF, 3, 1, 3, 1, 1, 1, 0); + do_seg_load(&cpu_state.seg_ss, sysexit_ss_seg_data); + stack32 = 1; + + flushmmucache_cr3(); + + cycles -= timing_call_pm; + + optype = 0; + + CPU_BLOCK_END(); + +#ifdef SYSEXIT_LOG + x386_dynarec_log("SYSEXIT completed:\n"); + x386_dynarec_log("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, cpu_state.seg_cs.base, cpu_state.seg_cs.limit, cpu_state.seg_cs.access, cpu_state.seg_cs.seg, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high, cpu_state.seg_cs.checked); + x386_dynarec_log("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, cpu_state.seg_ss.base, cpu_state.seg_ss.limit, cpu_state.seg_ss.access, cpu_state.seg_ss.seg, cpu_state.seg_ss.limit_low, cpu_state.seg_ss.limit_high, cpu_state.seg_ss.checked); + x386_dynarec_log("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + x386_dynarec_log("Other information: eip=%08X esp=%08X cpu_state.eflags=%04X cpu_state.flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, cpu_state.eflags, cpu_state.flags, use32, stack32, ECX, EDX); +#endif + + return 0; +} + +static int opFXSAVESTOR_a16(uint32_t fetchdat) +{ + uint8_t fxinst = 0; + uint16_t twd = x87_gettag(); + uint16_t old_eaaddr = 0; + uint8_t ftwb = 0; + uint16_t rec_ftw = 0; + uint16_t fpus = 0; + uint64_t *p; + + if (CPUID < 0x650) return ILLEGAL(fetchdat); + + FP_ENTER(); + + fetch_ea_16(fetchdat); + + if (cpu_state.eaaddr & 0xf) + { + x386_dynarec_log("Effective address %04X not on 16-byte boundary\n", cpu_state.eaaddr); + x86gpf(NULL, 0); + return cpu_state.abrt; + } + + fxinst = (rmdat >> 3) & 7; + + if ((fxinst > 1) || (cpu_mod == 3)) + { + x86illegal(); + return cpu_state.abrt; + } + + FP_ENTER(); + + old_eaaddr = cpu_state.eaaddr; + + if (fxinst == 1) + { + /* FXRSTOR */ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + fpus = readmemw(easeg, cpu_state.eaaddr + 2); + cpu_state.npxc = (cpu_state.npxc & ~FPU_CW_Reserved_Bits) | 0x0040; + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + cpu_state.TOP = (fpus >> 11) & 7; + cpu_state.npxs &= fpus & ~0x3800; + + /* foo = readmemw(easeg, cpu_state.eaaddr + 6) & 0x7FF; */ + + x87_pc_off = readmeml(easeg, cpu_state.eaaddr+8); + x87_pc_seg = readmemw(easeg, cpu_state.eaaddr+12); + /* if (cr0 & 1) + { + x87_pc_seg &= 0xFFFC; + x87_pc_seg |= ((cpu_state.seg_cs.access >> 5) & 3); + } */ + + ftwb = readmemb(easeg, cpu_state.eaaddr + 4); + + if (ftwb & 0x01) rec_ftw |= 0x0003; + if (ftwb & 0x02) rec_ftw |= 0x000C; + if (ftwb & 0x04) rec_ftw |= 0x0030; + if (ftwb & 0x08) rec_ftw |= 0x00C0; + if (ftwb & 0x10) rec_ftw |= 0x0300; + if (ftwb & 0x20) rec_ftw |= 0x0C00; + if (ftwb & 0x40) rec_ftw |= 0x3000; + if (ftwb & 0x80) rec_ftw |= 0xC000; + + x87_op_off = readmeml(easeg, cpu_state.eaaddr+16); + x87_op_off |= (readmemw(easeg, cpu_state.eaaddr + 6) >> 12) << 16; + x87_op_seg = readmemw(easeg, cpu_state.eaaddr+20); + /* if (cr0 & 1) + { + x87_op_seg &= 0xFFFC; + x87_op_seg |= ((_ds.access >> 5) & 3); + } */ + + cpu_state.eaaddr = old_eaaddr + 32; + x87_ldmmx(&(cpu_state.MM[0]), &(cpu_state.MM_w4[0])); x87_ld_frstor(0); + + cpu_state.eaaddr = old_eaaddr + 48; + x87_ldmmx(&(cpu_state.MM[1]), &(cpu_state.MM_w4[1])); x87_ld_frstor(1); + + cpu_state.eaaddr = old_eaaddr + 64; + x87_ldmmx(&(cpu_state.MM[2]), &(cpu_state.MM_w4[2])); x87_ld_frstor(2); + + cpu_state.eaaddr = old_eaaddr + 80; + x87_ldmmx(&(cpu_state.MM[3]), &(cpu_state.MM_w4[3])); x87_ld_frstor(3); + + cpu_state.eaaddr = old_eaaddr + 96; + x87_ldmmx(&(cpu_state.MM[4]), &(cpu_state.MM_w4[4])); x87_ld_frstor(4); + + cpu_state.eaaddr = old_eaaddr + 112; + x87_ldmmx(&(cpu_state.MM[5]), &(cpu_state.MM_w4[5])); x87_ld_frstor(5); + + cpu_state.eaaddr = old_eaaddr + 128; + x87_ldmmx(&(cpu_state.MM[6]), &(cpu_state.MM_w4[6])); x87_ld_frstor(6); + + cpu_state.eaaddr = old_eaaddr + 144; + x87_ldmmx(&(cpu_state.MM[7]), &(cpu_state.MM_w4[7])); x87_ld_frstor(7); + + cpu_state.ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + p = (uint64_t *)cpu_state.tag; + if (cpu_state.MM_w4[0] == 0xffff && cpu_state.MM_w4[1] == 0xffff && cpu_state.MM_w4[2] == 0xffff && cpu_state.MM_w4[3] == 0xffff && + cpu_state.MM_w4[4] == 0xffff && cpu_state.MM_w4[5] == 0xffff && cpu_state.MM_w4[6] == 0xffff && cpu_state.MM_w4[7] == 0xffff && + !cpu_state.TOP && !(*p)) + cpu_state.ismmx = 1; + + x87_settag(rec_ftw); + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + + if(cpu_state.abrt) x386_dynarec_log("FXRSTOR: abrt != 0\n"); + } + else + { + /* FXSAVE */ + if ((twd & 0x0003) == 0x0003) ftwb |= 0x01; + if ((twd & 0x000C) == 0x000C) ftwb |= 0x02; + if ((twd & 0x0030) == 0x0030) ftwb |= 0x04; + if ((twd & 0x00C0) == 0x00C0) ftwb |= 0x08; + if ((twd & 0x0300) == 0x0300) ftwb |= 0x10; + if ((twd & 0x0C00) == 0x0C00) ftwb |= 0x20; + if ((twd & 0x3000) == 0x3000) ftwb |= 0x40; + if ((twd & 0xC000) == 0xC000) ftwb |= 0x80; + + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememb(easeg,cpu_state.eaaddr+4,ftwb); + + writememw(easeg,cpu_state.eaaddr+6,(x87_op_off>>16)<<12); + writememl(easeg,cpu_state.eaaddr+8,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+12,x87_pc_seg); + + writememl(easeg,cpu_state.eaaddr+16,x87_op_off); + writememw(easeg,cpu_state.eaaddr+20,x87_op_seg); + + cpu_state.eaaddr = old_eaaddr + 32; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[0]) : x87_st_fsave(0); + + cpu_state.eaaddr = old_eaaddr + 48; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[1]) : x87_st_fsave(1); + + cpu_state.eaaddr = old_eaaddr + 64; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[2]) : x87_st_fsave(2); + + cpu_state.eaaddr = old_eaaddr + 80; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[3]) : x87_st_fsave(3); + + cpu_state.eaaddr = old_eaaddr + 96; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[4]) : x87_st_fsave(4); + + cpu_state.eaaddr = old_eaaddr + 112; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[5]) : x87_st_fsave(5); + + cpu_state.eaaddr = old_eaaddr + 128; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[6]) : x87_st_fsave(6); + + cpu_state.eaaddr = old_eaaddr + 144; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[7]) : x87_st_fsave(7); + + cpu_state.eaaddr = old_eaaddr; + + cpu_state.npxc = 0x37F; + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + cpu_state.npxs = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + + if(cpu_state.abrt) x386_dynarec_log("FXSAVE: abrt != 0\n"); + } + + return cpu_state.abrt; +} + +static int opFXSAVESTOR_a32(uint32_t fetchdat) +{ + uint8_t fxinst = 0; + uint16_t twd = x87_gettag(); + uint32_t old_eaaddr = 0; + uint8_t ftwb = 0; + uint16_t rec_ftw = 0; + uint16_t fpus = 0; + uint64_t *p; + + if (CPUID < 0x650) return ILLEGAL(fetchdat); + + FP_ENTER(); + + fetch_ea_32(fetchdat); + + if (cpu_state.eaaddr & 0xf) + { + x386_dynarec_log("Effective address %08X not on 16-byte boundary\n", cpu_state.eaaddr); + x86gpf(NULL, 0); + return cpu_state.abrt; + } + + fxinst = (rmdat >> 3) & 7; + + if ((fxinst > 1) || (cpu_mod == 3)) + { + x86illegal(); + return cpu_state.abrt; + } + + FP_ENTER(); + + old_eaaddr = cpu_state.eaaddr; + + if (fxinst == 1) + { + /* FXRSTOR */ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + fpus = readmemw(easeg, cpu_state.eaaddr + 2); + cpu_state.npxc = (cpu_state.npxc & ~FPU_CW_Reserved_Bits) | 0x0040; + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + cpu_state.TOP = (fpus >> 11) & 7; + cpu_state.npxs &= fpus & ~0x3800; + + /* foo = readmemw(easeg, cpu_state.eaaddr + 6) & 0x7FF; */ + + x87_pc_off = readmeml(easeg, cpu_state.eaaddr+8); + x87_pc_seg = readmemw(easeg, cpu_state.eaaddr+12); + /* if (cr0 & 1) + { + x87_pc_seg &= 0xFFFC; + x87_pc_seg |= ((cpu_state.seg_cs.access >> 5) & 3); + } */ + + ftwb = readmemb(easeg, cpu_state.eaaddr + 4); + + if (ftwb & 0x01) rec_ftw |= 0x0003; + if (ftwb & 0x02) rec_ftw |= 0x000C; + if (ftwb & 0x04) rec_ftw |= 0x0030; + if (ftwb & 0x08) rec_ftw |= 0x00C0; + if (ftwb & 0x10) rec_ftw |= 0x0300; + if (ftwb & 0x20) rec_ftw |= 0x0C00; + if (ftwb & 0x40) rec_ftw |= 0x3000; + if (ftwb & 0x80) rec_ftw |= 0xC000; + + x87_op_off = readmeml(easeg, cpu_state.eaaddr+16); + x87_op_off |= (readmemw(easeg, cpu_state.eaaddr + 6) >> 12) << 16; + x87_op_seg = readmemw(easeg, cpu_state.eaaddr+20); + /* if (cr0 & 1) + { + x87_op_seg &= 0xFFFC; + x87_op_seg |= ((_ds.access >> 5) & 3); + } */ + + cpu_state.eaaddr = old_eaaddr + 32; + x87_ldmmx(&(cpu_state.MM[0]), &(cpu_state.MM_w4[0])); x87_ld_frstor(0); + + cpu_state.eaaddr = old_eaaddr + 48; + x87_ldmmx(&(cpu_state.MM[1]), &(cpu_state.MM_w4[1])); x87_ld_frstor(1); + + cpu_state.eaaddr = old_eaaddr + 64; + x87_ldmmx(&(cpu_state.MM[2]), &(cpu_state.MM_w4[2])); x87_ld_frstor(2); + + cpu_state.eaaddr = old_eaaddr + 80; + x87_ldmmx(&(cpu_state.MM[3]), &(cpu_state.MM_w4[3])); x87_ld_frstor(3); + + cpu_state.eaaddr = old_eaaddr + 96; + x87_ldmmx(&(cpu_state.MM[4]), &(cpu_state.MM_w4[4])); x87_ld_frstor(4); + + cpu_state.eaaddr = old_eaaddr + 112; + x87_ldmmx(&(cpu_state.MM[5]), &(cpu_state.MM_w4[5])); x87_ld_frstor(5); + + cpu_state.eaaddr = old_eaaddr + 128; + x87_ldmmx(&(cpu_state.MM[6]), &(cpu_state.MM_w4[6])); x87_ld_frstor(6); + + cpu_state.eaaddr = old_eaaddr + 144; + x87_ldmmx(&(cpu_state.MM[7]), &(cpu_state.MM_w4[7])); x87_ld_frstor(7); + + cpu_state.ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + p = (uint64_t *)cpu_state.tag; + if (cpu_state.MM_w4[0] == 0xffff && cpu_state.MM_w4[1] == 0xffff && cpu_state.MM_w4[2] == 0xffff && cpu_state.MM_w4[3] == 0xffff && + cpu_state.MM_w4[4] == 0xffff && cpu_state.MM_w4[5] == 0xffff && cpu_state.MM_w4[6] == 0xffff && cpu_state.MM_w4[7] == 0xffff && + !cpu_state.TOP && !(*p)) + cpu_state.ismmx = 1; + + x87_settag(rec_ftw); + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + + if(cpu_state.abrt) x386_dynarec_log("FXRSTOR: abrt != 0\n"); + } + else + { + /* FXSAVE */ + if ((twd & 0x0003) == 0x0003) ftwb |= 0x01; + if ((twd & 0x000C) == 0x000C) ftwb |= 0x02; + if ((twd & 0x0030) == 0x0030) ftwb |= 0x04; + if ((twd & 0x00C0) == 0x00C0) ftwb |= 0x08; + if ((twd & 0x0300) == 0x0300) ftwb |= 0x10; + if ((twd & 0x0C00) == 0x0C00) ftwb |= 0x20; + if ((twd & 0x3000) == 0x3000) ftwb |= 0x40; + if ((twd & 0xC000) == 0xC000) ftwb |= 0x80; + + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememb(easeg,cpu_state.eaaddr+4,ftwb); + + writememw(easeg,cpu_state.eaaddr+6,(x87_op_off>>16)<<12); + writememl(easeg,cpu_state.eaaddr+8,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+12,x87_pc_seg); + + writememl(easeg,cpu_state.eaaddr+16,x87_op_off); + writememw(easeg,cpu_state.eaaddr+20,x87_op_seg); + + cpu_state.eaaddr = old_eaaddr + 32; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[0]) : x87_st_fsave(0); + + cpu_state.eaaddr = old_eaaddr + 48; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[1]) : x87_st_fsave(1); + + cpu_state.eaaddr = old_eaaddr + 64; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[2]) : x87_st_fsave(2); + + cpu_state.eaaddr = old_eaaddr + 80; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[3]) : x87_st_fsave(3); + + cpu_state.eaaddr = old_eaaddr + 96; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[4]) : x87_st_fsave(4); + + cpu_state.eaaddr = old_eaaddr + 112; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[5]) : x87_st_fsave(5); + + cpu_state.eaaddr = old_eaaddr + 128; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[6]) : x87_st_fsave(6); + + cpu_state.eaaddr = old_eaaddr + 144; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[7]) : x87_st_fsave(7); + + cpu_state.eaaddr = old_eaaddr; + + cpu_state.npxc = 0x37F; + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + cpu_state.npxs = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + + if(cpu_state.abrt) x386_dynarec_log("FXSAVE: abrt != 0\n"); + } + + return cpu_state.abrt; +} diff --git a/src/cpu_new/x86_ops_inc_dec.h b/src/cpu_new/x86_ops_inc_dec.h new file mode 100644 index 000000000..d14bae863 --- /dev/null +++ b/src/cpu_new/x86_ops_inc_dec.h @@ -0,0 +1,93 @@ +#define INC_DEC_OP(name, reg, inc, setflags) \ + static int op ## name (uint32_t fetchdat) \ + { \ + setflags(reg, 1); \ + reg += inc; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 1, -1, 0,0,0,0, 0); \ + return 0; \ + } + +INC_DEC_OP(INC_AX, AX, 1, setadd16nc) +INC_DEC_OP(INC_BX, BX, 1, setadd16nc) +INC_DEC_OP(INC_CX, CX, 1, setadd16nc) +INC_DEC_OP(INC_DX, DX, 1, setadd16nc) +INC_DEC_OP(INC_SI, SI, 1, setadd16nc) +INC_DEC_OP(INC_DI, DI, 1, setadd16nc) +INC_DEC_OP(INC_BP, BP, 1, setadd16nc) +INC_DEC_OP(INC_SP, SP, 1, setadd16nc) + +INC_DEC_OP(INC_EAX, EAX, 1, setadd32nc) +INC_DEC_OP(INC_EBX, EBX, 1, setadd32nc) +INC_DEC_OP(INC_ECX, ECX, 1, setadd32nc) +INC_DEC_OP(INC_EDX, EDX, 1, setadd32nc) +INC_DEC_OP(INC_ESI, ESI, 1, setadd32nc) +INC_DEC_OP(INC_EDI, EDI, 1, setadd32nc) +INC_DEC_OP(INC_EBP, EBP, 1, setadd32nc) +INC_DEC_OP(INC_ESP, ESP, 1, setadd32nc) + +INC_DEC_OP(DEC_AX, AX, -1, setsub16nc) +INC_DEC_OP(DEC_BX, BX, -1, setsub16nc) +INC_DEC_OP(DEC_CX, CX, -1, setsub16nc) +INC_DEC_OP(DEC_DX, DX, -1, setsub16nc) +INC_DEC_OP(DEC_SI, SI, -1, setsub16nc) +INC_DEC_OP(DEC_DI, DI, -1, setsub16nc) +INC_DEC_OP(DEC_BP, BP, -1, setsub16nc) +INC_DEC_OP(DEC_SP, SP, -1, setsub16nc) + +INC_DEC_OP(DEC_EAX, EAX, -1, setsub32nc) +INC_DEC_OP(DEC_EBX, EBX, -1, setsub32nc) +INC_DEC_OP(DEC_ECX, ECX, -1, setsub32nc) +INC_DEC_OP(DEC_EDX, EDX, -1, setsub32nc) +INC_DEC_OP(DEC_ESI, ESI, -1, setsub32nc) +INC_DEC_OP(DEC_EDI, EDI, -1, setsub32nc) +INC_DEC_OP(DEC_EBP, EBP, -1, setsub32nc) +INC_DEC_OP(DEC_ESP, ESP, -1, setsub32nc) + + +static int opINCDEC_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp=geteab(); if (cpu_state.abrt) return 1; + + if (rmdat&0x38) + { + seteab(temp - 1); if (cpu_state.abrt) return 1; + setsub8nc(temp, 1); + } + else + { + seteab(temp + 1); if (cpu_state.abrt) return 1; + setadd8nc(temp, 1); + } + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + return 0; +} +static int opINCDEC_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp=geteab(); if (cpu_state.abrt) return 1; + + if (rmdat&0x38) + { + seteab(temp - 1); if (cpu_state.abrt) return 1; + setsub8nc(temp, 1); + } + else + { + seteab(temp + 1); if (cpu_state.abrt) return 1; + setadd8nc(temp, 1); + } + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + return 0; +} diff --git a/src/cpu_new/x86_ops_int.h b/src/cpu_new/x86_ops_int.h new file mode 100644 index 000000000..260fcdad5 --- /dev/null +++ b/src/cpu_new/x86_ops_int.h @@ -0,0 +1,91 @@ +static int opINT3(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + x86_int_sw(3); + CLOCK_CYCLES((is486) ? 44 : 59); + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,0,0,0, 0); + return 1; +} + +static int opINT1(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + x86_int_sw(1); + CLOCK_CYCLES((is486) ? 44 : 59); + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,0,0,0, 0); + return 1; +} + +static int opINT(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + uint8_t temp = getbytef(); + + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + if (cr4 & CR4_VME) + { + uint16_t t; + uint8_t d; + + cpl_override = 1; + t = readmemw(tr.base, 0x66) - 32; + cpl_override = 0; + if (cpu_state.abrt) return 1; + + t += (temp >> 3); + if (t <= tr.limit) + { + cpl_override = 1; + d = readmemb(tr.base, t);// + (temp >> 3)); + cpl_override = 0; + if (cpu_state.abrt) return 1; + + if (!(d & (1 << (temp & 7)))) + { + x86_int_sw_rm(temp); + PREFETCH_RUN(cycles_old-cycles, 2, -1, 0,0,0,0, 0); + return 1; + } + } + } + x86gpf(NULL,0); + return 1; + } + + x86_int_sw(temp); + PREFETCH_RUN(cycles_old-cycles, 2, -1, 0,0,0,0, 0); + return 1; +} + +static int opINTO(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (VF_SET()) + { + cpu_state.oldpc = cpu_state.pc; + x86_int_sw(4); + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,0,0,0, 0); + return 1; + } + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + diff --git a/src/cpu_new/x86_ops_io.h b/src/cpu_new/x86_ops_io.h new file mode 100644 index 000000000..9fa91a215 --- /dev/null +++ b/src/cpu_new/x86_ops_io.h @@ -0,0 +1,146 @@ +static int opIN_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + AL = inb(port); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 2, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opIN_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + AX = inw(port); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 2, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opIN_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + EAX = inl(port); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 2, -1, 0,1,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} + +static int opOUT_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + outb(port, AL); + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, -1, 0,0,1,0, 0); + if (port == 0x64) + return x86_was_reset; + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opOUT_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + outw(port, AX); + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, -1, 0,0,1,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opOUT_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + outl(port, EAX); + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, -1, 0,0,0,1, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} + +static int opIN_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + AL = inb(DX); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 1, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opIN_AX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + AX = inw(DX); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 1, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opIN_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + EAX = inl(DX); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 1, -1, 0,1,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} + +static int opOUT_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + outb(DX, AL); + CLOCK_CYCLES(11); + PREFETCH_RUN(11, 1, -1, 0,0,1,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return x86_was_reset; +} +static int opOUT_AX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + outw(DX, AX); + CLOCK_CYCLES(11); + PREFETCH_RUN(11, 1, -1, 0,0,1,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opOUT_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + outl(DX, EAX); + PREFETCH_RUN(11, 1, -1, 0,0,0,1, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} diff --git a/src/cpu_new/x86_ops_jump.h b/src/cpu_new/x86_ops_jump.h new file mode 100644 index 000000000..c227939a3 --- /dev/null +++ b/src/cpu_new/x86_ops_jump.h @@ -0,0 +1,381 @@ +#define cond_O ( VF_SET()) +#define cond_NO (!VF_SET()) +#define cond_B ( CF_SET()) +#define cond_NB (!CF_SET()) +#define cond_E ( ZF_SET()) +#define cond_NE (!ZF_SET()) +#define cond_BE ( CF_SET() || ZF_SET()) +#define cond_NBE (!CF_SET() && !ZF_SET()) +#define cond_S ( NF_SET()) +#define cond_NS (!NF_SET()) +#define cond_P ( PF_SET()) +#define cond_NP (!PF_SET()) +#define cond_L (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0)) +#define cond_NL (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0)) +#define cond_LE (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0) || (ZF_SET())) +#define cond_NLE (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0) && (!ZF_SET())) + +#define opJ(condition) \ + static int opJ ## condition(uint32_t fetchdat) \ + { \ + int8_t offset = (int8_t)getbytef(); \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + if (!(cpu_state.op32 & 0x100)) \ + cpu_state.pc &= 0xffff; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + PREFETCH_RUN(timing_bt+timing_bnt, 2, -1, 0,0,0,0, 0); \ + PREFETCH_FLUSH(); \ + return 1; \ + } \ + PREFETCH_RUN(timing_bnt, 2, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int opJ ## condition ## _w(uint32_t fetchdat) \ + { \ + int16_t offset = (int16_t)getwordf(); \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + cpu_state.pc &= 0xffff; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + PREFETCH_RUN(timing_bt+timing_bnt, 3, -1, 0,0,0,0, 0); \ + PREFETCH_FLUSH(); \ + return 1; \ + } \ + PREFETCH_RUN(timing_bnt, 3, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int opJ ## condition ## _l(uint32_t fetchdat) \ + { \ + uint32_t offset = getlong(); if (cpu_state.abrt) return 1; \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + PREFETCH_RUN(timing_bt+timing_bnt, 5, -1, 0,0,0,0, 0); \ + PREFETCH_FLUSH(); \ + return 1; \ + } \ + PREFETCH_RUN(timing_bnt, 5, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + +opJ(O) +opJ(NO) +opJ(B) +opJ(NB) +opJ(E) +opJ(NE) +opJ(BE) +opJ(NBE) +opJ(S) +opJ(NS) +opJ(P) +opJ(NP) +opJ(L) +opJ(NL) +opJ(LE) +opJ(NLE) + + + +static int opLOOPNE_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (CX && !ZF_SET()) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} +static int opLOOPNE_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (ECX && !ZF_SET()) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} + +static int opLOOPE_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (CX && ZF_SET()) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} +static int opLOOPE_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (ECX && ZF_SET()) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} + +static int opLOOP_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (CX) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} +static int opLOOP_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (ECX) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} + +static int opJCXZ(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CLOCK_CYCLES(5); + if (!CX) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CLOCK_CYCLES(4); + CPU_BLOCK_END(); + PREFETCH_RUN(9, 2, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 1; + } + PREFETCH_RUN(5, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opJECXZ(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CLOCK_CYCLES(5); + if (!ECX) + { + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CLOCK_CYCLES(4); + CPU_BLOCK_END(); + PREFETCH_RUN(9, 2, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 1; + } + PREFETCH_RUN(5, 2, -1, 0,0,0,0, 0); + return 0; +} + + +static int opJMP_r8(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 2, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opJMP_r16(uint32_t fetchdat) +{ + int16_t offset = (int16_t)getwordf(); + cpu_state.pc += offset; + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 3, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opJMP_r32(uint32_t fetchdat) +{ + int32_t offset = (int32_t)getlong(); if (cpu_state.abrt) return 1; + cpu_state.pc += offset; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 5, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} + +static int opJMP_far_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + uint32_t old_pc; + addr = getwordf(); + seg = getword(); if (cpu_state.abrt) return 1; + old_pc = cpu_state.pc; + cpu_state.pc = addr; + loadcsjmp(seg, old_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(11, 5, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opJMP_far_a32(uint32_t fetchdat) +{ + uint16_t seg; + uint32_t addr, old_pc; + addr = getlong(); + seg = getword(); if (cpu_state.abrt) return 1; + old_pc = cpu_state.pc; + cpu_state.pc = addr; + loadcsjmp(seg, old_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(11, 7, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} + +static int opCALL_r16(uint32_t fetchdat) +{ + int16_t addr = (int16_t)getwordf(); + PUSH_W(cpu_state.pc); + cpu_state.pc += addr; + cpu_state.pc &= 0xffff; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 3, -1, 0,0,1,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opCALL_r32(uint32_t fetchdat) +{ + int32_t addr = getlong(); if (cpu_state.abrt) return 1; + PUSH_L(cpu_state.pc); + cpu_state.pc += addr; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 5, -1, 0,0,0,1, 0); + PREFETCH_FLUSH(); + return 0; +} + +static int opRET_w(uint32_t fetchdat) +{ + uint16_t ret; + + ret = POP_W(); if (cpu_state.abrt) return 1; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + PREFETCH_RUN(10, 1, -1, 1,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opRET_l(uint32_t fetchdat) +{ + uint32_t ret; + + ret = POP_L(); if (cpu_state.abrt) return 1; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + PREFETCH_RUN(10, 1, -1, 0,1,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} + +static int opRET_w_imm(uint32_t fetchdat) +{ + uint16_t ret; + uint16_t offset = getwordf(); + + ret = POP_W(); if (cpu_state.abrt) return 1; + if (stack32) ESP += offset; + else SP += offset; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + PREFETCH_RUN(10, 5, -1, 1,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opRET_l_imm(uint32_t fetchdat) +{ + uint32_t ret; + uint16_t offset = getwordf(); + + ret = POP_L(); if (cpu_state.abrt) return 1; + if (stack32) ESP += offset; + else SP += offset; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + PREFETCH_RUN(10, 5, -1, 0,1,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} + diff --git a/src/cpu_new/x86_ops_misc.h b/src/cpu_new/x86_ops_misc.h new file mode 100644 index 000000000..6ecfe268a --- /dev/null +++ b/src/cpu_new/x86_ops_misc.h @@ -0,0 +1,959 @@ +static int opCBW(uint32_t fetchdat) +{ + AH = (AL & 0x80) ? 0xff : 0; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCWDE(uint32_t fetchdat) +{ + EAX = (AX & 0x8000) ? (0xffff0000 | AX) : AX; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCWD(uint32_t fetchdat) +{ + DX = (AX & 0x8000) ? 0xFFFF : 0; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCDQ(uint32_t fetchdat) +{ + EDX = (EAX & 0x80000000) ? 0xffffffff : 0; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opNOP(uint32_t fetchdat) +{ + CLOCK_CYCLES((is486) ? 1 : 3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opSETALC(uint32_t fetchdat) +{ + AL = (CF_SET()) ? 0xff : 0; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 1, -1, 0,0,0,0, 0); + return 0; +} + + + +static int opF6_a16(uint32_t fetchdat) +{ + int tempws, tempws2 = 0; + uint16_t tempw, src16; + uint8_t src, dst; + int8_t temps; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) { + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + } + dst = geteab(); if (cpu_state.abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + case 0x08: + src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; + setznp8(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x10: /*NOT b*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteab(~dst); if (cpu_state.abrt) return 1; + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + break; + case 0x18: /*NEG b*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteab(0 - dst); if (cpu_state.abrt) return 1; + setsub8(0, dst); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + break; + case 0x20: /*MUL AL,b*/ + AX = AL * dst; + flags_rebuild(); + if (AH) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(13); + PREFETCH_RUN(13, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x28: /*IMUL AL,b*/ + tempws = (int)((int8_t)AL) * (int)((int8_t)dst); + AX = tempws & 0xffff; + flags_rebuild(); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x30: /*DIV AL,b*/ + src16 = AX; + if (dst) tempw = src16 / dst; + if (dst && !(tempw & 0xff00)) + { + AH = src16 % dst; + AL = (src16 / dst) &0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 16 : 14); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x38: /*IDIV AL,b*/ + tempws = (int)(int16_t)AX; + if (dst != 0) tempws2 = tempws / (int)((int8_t)dst); + temps = tempws2 & 0xff; + if (dst && ((int)temps == tempws2)) + { + AH = (tempws % (int)((int8_t)dst)) & 0xff; + AL = tempws2 & 0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + cpu_state.flags|=0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(19); + PREFETCH_RUN(19, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + + default: + x86illegal(); + } + return 0; +} +static int opF6_a32(uint32_t fetchdat) +{ + int tempws, tempws2 = 0; + uint16_t tempw, src16; + uint8_t src, dst; + int8_t temps; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + dst = geteab(); if (cpu_state.abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + case 0x08: + src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; + setznp8(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x10: /*NOT b*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteab(~dst); if (cpu_state.abrt) return 1; + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + break; + case 0x18: /*NEG b*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteab(0 - dst); if (cpu_state.abrt) return 1; + setsub8(0, dst); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + break; + case 0x20: /*MUL AL,b*/ + AX = AL * dst; + flags_rebuild(); + if (AH) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(13); + PREFETCH_RUN(13, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x28: /*IMUL AL,b*/ + tempws = (int)((int8_t)AL) * (int)((int8_t)dst); + AX = tempws & 0xffff; + flags_rebuild(); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x30: /*DIV AL,b*/ + src16 = AX; + if (dst) tempw = src16 / dst; + if (dst && !(tempw & 0xff00)) + { + AH = src16 % dst; + AL = (src16 / dst) &0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 16 : 14); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x38: /*IDIV AL,b*/ + tempws = (int)(int16_t)AX; + if (dst != 0) tempws2 = tempws / (int)((int8_t)dst); + temps = tempws2 & 0xff; + if (dst && ((int)temps == tempws2)) + { + AH = (tempws % (int)((int8_t)dst)) & 0xff; + AL = tempws2 & 0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(19); + PREFETCH_RUN(19, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + + default: + x86illegal(); + } + return 0; +} + + + +static int opF7_w_a16(uint32_t fetchdat) +{ + uint32_t templ, templ2; + int tempws, tempws2 = 0; + int16_t temps16; + uint16_t src, dst; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + dst = geteaw(); if (cpu_state.abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST w*/ + case 0x08: + src = getword(); if (cpu_state.abrt) return 1; + setznp16(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x10: /*NOT w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(~dst); if (cpu_state.abrt) return 1; + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + break; + case 0x18: /*NEG w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(0 - dst); if (cpu_state.abrt) return 1; + setsub16(0, dst); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + break; + case 0x20: /*MUL AX,w*/ + templ = AX * dst; + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (DX) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(21); + PREFETCH_RUN(21, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x28: /*IMUL AX,w*/ + templ = (int)((int16_t)AX) * (int)((int16_t)dst); + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(22); + PREFETCH_RUN(22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (dst) templ2 = templ / dst; + if (dst && !(templ2 & 0xffff0000)) + { + DX = templ % dst; + AX = (templ / dst) & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 24 : 22); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x38: /*IDIV AX,w*/ + tempws = (int)((DX << 16)|AX); + if (dst) tempws2 = tempws / (int)((int16_t)dst); + temps16 = tempws2 & 0xffff; + if ((dst != 0) && ((int)temps16 == tempws2)) + { + DX = tempws % (int)((int16_t)dst); + AX = tempws2 & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(27); + PREFETCH_RUN(27, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + + default: + x86illegal(); + } + return 0; +} +static int opF7_w_a32(uint32_t fetchdat) +{ + uint32_t templ, templ2; + int tempws, tempws2 = 1; + int16_t temps16; + uint16_t src, dst; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + dst = geteaw(); if (cpu_state.abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST w*/ + case 0x08: + src = getword(); if (cpu_state.abrt) return 1; + setznp16(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x10: /*NOT w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(~dst); if (cpu_state.abrt) return 1; + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + break; + case 0x18: /*NEG w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(0 - dst); if (cpu_state.abrt) return 1; + setsub16(0, dst); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + break; + case 0x20: /*MUL AX,w*/ + templ = AX * dst; + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (DX) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(21); + PREFETCH_RUN(21, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x28: /*IMUL AX,w*/ + templ = (int)((int16_t)AX) * (int)((int16_t)dst); + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(22); + PREFETCH_RUN(22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (dst) templ2 = templ / dst; + if (dst && !(templ2 & 0xffff0000)) + { + DX = templ % dst; + AX = (templ / dst) & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); + x86_int(0); + return 1; + } + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 24 : 22); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x38: /*IDIV AX,w*/ + tempws = (int)((DX << 16)|AX); + if (dst) tempws2 = tempws / (int)((int16_t)dst); + temps16 = tempws2 & 0xffff; + if ((dst != 0) && ((int)temps16 == tempws2)) + { + DX = tempws % (int)((int16_t)dst); + AX = tempws2 & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(27); + PREFETCH_RUN(27, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + + default: + x86illegal(); + } + return 0; +} + +static int opF7_l_a16(uint32_t fetchdat) +{ + uint64_t temp64; + uint32_t src, dst; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + dst = geteal(); if (cpu_state.abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*TEST l*/ + case 0x08: + src = getlong(); if (cpu_state.abrt) return 1; + setznp32(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 5, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + break; + case 0x10: /*NOT l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteal(~dst); if (cpu_state.abrt) return 1; + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + break; + case 0x18: /*NEG l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteal(0 - dst); if (cpu_state.abrt) return 1; + setsub32(0, dst); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + break; + case 0x20: /*MUL EAX,l*/ + temp64 = (uint64_t)EAX * (uint64_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (EDX) cpu_state.flags |= (C_FLAG|V_FLAG); + else cpu_state.flags &= ~(C_FLAG|V_FLAG); + CLOCK_CYCLES(21); + PREFETCH_RUN(21, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + break; + case 0x28: /*IMUL EAX,l*/ + temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(38); + PREFETCH_RUN(38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + break; + case 0x30: /*DIV EAX,l*/ + if (divl(dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES((is486) ? 40 : 38); + PREFETCH_RUN(is486 ? 40:38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + break; + case 0x38: /*IDIV EAX,l*/ + if (idivl((int32_t)dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES(43); + PREFETCH_RUN(43, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + break; + + default: + x86illegal(); + } + return 0; +} +static int opF7_l_a32(uint32_t fetchdat) +{ + uint64_t temp64; + uint32_t src, dst; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + dst = geteal(); if (cpu_state.abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*TEST l*/ + case 0x08: + src = getlong(); if (cpu_state.abrt) return 1; + setznp32(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 5, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + break; + case 0x10: /*NOT l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteal(~dst); if (cpu_state.abrt) return 1; + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + break; + case 0x18: /*NEG l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteal(0 - dst); if (cpu_state.abrt) return 1; + setsub32(0, dst); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + break; + case 0x20: /*MUL EAX,l*/ + temp64 = (uint64_t)EAX * (uint64_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (EDX) cpu_state.flags |= (C_FLAG|V_FLAG); + else cpu_state.flags &= ~(C_FLAG|V_FLAG); + CLOCK_CYCLES(21); + PREFETCH_RUN(21, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + break; + case 0x28: /*IMUL EAX,l*/ + temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(38); + PREFETCH_RUN(38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + break; + case 0x30: /*DIV EAX,l*/ + if (divl(dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES((is486) ? 40 : 38); + PREFETCH_RUN(is486 ? 40 : 38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + break; + case 0x38: /*IDIV EAX,l*/ + if (idivl((int32_t)dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES(43); + PREFETCH_RUN(43, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + break; + + default: + x86illegal(); + } + return 0; +} + + +static int opHLT(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + if (!((cpu_state.flags & I_FLAG) && pic_intpending)) + { + CLOCK_CYCLES_ALWAYS(100); + cpu_state.pc--; + } + else + CLOCK_CYCLES(5); + + CPU_BLOCK_END(); + PREFETCH_RUN(100, 1, -1, 0,0,0,0, 0); + + return 0; +} + + +static int opLOCK(uint32_t fetchdat) +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 0; + cpu_state.pc++; + + ILLEGAL_ON((fetchdat & 0xff) == 0x90); + + CLOCK_CYCLES(4); + PREFETCH_PREFIX(); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} + + + +static int opBOUND_w_a16(uint32_t fetchdat) +{ + int16_t low, high; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); + low = geteaw(); + high = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + + if (((int16_t)cpu_state.regs[cpu_reg].w < low) || ((int16_t)cpu_state.regs[cpu_reg].w > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 2,0,0,0, 0); + return 0; +} +static int opBOUND_w_a32(uint32_t fetchdat) +{ + int16_t low, high; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); + low = geteaw(); + high = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + + if (((int16_t)cpu_state.regs[cpu_reg].w < low) || ((int16_t)cpu_state.regs[cpu_reg].w > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 2,0,0,0, 1); + return 0; +} + +static int opBOUND_l_a16(uint32_t fetchdat) +{ + int32_t low, high; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); + low = geteal(); + high = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + + if (((int32_t)cpu_state.regs[cpu_reg].l < low) || ((int32_t)cpu_state.regs[cpu_reg].l > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 1,1,0,0, 0); + return 0; +} +static int opBOUND_l_a32(uint32_t fetchdat) +{ + int32_t low, high; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); + low = geteal(); + high = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + + if (((int32_t)cpu_state.regs[cpu_reg].l < low) || ((int32_t)cpu_state.regs[cpu_reg].l > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 1,1,0,0, 1); + return 0; +} + + +static int opCLTS(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + cr0 &= ~8; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opINVD(uint32_t fetchdat) +{ + if (!is486) + { + x86illegal(); + return 1; + } + CLOCK_CYCLES(1000); + CPU_BLOCK_END(); + return 0; +} +static int opWBINVD(uint32_t fetchdat) +{ + if (!is486) + { + x86illegal(); + return 1; + } + CLOCK_CYCLES(10000); + CPU_BLOCK_END(); + return 0; +} + +static int opLOADALL(uint32_t fetchdat) +{ + if (CPL && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + msw = (msw & 1) | readmemw(0, 0x806); + cpu_state.flags = (readmemw(0, 0x818) & 0xffd5) | 2; + flags_extract(); + tr.seg = readmemw(0, 0x816); + cpu_state.pc = readmemw(0, 0x81A); + ldt.seg = readmemw(0, 0x81C); + DS = readmemw(0, 0x81E); + SS = readmemw(0, 0x820); + CS = readmemw(0, 0x822); + ES = readmemw(0, 0x824); + DI = readmemw(0, 0x826); + SI = readmemw(0, 0x828); + BP = readmemw(0, 0x82A); + SP = readmemw(0, 0x82C); + BX = readmemw(0, 0x82E); + DX = readmemw(0, 0x830); + CX = readmemw(0, 0x832); + AX = readmemw(0, 0x834); + es = readmemw(0, 0x836) | (readmemb(0, 0x838) << 16); + cpu_state.seg_es.access = readmemb(0, 0x839); + cpu_state.seg_es.limit = readmemw(0, 0x83A); + cs = readmemw(0, 0x83C) | (readmemb(0, 0x83E) << 16); + cpu_state.seg_cs.access = readmemb(0, 0x83F); + cpu_state.seg_cs.limit = readmemw(0, 0x840); + ss = readmemw(0, 0x842) | (readmemb(0, 0x844) << 16); + cpu_state.seg_ss.access = readmemb(0, 0x845); + cpu_state.seg_ss.limit = readmemw(0, 0x846); + if (cpu_state.seg_ss.base == 0 && cpu_state.seg_ss.limit_low == 0 && cpu_state.seg_ss.limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + ds = readmemw(0, 0x848) | (readmemb(0, 0x84A) << 16); + cpu_state.seg_ds.access = readmemb(0, 0x84B); + cpu_state.seg_ds.limit = readmemw(0, 0x84C); + if (cpu_state.seg_ds.base == 0 && cpu_state.seg_ds.limit_low == 0 && cpu_state.seg_ds.limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + gdt.base = readmemw(0, 0x84E) | (readmemb(0, 0x850) << 16); + gdt.limit = readmemw(0, 0x852); + ldt.base = readmemw(0, 0x854) | (readmemb(0, 0x856) << 16); + ldt.access = readmemb(0, 0x857); + ldt.limit = readmemw(0, 0x858); + idt.base = readmemw(0, 0x85A) | (readmemb(0, 0x85C) << 16); + idt.limit = readmemw(0, 0x85E); + tr.base = readmemw(0, 0x860) | (readmemb(0, 0x862) << 16); + tr.access = readmemb(0, 0x863); + tr.limit = readmemw(0, 0x864); + CLOCK_CYCLES(195); + PREFETCH_RUN(195, 1, -1, 51,0,0,0, 0); + return 0; +} + +static void set_segment_limit(x86seg *s, uint8_t segdat3) +{ + if ((s->access & 0x18) != 0x10 || !(s->access & (1 << 2))) /*expand-down*/ + { + s->limit_high = s->limit; + s->limit_low = 0; + } + else + { + s->limit_high = (segdat3 & 0x40) ? 0xffffffff : 0xffff; + s->limit_low = s->limit + 1; + } +} + +static void loadall_load_segment(uint32_t addr, x86seg *s) +{ + uint32_t attrib = readmeml(0, addr); + uint32_t segdat3 = (attrib >> 16) & 0xff; + s->access = (attrib >> 8) & 0xff; + s->base = readmeml(0, addr + 4); + s->limit = readmeml(0, addr + 8); + + if (s == &cpu_state.seg_cs) + use32 = (segdat3 & 0x40) ? 0x300 : 0; + if (s == &cpu_state.seg_ss) + stack32 = (segdat3 & 0x40) ? 1 : 0; + + cpu_cur_status &= ~(CPU_STATUS_USE32 | CPU_STATUS_STACK32); + if (use32) + cpu_cur_status |= CPU_STATUS_USE32; + if (stack32) + cpu_cur_status |= CPU_STATUS_STACK32; + + set_segment_limit(s, segdat3); + + if (s == &cpu_state.seg_ds) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &cpu_state.seg_ss) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } +} + +static int opLOADALL386(uint32_t fetchdat) +{ + uint32_t la_addr = es + EDI; + + cr0 = readmeml(0, la_addr); + cpu_state.flags = readmemw(0, la_addr + 4); + cpu_state.eflags = readmemw(0, la_addr + 6); + flags_extract(); + cpu_state.pc = readmeml(0, la_addr + 8); + EDI = readmeml(0, la_addr + 0xC); + ESI = readmeml(0, la_addr + 0x10); + EBP = readmeml(0, la_addr + 0x14); + ESP = readmeml(0, la_addr + 0x18); + EBX = readmeml(0, la_addr + 0x1C); + EDX = readmeml(0, la_addr + 0x20); + ECX = readmeml(0, la_addr + 0x24); + EAX = readmeml(0, la_addr + 0x28); + dr[6] = readmeml(0, la_addr + 0x2C); + dr[7] = readmeml(0, la_addr + 0x30); + tr.seg = readmemw(0, la_addr + 0x34); + ldt.seg = readmemw(0, la_addr + 0x38); + GS = readmemw(0, la_addr + 0x3C); + FS = readmemw(0, la_addr + 0x40); + DS = readmemw(0, la_addr + 0x44); + SS = readmemw(0, la_addr + 0x48); + CS = readmemw(0, la_addr + 0x4C); + ES = readmemw(0, la_addr + 0x50); + + loadall_load_segment(la_addr + 0x54, &tr); + loadall_load_segment(la_addr + 0x60, &idt); + loadall_load_segment(la_addr + 0x6c, &gdt); + loadall_load_segment(la_addr + 0x78, &ldt); + loadall_load_segment(la_addr + 0x84, &cpu_state.seg_gs); + loadall_load_segment(la_addr + 0x90, &cpu_state.seg_fs); + loadall_load_segment(la_addr + 0x9c, &cpu_state.seg_ds); + loadall_load_segment(la_addr + 0xa8, &cpu_state.seg_ss); + loadall_load_segment(la_addr + 0xb4, &cpu_state.seg_cs); + loadall_load_segment(la_addr + 0xc0, &cpu_state.seg_es); + + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + + CLOCK_CYCLES(350); + return 0; +} + +static int opCPUID(uint32_t fetchdat) +{ + if (CPUID) + { + cpu_CPUID(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; +} + +static int opRDMSR(uint32_t fetchdat) +{ + if (cpu_has_feature(CPU_FEATURE_MSR)) + { + cpu_RDMSR(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; +} + +static int opWRMSR(uint32_t fetchdat) +{ + if (cpu_has_feature(CPU_FEATURE_MSR)) + { + cpu_WRMSR(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; +} + diff --git a/src/cpu_new/x86_ops_mmx.h b/src/cpu_new/x86_ops_mmx.h new file mode 100644 index 000000000..f9a7f9357 --- /dev/null +++ b/src/cpu_new/x86_ops_mmx.h @@ -0,0 +1,49 @@ +#define SSATB(val) (((val) < -128) ? -128 : (((val) > 127) ? 127 : (val))) +#define SSATW(val) (((val) < -32768) ? -32768 : (((val) > 32767) ? 32767 : (val))) +#define USATB(val) (((val) < 0) ? 0 : (((val) > 255) ? 255 : (val))) +#define USATW(val) (((val) < 0) ? 0 : (((val) > 65535) ? 65535 : (val))) + +#define MMX_GETSRC() \ + if (cpu_mod == 3) \ + { \ + src = cpu_state.MM[cpu_rm]; \ + CLOCK_CYCLES(1); \ + } \ + else \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + src.q = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; \ + CLOCK_CYCLES(2); \ + } + +#define MMX_ENTER() \ + if (!cpu_has_feature(CPU_FEATURE_MMX)) \ + { \ + cpu_state.pc = cpu_state.oldpc; \ + x86illegal(); \ + return 1; \ + } \ + if (cr0 & 0xc) \ + { \ + x86_int(7); \ + return 1; \ + } \ + x87_set_mmx() + +static int opEMMS(uint32_t fetchdat) +{ + if (!cpu_has_feature(CPU_FEATURE_MMX)) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + x87_emms(); + CLOCK_CYCLES(100); /*Guess*/ + return 0; +} diff --git a/src/cpu_new/x86_ops_mmx_arith.h b/src/cpu_new/x86_ops_mmx_arith.h new file mode 100644 index 000000000..22c34c738 --- /dev/null +++ b/src/cpu_new/x86_ops_mmx_arith.h @@ -0,0 +1,629 @@ +static int opPADDB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] += src.b[0]; + cpu_state.MM[cpu_reg].b[1] += src.b[1]; + cpu_state.MM[cpu_reg].b[2] += src.b[2]; + cpu_state.MM[cpu_reg].b[3] += src.b[3]; + cpu_state.MM[cpu_reg].b[4] += src.b[4]; + cpu_state.MM[cpu_reg].b[5] += src.b[5]; + cpu_state.MM[cpu_reg].b[6] += src.b[6]; + cpu_state.MM[cpu_reg].b[7] += src.b[7]; + + return 0; +} +static int opPADDB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] += src.b[0]; + cpu_state.MM[cpu_reg].b[1] += src.b[1]; + cpu_state.MM[cpu_reg].b[2] += src.b[2]; + cpu_state.MM[cpu_reg].b[3] += src.b[3]; + cpu_state.MM[cpu_reg].b[4] += src.b[4]; + cpu_state.MM[cpu_reg].b[5] += src.b[5]; + cpu_state.MM[cpu_reg].b[6] += src.b[6]; + cpu_state.MM[cpu_reg].b[7] += src.b[7]; + + return 0; +} + +static int opPADDW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] += src.w[0]; + cpu_state.MM[cpu_reg].w[1] += src.w[1]; + cpu_state.MM[cpu_reg].w[2] += src.w[2]; + cpu_state.MM[cpu_reg].w[3] += src.w[3]; + + return 0; +} +static int opPADDW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] += src.w[0]; + cpu_state.MM[cpu_reg].w[1] += src.w[1]; + cpu_state.MM[cpu_reg].w[2] += src.w[2]; + cpu_state.MM[cpu_reg].w[3] += src.w[3]; + + return 0; +} + +static int opPADDD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] += src.l[0]; + cpu_state.MM[cpu_reg].l[1] += src.l[1]; + + return 0; +} +static int opPADDD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] += src.l[0]; + cpu_state.MM[cpu_reg].l[1] += src.l[1]; + + return 0; +} + +static int opPADDSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] + src.sb[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] + src.sb[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] + src.sb[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(cpu_state.MM[cpu_reg].sb[3] + src.sb[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(cpu_state.MM[cpu_reg].sb[4] + src.sb[4]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(cpu_state.MM[cpu_reg].sb[5] + src.sb[5]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(cpu_state.MM[cpu_reg].sb[6] + src.sb[6]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(cpu_state.MM[cpu_reg].sb[7] + src.sb[7]); + + return 0; +} +static int opPADDSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] + src.sb[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] + src.sb[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] + src.sb[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(cpu_state.MM[cpu_reg].sb[3] + src.sb[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(cpu_state.MM[cpu_reg].sb[4] + src.sb[4]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(cpu_state.MM[cpu_reg].sb[5] + src.sb[5]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(cpu_state.MM[cpu_reg].sb[6] + src.sb[6]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(cpu_state.MM[cpu_reg].sb[7] + src.sb[7]); + + return 0; +} + +static int opPADDUSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] + src.b[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] + src.b[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] + src.b[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(cpu_state.MM[cpu_reg].b[3] + src.b[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(cpu_state.MM[cpu_reg].b[4] + src.b[4]); + cpu_state.MM[cpu_reg].b[5] = USATB(cpu_state.MM[cpu_reg].b[5] + src.b[5]); + cpu_state.MM[cpu_reg].b[6] = USATB(cpu_state.MM[cpu_reg].b[6] + src.b[6]); + cpu_state.MM[cpu_reg].b[7] = USATB(cpu_state.MM[cpu_reg].b[7] + src.b[7]); + + return 0; +} +static int opPADDUSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] + src.b[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] + src.b[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] + src.b[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(cpu_state.MM[cpu_reg].b[3] + src.b[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(cpu_state.MM[cpu_reg].b[4] + src.b[4]); + cpu_state.MM[cpu_reg].b[5] = USATB(cpu_state.MM[cpu_reg].b[5] + src.b[5]); + cpu_state.MM[cpu_reg].b[6] = USATB(cpu_state.MM[cpu_reg].b[6] + src.b[6]); + cpu_state.MM[cpu_reg].b[7] = USATB(cpu_state.MM[cpu_reg].b[7] + src.b[7]); + + return 0; +} + +static int opPADDSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] + src.sw[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] + src.sw[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] + src.sw[2]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(cpu_state.MM[cpu_reg].sw[3] + src.sw[3]); + + return 0; +} +static int opPADDSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] + src.sw[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] + src.sw[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] + src.sw[2]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(cpu_state.MM[cpu_reg].sw[3] + src.sw[3]); + + return 0; +} + +static int opPADDUSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] + src.w[0]); + cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] + src.w[1]); + cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] + src.w[2]); + cpu_state.MM[cpu_reg].w[3] = USATW(cpu_state.MM[cpu_reg].w[3] + src.w[3]); + + return 0; +} +static int opPADDUSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] + src.w[0]); + cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] + src.w[1]); + cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] + src.w[2]); + cpu_state.MM[cpu_reg].w[3] = USATW(cpu_state.MM[cpu_reg].w[3] + src.w[3]); + + return 0; +} + +static int opPMADDWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + if (cpu_state.MM[cpu_reg].l[0] == 0x80008000 && src.l[0] == 0x80008000) + cpu_state.MM[cpu_reg].l[0] = 0x80000000; + else + cpu_state.MM[cpu_reg].sl[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) + ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]); + + if (cpu_state.MM[cpu_reg].l[1] == 0x80008000 && src.l[1] == 0x80008000) + cpu_state.MM[cpu_reg].l[1] = 0x80000000; + else + cpu_state.MM[cpu_reg].sl[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]); + + return 0; +} +static int opPMADDWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + if (cpu_state.MM[cpu_reg].l[0] == 0x80008000 && src.l[0] == 0x80008000) + cpu_state.MM[cpu_reg].l[0] = 0x80000000; + else + cpu_state.MM[cpu_reg].sl[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) + ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]); + + if (cpu_state.MM[cpu_reg].l[1] == 0x80008000 && src.l[1] == 0x80008000) + cpu_state.MM[cpu_reg].l[1] = 0x80000000; + else + cpu_state.MM[cpu_reg].sl[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]); + + return 0; +} + + +static int opPMULLW_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].w[0] *= cpu_state.MM[cpu_rm].w[0]; + cpu_state.MM[cpu_reg].w[1] *= cpu_state.MM[cpu_rm].w[1]; + cpu_state.MM[cpu_reg].w[2] *= cpu_state.MM[cpu_rm].w[2]; + cpu_state.MM[cpu_reg].w[3] *= cpu_state.MM[cpu_rm].w[3]; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + SEG_CHECK_READ(cpu_state.ea_seg); + src.l[0] = readmeml(easeg, cpu_state.eaaddr); + src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].w[0] *= src.w[0]; + cpu_state.MM[cpu_reg].w[1] *= src.w[1]; + cpu_state.MM[cpu_reg].w[2] *= src.w[2]; + cpu_state.MM[cpu_reg].w[3] *= src.w[3]; + CLOCK_CYCLES(2); + } + return 0; +} +static int opPMULLW_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].w[0] *= cpu_state.MM[cpu_rm].w[0]; + cpu_state.MM[cpu_reg].w[1] *= cpu_state.MM[cpu_rm].w[1]; + cpu_state.MM[cpu_reg].w[2] *= cpu_state.MM[cpu_rm].w[2]; + cpu_state.MM[cpu_reg].w[3] *= cpu_state.MM[cpu_rm].w[3]; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + SEG_CHECK_READ(cpu_state.ea_seg); + src.l[0] = readmeml(easeg, cpu_state.eaaddr); + src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].w[0] *= src.w[0]; + cpu_state.MM[cpu_reg].w[1] *= src.w[1]; + cpu_state.MM[cpu_reg].w[2] *= src.w[2]; + cpu_state.MM[cpu_reg].w[3] *= src.w[3]; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPMULHW_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)cpu_state.MM[cpu_rm].sw[0]) >> 16; + cpu_state.MM[cpu_reg].w[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)cpu_state.MM[cpu_rm].sw[1]) >> 16; + cpu_state.MM[cpu_reg].w[2] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)cpu_state.MM[cpu_rm].sw[2]) >> 16; + cpu_state.MM[cpu_reg].w[3] = ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)cpu_state.MM[cpu_rm].sw[3]) >> 16; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + SEG_CHECK_READ(cpu_state.ea_seg); + src.l[0] = readmeml(easeg, cpu_state.eaaddr); + src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) >> 16; + cpu_state.MM[cpu_reg].w[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]) >> 16; + cpu_state.MM[cpu_reg].w[2] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) >> 16; + cpu_state.MM[cpu_reg].w[3] = ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]) >> 16; + CLOCK_CYCLES(2); + } + return 0; +} +static int opPMULHW_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)cpu_state.MM[cpu_rm].sw[0]) >> 16; + cpu_state.MM[cpu_reg].w[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)cpu_state.MM[cpu_rm].sw[1]) >> 16; + cpu_state.MM[cpu_reg].w[2] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)cpu_state.MM[cpu_rm].sw[2]) >> 16; + cpu_state.MM[cpu_reg].w[3] = ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)cpu_state.MM[cpu_rm].sw[3]) >> 16; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + SEG_CHECK_READ(cpu_state.ea_seg); + src.l[0] = readmeml(easeg, cpu_state.eaaddr); + src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) >> 16; + cpu_state.MM[cpu_reg].w[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]) >> 16; + cpu_state.MM[cpu_reg].w[2] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) >> 16; + cpu_state.MM[cpu_reg].w[3] = ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]) >> 16; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPSUBB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] -= src.b[0]; + cpu_state.MM[cpu_reg].b[1] -= src.b[1]; + cpu_state.MM[cpu_reg].b[2] -= src.b[2]; + cpu_state.MM[cpu_reg].b[3] -= src.b[3]; + cpu_state.MM[cpu_reg].b[4] -= src.b[4]; + cpu_state.MM[cpu_reg].b[5] -= src.b[5]; + cpu_state.MM[cpu_reg].b[6] -= src.b[6]; + cpu_state.MM[cpu_reg].b[7] -= src.b[7]; + + return 0; +} +static int opPSUBB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] -= src.b[0]; + cpu_state.MM[cpu_reg].b[1] -= src.b[1]; + cpu_state.MM[cpu_reg].b[2] -= src.b[2]; + cpu_state.MM[cpu_reg].b[3] -= src.b[3]; + cpu_state.MM[cpu_reg].b[4] -= src.b[4]; + cpu_state.MM[cpu_reg].b[5] -= src.b[5]; + cpu_state.MM[cpu_reg].b[6] -= src.b[6]; + cpu_state.MM[cpu_reg].b[7] -= src.b[7]; + + return 0; +} + +static int opPSUBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] -= src.w[0]; + cpu_state.MM[cpu_reg].w[1] -= src.w[1]; + cpu_state.MM[cpu_reg].w[2] -= src.w[2]; + cpu_state.MM[cpu_reg].w[3] -= src.w[3]; + + return 0; +} +static int opPSUBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] -= src.w[0]; + cpu_state.MM[cpu_reg].w[1] -= src.w[1]; + cpu_state.MM[cpu_reg].w[2] -= src.w[2]; + cpu_state.MM[cpu_reg].w[3] -= src.w[3]; + + return 0; +} + +static int opPSUBD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] -= src.l[0]; + cpu_state.MM[cpu_reg].l[1] -= src.l[1]; + + return 0; +} +static int opPSUBD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] -= src.l[0]; + cpu_state.MM[cpu_reg].l[1] -= src.l[1]; + + return 0; +} + +static int opPSUBSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] - src.sb[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] - src.sb[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] - src.sb[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(cpu_state.MM[cpu_reg].sb[3] - src.sb[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(cpu_state.MM[cpu_reg].sb[4] - src.sb[4]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(cpu_state.MM[cpu_reg].sb[5] - src.sb[5]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(cpu_state.MM[cpu_reg].sb[6] - src.sb[6]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(cpu_state.MM[cpu_reg].sb[7] - src.sb[7]); + + return 0; +} +static int opPSUBSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] - src.sb[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] - src.sb[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] - src.sb[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(cpu_state.MM[cpu_reg].sb[3] - src.sb[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(cpu_state.MM[cpu_reg].sb[4] - src.sb[4]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(cpu_state.MM[cpu_reg].sb[5] - src.sb[5]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(cpu_state.MM[cpu_reg].sb[6] - src.sb[6]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(cpu_state.MM[cpu_reg].sb[7] - src.sb[7]); + + return 0; +} + +static int opPSUBUSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] - src.b[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] - src.b[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] - src.b[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(cpu_state.MM[cpu_reg].b[3] - src.b[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(cpu_state.MM[cpu_reg].b[4] - src.b[4]); + cpu_state.MM[cpu_reg].b[5] = USATB(cpu_state.MM[cpu_reg].b[5] - src.b[5]); + cpu_state.MM[cpu_reg].b[6] = USATB(cpu_state.MM[cpu_reg].b[6] - src.b[6]); + cpu_state.MM[cpu_reg].b[7] = USATB(cpu_state.MM[cpu_reg].b[7] - src.b[7]); + + return 0; +} +static int opPSUBUSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] - src.b[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] - src.b[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] - src.b[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(cpu_state.MM[cpu_reg].b[3] - src.b[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(cpu_state.MM[cpu_reg].b[4] - src.b[4]); + cpu_state.MM[cpu_reg].b[5] = USATB(cpu_state.MM[cpu_reg].b[5] - src.b[5]); + cpu_state.MM[cpu_reg].b[6] = USATB(cpu_state.MM[cpu_reg].b[6] - src.b[6]); + cpu_state.MM[cpu_reg].b[7] = USATB(cpu_state.MM[cpu_reg].b[7] - src.b[7]); + + return 0; +} + +static int opPSUBSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] - src.sw[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] - src.sw[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] - src.sw[2]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(cpu_state.MM[cpu_reg].sw[3] - src.sw[3]); + + return 0; +} +static int opPSUBSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] - src.sw[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] - src.sw[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] - src.sw[2]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(cpu_state.MM[cpu_reg].sw[3] - src.sw[3]); + + return 0; +} + +static int opPSUBUSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] - src.w[0]); + cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] - src.w[1]); + cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] - src.w[2]); + cpu_state.MM[cpu_reg].w[3] = USATW(cpu_state.MM[cpu_reg].w[3] - src.w[3]); + + return 0; +} +static int opPSUBUSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] - src.w[0]); + cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] - src.w[1]); + cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] - src.w[2]); + cpu_state.MM[cpu_reg].w[3] = USATW(cpu_state.MM[cpu_reg].w[3] - src.w[3]); + + return 0; +} diff --git a/src/cpu_new/x86_ops_mmx_cmp.h b/src/cpu_new/x86_ops_mmx_cmp.h new file mode 100644 index 000000000..0fee95923 --- /dev/null +++ b/src/cpu_new/x86_ops_mmx_cmp.h @@ -0,0 +1,205 @@ +static int opPCMPEQB_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].b[0] == src.b[0]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].b[1] == src.b[1]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].b[2] == src.b[2]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].b[3] == src.b[3]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].b[4] == src.b[4]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].b[5] == src.b[5]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].b[6] == src.b[6]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].b[7] == src.b[7]) ? 0xff : 0; + + return 0; +} +static int opPCMPEQB_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].b[0] == src.b[0]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].b[1] == src.b[1]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].b[2] == src.b[2]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].b[3] == src.b[3]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].b[4] == src.b[4]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].b[5] == src.b[5]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].b[6] == src.b[6]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].b[7] == src.b[7]) ? 0xff : 0; + + return 0; +} + +static int opPCMPGTB_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].sb[0] > src.sb[0]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].sb[1] > src.sb[1]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].sb[2] > src.sb[2]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].sb[3] > src.sb[3]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].sb[4] > src.sb[4]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].sb[5] > src.sb[5]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].sb[6] > src.sb[6]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].sb[7] > src.sb[7]) ? 0xff : 0; + + return 0; +} +static int opPCMPGTB_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].sb[0] > src.sb[0]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].sb[1] > src.sb[1]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].sb[2] > src.sb[2]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].sb[3] > src.sb[3]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].sb[4] > src.sb[4]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].sb[5] > src.sb[5]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].sb[6] > src.sb[6]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].sb[7] > src.sb[7]) ? 0xff : 0; + + return 0; +} + +static int opPCMPEQW_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = (cpu_state.MM[cpu_reg].w[0] == src.w[0]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].w[1] == src.w[1]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].w[2] == src.w[2]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].w[3] == src.w[3]) ? 0xffff : 0; + + return 0; +} +static int opPCMPEQW_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = (cpu_state.MM[cpu_reg].w[0] == src.w[0]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].w[1] == src.w[1]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].w[2] == src.w[2]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].w[3] == src.w[3]) ? 0xffff : 0; + + return 0; +} + +static int opPCMPGTW_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = (cpu_state.MM[cpu_reg].sw[0] > src.sw[0]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].sw[1] > src.sw[1]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].sw[2] > src.sw[2]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].sw[3] > src.sw[3]) ? 0xffff : 0; + + return 0; +} +static int opPCMPGTW_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = (cpu_state.MM[cpu_reg].sw[0] > src.sw[0]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].sw[1] > src.sw[1]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].sw[2] > src.sw[2]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].sw[3] > src.sw[3]) ? 0xffff : 0; + + return 0; +} + +static int opPCMPEQD_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].l[0] == src.l[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].l[1] == src.l[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPCMPEQD_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].l[0] == src.l[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].l[1] == src.l[1]) ? 0xffffffff : 0; + + return 0; +} + +static int opPCMPGTD_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPCMPGTD_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; + + return 0; +} diff --git a/src/cpu_new/x86_ops_mmx_logic.h b/src/cpu_new/x86_ops_mmx_logic.h new file mode 100644 index 000000000..be5132e85 --- /dev/null +++ b/src/cpu_new/x86_ops_mmx_logic.h @@ -0,0 +1,91 @@ +static int opPAND_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q &= src.q; + return 0; +} +static int opPAND_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q &= src.q; + return 0; +} + +static int opPANDN_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q = ~cpu_state.MM[cpu_reg].q & src.q; + return 0; +} +static int opPANDN_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q = ~cpu_state.MM[cpu_reg].q & src.q; + return 0; +} + +static int opPOR_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q |= src.q; + return 0; +} +static int opPOR_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q |= src.q; + return 0; +} + +static int opPXOR_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q ^= src.q; + return 0; +} +static int opPXOR_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q ^= src.q; + return 0; +} diff --git a/src/cpu_new/x86_ops_mmx_mov.h b/src/cpu_new/x86_ops_mmx_mov.h new file mode 100644 index 000000000..f598d5b24 --- /dev/null +++ b/src/cpu_new/x86_ops_mmx_mov.h @@ -0,0 +1,169 @@ +static int opMOVD_l_mm_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].l[0] = cpu_state.regs[cpu_rm].l; + cpu_state.MM[cpu_reg].l[1] = 0; + CLOCK_CYCLES(1); + } + else + { + uint32_t dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + dst = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; + cpu_state.MM[cpu_reg].l[0] = dst; + cpu_state.MM[cpu_reg].l[1] = 0; + + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVD_l_mm_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].l[0] = cpu_state.regs[cpu_rm].l; + cpu_state.MM[cpu_reg].l[1] = 0; + CLOCK_CYCLES(1); + } + else + { + uint32_t dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + dst = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; + cpu_state.MM[cpu_reg].l[0] = dst; + cpu_state.MM[cpu_reg].l[1] = 0; + + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVD_mm_l_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.MM[cpu_reg].l[0]; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVD_mm_l_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.MM[cpu_reg].l[0]; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVQ_q_mm_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].q = cpu_state.MM[cpu_rm].q; + CLOCK_CYCLES(1); + } + else + { + uint64_t dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + dst = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; + cpu_state.MM[cpu_reg].q = dst; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVQ_q_mm_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].q = cpu_state.MM[cpu_rm].q; + CLOCK_CYCLES(1); + } + else + { + uint64_t dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + dst = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; + cpu_state.MM[cpu_reg].q = dst; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVQ_mm_q_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_rm].q = cpu_state.MM[cpu_reg].q; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); + writememq(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].q); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVQ_mm_q_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_rm].q = cpu_state.MM[cpu_reg].q; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); + writememq(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].q); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} diff --git a/src/cpu_new/x86_ops_mmx_pack.h b/src/cpu_new/x86_ops_mmx_pack.h new file mode 100644 index 000000000..b03ef842e --- /dev/null +++ b/src/cpu_new/x86_ops_mmx_pack.h @@ -0,0 +1,326 @@ +static int opPUNPCKLDQ_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].l[1] = cpu_state.MM[cpu_rm].l[0]; + CLOCK_CYCLES(1); + } + else + { + uint32_t src; + + SEG_CHECK_READ(cpu_state.ea_seg); + src = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].l[1] = src; + + CLOCK_CYCLES(2); + } + return 0; +} +static int opPUNPCKLDQ_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].l[1] = cpu_state.MM[cpu_rm].l[0]; + CLOCK_CYCLES(1); + } + else + { + uint32_t src; + + SEG_CHECK_READ(cpu_state.ea_seg); + src = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].l[1] = src; + + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPUNPCKHDQ_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = cpu_state.MM[cpu_reg].l[1]; + cpu_state.MM[cpu_reg].l[1] = src.l[1]; + + return 0; +} +static int opPUNPCKHDQ_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = cpu_state.MM[cpu_reg].l[1]; + cpu_state.MM[cpu_reg].l[1] = src.l[1]; + + return 0; +} + +static int opPUNPCKLBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[7] = src.b[3]; + cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[3]; + cpu_state.MM[cpu_reg].b[5] = src.b[2]; + cpu_state.MM[cpu_reg].b[4] = cpu_state.MM[cpu_reg].b[2]; + cpu_state.MM[cpu_reg].b[3] = src.b[1]; + cpu_state.MM[cpu_reg].b[2] = cpu_state.MM[cpu_reg].b[1]; + cpu_state.MM[cpu_reg].b[1] = src.b[0]; + cpu_state.MM[cpu_reg].b[0] = cpu_state.MM[cpu_reg].b[0]; + + return 0; +} +static int opPUNPCKLBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[7] = src.b[3]; + cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[3]; + cpu_state.MM[cpu_reg].b[5] = src.b[2]; + cpu_state.MM[cpu_reg].b[4] = cpu_state.MM[cpu_reg].b[2]; + cpu_state.MM[cpu_reg].b[3] = src.b[1]; + cpu_state.MM[cpu_reg].b[2] = cpu_state.MM[cpu_reg].b[1]; + cpu_state.MM[cpu_reg].b[1] = src.b[0]; + cpu_state.MM[cpu_reg].b[0] = cpu_state.MM[cpu_reg].b[0]; + + return 0; +} + +static int opPUNPCKHBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = cpu_state.MM[cpu_reg].b[4]; + cpu_state.MM[cpu_reg].b[1] = src.b[4]; + cpu_state.MM[cpu_reg].b[2] = cpu_state.MM[cpu_reg].b[5]; + cpu_state.MM[cpu_reg].b[3] = src.b[5]; + cpu_state.MM[cpu_reg].b[4] = cpu_state.MM[cpu_reg].b[6]; + cpu_state.MM[cpu_reg].b[5] = src.b[6]; + cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[7]; + cpu_state.MM[cpu_reg].b[7] = src.b[7]; + + return 0; +} +static int opPUNPCKHBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = cpu_state.MM[cpu_reg].b[4]; + cpu_state.MM[cpu_reg].b[1] = src.b[4]; + cpu_state.MM[cpu_reg].b[2] = cpu_state.MM[cpu_reg].b[5]; + cpu_state.MM[cpu_reg].b[3] = src.b[5]; + cpu_state.MM[cpu_reg].b[4] = cpu_state.MM[cpu_reg].b[6]; + cpu_state.MM[cpu_reg].b[5] = src.b[6]; + cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[7]; + cpu_state.MM[cpu_reg].b[7] = src.b[7]; + + return 0; +} + +static int opPUNPCKLWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[3] = src.w[1]; + cpu_state.MM[cpu_reg].w[2] = cpu_state.MM[cpu_reg].w[1]; + cpu_state.MM[cpu_reg].w[1] = src.w[0]; + cpu_state.MM[cpu_reg].w[0] = cpu_state.MM[cpu_reg].w[0]; + + return 0; +} +static int opPUNPCKLWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[3] = src.w[1]; + cpu_state.MM[cpu_reg].w[2] = cpu_state.MM[cpu_reg].w[1]; + cpu_state.MM[cpu_reg].w[1] = src.w[0]; + cpu_state.MM[cpu_reg].w[0] = cpu_state.MM[cpu_reg].w[0]; + + return 0; +} + +static int opPUNPCKHWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = cpu_state.MM[cpu_reg].w[2]; + cpu_state.MM[cpu_reg].w[1] = src.w[2]; + cpu_state.MM[cpu_reg].w[2] = cpu_state.MM[cpu_reg].w[3]; + cpu_state.MM[cpu_reg].w[3] = src.w[3]; + + return 0; +} +static int opPUNPCKHWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = cpu_state.MM[cpu_reg].w[2]; + cpu_state.MM[cpu_reg].w[1] = src.w[2]; + cpu_state.MM[cpu_reg].w[2] = cpu_state.MM[cpu_reg].w[3]; + cpu_state.MM[cpu_reg].w[3] = src.w[3]; + + return 0; +} + +static int opPACKSSWB_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].sb[0] = SSATB(dst.sw[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(dst.sw[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(dst.sw[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(dst.sw[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(src.sw[0]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(src.sw[1]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(src.sw[2]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(src.sw[3]); + + return 0; +} +static int opPACKSSWB_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].sb[0] = SSATB(dst.sw[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(dst.sw[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(dst.sw[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(dst.sw[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(src.sw[0]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(src.sw[1]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(src.sw[2]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(src.sw[3]); + + return 0; +} + +static int opPACKUSWB_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].b[0] = USATB(dst.sw[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(dst.sw[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(dst.sw[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(dst.sw[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(src.sw[0]); + cpu_state.MM[cpu_reg].b[5] = USATB(src.sw[1]); + cpu_state.MM[cpu_reg].b[6] = USATB(src.sw[2]); + cpu_state.MM[cpu_reg].b[7] = USATB(src.sw[3]); + + return 0; +} +static int opPACKUSWB_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].b[0] = USATB(dst.sw[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(dst.sw[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(dst.sw[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(dst.sw[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(src.sw[0]); + cpu_state.MM[cpu_reg].b[5] = USATB(src.sw[1]); + cpu_state.MM[cpu_reg].b[6] = USATB(src.sw[2]); + cpu_state.MM[cpu_reg].b[7] = USATB(src.sw[3]); + + return 0; +} + +static int opPACKSSDW_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].sw[0] = SSATW(dst.sl[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(dst.sl[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(src.sl[0]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(src.sl[1]); + + return 0; +} +static int opPACKSSDW_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].sw[0] = SSATW(dst.sl[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(dst.sl[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(src.sl[0]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(src.sl[1]); + + return 0; +} diff --git a/src/cpu_new/x86_ops_mmx_shift.h b/src/cpu_new/x86_ops_mmx_shift.h new file mode 100644 index 000000000..a0a4d90c1 --- /dev/null +++ b/src/cpu_new/x86_ops_mmx_shift.h @@ -0,0 +1,450 @@ +#define MMX_GETSHIFT() \ + if (cpu_mod == 3) \ + { \ + shift = cpu_state.MM[cpu_rm].b[0]; \ + CLOCK_CYCLES(1); \ + } \ + else \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + shift = readmemb(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; \ + CLOCK_CYCLES(2); \ + } + +static int opPSxxW_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLW*/ + if (shift > 15) + cpu_state.MM[reg].q = 0; + else + { + cpu_state.MM[reg].w[0] >>= shift; + cpu_state.MM[reg].w[1] >>= shift; + cpu_state.MM[reg].w[2] >>= shift; + cpu_state.MM[reg].w[3] >>= shift; + } + break; + case 0x20: /*PSRAW*/ + if (shift > 15) + shift = 15; + cpu_state.MM[reg].sw[0] >>= shift; + cpu_state.MM[reg].sw[1] >>= shift; + cpu_state.MM[reg].sw[2] >>= shift; + cpu_state.MM[reg].sw[3] >>= shift; + break; + case 0x30: /*PSLLW*/ + if (shift > 15) + cpu_state.MM[reg].q = 0; + else + { + cpu_state.MM[reg].w[0] <<= shift; + cpu_state.MM[reg].w[1] <<= shift; + cpu_state.MM[reg].w[2] <<= shift; + cpu_state.MM[reg].w[3] <<= shift; + } + break; + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].w[0] <<= shift; + cpu_state.MM[cpu_reg].w[1] <<= shift; + cpu_state.MM[cpu_reg].w[2] <<= shift; + cpu_state.MM[cpu_reg].w[3] <<= shift; + } + + return 0; +} +static int opPSLLW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].w[0] <<= shift; + cpu_state.MM[cpu_reg].w[1] <<= shift; + cpu_state.MM[cpu_reg].w[2] <<= shift; + cpu_state.MM[cpu_reg].w[3] <<= shift; + } + + return 0; +} + +static int opPSRLW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].w[0] >>= shift; + cpu_state.MM[cpu_reg].w[1] >>= shift; + cpu_state.MM[cpu_reg].w[2] >>= shift; + cpu_state.MM[cpu_reg].w[3] >>= shift; + } + + return 0; +} +static int opPSRLW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].w[0] >>= shift; + cpu_state.MM[cpu_reg].w[1] >>= shift; + cpu_state.MM[cpu_reg].w[2] >>= shift; + cpu_state.MM[cpu_reg].w[3] >>= shift; + } + + return 0; +} + +static int opPSRAW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + shift = 15; + + cpu_state.MM[cpu_reg].sw[0] >>= shift; + cpu_state.MM[cpu_reg].sw[1] >>= shift; + cpu_state.MM[cpu_reg].sw[2] >>= shift; + cpu_state.MM[cpu_reg].sw[3] >>= shift; + + return 0; +} +static int opPSRAW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + shift = 15; + + cpu_state.MM[cpu_reg].sw[0] >>= shift; + cpu_state.MM[cpu_reg].sw[1] >>= shift; + cpu_state.MM[cpu_reg].sw[2] >>= shift; + cpu_state.MM[cpu_reg].sw[3] >>= shift; + + return 0; +} + +static int opPSxxD_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLD*/ + if (shift > 31) + cpu_state.MM[reg].q = 0; + else + { + cpu_state.MM[reg].l[0] >>= shift; + cpu_state.MM[reg].l[1] >>= shift; + } + break; + case 0x20: /*PSRAD*/ + if (shift > 31) + shift = 31; + cpu_state.MM[reg].sl[0] >>= shift; + cpu_state.MM[reg].sl[1] >>= shift; + break; + case 0x30: /*PSLLD*/ + if (shift > 31) + cpu_state.MM[reg].q = 0; + else + { + cpu_state.MM[reg].l[0] <<= shift; + cpu_state.MM[reg].l[1] <<= shift; + } + break; + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].l[0] <<= shift; + cpu_state.MM[cpu_reg].l[1] <<= shift; + } + + return 0; +} +static int opPSLLD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].l[0] <<= shift; + cpu_state.MM[cpu_reg].l[1] <<= shift; + } + + return 0; +} + +static int opPSRLD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].l[0] >>= shift; + cpu_state.MM[cpu_reg].l[1] >>= shift; + } + + return 0; +} +static int opPSRLD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].l[0] >>= shift; + cpu_state.MM[cpu_reg].l[1] >>= shift; + } + + return 0; +} + +static int opPSRAD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + shift = 31; + + cpu_state.MM[cpu_reg].sl[0] >>= shift; + cpu_state.MM[cpu_reg].sl[1] >>= shift; + + return 0; +} +static int opPSRAD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + shift = 31; + + cpu_state.MM[cpu_reg].sl[0] >>= shift; + cpu_state.MM[cpu_reg].sl[1] >>= shift; + + return 0; +} + +static int opPSxxQ_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLW*/ + if (shift > 63) + cpu_state.MM[reg].q = 0; + else + cpu_state.MM[reg].q >>= shift; + break; + case 0x20: /*PSRAW*/ + if (shift > 63) + shift = 63; + cpu_state.MM[reg].sq >>= shift; + break; + case 0x30: /*PSLLW*/ + if (shift > 63) + cpu_state.MM[reg].q = 0; + else + cpu_state.MM[reg].q <<= shift; + break; + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLQ_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + cpu_state.MM[cpu_reg].q = 0; + else + cpu_state.MM[cpu_reg].q <<= shift; + + return 0; +} +static int opPSLLQ_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + cpu_state.MM[cpu_reg].q = 0; + else + cpu_state.MM[cpu_reg].q <<= shift; + + return 0; +} + +static int opPSRLQ_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + cpu_state.MM[cpu_reg].q = 0; + else + cpu_state.MM[cpu_reg].q >>= shift; + + return 0; +} +static int opPSRLQ_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + cpu_state.MM[cpu_reg].q = 0; + else + cpu_state.MM[cpu_reg].q >>= shift; + + return 0; +} diff --git a/src/cpu_new/x86_ops_mov.h b/src/cpu_new/x86_ops_mov.h new file mode 100644 index 000000000..ca123607c --- /dev/null +++ b/src/cpu_new/x86_ops_mov.h @@ -0,0 +1,796 @@ +static int opMOV_AL_imm(uint32_t fetchdat) +{ + AL = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_AH_imm(uint32_t fetchdat) +{ + AH = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_BL_imm(uint32_t fetchdat) +{ + BL = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_BH_imm(uint32_t fetchdat) +{ + BH = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_CL_imm(uint32_t fetchdat) +{ + CL = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_CH_imm(uint32_t fetchdat) +{ + CH = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_DL_imm(uint32_t fetchdat) +{ + DL = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_DH_imm(uint32_t fetchdat) +{ + DH = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opMOV_AX_imm(uint32_t fetchdat) +{ + AX = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_BX_imm(uint32_t fetchdat) +{ + BX = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_CX_imm(uint32_t fetchdat) +{ + CX = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_DX_imm(uint32_t fetchdat) +{ + DX = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_SI_imm(uint32_t fetchdat) +{ + SI = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_DI_imm(uint32_t fetchdat) +{ + DI = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_BP_imm(uint32_t fetchdat) +{ + BP = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_SP_imm(uint32_t fetchdat) +{ + SP = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} + +static int opMOV_EAX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EAX = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_EBX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EBX = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_ECX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + ECX = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_EDX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EDX = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_ESI_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + ESI = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_EDI_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EDI = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_EBP_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EBP = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_ESP_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + ESP = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + +static int opMOV_b_imm_a16(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_16(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = readmemb(cs,cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + seteab(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 0); + return cpu_state.abrt; +} +static int opMOV_b_imm_a32(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_32(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = getbyte(); if (cpu_state.abrt) return 1; + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + seteab(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 1); + return cpu_state.abrt; +} + +static int opMOV_w_imm_a16(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_16(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = getword(); if (cpu_state.abrt) return 1; + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); + seteaw(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 4, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 0); + return cpu_state.abrt; +} +static int opMOV_w_imm_a32(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_32(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = getword(); if (cpu_state.abrt) return 1; + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 1); + seteaw(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 4, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 1); + return cpu_state.abrt; +} +static int opMOV_l_imm_a16(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_16(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = getlong(); if (cpu_state.abrt) return 1; + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + seteal(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 6, rmdat, 0,0,0,(cpu_mod == 3) ? 1:0, 0); + return cpu_state.abrt; +} +static int opMOV_l_imm_a32(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_32(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = getlong(); if (cpu_state.abrt) return 1; + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + seteal(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 6, rmdat, 0,0,0,(cpu_mod == 3) ? 1:0, 1); + return cpu_state.abrt; +} + + +static int opMOV_AL_a16(uint32_t fetchdat) +{ + uint8_t temp; + uint16_t addr = getwordf(); + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr); + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + AL = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 3, -1, 1,0,0,0, 0); + return 0; +} +static int opMOV_AL_a32(uint32_t fetchdat) +{ + uint8_t temp; + uint32_t addr = getlong(); + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr); + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + AL = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 5, -1, 1,0,0,0, 1); + return 0; +} +static int opMOV_AX_a16(uint32_t fetchdat) +{ + uint16_t temp; + uint16_t addr = getwordf(); + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr+1); + temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + AX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 3, -1, 1,0,0,0, 0); + return 0; +} +static int opMOV_AX_a32(uint32_t fetchdat) +{ + uint16_t temp; + uint32_t addr = getlong(); + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr+1); + temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + AX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 5, -1, 1,0,0,0, 1); + return 0; +} +static int opMOV_EAX_a16(uint32_t fetchdat) +{ + uint32_t temp; + uint16_t addr = getwordf(); + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr+3); + temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + EAX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 3, -1, 0,1,0,0, 0); + return 0; +} +static int opMOV_EAX_a32(uint32_t fetchdat) +{ + uint32_t temp; + uint32_t addr = getlong(); + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr+3); + temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + EAX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 5, -1, 0,1,0,0, 1); + return 0; +} + +static int opMOV_a16_AL(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, addr, addr); + writememb(cpu_state.ea_seg->base, addr, AL); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opMOV_a32_AL(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, addr, addr); + writememb(cpu_state.ea_seg->base, addr, AL); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 5, -1, 0,0,1,0, 1); + return cpu_state.abrt; +} +static int opMOV_a16_AX(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, addr, addr + 1); + writememw(cpu_state.ea_seg->base, addr, AX); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opMOV_a32_AX(uint32_t fetchdat) +{ + uint32_t addr = getlong(); if (cpu_state.abrt) return 1; + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, addr, addr + 1); + writememw(cpu_state.ea_seg->base, addr, AX); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 5, -1, 0,0,1,0, 1); + return cpu_state.abrt; +} +static int opMOV_a16_EAX(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, addr, addr + 3); + writememl(cpu_state.ea_seg->base, addr, EAX); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 3, -1, 0,0,0,1, 0); + return cpu_state.abrt; +} +static int opMOV_a32_EAX(uint32_t fetchdat) +{ + uint32_t addr = getlong(); if (cpu_state.abrt) return 1; + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, addr, addr + 3); + writememl(cpu_state.ea_seg->base, addr, EAX); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 5, -1, 0,0,0,1, 1); + return cpu_state.abrt; +} + + +static int opLEA_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opLEA_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opLEA_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].l = cpu_state.eaaddr & 0xffff; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opLEA_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + cpu_state.regs[cpu_reg].l = cpu_state.eaaddr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + return 0; +} + + + +static int opXLAT_a16(uint32_t fetchdat) +{ + uint32_t addr = (BX + AL)&0xFFFF; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + AL = temp; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opXLAT_a32(uint32_t fetchdat) +{ + uint32_t addr = EBX + AL; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + AL = temp; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); + return 0; +} + +static int opMOV_b_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + setr8(cpu_rm, getr8(cpu_reg)); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + seteab(getr8(cpu_reg)); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 0); + } + return cpu_state.abrt; +} +static int opMOV_b_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + setr8(cpu_rm, getr8(cpu_reg)); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + seteab(getr8(cpu_reg)); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 1); + } + return cpu_state.abrt; +} +static int opMOV_w_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].w = cpu_state.regs[cpu_reg].w; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); + seteaw(cpu_state.regs[cpu_reg].w); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 0); + } + return cpu_state.abrt; +} +static int opMOV_w_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].w = cpu_state.regs[cpu_reg].w; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); + seteaw(cpu_state.regs[cpu_reg].w); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 1); + } + return cpu_state.abrt; +} +static int opMOV_l_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.regs[cpu_reg].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); + seteal(cpu_state.regs[cpu_reg].l); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,0,1, 0); + } + return cpu_state.abrt; +} +static int opMOV_l_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.regs[cpu_reg].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); + seteal(cpu_state.regs[cpu_reg].l); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,0,1, 1); + } + return cpu_state.abrt; +} + +static int opMOV_r_b_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + setr8(cpu_reg, getr8(cpu_rm)); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + uint8_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + temp = geteab(); if (cpu_state.abrt) return 1; + setr8(cpu_reg, temp); + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 1,0,0,0, 0); + } + return 0; +} +static int opMOV_r_b_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + setr8(cpu_reg, getr8(cpu_rm)); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + uint8_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + temp = geteab(); if (cpu_state.abrt) return 1; + setr8(cpu_reg, temp); + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 1,0,0,0, 1); + } + return 0; +} +static int opMOV_r_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_reg].w = cpu_state.regs[cpu_rm].w; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + uint16_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 1,0,0,0, 0); + } + return 0; +} +static int opMOV_r_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_reg].w = cpu_state.regs[cpu_rm].w; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + uint16_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 1,0,0,0, 1); + } + return 0; +} +static int opMOV_r_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_reg].l = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + uint32_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); + temp = geteal(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 0,1,0,0, 0); + } + return 0; +} +static int opMOV_r_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_reg].l = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + uint32_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); + temp = geteal(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 0,1,0,0, 1); + } + return 0; +} + +#define opCMOV(condition) \ + static int opCMOV ## condition ## _w_a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (cpu_mod == 3) \ + cpu_state.regs[cpu_reg].w = cpu_state.regs[cpu_rm].w; \ + else \ + { \ + uint16_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); \ + temp = geteaw(); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].w = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _w_a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (cpu_mod == 3) \ + cpu_state.regs[cpu_reg].w = cpu_state.regs[cpu_rm].w; \ + else \ + { \ + uint16_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); \ + temp = geteaw(); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].w = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _l_a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (cpu_mod == 3) \ + cpu_state.regs[cpu_reg].l = cpu_state.regs[cpu_rm].l; \ + else \ + { \ + uint32_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); \ + temp = geteal(); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].l = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _l_a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (cpu_mod == 3) \ + cpu_state.regs[cpu_reg].l = cpu_state.regs[cpu_rm].l; \ + else \ + { \ + uint32_t temp; \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + temp = geteal(); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].l = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } + +opCMOV(O) +opCMOV(NO) +opCMOV(B) +opCMOV(NB) +opCMOV(E) +opCMOV(NE) +opCMOV(BE) +opCMOV(NBE) +opCMOV(S) +opCMOV(NS) +opCMOV(P) +opCMOV(NP) +opCMOV(L) +opCMOV(NL) +opCMOV(LE) +opCMOV(NLE) diff --git a/src/cpu_new/x86_ops_mov_ctrl.h b/src/cpu_new/x86_ops_mov_ctrl.h new file mode 100644 index 000000000..55326dfe1 --- /dev/null +++ b/src/cpu_new/x86_ops_mov_ctrl.h @@ -0,0 +1,288 @@ +static int opMOV_r_CRx_a16(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + switch (cpu_reg) + { + case 0: + cpu_state.regs[cpu_rm].l = cr0; + if (is486) + cpu_state.regs[cpu_rm].l |= 0x10; /*ET hardwired on 486*/ + break; + case 2: + cpu_state.regs[cpu_rm].l = cr2; + break; + case 3: + cpu_state.regs[cpu_rm].l = cr3; + break; + case 4: + if (cpu_has_feature(CPU_FEATURE_CR4)) + { + cpu_state.regs[cpu_rm].l = cr4; + break; + } + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_r_CRx_a32(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + switch (cpu_reg) + { + case 0: + cpu_state.regs[cpu_rm].l = cr0; + if (is486) + cpu_state.regs[cpu_rm].l |= 0x10; /*ET hardwired on 486*/ + break; + case 2: + cpu_state.regs[cpu_rm].l = cr2; + break; + case 3: + cpu_state.regs[cpu_rm].l = cr3; + break; + case 4: + if (cpu_has_feature(CPU_FEATURE_CR4)) + { + cpu_state.regs[cpu_rm].l = cr4; + break; + } + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_r_DRx_a16(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + cpu_state.regs[cpu_rm].l = dr[cpu_reg]; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_r_DRx_a32(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + cpu_state.regs[cpu_rm].l = dr[cpu_reg]; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_CRx_r_a16(uint32_t fetchdat) +{ + uint32_t old_cr0 = cr0; + + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + fetch_ea_16(fetchdat); + switch (cpu_reg) + { + case 0: + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) + flushmmucache(); + cr0 = cpu_state.regs[cpu_rm].l; + if (cpu_16bitbus) + cr0 |= 0x10; + if (!(cr0 & 0x80000000)) + mmu_perm=4; + if (is486 && !(cr0 & (1 << 30))) + cpu_cache_int_enabled = 1; + else + cpu_cache_int_enabled = 0; + if (is486 && ((cr0 ^ old_cr0) & (1 << 30))) + cpu_update_waitstates(); + if (cr0 & 1) + cpu_cur_status |= CPU_STATUS_PMODE; + else + cpu_cur_status &= ~CPU_STATUS_PMODE; + break; + case 2: + cr2 = cpu_state.regs[cpu_rm].l; + break; + case 3: + cr3 = cpu_state.regs[cpu_rm].l; + flushmmucache(); + break; + case 4: + if (cpu_has_feature(CPU_FEATURE_CR4)) + { + cr4 = cpu_state.regs[cpu_rm].l & cpu_CR4_mask; + break; + } + + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_CRx_r_a32(uint32_t fetchdat) +{ + uint32_t old_cr0 = cr0; + + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + fetch_ea_32(fetchdat); + switch (cpu_reg) + { + case 0: + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) + flushmmucache(); + cr0 = cpu_state.regs[cpu_rm].l; + if (cpu_16bitbus) + cr0 |= 0x10; + if (!(cr0 & 0x80000000)) + mmu_perm=4; + if (is486 && !(cr0 & (1 << 30))) + cpu_cache_int_enabled = 1; + else + cpu_cache_int_enabled = 0; + if (is486 && ((cr0 ^ old_cr0) & (1 << 30))) + cpu_update_waitstates(); + if (cr0 & 1) + cpu_cur_status |= CPU_STATUS_PMODE; + else + cpu_cur_status &= ~CPU_STATUS_PMODE; + break; + case 2: + cr2 = cpu_state.regs[cpu_rm].l; + break; + case 3: + cr3 = cpu_state.regs[cpu_rm].l; + flushmmucache(); + break; + case 4: + if (cpu_has_feature(CPU_FEATURE_CR4)) + { + cr4 = cpu_state.regs[cpu_rm].l & cpu_CR4_mask; + break; + } + + default: + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_DRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + dr[cpu_reg] = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_DRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + dr[cpu_reg] = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_r_TRx_a16(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + cpu_state.regs[cpu_rm].l = 0; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_r_TRx_a32(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + cpu_state.regs[cpu_rm].l = 0; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_TRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_TRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + diff --git a/src/cpu_new/x86_ops_mov_seg.h b/src/cpu_new/x86_ops_mov_seg.h new file mode 100644 index 000000000..da7727143 --- /dev/null +++ b/src/cpu_new/x86_ops_mov_seg.h @@ -0,0 +1,434 @@ +static int opMOV_w_seg_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + seteaw(DS); + break; + case 0x10: /*SS*/ + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return cpu_state.abrt; +} +static int opMOV_w_seg_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + seteaw(DS); + break; + case 0x10: /*SS*/ + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return cpu_state.abrt; +} + +static int opMOV_l_seg_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = GS; + else seteaw(GS); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return cpu_state.abrt; +} +static int opMOV_l_seg_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = GS; + else seteaw(GS); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return cpu_state.abrt; +} + +static int opMOV_seg_w_a16(uint32_t fetchdat) +{ + uint16_t new_seg; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_seg=geteaw(); if (cpu_state.abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + loadseg(new_seg, &cpu_state.seg_es); + break; + case 0x18: /*DS*/ + loadseg(new_seg, &cpu_state.seg_ds); + break; + case 0x10: /*SS*/ + loadseg(new_seg, &cpu_state.seg_ss); + if (cpu_state.abrt) return 1; + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + cpu_state.ssegs = 0; + cpu_state.ea_seg = &cpu_state.seg_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (cpu_state.abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return 1; + case 0x20: /*FS*/ + loadseg(new_seg, &cpu_state.seg_fs); + break; + case 0x28: /*GS*/ + loadseg(new_seg, &cpu_state.seg_gs); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return cpu_state.abrt; +} +static int opMOV_seg_w_a32(uint32_t fetchdat) +{ + uint16_t new_seg; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + new_seg=geteaw(); if (cpu_state.abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + loadseg(new_seg, &cpu_state.seg_es); + break; + case 0x18: /*DS*/ + loadseg(new_seg, &cpu_state.seg_ds); + break; + case 0x10: /*SS*/ + loadseg(new_seg, &cpu_state.seg_ss); + if (cpu_state.abrt) return 1; + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + cpu_state.ssegs = 0; + cpu_state.ea_seg = &cpu_state.seg_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (cpu_state.abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return 1; + case 0x20: /*FS*/ + loadseg(new_seg, &cpu_state.seg_fs); + break; + case 0x28: /*GS*/ + loadseg(new_seg, &cpu_state.seg_gs); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return cpu_state.abrt; +} + + +static int opLDS_w_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); + addr = readmemw(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); + return 0; +} +static int opLDS_w_a32(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); + addr = readmemw(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); + return 0; +} +static int opLDS_l_a16(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); + addr = readmeml(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 0); + return 0; +} +static int opLDS_l_a32(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); + addr = readmeml(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 1); + return 0; +} + +static int opLSS_w_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); + addr = readmemw(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); + return 1; +} +static int opLSS_w_a32(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); + addr = readmemw(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); + return 1; +} +static int opLSS_l_a16(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); + addr = readmeml(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); + return 1; +} +static int opLSS_l_a32(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); + addr = readmeml(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); + return 1; +} + +#define opLsel(name, sel) \ + static int opL ## name ## _w_a16(uint32_t fetchdat) \ + { \ + uint16_t addr, seg; \ + \ + fetch_ea_16(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + ILLEGAL_ON(cpu_mod == 3); \ + addr = readmemw(easeg, cpu_state.eaaddr); \ + seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; \ + loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].w = addr; \ + \ + CLOCK_CYCLES(7); \ + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); \ + return 0; \ + } \ + \ + static int opL ## name ## _w_a32(uint32_t fetchdat) \ + { \ + uint16_t addr, seg; \ + \ + fetch_ea_32(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + ILLEGAL_ON(cpu_mod == 3); \ + addr = readmemw(easeg, cpu_state.eaaddr); \ + seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; \ + loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].w = addr; \ + \ + CLOCK_CYCLES(7); \ + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); \ + return 0; \ + } \ + \ + static int opL ## name ## _l_a16(uint32_t fetchdat) \ + { \ + uint32_t addr; \ + uint16_t seg; \ + \ + fetch_ea_16(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + ILLEGAL_ON(cpu_mod == 3); \ + addr = readmeml(easeg, cpu_state.eaaddr); \ + seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; \ + loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].l = addr; \ + \ + CLOCK_CYCLES(7); \ + PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 0); \ + return 0; \ + } \ + \ + static int opL ## name ## _l_a32(uint32_t fetchdat) \ + { \ + uint32_t addr; \ + uint16_t seg; \ + \ + fetch_ea_32(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + ILLEGAL_ON(cpu_mod == 3); \ + addr = readmeml(easeg, cpu_state.eaaddr); \ + seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; \ + loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].l = addr; \ + \ + CLOCK_CYCLES(7); \ + PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 1); \ + return 0; \ + } + +opLsel(ES, cpu_state.seg_es) +opLsel(FS, cpu_state.seg_fs) +opLsel(GS, cpu_state.seg_gs) diff --git a/src/cpu_new/x86_ops_movx.h b/src/cpu_new/x86_ops_movx.h new file mode 100644 index 000000000..2e4fa2001 --- /dev/null +++ b/src/cpu_new/x86_ops_movx.h @@ -0,0 +1,209 @@ +static int opMOVZX_w_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = (uint16_t)temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVZX_w_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = (uint16_t)temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opMOVZX_l_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVZX_l_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opMOVZX_w_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVZX_w_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opMOVZX_l_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVZX_l_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} + +static int opMOVSX_w_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = (uint16_t)temp; + if (temp & 0x80) + cpu_state.regs[cpu_reg].w |= 0xff00; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVSX_w_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = (uint16_t)temp; + if (temp & 0x80) + cpu_state.regs[cpu_reg].w |= 0xff00; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opMOVSX_l_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + if (temp & 0x80) + cpu_state.regs[cpu_reg].l |= 0xffffff00; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVSX_l_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + if (temp & 0x80) + cpu_state.regs[cpu_reg].l |= 0xffffff00; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opMOVSX_l_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + if (temp & 0x8000) + cpu_state.regs[cpu_reg].l |= 0xffff0000; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVSX_l_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + if (temp & 0x8000) + cpu_state.regs[cpu_reg].l |= 0xffff0000; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} diff --git a/src/cpu_new/x86_ops_msr.h b/src/cpu_new/x86_ops_msr.h new file mode 100644 index 000000000..2a8bdcf4c --- /dev/null +++ b/src/cpu_new/x86_ops_msr.h @@ -0,0 +1,30 @@ +static int opRDTSC(uint32_t fetchdat) +{ + if (!cpu_has_feature(CPU_FEATURE_RDTSC)) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + if ((cr4 & CR4_TSD) && CPL) + { + x86gpf("RDTSC when TSD set and CPL != 0", 0); + return 1; + } + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + CLOCK_CYCLES(1); + return 0; +} + +static int opRDPMC(uint32_t fetchdat) +{ + if (ECX > 1 || (!(cr4 & CR4_PCE) && (cr0 & 1) && CPL)) + { + x86gpf("RDPMC not allowed", 0); + return 1; + } + EAX = EDX = 0; + CLOCK_CYCLES(1); + return 0; +} diff --git a/src/cpu_new/x86_ops_mul.h b/src/cpu_new/x86_ops_mul.h new file mode 100644 index 000000000..f3e10e5a0 --- /dev/null +++ b/src/cpu_new/x86_ops_mul.h @@ -0,0 +1,264 @@ +static int opIMUL_w_iw_a16(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + + tempw = geteaw(); if (cpu_state.abrt) return 1; + tempw2 = getword(); if (cpu_state.abrt) return 1; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].w = templ & 0xffff; + + CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); + PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 4, rmdat, 1,0,0,0, 0); + return 0; +} +static int opIMUL_w_iw_a32(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + + tempw = geteaw(); if (cpu_state.abrt) return 1; + tempw2 = getword(); if (cpu_state.abrt) return 1; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].w = templ & 0xffff; + + CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); + PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 4, rmdat, 1,0,0,0, 1); + return 0; +} + +static int opIMUL_l_il_a16(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + + templ = geteal(); if (cpu_state.abrt) return 1; + templ2 = getlong(); if (cpu_state.abrt) return 1; + + temp64 = ((int64_t)templ) * ((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(25); + PREFETCH_RUN(25, 6, rmdat, 0,1,0,0, 0); + return 0; +} +static int opIMUL_l_il_a32(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + + templ = geteal(); if (cpu_state.abrt) return 1; + templ2 = getlong(); if (cpu_state.abrt) return 1; + + temp64 = ((int64_t)templ) * ((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(25); + PREFETCH_RUN(25, 6, rmdat, 0,1,0,0, 1); + return 0; +} + +static int opIMUL_w_ib_a16(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + + tempw = geteaw(); if (cpu_state.abrt) return 1; + tempw2 = getbyte(); if (cpu_state.abrt) return 1; + if (tempw2 & 0x80) tempw2 |= 0xff00; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].w = templ & 0xffff; + + CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); + PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 3, rmdat, 1,0,0,0, 0); + return 0; +} +static int opIMUL_w_ib_a32(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + + tempw = geteaw(); if (cpu_state.abrt) return 1; + tempw2 = getbyte(); if (cpu_state.abrt) return 1; + if (tempw2 & 0x80) tempw2 |= 0xff00; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].w = templ & 0xffff; + + CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); + PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 3, rmdat, 1,0,0,0, 1); + return 0; +} + +static int opIMUL_l_ib_a16(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + + templ = geteal(); if (cpu_state.abrt) return 1; + templ2 = getbyte(); if (cpu_state.abrt) return 1; + if (templ2 & 0x80) templ2 |= 0xffffff00; + + temp64 = ((int64_t)templ)*((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 3, rmdat, 0,1,0,0, 0); + return 0; +} +static int opIMUL_l_ib_a32(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + + templ = geteal(); if (cpu_state.abrt) return 1; + templ2 = getbyte(); if (cpu_state.abrt) return 1; + if (templ2 & 0x80) templ2 |= 0xffffff00; + + temp64 = ((int64_t)templ)*((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 3, rmdat, 0,1,0,0, 1); + return 0; +} + + + +static int opIMUL_w_w_a16(uint32_t fetchdat) +{ + int32_t templ; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + + templ = (int32_t)(int16_t)cpu_state.regs[cpu_reg].w * (int32_t)(int16_t)geteaw(); + if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = templ & 0xFFFF; + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(18); + PREFETCH_RUN(18, 2, rmdat, 1,0,0,0, 0); + return 0; +} +static int opIMUL_w_w_a32(uint32_t fetchdat) +{ + int32_t templ; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + + templ = (int32_t)(int16_t)cpu_state.regs[cpu_reg].w * (int32_t)(int16_t)geteaw(); + if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = templ & 0xFFFF; + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(18); + PREFETCH_RUN(18, 2, rmdat, 1,0,0,0, 1); + return 0; +} + +static int opIMUL_l_l_a16(uint32_t fetchdat) +{ + int64_t temp64; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + + temp64 = (int64_t)(int32_t)cpu_state.regs[cpu_reg].l * (int64_t)(int32_t)geteal(); + if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = temp64 & 0xFFFFFFFF; + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(30); + PREFETCH_RUN(30, 2, rmdat, 0,1,0,0, 0); + return 0; +} +static int opIMUL_l_l_a32(uint32_t fetchdat) +{ + int64_t temp64; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + + temp64 = (int64_t)(int32_t)cpu_state.regs[cpu_reg].l * (int64_t)(int32_t)geteal(); + if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = temp64 & 0xFFFFFFFF; + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(30); + PREFETCH_RUN(30, 2, rmdat, 0,1,0,0, 1); + return 0; +} + diff --git a/src/cpu_new/x86_ops_pmode.h b/src/cpu_new/x86_ops_pmode.h new file mode 100644 index 000000000..7fe5d4938 --- /dev/null +++ b/src/cpu_new/x86_ops_pmode.h @@ -0,0 +1,456 @@ +static int opARPL_a16(uint32_t fetchdat) +{ + uint16_t temp_seg; + + NOTRM + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp_seg = geteaw(); if (cpu_state.abrt) return 1; + + flags_rebuild(); + if ((temp_seg & 3) < (cpu_state.regs[cpu_reg].w & 3)) + { + temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[cpu_reg].w & 3); + seteaw(temp_seg); if (cpu_state.abrt) return 1; + cpu_state.flags |= Z_FLAG; + } + else + cpu_state.flags &= ~Z_FLAG; + + CLOCK_CYCLES(is486 ? 9 : 20); + PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 0); + return 0; +} +static int opARPL_a32(uint32_t fetchdat) +{ + uint16_t temp_seg; + + NOTRM + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp_seg = geteaw(); if (cpu_state.abrt) return 1; + + flags_rebuild(); + if ((temp_seg & 3) < (cpu_state.regs[cpu_reg].w & 3)) + { + temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[cpu_reg].w & 3); + seteaw(temp_seg); if (cpu_state.abrt) return 1; + cpu_state.flags |= Z_FLAG; + } + else + cpu_state.flags &= ~Z_FLAG; + + CLOCK_CYCLES(is486 ? 9 : 20); + PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 1); + return 0; +} + +#define opLAR(name, fetch_ea, is32, ea32) \ + static int opLAR_ ## name(uint32_t fetchdat) \ + { \ + int valid; \ + uint16_t sel, desc = 0; \ + \ + NOTRM \ + fetch_ea(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + \ + sel = geteaw(); if (cpu_state.abrt) return 1; \ + \ + flags_rebuild(); \ + if (!(sel & 0xfffc)) { cpu_state.flags &= ~Z_FLAG; return 0; } /*Null selector*/ \ + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ + if (valid) \ + { \ + cpl_override = 1; \ + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ + cpl_override = 0; if (cpu_state.abrt) return 1; \ + } \ + cpu_state.flags &= ~Z_FLAG; \ + if ((desc & 0x1f00) == 0x000) valid = 0; \ + if ((desc & 0x1f00) == 0x800) valid = 0; \ + if ((desc & 0x1f00) == 0xa00) valid = 0; \ + if ((desc & 0x1f00) == 0xd00) valid = 0; \ + if ((desc & 0x1c00) < 0x1c00) /*Exclude conforming code segments*/ \ + { \ + int dpl = (desc >> 13) & 3; \ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; \ + } \ + if (valid) \ + { \ + cpu_state.flags |= Z_FLAG; \ + cpl_override = 1; \ + if (is32) \ + cpu_state.regs[cpu_reg].l = readmeml(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xffff00; \ + else \ + cpu_state.regs[cpu_reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xff00; \ + cpl_override = 0; \ + } \ + CLOCK_CYCLES(11); \ + PREFETCH_RUN(11, 2, rmdat, 2,0,0,0, ea32); \ + return cpu_state.abrt; \ + } + +opLAR(w_a16, fetch_ea_16, 0, 0) +opLAR(w_a32, fetch_ea_32, 0, 1) +opLAR(l_a16, fetch_ea_16, 1, 0) +opLAR(l_a32, fetch_ea_32, 1, 1) + +#define opLSL(name, fetch_ea, is32, ea32) \ + static int opLSL_ ## name(uint32_t fetchdat) \ + { \ + int valid; \ + uint16_t sel, desc = 0; \ + \ + NOTRM \ + fetch_ea(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + \ + sel = geteaw(); if (cpu_state.abrt) return 1; \ + flags_rebuild(); \ + cpu_state.flags &= ~Z_FLAG; \ + if (!(sel & 0xfffc)) return 0; /*Null selector*/ \ + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ + if (valid) \ + { \ + cpl_override = 1; \ + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ + cpl_override = 0; if (cpu_state.abrt) return 1; \ + } \ + if ((desc & 0x1400) == 0x400) valid = 0; /*Interrupt or trap or call gate*/ \ + if ((desc & 0x1f00) == 0x000) valid = 0; /*Invalid*/ \ + if ((desc & 0x1f00) == 0xa00) valid = 0; /*Invalid*/ \ + if ((desc & 0x1c00) != 0x1c00) /*Exclude conforming code segments*/ \ + { \ + int rpl = (desc >> 13) & 3; \ + if (rpl < CPL || rpl < (sel & 3)) valid = 0; \ + } \ + if (valid) \ + { \ + cpu_state.flags |= Z_FLAG; \ + cpl_override = 1; \ + if (is32) \ + { \ + cpu_state.regs[cpu_reg].l = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \ + cpu_state.regs[cpu_reg].l |= (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0xF) << 16; \ + if (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0x80) \ + { \ + cpu_state.regs[cpu_reg].l <<= 12; \ + cpu_state.regs[cpu_reg].l |= 0xFFF; \ + } \ + } \ + else \ + cpu_state.regs[cpu_reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \ + cpl_override = 0; \ + } \ + CLOCK_CYCLES(10); \ + PREFETCH_RUN(10, 2, rmdat, 4,0,0,0, ea32); \ + return cpu_state.abrt; \ + } + +opLSL(w_a16, fetch_ea_16, 0, 0) +opLSL(w_a32, fetch_ea_32, 0, 1) +opLSL(l_a16, fetch_ea_16, 1, 0) +opLSL(l_a32, fetch_ea_32, 1, 1) + + +static int op0F00_common(uint32_t fetchdat, int ea32) +{ + int dpl, valid, granularity; + uint32_t addr, base, limit; + uint16_t desc, sel; + uint8_t access; + + switch (rmdat & 0x38) + { + case 0x00: /*SLDT*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(ldt.seg); + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); + break; + case 0x08: /*STR*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(tr.seg); + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); + break; + case 0x10: /*LLDT*/ + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + sel = geteaw(); if (cpu_state.abrt) return 1; + addr = (sel & ~7) + gdt.base; + limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); + base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24); + access = readmemb(0, addr + 5); + granularity = readmemb(0, addr + 6) & 0x80; + if (cpu_state.abrt) return 1; + ldt.limit = limit; + ldt.access = access; + if (granularity) + { + ldt.limit <<= 12; + ldt.limit |= 0xfff; + } + ldt.base = base; + ldt.seg = sel; + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 0:1,2,0,0, ea32); + break; + case 0x18: /*LTR*/ + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) + { + x86gpf(NULL,0); + break; + } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + sel = geteaw(); if (cpu_state.abrt) return 1; + addr = (sel & ~7) + gdt.base; + limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); + base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24); + access = readmemb(0, addr + 5); + granularity = readmemb(0, addr + 6) & 0x80; + if (cpu_state.abrt) return 1; + access |= 2; + writememb(0, addr + 5, access); + if (cpu_state.abrt) return 1; + tr.seg = sel; + tr.limit = limit; + tr.access = access; + if (granularity) + { + tr.limit <<= 12; + tr.limit |= 0xFFF; + } + tr.base = base; + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 0:1,2,0,0, ea32); + break; + case 0x20: /*VERR*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + sel = geteaw(); if (cpu_state.abrt) return 1; + flags_rebuild(); + cpu_state.flags &= ~Z_FLAG; + if (!(sel & 0xfffc)) return 0; /*Null selector*/ + cpl_override = 1; + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); + cpl_override = 0; if (cpu_state.abrt) return 1; + if (!(desc & 0x1000)) valid = 0; + if ((desc & 0xC00) != 0xC00) /*Exclude conforming code segments*/ + { + dpl = (desc >> 13) & 3; /*Check permissions*/ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; + } + if ((desc & 0x0800) && !(desc & 0x0200)) valid = 0; /*Non-readable code*/ + if (valid) cpu_state.flags |= Z_FLAG; + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 1:2,0,0,0, ea32); + break; + case 0x28: /*VERW*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + sel = geteaw(); if (cpu_state.abrt) return 1; + flags_rebuild(); + cpu_state.flags &= ~Z_FLAG; + if (!(sel & 0xfffc)) return 0; /*Null selector*/ + cpl_override = 1; + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); + cpl_override = 0; if (cpu_state.abrt) return 1; + if (!(desc & 0x1000)) valid = 0; + dpl = (desc >> 13) & 3; /*Check permissions*/ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; + if (desc & 0x0800) valid = 0; /*Code*/ + if (!(desc & 0x0200)) valid = 0; /*Read-only data*/ + if (valid) cpu_state.flags |= Z_FLAG; + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 1:2,0,0,0, ea32); + break; + + default: + cpu_state.pc -= 3; + x86illegal(); + break; + } + return cpu_state.abrt; +} + +static int op0F00_a16(uint32_t fetchdat) +{ + NOTRM + + fetch_ea_16(fetchdat); + + return op0F00_common(fetchdat, 0); +} +static int op0F00_a32(uint32_t fetchdat) +{ + NOTRM + + fetch_ea_32(fetchdat); + + return op0F00_common(fetchdat, 1); +} + +static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) +{ + uint32_t base; + uint16_t limit, tempw; + switch (rmdat & 0x38) + { + case 0x00: /*SGDT*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(gdt.limit); + base = gdt.base; //is32 ? gdt.base : (gdt.base & 0xffffff); + if (is286) + base |= 0xff000000; + writememl(easeg, cpu_state.eaaddr + 2, base); + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 0,0,1,1, ea32); + break; + case 0x08: /*SIDT*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(idt.limit); + base = idt.base; + if (is286) + base |= 0xff000000; + writememl(easeg, cpu_state.eaaddr + 2, base); + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 0,0,1,1, ea32); + break; + case 0x10: /*LGDT*/ + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) + { + x86gpf(NULL,0); + break; + } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + limit = geteaw(); + base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + gdt.limit = limit; + gdt.base = base; + if (!is32) gdt.base &= 0xffffff; + CLOCK_CYCLES(11); + PREFETCH_RUN(11, 2, rmdat, 1,1,0,0, ea32); + break; + case 0x18: /*LIDT*/ + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) + { + x86gpf(NULL,0); + break; + } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + limit = geteaw(); + base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + idt.limit = limit; + idt.base = base; + if (!is32) idt.base &= 0xffffff; + CLOCK_CYCLES(11); + PREFETCH_RUN(11, 2, rmdat, 1,1,0,0, ea32); + break; + + case 0x20: /*SMSW*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + if (is486) seteaw(msw); + else if (is386) seteaw(msw | 0xFF00); + else seteaw(msw | 0xFFF0); + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); + break; + case 0x30: /*LMSW*/ + if ((CPL || cpu_state.eflags&VM_FLAG) && (msw&1)) + { + x86gpf(NULL, 0); + break; + } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + tempw = geteaw(); if (cpu_state.abrt) return 1; + if (msw & 1) tempw |= 1; + if (is386) + { + tempw &= ~0x10; + tempw |= (msw & 0x10); + } + else tempw &= 0xF; + msw = tempw; + if (msw & 1) + cpu_cur_status |= CPU_STATUS_PMODE; + else + cpu_cur_status &= ~CPU_STATUS_PMODE; + PREFETCH_RUN(2, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); + break; + + case 0x38: /*INVLPG*/ + if (is486) + { + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) + { + x86gpf(NULL, 0); + break; + } + SEG_CHECK_READ(cpu_state.ea_seg); + mmu_invalidate(ds + cpu_state.eaaddr); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 2, rmdat, 0,0,0,0, ea32); + break; + } + + default: + cpu_state.pc -= 3; + x86illegal(); + break; + } + return cpu_state.abrt; +} + +static int op0F01_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 0, 0, 0); +} +static int op0F01_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + return op0F01_common(fetchdat, 0, 0, 1); +} +static int op0F01_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 1, 0, 0); +} +static int op0F01_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + return op0F01_common(fetchdat, 1, 0, 1); +} + +static int op0F01_286(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 0, 1, 0); +} diff --git a/src/cpu_new/x86_ops_prefix.h b/src/cpu_new/x86_ops_prefix.h new file mode 100644 index 000000000..8d191103d --- /dev/null +++ b/src/cpu_new/x86_ops_prefix.h @@ -0,0 +1,161 @@ +#define op_seg(name, seg, opcode_table, normal_opcode_table) \ +static int op ## name ## _w_a16(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) return 1; \ + cpu_state.pc++; \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + if (opcode_table[fetchdat & 0xff]) \ + return opcode_table[fetchdat & 0xff](fetchdat >> 8); \ + return normal_opcode_table[fetchdat & 0xff](fetchdat >> 8); \ +} \ + \ +static int op ## name ## _l_a16(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) return 1; \ + cpu_state.pc++; \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + if (opcode_table[(fetchdat & 0xff) | 0x100]) \ + return opcode_table[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ +} \ + \ +static int op ## name ## _w_a32(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) return 1; \ + cpu_state.pc++; \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + if (opcode_table[(fetchdat & 0xff) | 0x200]) \ + return opcode_table[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ +} \ + \ +static int op ## name ## _l_a32(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) return 1; \ + cpu_state.pc++; \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + if (opcode_table[(fetchdat & 0xff) | 0x300]) \ + return opcode_table[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ +} + +op_seg(CS, cpu_state.seg_cs, x86_opcodes, x86_opcodes) +op_seg(DS, cpu_state.seg_ds, x86_opcodes, x86_opcodes) +op_seg(ES, cpu_state.seg_es, x86_opcodes, x86_opcodes) +op_seg(FS, cpu_state.seg_fs, x86_opcodes, x86_opcodes) +op_seg(GS, cpu_state.seg_gs, x86_opcodes, x86_opcodes) +op_seg(SS, cpu_state.seg_ss, x86_opcodes, x86_opcodes) + +op_seg(CS_REPE, cpu_state.seg_cs, x86_opcodes_REPE, x86_opcodes) +op_seg(DS_REPE, cpu_state.seg_ds, x86_opcodes_REPE, x86_opcodes) +op_seg(ES_REPE, cpu_state.seg_es, x86_opcodes_REPE, x86_opcodes) +op_seg(FS_REPE, cpu_state.seg_fs, x86_opcodes_REPE, x86_opcodes) +op_seg(GS_REPE, cpu_state.seg_gs, x86_opcodes_REPE, x86_opcodes) +op_seg(SS_REPE, cpu_state.seg_ss, x86_opcodes_REPE, x86_opcodes) + +op_seg(CS_REPNE, cpu_state.seg_cs, x86_opcodes_REPNE, x86_opcodes) +op_seg(DS_REPNE, cpu_state.seg_ds, x86_opcodes_REPNE, x86_opcodes) +op_seg(ES_REPNE, cpu_state.seg_es, x86_opcodes_REPNE, x86_opcodes) +op_seg(FS_REPNE, cpu_state.seg_fs, x86_opcodes_REPNE, x86_opcodes) +op_seg(GS_REPNE, cpu_state.seg_gs, x86_opcodes_REPNE, x86_opcodes) +op_seg(SS_REPNE, cpu_state.seg_ss, x86_opcodes_REPNE, x86_opcodes) + +static int op_66(uint32_t fetchdat) /*Data size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x100) ^ 0x100) | (cpu_state.op32 & 0x200); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int op_67(uint32_t fetchdat) /*Address size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x200) ^ 0x200) | (cpu_state.op32 & 0x100); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} + +static int op_66_REPE(uint32_t fetchdat) /*Data size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x100) ^ 0x100) | (cpu_state.op32 & 0x200); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int op_67_REPE(uint32_t fetchdat) /*Address size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x200) ^ 0x200) | (cpu_state.op32 & 0x100); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int op_66_REPNE(uint32_t fetchdat) /*Data size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x100) ^ 0x100) | (cpu_state.op32 & 0x200); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int op_67_REPNE(uint32_t fetchdat) /*Address size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x200) ^ 0x200) | (cpu_state.op32 & 0x100); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} diff --git a/src/cpu_new/x86_ops_rep.h b/src/cpu_new/x86_ops_rep.h new file mode 100644 index 000000000..efbb088ef --- /dev/null +++ b/src/cpu_new/x86_ops_rep.h @@ -0,0 +1,713 @@ +#define REP_OPS(size, CNT_REG, SRC_REG, DEST_REG) \ +static int opREP_INSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint8_t temp; \ + \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + temp = inb(DX); \ + writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ + else DEST_REG++; \ + CNT_REG--; \ + cycles -= 15; \ + reads++; writes++; total_cycles += 15; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_INSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint16_t temp; \ + \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + temp = inw(DX); \ + writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ + else DEST_REG += 2; \ + CNT_REG--; \ + cycles -= 15; \ + reads++; writes++; total_cycles += 15; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_INSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint32_t temp; \ + \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + check_io_perm(DX+2); \ + check_io_perm(DX+3); \ + CHECK_WRITE(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + temp = inl(DX); \ + writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ + else DEST_REG += 4; \ + CNT_REG--; \ + cycles -= 15; \ + reads++; writes++; total_cycles += 15; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, writes, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_OUTSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint8_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + check_io_perm(DX); \ + outb(DX, temp); \ + if (cpu_state.flags & D_FLAG) SRC_REG--; \ + else SRC_REG++; \ + CNT_REG--; \ + cycles -= 14; \ + reads++; writes++; total_cycles += 14; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_OUTSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint16_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + outw(DX, temp); \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 2; \ + else SRC_REG += 2; \ + CNT_REG--; \ + cycles -= 14; \ + reads++; writes++; total_cycles += 14; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_OUTSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint32_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + check_io_perm(DX+2); \ + check_io_perm(DX+3); \ + outl(DX, temp); \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 4; \ + else SRC_REG += 4; \ + CNT_REG--; \ + cycles -= 14; \ + reads++; writes++; total_cycles += 14; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, writes, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_MOVSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + } \ + while (CNT_REG > 0) \ + { \ + uint8_t temp; \ + \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ + else { DEST_REG++; SRC_REG++; } \ + CNT_REG--; \ + cycles -= is486 ? 3 : 4; \ + ins++; \ + reads++; writes++; total_cycles += is486 ? 3 : 4; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_MOVSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + } \ + while (CNT_REG > 0) \ + { \ + uint16_t temp; \ + \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ + else { DEST_REG += 2; SRC_REG += 2; } \ + CNT_REG--; \ + cycles -= is486 ? 3 : 4; \ + ins++; \ + reads++; writes++; total_cycles += is486 ? 3 : 4; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_MOVSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + } \ + while (CNT_REG > 0) \ + { \ + uint32_t temp; \ + \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ + else { DEST_REG += 4; SRC_REG += 4; } \ + CNT_REG--; \ + cycles -= is486 ? 3 : 4; \ + ins++; \ + reads++; writes++; total_cycles += is486 ? 3 : 4; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ + \ +static int opREP_STOSB_ ## size(uint32_t fetchdat) \ +{ \ + int writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + while (CNT_REG > 0) \ + { \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + writememb(es, DEST_REG, AL); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ + else DEST_REG++; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + writes++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_STOSW_ ## size(uint32_t fetchdat) \ +{ \ + int writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + while (CNT_REG > 0) \ + { \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + writememw(es, DEST_REG, AX); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ + else DEST_REG += 2; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + writes++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_STOSL_ ## size(uint32_t fetchdat) \ +{ \ + int writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + while (CNT_REG > 0) \ + { \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + writememl(es, DEST_REG, EAX); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ + else DEST_REG += 4; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + writes++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, 0, 0, writes, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_LODSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + while (CNT_REG > 0) \ + { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + AL = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) SRC_REG--; \ + else SRC_REG++; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + reads++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_LODSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + while (CNT_REG > 0) \ + { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + AX = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 2; \ + else SRC_REG += 2; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + reads++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_LODSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + while (CNT_REG > 0) \ + { \ + CHECK_READ_REP(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + EAX = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 4; \ + else SRC_REG += 4; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + reads++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + + +#define REP_OPS_CMPS_SCAS(size, CNT_REG, SRC_REG, DEST_REG, FV) \ +static int opREP_CMPSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint8_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG); \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + temp = readmemb(cpu_state.ea_seg->base, SRC_REG); \ + temp2 = readmemb(es, DEST_REG); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ + else { DEST_REG++; SRC_REG++; } \ + CNT_REG--; \ + cycles -= is486 ? 7 : 9; \ + reads += 2; total_cycles += is486 ? 7 : 9; \ + setsub8(temp, temp2); \ + tempz = (ZF_SET()) ? 1 : 0; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_CMPSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint16_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 1); \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + temp = readmemw(cpu_state.ea_seg->base, SRC_REG); \ + temp2 = readmemw(es, DEST_REG); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ + else { DEST_REG += 2; SRC_REG += 2; } \ + CNT_REG--; \ + cycles -= is486 ? 7 : 9; \ + reads += 2; total_cycles += is486 ? 7 : 9; \ + setsub16(temp, temp2); \ + tempz = (ZF_SET()) ? 1 : 0; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_CMPSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint32_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + CHECK_READ(cpu_state.ea_seg, SRC_REG, SRC_REG + 3); \ + CHECK_READ(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + temp = readmeml(cpu_state.ea_seg->base, SRC_REG); \ + temp2 = readmeml(es, DEST_REG); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ + else { DEST_REG += 4; SRC_REG += 4; } \ + CNT_REG--; \ + cycles -= is486 ? 7 : 9; \ + reads += 2; total_cycles += is486 ? 7 : 9; \ + setsub32(temp, temp2); \ + tempz = (ZF_SET()) ? 1 : 0; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_SCASB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + while ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + uint8_t temp = readmemb(es, DEST_REG); if (cpu_state.abrt) break;\ + setsub8(AL, temp); \ + tempz = (ZF_SET()) ? 1 : 0; \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ + else DEST_REG++; \ + CNT_REG--; \ + cycles -= is486 ? 5 : 8; \ + reads++; total_cycles += is486 ? 5 : 8; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_SCASW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + while ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 1); \ + uint16_t temp = readmemw(es, DEST_REG); if (cpu_state.abrt) break;\ + setsub16(AX, temp); \ + tempz = (ZF_SET()) ? 1 : 0; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ + else DEST_REG += 2; \ + CNT_REG--; \ + cycles -= is486 ? 5 : 8; \ + reads++; total_cycles += is486 ? 5 : 8; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_SCASL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + while ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CHECK_READ_REP(&cpu_state.seg_es, DEST_REG, DEST_REG + 3); \ + uint32_t temp = readmeml(es, DEST_REG); if (cpu_state.abrt) break;\ + setsub32(EAX, temp); \ + tempz = (ZF_SET()) ? 1 : 0; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ + else DEST_REG += 4; \ + CNT_REG--; \ + cycles -= is486 ? 5 : 8; \ + reads++; total_cycles += is486 ? 5 : 8; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} + +REP_OPS(a16, CX, SI, DI) +REP_OPS(a32, ECX, ESI, EDI) +REP_OPS_CMPS_SCAS(a16_NE, CX, SI, DI, 0) +REP_OPS_CMPS_SCAS(a16_E, CX, SI, DI, 1) +REP_OPS_CMPS_SCAS(a32_NE, ECX, ESI, EDI, 0) +REP_OPS_CMPS_SCAS(a32_E, ECX, ESI, EDI, 1) + +static int opREPNE(uint32_t fetchdat) +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int opREPE(uint32_t fetchdat) +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} diff --git a/src/cpu_new/x86_ops_ret.h b/src/cpu_new/x86_ops_ret.h new file mode 100644 index 000000000..133c6153b --- /dev/null +++ b/src/cpu_new/x86_ops_ret.h @@ -0,0 +1,256 @@ +#define RETF_a16(stack_offset) \ + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) \ + { \ + pmoderetf(0, stack_offset); \ + return 1; \ + } \ + if (stack32) \ + { \ + cpu_state.pc = readmemw(ss, ESP); \ + loadcs(readmemw(ss, ESP + 2)); \ + } \ + else \ + { \ + cpu_state.pc = readmemw(ss, SP); \ + loadcs(readmemw(ss, SP + 2)); \ + } \ + if (cpu_state.abrt) return 1; \ + if (stack32) ESP += 4 + stack_offset; \ + else SP += 4 + stack_offset; \ + cycles -= timing_retf_rm; + +#define RETF_a32(stack_offset) \ + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) \ + { \ + pmoderetf(1, stack_offset); \ + return 1; \ + } \ + if (stack32) \ + { \ + cpu_state.pc = readmeml(ss, ESP); \ + loadcs(readmeml(ss, ESP + 4) & 0xffff); \ + } \ + else \ + { \ + cpu_state.pc = readmeml(ss, SP); \ + loadcs(readmeml(ss, SP + 4) & 0xffff); \ + } \ + if (cpu_state.abrt) return 1; \ + if (stack32) ESP += 8 + stack_offset; \ + else SP += 8 + stack_offset; \ + cycles -= timing_retf_rm; + +static int opRETF_a16(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + CPU_BLOCK_END(); + RETF_a16(0); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opRETF_a32(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + CPU_BLOCK_END(); + RETF_a32(0); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,2,0,0, 1); + PREFETCH_FLUSH(); + return 0; +} + +static int opRETF_a16_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + int cycles_old = cycles; UN_USED(cycles_old); + + CPU_BLOCK_END(); + RETF_a16(offset); + + PREFETCH_RUN(cycles_old-cycles, 3, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opRETF_a32_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + int cycles_old = cycles; UN_USED(cycles_old); + + CPU_BLOCK_END(); + RETF_a32(offset); + + PREFETCH_RUN(cycles_old-cycles, 3, -1, 0,2,0,0, 1); + PREFETCH_FLUSH(); + return 0; +} + +static int opIRET_286(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + cpu_state.flags = (cpu_state.flags & 0x7000) | (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + cpu_state.pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + cpu_state.flags = (cpu_state.flags & 0x7000) | (readmemw(ss, ((SP + 4) & 0xffff)) & 0x0fd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return cpu_state.abrt; +} + +static int opIRET(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + if (cr4 & CR4_VME) + { + uint16_t new_pc, new_cs, new_flags; + + new_pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + new_flags = readmemw(ss, ((SP + 4) & 0xffff)); + if (cpu_state.abrt) + return 1; + + if ((new_flags & T_FLAG) || ((new_flags & I_FLAG) && (cpu_state.eflags & VIP_FLAG))) + { + x86gpf(NULL, 0); + return 1; + } + SP += 6; + if (new_flags & I_FLAG) + cpu_state.eflags |= VIF_FLAG; + else + cpu_state.eflags &= ~VIF_FLAG; + cpu_state.flags = (cpu_state.flags & 0x3300) | (new_flags & 0x4cd5) | 2; + loadcs(new_cs); + cpu_state.pc = new_pc; + + cycles -= timing_iret_rm; + } + else + { + x86gpf(NULL,0); + return 1; + } + } + else + { + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + cpu_state.flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + cpu_state.pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + cpu_state.flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return cpu_state.abrt; +} + +static int opIRETD(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (msw & 1) + { + optype = IRET; + pmodeiret(1); + optype = 0; + } + else + { + uint16_t new_cs; + if (stack32) + { + cpu_state.pc = readmeml(ss, ESP); + new_cs = readmemw(ss, ESP + 4); + cpu_state.flags = (readmemw(ss, ESP + 8) & 0xffd5) | 2; + cpu_state.eflags = readmemw(ss, ESP + 10); + ESP += 12; + } + else + { + cpu_state.pc = readmeml(ss, SP); + new_cs = readmemw(ss, ((SP + 4) & 0xffff)); + cpu_state.flags = (readmemw(ss,(SP + 8) & 0xffff) & 0xffd5) | 2; + cpu_state.eflags = readmemw(ss, (SP + 10) & 0xffff); + SP += 12; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,2,0,0, 1); + PREFETCH_FLUSH(); + return cpu_state.abrt; +} + diff --git a/src/cpu_new/x86_ops_set.h b/src/cpu_new/x86_ops_set.h new file mode 100644 index 000000000..f6fd50e69 --- /dev/null +++ b/src/cpu_new/x86_ops_set.h @@ -0,0 +1,37 @@ +#define opSET(condition) \ + static int opSET ## condition ## _a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + seteab((cond_ ## condition) ? 1 : 0); \ + CLOCK_CYCLES(4); \ + return cpu_state.abrt; \ + } \ + \ + static int opSET ## condition ## _a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + seteab((cond_ ## condition) ? 1 : 0); \ + CLOCK_CYCLES(4); \ + return cpu_state.abrt; \ + } + +opSET(O) +opSET(NO) +opSET(B) +opSET(NB) +opSET(E) +opSET(NE) +opSET(BE) +opSET(NBE) +opSET(S) +opSET(NS) +opSET(P) +opSET(NP) +opSET(L) +opSET(NL) +opSET(LE) +opSET(NLE) diff --git a/src/cpu_new/x86_ops_shift.h b/src/cpu_new/x86_ops_shift.h new file mode 100644 index 000000000..106a5701a --- /dev/null +++ b/src/cpu_new/x86_ops_shift.h @@ -0,0 +1,607 @@ +#define OP_SHIFT_b(c, ea32) \ + { \ + uint8_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL b, c*/ \ + temp = (temp << (c & 7)) | (temp >> (8-(c & 7))); \ + seteab(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROL8, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x08: /*ROR b,CL*/ \ + temp = (temp >> (c & 7)) | (temp << (8-(c & 7))); \ + seteab(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROR8, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x10: /*RCL b,CL*/ \ + temp2 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteab(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((cpu_state.flags & C_FLAG) ^ (temp >> 7)) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x18: /*RCR b,CL*/ \ + temp2 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteab(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x20: case 0x30: /*SHL b,CL*/ \ + seteab(temp << c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHL8, temp_orig, c, (temp << c) & 0xff); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x28: /*SHR b,CL*/ \ + seteab(temp >> c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHR8, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x38: /*SAR b,CL*/ \ + temp = (int8_t)temp >> c; \ + seteab(temp); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SAR8, temp_orig, c, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + } \ + } + +#define OP_SHIFT_w(c, ea32) \ + { \ + uint16_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL w, c*/ \ + temp = (temp << (c & 15)) | (temp >> (16-(c & 15))); \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROL16, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x08: /*ROR w,CL*/ \ + temp = (temp >> (c & 15)) | (temp << (16-(c & 15))); \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROR16, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x10: /*RCL w, c*/ \ + temp2 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x8000; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((cpu_state.flags & C_FLAG) ^ (temp >> 15)) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x18: /*RCR w, c*/ \ + temp2 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x8000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x20: case 0x30: /*SHL w, c*/ \ + seteaw(temp << c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHL16, temp_orig, c, (temp << c) & 0xffff); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x28: /*SHR w, c*/ \ + seteaw(temp >> c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHR16, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x38: /*SAR w, c*/ \ + temp = (int16_t)temp >> c; \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SAR16, temp_orig, c, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + } \ + } + +#define OP_SHIFT_l(c, ea32) \ + { \ + uint32_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL l, c*/ \ + temp = (temp << c) | (temp >> (32-c)); \ + seteal(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROL32, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x08: /*ROR l,CL*/ \ + temp = (temp >> c) | (temp << (32-c)); \ + seteal(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROR32, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x10: /*RCL l, c*/ \ + temp2 = CF_SET(); \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80000000; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteal(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((cpu_state.flags & C_FLAG) ^ (temp >> 31)) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x18: /*RCR l, c*/ \ + temp2 = cpu_state.flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80000000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteal(temp); if (cpu_state.abrt) return 1; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) cpu_state.flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x20: case 0x30: /*SHL l, c*/ \ + seteal(temp << c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHL32, temp_orig, c, temp << c); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x28: /*SHR l, c*/ \ + seteal(temp >> c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHR32, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x38: /*SAR l, c*/ \ + temp = (int32_t)temp >> c; \ + seteal(temp); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SAR32, temp_orig, c, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + } \ + } + +static int opC0_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + PREFETCH_PREFIX(); + temp = geteab(); if (cpu_state.abrt) return 1; + OP_SHIFT_b(c, 0); + return 0; +} +static int opC0_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + PREFETCH_PREFIX(); + temp = geteab(); if (cpu_state.abrt) return 1; + OP_SHIFT_b(c, 1); + return 0; +} +static int opC1_w_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + PREFETCH_PREFIX(); + temp = geteaw(); if (cpu_state.abrt) return 1; + OP_SHIFT_w(c, 0); + return 0; +} +static int opC1_w_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + PREFETCH_PREFIX(); + temp = geteaw(); if (cpu_state.abrt) return 1; + OP_SHIFT_w(c, 1); + return 0; +} +static int opC1_l_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + PREFETCH_PREFIX(); + temp = geteal(); if (cpu_state.abrt) return 1; + OP_SHIFT_l(c, 0); + return 0; +} +static int opC1_l_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + PREFETCH_PREFIX(); + temp = geteal(); if (cpu_state.abrt) return 1; + OP_SHIFT_l(c, 1); + return 0; +} + +static int opD0_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint8_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + OP_SHIFT_b(c, 0); + return 0; +} +static int opD0_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint8_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + OP_SHIFT_b(c, 1); + return 0; +} +static int opD1_w_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint16_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + OP_SHIFT_w(c, 0); + return 0; +} +static int opD1_w_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint16_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + OP_SHIFT_w(c, 1); + return 0; +} +static int opD1_l_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint32_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + OP_SHIFT_l(c, 0); + return 0; +} +static int opD1_l_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint32_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + OP_SHIFT_l(c, 1); + return 0; +} + +static int opD2_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + c = CL & 31; + temp = geteab(); if (cpu_state.abrt) return 1; + OP_SHIFT_b(c, 0); + return 0; +} +static int opD2_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + c = CL & 31; + temp = geteab(); if (cpu_state.abrt) return 1; + OP_SHIFT_b(c, 1); + return 0; +} +static int opD3_w_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + c = CL & 31; + temp = geteaw(); if (cpu_state.abrt) return 1; + OP_SHIFT_w(c, 0); + return 0; +} +static int opD3_w_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + c = CL & 31; + temp = geteaw(); if (cpu_state.abrt) return 1; + OP_SHIFT_w(c, 1); + return 0; +} +static int opD3_l_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + c = CL & 31; + temp = geteal(); if (cpu_state.abrt) return 1; + OP_SHIFT_l(c, 0); + return 0; +} +static int opD3_l_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + c = CL & 31; + temp = geteal(); if (cpu_state.abrt) return 1; + OP_SHIFT_l(c, 1); + return 0; +} + + +#define SHLD_w() \ + if (count) \ + { \ + int tempc; \ + uint32_t templ; \ + uint16_t tempw = geteaw(); if (cpu_state.abrt) return 1; \ + tempc = ((tempw << (count - 1)) & (1 << 15)) ? 1 : 0; \ + templ = (tempw << 16) | cpu_state.regs[cpu_reg].w; \ + if (count <= 16) tempw = templ >> (16 - count); \ + else tempw = (templ << count) >> 16; \ + seteaw(tempw); if (cpu_state.abrt) return 1; \ + setznp16(tempw); \ + flags_rebuild(); \ + if (tempc) cpu_state.flags |= C_FLAG; \ + } + +#define SHLD_l() \ + if (count) \ + { \ + int tempc; \ + uint32_t templ = geteal(); if (cpu_state.abrt) return 1; \ + tempc = ((templ << (count - 1)) & (1 << 31)) ? 1 : 0; \ + templ = (templ << count) | (cpu_state.regs[cpu_reg].l >> (32 - count)); \ + seteal(templ); if (cpu_state.abrt) return 1; \ + setznp32(templ); \ + flags_rebuild(); \ + if (tempc) cpu_state.flags |= C_FLAG; \ + } + + +#define SHRD_w() \ + if (count) \ + { \ + int tempc; \ + uint32_t templ; \ + uint16_t tempw = geteaw(); if (cpu_state.abrt) return 1; \ + tempc = (tempw >> (count - 1)) & 1; \ + templ = tempw | (cpu_state.regs[cpu_reg].w << 16); \ + tempw = templ >> count; \ + seteaw(tempw); if (cpu_state.abrt) return 1; \ + setznp16(tempw); \ + flags_rebuild(); \ + if (tempc) cpu_state.flags |= C_FLAG; \ + } + +#define SHRD_l() \ + if (count) \ + { \ + int tempc; \ + uint32_t templ = geteal(); if (cpu_state.abrt) return 1; \ + tempc = (templ >> (count - 1)) & 1; \ + templ = (templ >> count) | (cpu_state.regs[cpu_reg].l << (32 - count)); \ + seteal(templ); if (cpu_state.abrt) return 1; \ + setznp32(templ); \ + flags_rebuild(); \ + if (tempc) cpu_state.flags |= C_FLAG; \ + } + +#define opSHxD(operation) \ + static int op ## operation ## _i_a16(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + count = getbyte() & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); \ + return 0; \ + } \ + static int op ## operation ## _CL_a16(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + count = CL & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); \ + return 0; \ + } \ + static int op ## operation ## _i_a32(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + count = getbyte() & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); \ + return 0; \ + } \ + static int op ## operation ## _CL_a32(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + count = CL & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); \ + return 0; \ + } + +opSHxD(SHLD_w) +opSHxD(SHLD_l) +opSHxD(SHRD_w) +opSHxD(SHRD_l) diff --git a/src/cpu_new/x86_ops_stack.h b/src/cpu_new/x86_ops_stack.h new file mode 100644 index 000000000..9ca1171a0 --- /dev/null +++ b/src/cpu_new/x86_ops_stack.h @@ -0,0 +1,525 @@ +#define PUSH_W_OP(reg) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + { \ + PUSH_W(reg); \ + CLOCK_CYCLES((is486) ? 1 : 2); \ + PREFETCH_RUN(2, 1, -1, 0,0,1,0, 0); \ + return cpu_state.abrt; \ + } + +#define PUSH_L_OP(reg) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + { \ + PUSH_L(reg); \ + CLOCK_CYCLES((is486) ? 1 : 2); \ + PREFETCH_RUN(2, 1, -1, 0,0,0,1, 0); \ + return cpu_state.abrt; \ + } + +#define POP_W_OP(reg) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + { \ + reg = POP_W(); \ + CLOCK_CYCLES((is486) ? 1 : 4); \ + PREFETCH_RUN(4, 1, -1, 1,0,0,0, 0); \ + return cpu_state.abrt; \ + } + +#define POP_L_OP(reg) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + { \ + reg = POP_L(); \ + CLOCK_CYCLES((is486) ? 1 : 4); \ + PREFETCH_RUN(4, 1, -1, 0,1,0,0, 0); \ + return cpu_state.abrt; \ + } + +PUSH_W_OP(AX) +PUSH_W_OP(BX) +PUSH_W_OP(CX) +PUSH_W_OP(DX) +PUSH_W_OP(SI) +PUSH_W_OP(DI) +PUSH_W_OP(BP) +PUSH_W_OP(SP) + +PUSH_L_OP(EAX) +PUSH_L_OP(EBX) +PUSH_L_OP(ECX) +PUSH_L_OP(EDX) +PUSH_L_OP(ESI) +PUSH_L_OP(EDI) +PUSH_L_OP(EBP) +PUSH_L_OP(ESP) + +POP_W_OP(AX) +POP_W_OP(BX) +POP_W_OP(CX) +POP_W_OP(DX) +POP_W_OP(SI) +POP_W_OP(DI) +POP_W_OP(BP) +POP_W_OP(SP) + +POP_L_OP(EAX) +POP_L_OP(EBX) +POP_L_OP(ECX) +POP_L_OP(EDX) +POP_L_OP(ESI) +POP_L_OP(EDI) +POP_L_OP(EBP) +POP_L_OP(ESP) + + +static int opPUSHA_w(uint32_t fetchdat) +{ + if (stack32) + { + writememw(ss, ESP - 2, AX); + writememw(ss, ESP - 4, CX); + writememw(ss, ESP - 6, DX); + writememw(ss, ESP - 8, BX); + writememw(ss, ESP - 10, SP); + writememw(ss, ESP - 12, BP); + writememw(ss, ESP - 14, SI); + writememw(ss, ESP - 16, DI); + if (!cpu_state.abrt) ESP -= 16; + } + else + { + writememw(ss, ((SP - 2) & 0xFFFF), AX); + writememw(ss, ((SP - 4) & 0xFFFF), CX); + writememw(ss, ((SP - 6) & 0xFFFF), DX); + writememw(ss, ((SP - 8) & 0xFFFF), BX); + writememw(ss, ((SP - 10) & 0xFFFF), SP); + writememw(ss, ((SP - 12) & 0xFFFF), BP); + writememw(ss, ((SP - 14) & 0xFFFF), SI); + writememw(ss, ((SP - 16) & 0xFFFF), DI); + if (!cpu_state.abrt) SP -= 16; + } + CLOCK_CYCLES((is486) ? 11 : 18); + PREFETCH_RUN(18, 1, -1, 0,0,8,0, 0); + return cpu_state.abrt; +} +static int opPUSHA_l(uint32_t fetchdat) +{ + if (stack32) + { + writememl(ss, ESP - 4, EAX); + writememl(ss, ESP - 8, ECX); + writememl(ss, ESP - 12, EDX); + writememl(ss, ESP - 16, EBX); + writememl(ss, ESP - 20, ESP); + writememl(ss, ESP - 24, EBP); + writememl(ss, ESP - 28, ESI); + writememl(ss, ESP - 32, EDI); + if (!cpu_state.abrt) ESP -= 32; + } + else + { + writememl(ss, ((SP - 4) & 0xFFFF), EAX); + writememl(ss, ((SP - 8) & 0xFFFF), ECX); + writememl(ss, ((SP - 12) & 0xFFFF), EDX); + writememl(ss, ((SP - 16) & 0xFFFF), EBX); + writememl(ss, ((SP - 20) & 0xFFFF), ESP); + writememl(ss, ((SP - 24) & 0xFFFF), EBP); + writememl(ss, ((SP - 28) & 0xFFFF), ESI); + writememl(ss, ((SP - 32) & 0xFFFF), EDI); + if (!cpu_state.abrt) SP -= 32; + } + CLOCK_CYCLES((is486) ? 11 : 18); + PREFETCH_RUN(18, 1, -1, 0,0,0,8, 0); + return cpu_state.abrt; +} + +static int opPOPA_w(uint32_t fetchdat) +{ + if (stack32) + { + DI = readmemw(ss, ESP); if (cpu_state.abrt) return 1; + SI = readmemw(ss, ESP + 2); if (cpu_state.abrt) return 1; + BP = readmemw(ss, ESP + 4); if (cpu_state.abrt) return 1; + BX = readmemw(ss, ESP + 8); if (cpu_state.abrt) return 1; + DX = readmemw(ss, ESP + 10); if (cpu_state.abrt) return 1; + CX = readmemw(ss, ESP + 12); if (cpu_state.abrt) return 1; + AX = readmemw(ss, ESP + 14); if (cpu_state.abrt) return 1; + ESP += 16; + } + else + { + DI = readmemw(ss, ((SP) & 0xFFFF)); if (cpu_state.abrt) return 1; + SI = readmemw(ss, ((SP + 2) & 0xFFFF)); if (cpu_state.abrt) return 1; + BP = readmemw(ss, ((SP + 4) & 0xFFFF)); if (cpu_state.abrt) return 1; + BX = readmemw(ss, ((SP + 8) & 0xFFFF)); if (cpu_state.abrt) return 1; + DX = readmemw(ss, ((SP + 10) & 0xFFFF)); if (cpu_state.abrt) return 1; + CX = readmemw(ss, ((SP + 12) & 0xFFFF)); if (cpu_state.abrt) return 1; + AX = readmemw(ss, ((SP + 14) & 0xFFFF)); if (cpu_state.abrt) return 1; + SP += 16; + } + CLOCK_CYCLES((is486) ? 9 : 24); + PREFETCH_RUN(24, 1, -1, 7,0,0,0, 0); + return 0; +} +static int opPOPA_l(uint32_t fetchdat) +{ + if (stack32) + { + EDI = readmeml(ss, ESP); if (cpu_state.abrt) return 1; + ESI = readmeml(ss, ESP + 4); if (cpu_state.abrt) return 1; + EBP = readmeml(ss, ESP + 8); if (cpu_state.abrt) return 1; + EBX = readmeml(ss, ESP + 16); if (cpu_state.abrt) return 1; + EDX = readmeml(ss, ESP + 20); if (cpu_state.abrt) return 1; + ECX = readmeml(ss, ESP + 24); if (cpu_state.abrt) return 1; + EAX = readmeml(ss, ESP + 28); if (cpu_state.abrt) return 1; + ESP += 32; + } + else + { + EDI = readmeml(ss, ((SP) & 0xFFFF)); if (cpu_state.abrt) return 1; + ESI = readmeml(ss, ((SP + 4) & 0xFFFF)); if (cpu_state.abrt) return 1; + EBP = readmeml(ss, ((SP + 8) & 0xFFFF)); if (cpu_state.abrt) return 1; + EBX = readmeml(ss, ((SP + 16) & 0xFFFF)); if (cpu_state.abrt) return 1; + EDX = readmeml(ss, ((SP + 20) & 0xFFFF)); if (cpu_state.abrt) return 1; + ECX = readmeml(ss, ((SP + 24) & 0xFFFF)); if (cpu_state.abrt) return 1; + EAX = readmeml(ss, ((SP + 28) & 0xFFFF)); if (cpu_state.abrt) return 1; + SP += 32; + } + CLOCK_CYCLES((is486) ? 9 : 24); + PREFETCH_RUN(24, 1, -1, 0,7,0,0, 0); + return 0; +} + +static int opPUSH_imm_w(uint32_t fetchdat) +{ + uint16_t val = getwordf(); + PUSH_W(val); + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opPUSH_imm_l(uint32_t fetchdat) +{ + uint32_t val = getlong(); if (cpu_state.abrt) return 1; + PUSH_L(val); + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 3, -1, 0,0,0,1, 0); + return cpu_state.abrt; +} + +static int opPUSH_imm_bw(uint32_t fetchdat) +{ + uint16_t tempw = getbytef(); + + if (tempw & 0x80) tempw |= 0xFF00; + PUSH_W(tempw); + + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 2, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opPUSH_imm_bl(uint32_t fetchdat) +{ + uint32_t templ = getbytef(); + + if (templ & 0x80) templ |= 0xFFFFFF00; + PUSH_L(templ); + + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 2, -1, 0,0,0,1, 0); + return cpu_state.abrt; +} + +static int opPOPW_a16(uint32_t fetchdat) +{ + uint16_t temp; + + temp = POP_W(); if (cpu_state.abrt) return 1; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(temp); + if (cpu_state.abrt) + { + if (stack32) ESP -= 2; + else SP -= 2; + } + + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); + else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 1,0,(cpu_mod == 3) ? 0:1,0, 0); + return cpu_state.abrt; +} +static int opPOPW_a32(uint32_t fetchdat) +{ + uint16_t temp; + + temp = POP_W(); if (cpu_state.abrt) return 1; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(temp); + if (cpu_state.abrt) + { + if (stack32) ESP -= 2; + else SP -= 2; + } + + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); + else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 1,0,(cpu_mod == 3) ? 0:1,0, 1); + return cpu_state.abrt; +} + +static int opPOPL_a16(uint32_t fetchdat) +{ + uint32_t temp; + + temp = POP_L(); if (cpu_state.abrt) return 1; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteal(temp); + if (cpu_state.abrt) + { + if (stack32) ESP -= 4; + else SP -= 4; + } + + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); + else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 0,1,0,(cpu_mod == 3) ? 0:1, 0); + return cpu_state.abrt; +} +static int opPOPL_a32(uint32_t fetchdat) +{ + uint32_t temp; + + temp = POP_L(); if (cpu_state.abrt) return 1; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteal(temp); + if (cpu_state.abrt) + { + if (stack32) ESP -= 4; + else SP -= 4; + } + + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); + else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 0,1,0,(cpu_mod == 3) ? 0:1, 1); + return cpu_state.abrt; +} + + +static int opENTER_w(uint32_t fetchdat) +{ + uint16_t offset; + int count; + uint32_t tempEBP, tempESP, frame_ptr; + int reads = 0, writes = 1, instr_cycles = 0; + uint16_t tempw; + + offset = getwordf(); + count = (fetchdat >> 16) & 0xff; cpu_state.pc++; + tempEBP = EBP; + tempESP = ESP; + + PUSH_W(BP); if (cpu_state.abrt) return 1; + frame_ptr = ESP; + + if (count > 0) + { + while (--count) + { + BP -= 2; + tempw = readmemw(ss, BP); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + PUSH_W(tempw); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 4); + reads++; writes++; instr_cycles += (is486) ? 3 : 4; + } + PUSH_W(frame_ptr); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 5); + writes++; instr_cycles += (is486) ? 3 : 5; + } + BP = frame_ptr; + + if (stack32) ESP -= offset; + else SP -= offset; + CLOCK_CYCLES((is486) ? 14 : 10); + instr_cycles += (is486) ? 14 : 10; + PREFETCH_RUN(instr_cycles, 3, -1, reads,0,writes,0, 0); + return 0; +} +static int opENTER_l(uint32_t fetchdat) +{ + uint16_t offset; + int count; + uint32_t tempEBP, tempESP, frame_ptr; + int reads = 0, writes = 1, instr_cycles = 0; + uint32_t templ; + + offset = getwordf(); + count = (fetchdat >> 16) & 0xff; cpu_state.pc++; + tempEBP = EBP; tempESP = ESP; + + PUSH_L(EBP); if (cpu_state.abrt) return 1; + frame_ptr = ESP; + + if (count > 0) + { + while (--count) + { + EBP -= 4; + templ = readmeml(ss, EBP); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + PUSH_L(templ); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 4); + reads++; writes++; instr_cycles += (is486) ? 3 : 4; + } + PUSH_L(frame_ptr); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 5); + writes++; instr_cycles += (is486) ? 3 : 5; + } + EBP = frame_ptr; + + if (stack32) ESP -= offset; + else SP -= offset; + CLOCK_CYCLES((is486) ? 14 : 10); + instr_cycles += (is486) ? 14 : 10; + PREFETCH_RUN(instr_cycles, 3, -1, reads,0,writes,0, 0); + return 0; +} + + +static int opLEAVE_w(uint32_t fetchdat) +{ + uint32_t tempESP = ESP; + uint16_t temp; + + SP = BP; + temp = POP_W(); + if (cpu_state.abrt) { ESP = tempESP; return 1; } + BP = temp; + + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opLEAVE_l(uint32_t fetchdat) +{ + uint32_t tempESP = ESP; + uint32_t temp; + + ESP = EBP; + temp = POP_L(); + if (cpu_state.abrt) { ESP = tempESP; return 1; } + EBP = temp; + + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,1,0,0, 0); + return 0; +} + + +#define PUSH_SEG_OPS(seg) \ + static int opPUSH_ ## seg ## _w(uint32_t fetchdat) \ + { \ + PUSH_W(seg); \ + CLOCK_CYCLES(2); \ + PREFETCH_RUN(2, 1, -1, 0,0,1,0, 0); \ + return cpu_state.abrt; \ + } \ + static int opPUSH_ ## seg ## _l(uint32_t fetchdat) \ + { \ + PUSH_L(seg); \ + CLOCK_CYCLES(2); \ + PREFETCH_RUN(2, 1, -1, 0,0,0,1, 0); \ + return cpu_state.abrt; \ + } + +#define POP_SEG_OPS(seg, realseg) \ + static int opPOP_ ## seg ## _w(uint32_t fetchdat) \ + { \ + uint16_t temp_seg; \ + uint32_t temp_esp = ESP; \ + temp_seg = POP_W(); if (cpu_state.abrt) return 1; \ + loadseg(temp_seg, realseg); if (cpu_state.abrt) ESP = temp_esp; \ + CLOCK_CYCLES(is486 ? 3 : 7); \ + PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); \ + return cpu_state.abrt; \ + } \ + static int opPOP_ ## seg ## _l(uint32_t fetchdat) \ + { \ + uint32_t temp_seg; \ + uint32_t temp_esp = ESP; \ + temp_seg = POP_L(); if (cpu_state.abrt) return 1; \ + loadseg(temp_seg & 0xffff, realseg); if (cpu_state.abrt) ESP = temp_esp; \ + CLOCK_CYCLES(is486 ? 3 : 7); \ + PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); \ + return cpu_state.abrt; \ + } + + +PUSH_SEG_OPS(CS); +PUSH_SEG_OPS(DS); +PUSH_SEG_OPS(ES); +PUSH_SEG_OPS(FS); +PUSH_SEG_OPS(GS); +PUSH_SEG_OPS(SS); + +POP_SEG_OPS(DS, &cpu_state.seg_ds); +POP_SEG_OPS(ES, &cpu_state.seg_es); +POP_SEG_OPS(FS, &cpu_state.seg_fs); +POP_SEG_OPS(GS, &cpu_state.seg_gs); + + +static int opPOP_SS_w(uint32_t fetchdat) +{ + uint16_t temp_seg; + uint32_t temp_esp = ESP; + temp_seg = POP_W(); if (cpu_state.abrt) return 1; + loadseg(temp_seg, &cpu_state.seg_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } + CLOCK_CYCLES(is486 ? 3 : 7); + PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); + + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + cpu_state.ssegs = 0; + cpu_state.ea_seg = &cpu_state.seg_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (cpu_state.abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + + return 1; +} +static int opPOP_SS_l(uint32_t fetchdat) +{ + uint32_t temp_seg; + uint32_t temp_esp = ESP; + temp_seg = POP_L(); if (cpu_state.abrt) return 1; + loadseg(temp_seg & 0xffff, &cpu_state.seg_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } + CLOCK_CYCLES(is486 ? 3 : 7); + PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); + + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + cpu_state.ssegs = 0; + cpu_state.ea_seg = &cpu_state.seg_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (cpu_state.abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + + return 1; +} diff --git a/src/cpu_new/x86_ops_string.h b/src/cpu_new/x86_ops_string.h new file mode 100644 index 000000000..c02725138 --- /dev/null +++ b/src/cpu_new/x86_ops_string.h @@ -0,0 +1,597 @@ +static int opMOVSB_a16(uint32_t fetchdat) +{ + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + writememb(es, DI, temp); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opMOVSB_a32(uint32_t fetchdat) +{ + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + writememb(es, EDI, temp); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opMOVSW_a16(uint32_t fetchdat) +{ + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + writememw(es, DI, temp); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) { DI -= 2; SI -= 2; } + else { DI += 2; SI += 2; } + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opMOVSW_a32(uint32_t fetchdat) +{ + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + writememw(es, EDI, temp); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) { EDI -= 2; ESI -= 2; } + else { EDI += 2; ESI += 2; } + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opMOVSL_a16(uint32_t fetchdat) +{ + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + writememl(es, DI, temp); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) { DI -= 4; SI -= 4; } + else { DI += 4; SI += 4; } + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 0,1,0,1, 0); + return 0; +} +static int opMOVSL_a32(uint32_t fetchdat) +{ + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + writememl(es, EDI, temp); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) { EDI -= 4; ESI -= 4; } + else { EDI += 4; ESI += 4; } + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 0,1,0,1, 1); + return 0; +} + + +static int opCMPSB_a16(uint32_t fetchdat) +{ + uint8_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmemb(cpu_state.ea_seg->base, SI); + dst = readmemb(es, DI); if (cpu_state.abrt) return 1; + setsub8(src, dst); + if (cpu_state.flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + CLOCK_CYCLES((is486) ? 8 : 10); + PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 0); + return 0; +} +static int opCMPSB_a32(uint32_t fetchdat) +{ + uint8_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmemb(cpu_state.ea_seg->base, ESI); + dst = readmemb(es, EDI); if (cpu_state.abrt) return 1; + setsub8(src, dst); + if (cpu_state.flags & D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + CLOCK_CYCLES((is486) ? 8 : 10); + PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 1); + return 0; +} + +static int opCMPSW_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmemw(cpu_state.ea_seg->base, SI); + dst = readmemw(es, DI); if (cpu_state.abrt) return 1; + setsub16(src, dst); + if (cpu_state.flags & D_FLAG) { DI -= 2; SI -= 2; } + else { DI += 2; SI += 2; } + CLOCK_CYCLES((is486) ? 8 : 10); + PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 0); + return 0; +} +static int opCMPSW_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmemw(cpu_state.ea_seg->base, ESI); + dst = readmemw(es, EDI); if (cpu_state.abrt) return 1; + setsub16(src, dst); + if (cpu_state.flags & D_FLAG) { EDI -= 2; ESI -= 2; } + else { EDI += 2; ESI += 2; } + CLOCK_CYCLES((is486) ? 8 : 10); + PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 1); + return 0; +} + +static int opCMPSL_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmeml(cpu_state.ea_seg->base, SI); + dst = readmeml(es, DI); if (cpu_state.abrt) return 1; + setsub32(src, dst); + if (cpu_state.flags & D_FLAG) { DI -= 4; SI -= 4; } + else { DI += 4; SI += 4; } + CLOCK_CYCLES((is486) ? 8 : 10); + PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 0,2,0,0, 0); + return 0; +} +static int opCMPSL_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmeml(cpu_state.ea_seg->base, ESI); + dst = readmeml(es, EDI); if (cpu_state.abrt) return 1; + setsub32(src, dst); + if (cpu_state.flags & D_FLAG) { EDI -= 4; ESI -= 4; } + else { EDI += 4; ESI += 4; } + CLOCK_CYCLES((is486) ? 8 : 10); + PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 0,2,0,0, 1); + return 0; +} + +static int opSTOSB_a16(uint32_t fetchdat) +{ + SEG_CHECK_WRITE(&cpu_state.seg_es); + writememb(es, DI, AL); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); + return 0; +} +static int opSTOSB_a32(uint32_t fetchdat) +{ + SEG_CHECK_WRITE(&cpu_state.seg_es); + writememb(es, EDI, AL); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1); + return 0; +} + +static int opSTOSW_a16(uint32_t fetchdat) +{ + SEG_CHECK_WRITE(&cpu_state.seg_es); + writememw(es, DI, AX); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) DI -= 2; + else DI += 2; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); + return 0; +} +static int opSTOSW_a32(uint32_t fetchdat) +{ + SEG_CHECK_WRITE(&cpu_state.seg_es); + writememw(es, EDI, AX); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) EDI -= 2; + else EDI += 2; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1); + return 0; +} + +static int opSTOSL_a16(uint32_t fetchdat) +{ + SEG_CHECK_WRITE(&cpu_state.seg_es); + writememl(es, DI, EAX); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) DI -= 4; + else DI += 4; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,1, 0); + return 0; +} +static int opSTOSL_a32(uint32_t fetchdat) +{ + SEG_CHECK_WRITE(&cpu_state.seg_es); + writememl(es, EDI, EAX); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) EDI -= 4; + else EDI += 4; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,1, 1); + return 0; +} + + +static int opLODSB_a16(uint32_t fetchdat) +{ + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + AL = temp; + if (cpu_state.flags & D_FLAG) SI--; + else SI++; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opLODSB_a32(uint32_t fetchdat) +{ + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + AL = temp; + if (cpu_state.flags & D_FLAG) ESI--; + else ESI++; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); + return 0; +} + +static int opLODSW_a16(uint32_t fetchdat) +{ + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + AX = temp; + if (cpu_state.flags & D_FLAG) SI -= 2; + else SI += 2; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opLODSW_a32(uint32_t fetchdat) +{ + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + AX = temp; + if (cpu_state.flags & D_FLAG) ESI -= 2; + else ESI += 2; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); + return 0; +} + +static int opLODSL_a16(uint32_t fetchdat) +{ + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + EAX = temp; + if (cpu_state.flags & D_FLAG) SI -= 4; + else SI += 4; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 0,1,0,0, 0); + return 0; +} +static int opLODSL_a32(uint32_t fetchdat) +{ + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + EAX = temp; + if (cpu_state.flags & D_FLAG) ESI -= 4; + else ESI += 4; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 0,1,0,0, 1); + return 0; +} + + +static int opSCASB_a16(uint32_t fetchdat) +{ + uint8_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemb(es, DI); if (cpu_state.abrt) return 1; + setsub8(AL, temp); + if (cpu_state.flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opSCASB_a32(uint32_t fetchdat) +{ + uint8_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemb(es, EDI); if (cpu_state.abrt) return 1; + setsub8(AL, temp); + if (cpu_state.flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1); + return 0; +} + +static int opSCASW_a16(uint32_t fetchdat) +{ + uint16_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemw(es, DI); if (cpu_state.abrt) return 1; + setsub16(AX, temp); + if (cpu_state.flags & D_FLAG) DI -= 2; + else DI += 2; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opSCASW_a32(uint32_t fetchdat) +{ + uint16_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemw(es, EDI); if (cpu_state.abrt) return 1; + setsub16(AX, temp); + if (cpu_state.flags & D_FLAG) EDI -= 2; + else EDI += 2; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1); + return 0; +} + +static int opSCASL_a16(uint32_t fetchdat) +{ + uint32_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmeml(es, DI); if (cpu_state.abrt) return 1; + setsub32(EAX, temp); + if (cpu_state.flags & D_FLAG) DI -= 4; + else DI += 4; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 0,1,0,0, 0); + return 0; +} +static int opSCASL_a32(uint32_t fetchdat) +{ + uint32_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmeml(es, EDI); if (cpu_state.abrt) return 1; + setsub32(EAX, temp); + if (cpu_state.flags & D_FLAG) EDI -= 4; + else EDI += 4; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 0,1,0,0, 1); + return 0; +} + +static int opINSB_a16(uint32_t fetchdat) +{ + uint8_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); + check_io_perm(DX); + temp = inb(DX); + writememb(es, DI, temp); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opINSB_a32(uint32_t fetchdat) +{ + uint8_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); + check_io_perm(DX); + temp = inb(DX); + writememb(es, EDI, temp); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opINSW_a16(uint32_t fetchdat) +{ + uint16_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); + check_io_perm(DX); + check_io_perm(DX + 1); + temp = inw(DX); + writememw(es, DI, temp); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) DI -= 2; + else DI += 2; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opINSW_a32(uint32_t fetchdat) +{ + uint16_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); + check_io_perm(DX); + check_io_perm(DX + 1); + temp = inw(DX); + writememw(es, EDI, temp); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) EDI -= 2; + else EDI += 2; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opINSL_a16(uint32_t fetchdat) +{ + uint32_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + temp = inl(DX); + writememl(es, DI, temp); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) DI -= 4; + else DI += 4; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 0,1,0,1, 0); + return 0; +} +static int opINSL_a32(uint32_t fetchdat) +{ + uint32_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + temp = inl(DX); + writememl(es, EDI, temp); if (cpu_state.abrt) return 1; + if (cpu_state.flags & D_FLAG) EDI -= 4; + else EDI += 4; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 0,1,0,1, 1); + return 0; +} + +static int opOUTSB_a16(uint32_t fetchdat) +{ + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + check_io_perm(DX); + if (cpu_state.flags & D_FLAG) SI--; + else SI++; + outb(DX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opOUTSB_a32(uint32_t fetchdat) +{ + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + check_io_perm(DX); + if (cpu_state.flags & D_FLAG) ESI--; + else ESI++; + outb(DX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opOUTSW_a16(uint32_t fetchdat) +{ + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + if (cpu_state.flags & D_FLAG) SI -= 2; + else SI += 2; + outw(DX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opOUTSW_a32(uint32_t fetchdat) +{ + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + if (cpu_state.flags & D_FLAG) ESI -= 2; + else ESI += 2; + outw(DX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opOUTSL_a16(uint32_t fetchdat) +{ + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + if (cpu_state.flags & D_FLAG) SI -= 4; + else SI += 4; + outl(EDX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 0,1,0,1, 0); + return 0; +} +static int opOUTSL_a32(uint32_t fetchdat) +{ + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + if (cpu_state.flags & D_FLAG) ESI -= 4; + else ESI += 4; + outl(EDX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 0,1,0,1, 1); + return 0; +} diff --git a/src/cpu_new/x86_ops_xchg.h b/src/cpu_new/x86_ops_xchg.h new file mode 100644 index 000000000..6a787273e --- /dev/null +++ b/src/cpu_new/x86_ops_xchg.h @@ -0,0 +1,234 @@ +static int opXCHG_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + seteab(getr8(cpu_reg)); if (cpu_state.abrt) return 1; + setr8(cpu_reg, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + return 0; +} +static int opXCHG_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteab(); if (cpu_state.abrt) return 1; + seteab(getr8(cpu_reg)); if (cpu_state.abrt) return 1; + setr8(cpu_reg, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + return 0; +} + +static int opXCHG_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + return 0; +} +static int opXCHG_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + return 0; +} + +static int opXCHG_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + return 0; +} +static int opXCHG_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + return 0; +} + + +static int opXCHG_AX_BX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = BX; + BX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_CX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = CX; + CX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_DX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = DX; + DX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_SI(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = SI; + SI = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_DI(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = DI; + DI = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_BP(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = BP; + BP = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_SP(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = SP; + SP = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opXCHG_EAX_EBX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EBX; + EBX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_ECX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ECX; + ECX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_EDX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EDX; + EDX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_ESI(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ESI; + ESI = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_EDI(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EDI; + EDI = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_EBP(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EBP; + EBP = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_ESP(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ESP; + ESP = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + + +#define opBSWAP(reg) \ + static int opBSWAP_ ## reg(uint32_t fetchdat) \ + { \ + reg = (reg >> 24) | ((reg >> 8) & 0xff00) | ((reg << 8) & 0xff0000) | ((reg << 24) & 0xff000000); \ + CLOCK_CYCLES(1); \ + PREFETCH_RUN(1, 1, -1, 0,0,0,0, 0); \ + return 0; \ + } + +opBSWAP(EAX) +opBSWAP(EBX) +opBSWAP(ECX) +opBSWAP(EDX) +opBSWAP(ESI) +opBSWAP(EDI) +opBSWAP(EBP) +opBSWAP(ESP) diff --git a/src/cpu_new/x86seg.c b/src/cpu_new/x86seg.c new file mode 100644 index 000000000..2a438d862 --- /dev/null +++ b/src/cpu_new/x86seg.c @@ -0,0 +1,2577 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * x86 CPU segment emulation. + * + * Version: @(#)x86seg.c 1.0.9 2018/11/14 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "../device.h" +#include "../timer.h" +#include "../machine/machine.h" +#include "../mem.h" +#include "../nvr.h" +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" + + +extern FILE *stdlog; /* file to log output to */ + + +/*Controls whether the accessed bit in a descriptor is set when CS is loaded.*/ +#define CS_ACCESSED + +/*Controls whether the accessed bit in a descriptor is set when a data or stack + selector is loaded.*/ +#define SEL_ACCESSED +int stimes = 0; +int dtimes = 0; +int btimes = 0; + +uint32_t abrt_error; +int cgate16, cgate32; + +#define breaknullsegs 0 + +int intgatesize; + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32); +void taskswitch386(uint16_t seg, uint16_t *segdat); + +void pmodeint(int num, int soft); +/*NOT PRESENT is INT 0B + GPF is INT 0D*/ + + +#ifdef ENABLE_X86SEG_LOG +int x86seg_do_log = ENABLE_X86SEG_LOG; + + +static void +x86seg_log(const char *fmt, ...) +{ + va_list ap; + + if (x86seg_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define x86seg_log(fmt, ...) +#endif + + +void x86abort(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + + nvr_save(); +#ifdef ENABLE_808X_LOG + dumpregs(1); +#endif + fflush(stdlog); + exit(-1); +} + +uint8_t opcode2; + +static void seg_reset(x86seg *s) +{ + s->access = (0 << 5) | 2 | 0x80; + s->limit = 0xFFFF; + s->limit_low = 0; + s->limit_high = 0xffff; + if (s == &cpu_state.seg_cs) + { + /* TODO - When the PC is reset, initialization of the CS descriptor must be like the annotated line below: + s->base = AT ? (cpu_16bitbus ? 0xFF0000 : 0xFFFF0000) : 0xFFFF0; */ + s->base = AT ? 0xF0000 : 0xFFFF0; + s->seg = AT ? 0xF000 : 0xFFFF; + } + else + { + s->base = 0; + s->seg = 0; + } +} + +void x86seg_reset() +{ + seg_reset(&cpu_state.seg_cs); + seg_reset(&cpu_state.seg_ds); + seg_reset(&cpu_state.seg_es); + seg_reset(&cpu_state.seg_fs); + seg_reset(&cpu_state.seg_gs); + seg_reset(&cpu_state.seg_ss); +} + +void x86_doabrt(int x86_abrt) +{ + cpu_state.pc = cpu_state.oldpc; + cpu_state.seg_cs.access = (oldcpl << 5) | 0x80; + + if (msw & 1) + pmodeint(x86_abrt, 0); + else + { + uint32_t addr = (x86_abrt << 2) + idt.base; + if (stack32) + { + writememw(ss,ESP-2,cpu_state.flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + return; + } + + if (cpu_state.abrt || x86_was_reset) return; + + if (intgatesize == 16) + { + if (stack32) + { + writememw(ss, ESP-2, abrt_error); + ESP-=2; + } + else + { + writememw(ss, ((SP-2)&0xFFFF), abrt_error); + SP-=2; + } + } + else + { + if (stack32) + { + writememl(ss, ESP-4, abrt_error); + ESP-=4; + } + else + { + writememl(ss, ((SP-4)&0xFFFF), abrt_error); + SP-=4; + } + } +} +void x86gpf(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_GPF; + abrt_error = error; +} +void x86ss(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_SS; + abrt_error = error; +} +void x86ts(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_TS; + abrt_error = error; +} +void x86np(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_NP; + abrt_error = error; +} + + +static void set_stack32(int s) +{ + stack32 = s; + if (stack32) + cpu_cur_status |= CPU_STATUS_STACK32; + else + cpu_cur_status &= ~CPU_STATUS_STACK32; +} + +static void set_use32(int u) +{ + if (u) + { + use32 = 0x300; + cpu_cur_status |= CPU_STATUS_USE32; + } + else + { + use32 = 0; + cpu_cur_status &= ~CPU_STATUS_USE32; + } +} + +void do_seg_load(x86seg *s, uint16_t *segdat) +{ + s->limit = segdat[0] | ((segdat[3] & 0xF) << 16); + if (segdat[3] & 0x80) + s->limit = (s->limit << 12) | 0xFFF; + s->base = segdat[1] | ((segdat[2] & 0xFF) << 16); + if (is386) + s->base |= ((segdat[3] >> 8) << 24); + s->access = segdat[2] >> 8; + + if ((segdat[2] & 0x1800) != 0x1000 || !(segdat[2] & (1 << 10))) /*expand-down*/ + { + s->limit_high = s->limit; + s->limit_low = 0; + } + else + { + s->limit_high = (segdat[3] & 0x40) ? 0xffffffff : 0xffff; + s->limit_low = s->limit + 1; + } + + if (s == &cpu_state.seg_ds) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &cpu_state.seg_ss) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } +} + +static void do_seg_v86_init(x86seg *s) +{ + s->access = (3 << 5) | 2 | 0x80; + s->limit = 0xffff; + s->limit_low = 0; + s->limit_high = 0xffff; +} + +static void check_seg_valid(x86seg *s) +{ + int dpl = (s->access >> 5) & 3; + int valid = 1; + + if (s->seg & 4) + { + if ((s->seg & ~7) >= ldt.limit) + { + valid = 0; + } + } + else + { + if ((s->seg & ~7) >= gdt.limit) + { + valid = 0; + } + } + + switch (s->access & 0x1f) + { + case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1A: case 0x1B: /*Readable non-conforming code*/ + if ((s->seg & 3) > dpl || (CPL) > dpl) + { + valid = 0; + break; + } + break; + + case 0x1E: case 0x1F: /*Readable conforming code*/ + break; + + default: + valid = 0; + break; + } + + if (!valid) + loadseg(0, s); +} + +int loadseg(uint16_t seg, x86seg *s) +{ + uint16_t segdat[4]; + uint32_t addr; + int dpl; + + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) + { + if (!(seg&~3)) + { + if (s==&cpu_state.seg_ss) + { + x86ss(NULL,0); + return 1; + } + s->seg=0; + s->access = 0x80; + s->base=-1; + if (s == &cpu_state.seg_ds) + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + return 0; + } + addr=seg&~7; + if (seg&4) + { + if ((addr+7)>ldt.limit) + { + x86gpf("loadseg(): Bigger than LDT limit",seg&~3); + return 1; + } + addr+=ldt.base; + } + else + { + if ((addr+7)>gdt.limit) + { + x86gpf("loadseg(): Bigger than GDT limit",seg&~3); + return 1; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return 1; + dpl=(segdat[2]>>13)&3; + if (s==&cpu_state.seg_ss) + { + if (!(seg&~3)) + { + x86gpf(NULL,seg&~3); + return 1; + } + if ((seg&3)!=CPL || dpl!=CPL) + { + x86gpf(NULL,seg&~3); + return 1; + } + switch ((segdat[2]>>8)&0x1F) + { + case 0x12: case 0x13: case 0x16: case 0x17: /*r/w*/ + break; + default: + x86gpf(NULL,seg&~3); + return 1; + } + if (!(segdat[2]&0x8000)) + { + x86ss(NULL,seg&~3); + return 1; + } + set_stack32((segdat[3] & 0x40) ? 1 : 0); + } + else if (s!=&cpu_state.seg_cs) + { + x86seg_log("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); + x86seg_log("Seg type %03X\n",segdat[2]&0x1F00); + switch ((segdat[2]>>8)&0x1F) + { + case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1A: case 0x1B: /*Readable non-conforming code*/ + if ((seg&3)>dpl || (CPL)>dpl) + { + x86gpf(NULL,seg&~3); + return 1; + } + break; + case 0x1E: case 0x1F: /*Readable conforming code*/ + break; + default: + x86gpf(NULL,seg&~3); + return 1; + } + } + + if (!(segdat[2] & 0x8000)) + { + x86np("Load data seg not present", seg & 0xfffc); + return 1; + } + s->seg = seg; + do_seg_load(s, segdat); + +#ifndef CS_ACCESSED + if (s != &_cs) + { +#endif +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif +#ifndef CS_ACCESSED + } +#endif + s->checked = 0; +#ifdef USE_DYNAREC + if (s == &cpu_state.seg_ds) + codegen_flat_ds = 0; + if (s == &cpu_state.seg_ss) + codegen_flat_ss = 0; +#endif + } + else + { + s->access = (3 << 5) | 2 | 0x80; + s->base = seg << 4; + s->seg = seg; + s->checked = 1; +#ifdef USE_DYNAREC + if (s == &cpu_state.seg_ds) + codegen_flat_ds = 0; + if (s == &cpu_state.seg_ss) + codegen_flat_ss = 0; +#endif + if (s == &cpu_state.seg_ss && (cpu_state.eflags & VM_FLAG)) + set_stack32(0); + } + + if (s == &cpu_state.seg_ds) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &cpu_state.seg_ss) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } + + return cpu_state.abrt; +} + +#define DPL ((segdat[2]>>13)&3) +#define DPL2 ((segdat2[2]>>13)&3) +#define DPL3 ((segdat3[2]>>13)&3) + +void loadcs(uint16_t seg) +{ + uint16_t segdat[4]; + uint32_t addr; + x86seg_log("Load CS %04X\n",seg); + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) + { + if (!(seg&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + if (segdat[2]&0x1000) /*Normal code segment*/ + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf(NULL,seg&~3); + return; + } + if (CPL != DPL) + { + x86gpf("loadcs(): CPL != DPL",seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf("loadcs(): CPL < DPL",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS not present", seg & 0xfffc); + return; + } + set_use32(segdat[3] & 0x40); + CS=(seg&~3)|CPL; + do_seg_load(&cpu_state.seg_cs, segdat); + use32=(segdat[3]&0x40)?0x300:0; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + } + else /*System segment*/ + { + if (!(segdat[2]&0x8000)) + { + x86np("Load CS system seg not present\n", seg & 0xfffc); + return; + } + switch (segdat[2]&0xF00) + { + default: + x86gpf(NULL,seg&~3); + return; + } + } + } + else + { + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + CS=seg & 0xFFFF; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + } +} + +void loadcsjmp(uint16_t seg, uint32_t old_pc) +{ + uint16_t segdat[4]; + uint32_t addr; + uint16_t type,seg2; + uint32_t newpc; + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) + { + if (!(seg&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + x86seg_log("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); + if (segdat[2]&0x1000) /*Normal code segment*/ + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf("loadcsjmp(): segment PL > CPL",seg&~3); + return; + } + if (CPL != DPL) + { + x86gpf("loadcsjmp(): CPL != DPL",seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf("loadcsjmp(): CPL < DPL",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP not present\n", seg & 0xfffc); + return; + } + set_use32(segdat[3]&0x40); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + CS = (seg & ~3) | CPL; + segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + + do_seg_load(&cpu_state.seg_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + cycles -= timing_jmp_pm; + } + else /*System segment*/ + { + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP system selector not present\n", seg & 0xfffc); + return; + } + type=segdat[2]&0xF00; + newpc=segdat[0]; + if (type&0x800) newpc|=segdat[3]<<16; + switch (type) + { + case 0x400: /*Call gate*/ + case 0xC00: + cgate32=(type&0x800); + cgate16=!cgate32; + cpu_state.oldpc = cpu_state.pc; + if ((DPL < CPL) || (DPL < (seg&3))) + { + x86gpf(NULL,seg&~3); + return; + } + if (DPL < CPL) + { + x86gpf("loadcsjmp(): ex DPL < CPL",seg&~3); + return; + } + if ((DPL < (seg&3))) + { + x86gpf("loadcsjmp(): ex (DPL < (seg&3))",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP call gate not present\n", seg & 0xfffc); + return; + } + seg2=segdat[1]; + + if (!(seg2&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg2&~7; + if (seg2&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg2&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg2&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + + if (DPL > CPL) + { + x86gpf("loadcsjmp(): ex DPL > CPL",seg2&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP from call gate not present\n", seg2 & 0xfffc); + return; + } + + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if (DPL > CPL) + { + x86gpf(NULL,seg2&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + CS=seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + break; + + default: + x86gpf(NULL,seg2&~3); + return; + } + cycles -= timing_jmp_pm_gate; + break; + + + case 0x100: /*286 Task gate*/ + case 0x900: /*386 Task gate*/ + cpu_state.pc = old_pc; + optype=JMP; + cpl_override=1; + taskswitch286(seg,segdat,segdat[2]&0x800); + cpu_state.flags &= ~NT_FLAG; + cpl_override=0; + return; + + default: + x86gpf(NULL,0); + return; + } + } + } + else + { + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + CS=seg; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + cycles -= timing_jmp_rm; + } +} + +void PUSHW(uint16_t v) +{ + if (stack32) + { + writememw(ss,ESP-2,v); + if (cpu_state.abrt) return; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),v); + if (cpu_state.abrt) return; + SP-=2; + } +} +void PUSHL(uint32_t v) +{ + if (stack32) + { + writememl(ss,ESP-4,v); + if (cpu_state.abrt) return; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),v); + if (cpu_state.abrt) return; + SP-=4; + } +} +uint16_t POPW() +{ + uint16_t tempw; + if (stack32) + { + tempw=readmemw(ss,ESP); + if (cpu_state.abrt) return 0; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); + if (cpu_state.abrt) return 0; + SP+=2; + } + return tempw; +} +uint32_t POPL() +{ + uint32_t templ; + if (stack32) + { + templ=readmeml(ss,ESP); + if (cpu_state.abrt) return 0; + ESP+=4; + } + else + { + templ=readmeml(ss,SP); + if (cpu_state.abrt) return 0; + SP+=4; + } + return templ; +} + +void loadcscall(uint16_t seg, uint32_t old_pc) +{ + uint16_t seg2; + uint16_t segdat[4],segdat2[4],newss; + uint32_t addr,oldssbase=ss, oaddr; + uint32_t newpc; + int count; + uint32_t oldss,oldsp,newsp, oldsp2; + int type; + uint16_t tempw; + + int csout = output; + + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) + { + if (csout) x86seg_log("Protected mode CS load! %04X\n",seg); + if (!(seg&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + type=segdat[2]&0xF00; + newpc=segdat[0]; + if (type&0x800) newpc|=segdat[3]<<16; + + if (csout) x86seg_log("Code seg call - %04X - %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2]); + if (segdat[2]&0x1000) + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf("loadcscall(): segment > CPL",seg&~3); + return; + } + if (CPL != DPL) + { + x86gpf(NULL,seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS call not present", seg & 0xfffc); + return; + } + set_use32(segdat[3]&0x40); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + /*Conforming segments don't change CPL, so preserve existing CPL*/ + if (segdat[2]&0x400) + { + seg = (seg & ~3) | CPL; + segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + } + else /*On non-conforming segments, set RPL = CPL*/ + seg = (seg & ~3) | CPL; + CS=seg; + do_seg_load(&cpu_state.seg_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + if (csout) x86seg_log("Complete\n"); + cycles -= timing_call_pm; + } + else + { + type=segdat[2]&0xF00; + if (csout) x86seg_log("Type %03X\n",type); + switch (type) + { + case 0x400: /*Call gate*/ + case 0xC00: /*386 Call gate*/ + x86seg_log("Callgate %08X\n", cpu_state.pc); + cgate32=(type&0x800); + cgate16=!cgate32; + count=segdat[2]&31; + if (DPL < CPL) + { + x86gpf("loadcscall(): ex DPL < CPL",seg&~3); + return; + } + if ((DPL < (seg&3))) + { + x86gpf("loadcscall(): ex (DPL < (seg&3))",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86seg_log("Call gate not present %04X\n",seg); + x86np("Call gate not present\n", seg & 0xfffc); + return; + } + seg2=segdat[1]; + + x86seg_log("New address : %04X:%08X\n", seg2, newpc); + + if (!(seg2&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg2&~7; + if (seg2&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg2&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg2&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + + x86seg_log("Code seg2 call - %04X - %04X %04X %04X\n",seg2,segdat[0],segdat[1],segdat[2]); + + if (DPL > CPL) + { + x86gpf("loadcscall(): ex DPL > CPL",seg2&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86seg_log("Call gate CS not present %04X\n",seg2); + x86np("Call gate CS not present", seg2 & 0xfffc); + return; + } + + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if (DPL < CPL) + { + uint16_t oldcs = CS; + oaddr = addr; + /*Load new stack*/ + oldss=SS; + oldsp=oldsp2=ESP; + cpl_override=1; + if (tr.access&8) + { + addr = 4 + tr.base + (DPL * 8); + newss=readmemw(0,addr+4); + newsp=readmeml(0,addr); + } + else + { + addr = 2 + tr.base + (DPL * 4); + newss=readmemw(0,addr+2); + newsp=readmemw(0,addr); + } + cpl_override=0; + if (cpu_state.abrt) return; + x86seg_log("New stack %04X:%08X\n",newss,newsp); + if (!(newss&~3)) + { + x86ts(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if ((addr+7)>ldt.limit) + { + x86abort("Bigger than LDT limit %04X %08X %04X CSC SS\n",newss,addr,ldt.limit); + x86ts(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if ((addr+7)>gdt.limit) + { + x86abort("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); + x86ts(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + x86seg_log("Read stack seg\n"); + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + x86seg_log("Read stack seg done!\n"); + if (((newss & 3) != DPL) || (DPL2 != DPL)) + { + x86ts(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + x86ts(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + x86ss("Call gate loading SS not present\n", newss & 0xfffc); + return; + } + if (!stack32) oldsp &= 0xFFFF; + SS=newss; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); + if (stack32) ESP=newsp; + else SP=newsp; + + do_seg_load(&cpu_state.seg_ss, segdat2); + + x86seg_log("Set access 1\n"); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + CS=seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; + + x86seg_log("Set access 2\n"); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + x86seg_log("Type %04X\n",type); + if (type==0xC00) + { + PUSHL(oldss); + PUSHL(oldsp2); + if (cpu_state.abrt) + { + SS = oldss; + ESP = oldsp2; + CS = oldcs; + return; + } + if (count) + { + while (count) + { + count--; + PUSHL(readmeml(oldssbase,oldsp+(count*4))); + if (cpu_state.abrt) + { + SS = oldss; + ESP = oldsp2; + CS = oldcs; + return; + } + } + } + } + else + { + x86seg_log("Stack %04X\n",SP); + PUSHW(oldss); + x86seg_log("Write SS to %04X:%04X\n",SS,SP); + PUSHW(oldsp2); + if (cpu_state.abrt) + { + SS = oldss; + ESP = oldsp2; + CS = oldcs; + return; + } + x86seg_log("Write SP to %04X:%04X\n",SS,SP); + if (count) + { + while (count) + { + count--; + tempw=readmemw(oldssbase,(oldsp&0xFFFF)+(count*2)); + x86seg_log("PUSH %04X\n",tempw); + PUSHW(tempw); + if (cpu_state.abrt) + { + SS = oldss; + ESP = oldsp2; + CS = oldcs; + return; + } + } + } + } + cycles -= timing_call_pm_gate_inner; + break; + } + else if (DPL > CPL) + { + x86gpf(NULL,seg2&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + CS=seg2; + do_seg_load(&cpu_state.seg_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + cycles -= timing_call_pm_gate; + break; + + default: + x86gpf(NULL,seg2&~3); + return; + } + break; + + case 0x100: /*286 Task gate*/ + case 0x900: /*386 Task gate*/ + cpu_state.pc = old_pc; + cpl_override=1; + taskswitch286(seg,segdat,segdat[2]&0x800); + cpl_override=0; + break; + + default: + x86gpf(NULL,seg&~3); + return; + } + } + } + else + { + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + CS=seg; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + else cpu_state.seg_cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + } +} + +void pmoderetf(int is32, uint16_t off) +{ + uint32_t newpc; + uint32_t newsp; + uint32_t addr, oaddr; + uint16_t segdat[4],segdat2[4],seg,newss; + uint32_t oldsp=ESP; + x86seg_log("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,cpu_state.eflags); + if (is32) + { + newpc=POPL(); + seg=POPL(); if (cpu_state.abrt) return; + } + else + { + x86seg_log("PC read from %04X:%04X\n",SS,SP); + newpc=POPW(); + x86seg_log("CS read from %04X:%04X\n",SS,SP); + seg=POPW(); if (cpu_state.abrt) return; + } + x86seg_log("Return to %04X:%08X\n",seg,newpc); + if ((seg&3)=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } + oaddr = addr; + + x86seg_log("CPL %i RPL %i %i\n",CPL,seg&3,is32); + + if (stack32) ESP+=off; + else SP+=off; + + if (CPL==(seg&3)) + { + x86seg_log("RETF CPL = RPL %04X\n", segdat[2]); + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if (CPL != DPL) + { + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if (CPL < DPL) + { + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + default: + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + ESP=oldsp; + x86np("RETF CS not present\n", seg & 0xfffc); + return; + } + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + cpu_state.pc=newpc; + if (segdat[2] & 0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + CS = seg; + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat[3] & 0x40); + + cycles -= timing_retf_pm; + } + else + { + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((seg&3) != DPL) + { + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + x86seg_log("RETF non-conforming, %i %i\n",seg&3, DPL); + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((seg&3) < DPL) + { + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + x86seg_log("RETF conforming, %i %i\n",seg&3, DPL); + break; + default: + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + ESP=oldsp; + x86np("RETF CS not present\n", seg & 0xfffc); + return; + } + if (is32) + { + newsp=POPL(); + newss=POPL(); if (cpu_state.abrt) return; + } + else + { + x86seg_log("SP read from %04X:%04X\n",SS,SP); + newsp=POPW(); + x86seg_log("SS read from %04X:%04X\n",SS,SP); + newss=POPW(); if (cpu_state.abrt) return; + } + x86seg_log("Read new stack : %04X:%04X (%08X)\n", newss, newsp, ldt.base); + if (!(newss&~3)) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } + x86seg_log("Segment data %04X %04X %04X %04X\n", segdat2[0], segdat2[1], segdat2[2], segdat2[3]); + if ((newss & 3) != (seg & 3)) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + ESP=oldsp; + x86np("RETF loading SS not present\n", newss & 0xfffc); + return; + } + if (DPL2 != (seg & 3)) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + SS=newss; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&cpu_state.seg_ss, segdat2); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + +#ifdef CS_ACCESSED + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ +#endif + cpl_override = 0; +#endif + /*Conforming segments don't change CPL, so CPL = RPL*/ + if (segdat[2]&0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + + cpu_state.pc=newpc; + CS=seg; + do_seg_load(&cpu_state.seg_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat[3] & 0x40); + + if (stack32) ESP+=off; + else SP+=off; + + check_seg_valid(&cpu_state.seg_ds); + check_seg_valid(&cpu_state.seg_es); + check_seg_valid(&cpu_state.seg_fs); + check_seg_valid(&cpu_state.seg_gs); + cycles -= timing_retf_pm_outer; + } +} + +void pmodeint(int num, int soft) +{ + uint16_t segdat[4],segdat2[4],segdat3[4]; + uint32_t addr, oaddr; + uint16_t newss; + uint32_t oldss,oldsp; + int type; + uint32_t newsp; + uint16_t seg = 0; + int new_cpl; + + if (cpu_state.eflags&VM_FLAG && IOPL!=3 && soft) + { + x86seg_log("V86 banned int\n"); + x86gpf(NULL,0); + return; + } + addr=(num<<3); + if (addr>=idt.limit) + { + if (num==8) + { + /*Triple fault - reset!*/ + softresetx86(); + cpu_set_edx(); + } + else if (num==0xD) + { + pmodeint(8,0); + } + else + { + x86gpf(NULL,(num*8)+2+((soft)?0:1)); + } + x86seg_log("addr >= IDT.limit\n"); + return; + } + addr+=idt.base; + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(2,addr); + segdat[2]=readmemw(4,addr); + segdat[3]=readmemw(6,addr); cpl_override=0; + if (cpu_state.abrt) { + x86seg_log("Abrt reading from %08X\n",addr); + return; + } + oaddr = addr; + + x86seg_log("Addr %08X seg %04X %04X %04X %04X\n",addr,segdat[0],segdat[1],segdat[2],segdat[3]); + if (!(segdat[2]&0x1F00)) + { + x86gpf(NULL,(num*8)+2); + return; + } + if (DPL=0x800)?32:16; + if (!(segdat[2]&0x8000)) + { + x86np("Int gate not present\n", (num << 3) | 2); + return; + } + seg=segdat[1]; + new_cpl = seg & 3; + + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + oaddr = addr; + + if (DPL2 > CPL) + { + x86gpf(NULL,seg&~3); + return; + } + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if (DPL2=ldt.limit) + { + x86ss(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86ss(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat3[0]=readmemw(0,addr); + segdat3[1]=readmemw(0,addr+2); + segdat3[2]=readmemw(0,addr+4); + segdat3[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + if (((newss & 3) != DPL2) || (DPL3 != DPL2)) + { + x86ss(NULL,newss&~3); + return; + } + if ((segdat3[2]&0x1A00)!=0x1200) + { + x86ss(NULL,newss&~3); + return; + } + if (!(segdat3[2]&0x8000)) + { + x86np("Int gate loading SS not present\n", newss & 0xfffc); + return; + } + SS=newss; + set_stack32((segdat3[3] & 0x40) ? 1 : 0); + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&cpu_state.seg_ss, segdat3); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat3[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + x86seg_log("New stack %04X:%08X\n",SS,ESP); + cpl_override=1; + if (type>=0x800) + { + if (cpu_state.eflags & VM_FLAG) + { + PUSHL(GS); + PUSHL(FS); + PUSHL(DS); + PUSHL(ES); if (cpu_state.abrt) return; + loadseg(0,&cpu_state.seg_ds); + loadseg(0,&cpu_state.seg_es); + loadseg(0,&cpu_state.seg_fs); + loadseg(0,&cpu_state.seg_gs); + } + PUSHL(oldss); + PUSHL(oldsp); + PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); + PUSHL(CS); + PUSHL(cpu_state.pc); if (cpu_state.abrt) return; + } + else + { + PUSHW(oldss); + PUSHW(oldsp); + PUSHW(cpu_state.flags); + PUSHW(CS); + PUSHW(cpu_state.pc); if (cpu_state.abrt) return; + } + cpl_override=0; + cpu_state.seg_cs.access=0 | 0x80; + cycles -= timing_int_pm_outer - timing_int_pm; + break; + } + else if (DPL2!=CPL) + { + x86gpf(NULL,seg&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if (!(segdat2[2]&0x8000)) + { + x86np("Int gate CS not present\n", segdat[1] & 0xfffc); + return; + } + if ((cpu_state.eflags & VM_FLAG) && DPL20x800) + { + PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); + PUSHL(CS); + PUSHL(cpu_state.pc); if (cpu_state.abrt) return; + } + else + { + PUSHW(cpu_state.flags); + PUSHW(CS); + PUSHW(cpu_state.pc); if (cpu_state.abrt) return; + } + new_cpl = CS & 3; + break; + default: + x86gpf(NULL,seg&~3); + return; + } + do_seg_load(&cpu_state.seg_cs, segdat2); + CS = (seg & ~3) | new_cpl; + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | (new_cpl << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + if (type>0x800) cpu_state.pc=segdat[0]|(segdat[3]<<16); + else cpu_state.pc=segdat[0]; + set_use32(segdat2[3]&0x40); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, oaddr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + cpu_state.eflags &= ~VM_FLAG; + cpu_cur_status &= ~CPU_STATUS_V86; + if (!(type&0x100)) + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~(T_FLAG|NT_FLAG); + cycles -= timing_int_pm; + break; + + case 0x500: /*Task gate*/ + seg=segdat[1]; + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + cpl_override=0; if (cpu_state.abrt) return; + if (!(segdat2[2]&0x8000)) + { + x86np("Int task gate not present\n", segdat[1] & 0xfffc); + return; + } + optype=OPTYPE_INT; + cpl_override=1; + taskswitch286(seg,segdat2,segdat2[2]&0x800); + cpl_override=0; + break; + + default: + x86gpf(NULL,seg&~3); + return; + } +} + +void pmodeiret(int is32) +{ + uint32_t newsp; + uint16_t newss; + uint32_t tempflags,flagmask; + uint32_t newpc; + uint16_t segdat[4],segdat2[4]; + uint16_t segs[4]; + uint16_t seg = 0; + uint32_t addr, oaddr; + uint32_t oldsp=ESP; + if (is386 && (cpu_state.eflags & VM_FLAG)) + { + if (IOPL!=3) + { + x86gpf(NULL,0); + return; + } + if (is32) + { + newpc=POPL(); + seg=POPL(); + tempflags=POPL(); if (cpu_state.abrt) return; + } + else + { + newpc=POPW(); + seg=POPW(); + tempflags=POPW(); if (cpu_state.abrt) return; + } + cpu_state.pc=newpc; + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + cpu_state.seg_cs.access |= 0x80; + CS=seg; + cpu_state.flags = (cpu_state.flags & 0x3000) | (tempflags & 0xCFD5) | 2; + cycles -= timing_iret_rm; + return; + } + + if (cpu_state.flags & NT_FLAG) + { + seg=readmemw(tr.base,0); + addr=seg&~7; + if (seg&4) + { + x86seg_log("TS LDT %04X %04X IRET\n",seg,gdt.limit); + x86ts(NULL,seg&~3); + return; + } + else + { + if (addr>=gdt.limit) + { + x86ts(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); + taskswitch286(seg,segdat,segdat[2] & 0x800); + cpl_override=0; + return; + } + flagmask=0xFFFF; + if (CPL) flagmask&=~0x3000; + if (IOPL>16)&VM_FLAG)) + { + newsp=POPL(); + newss=POPL(); + segs[0]=POPL(); + segs[1]=POPL(); + segs[2]=POPL(); + segs[3]=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } + cpu_state.eflags = tempflags>>16; + cpu_cur_status |= CPU_STATUS_V86; + loadseg(segs[0],&cpu_state.seg_es); + do_seg_v86_init(&cpu_state.seg_es); + loadseg(segs[1],&cpu_state.seg_ds); + do_seg_v86_init(&cpu_state.seg_ds); + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + loadseg(segs[2],&cpu_state.seg_fs); + do_seg_v86_init(&cpu_state.seg_fs); + loadseg(segs[3],&cpu_state.seg_gs); + do_seg_v86_init(&cpu_state.seg_gs); + + cpu_state.pc = newpc & 0xffff; + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; + CS=seg; + cpu_state.seg_cs.access=(3<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + + ESP=newsp; + loadseg(newss,&cpu_state.seg_ss); + do_seg_v86_init(&cpu_state.seg_ss); + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + use32=0; + cpu_cur_status &= ~CPU_STATUS_USE32; + cpu_state.flags = (tempflags&0xFFD5)|2; + cycles -= timing_iret_v86; + return; + } + } + else + { + newpc=POPW(); + seg=POPW(); + tempflags=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } + } + if (!(seg&~3)) + { + ESP = oldsp; + x86gpf(NULL,0); + return; + } + + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + if ((seg&3) < CPL) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if ((seg&3) != DPL) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming code*/ + if ((seg&3) < DPL) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + default: + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + ESP = oldsp; + x86np("IRET CS not present\n", seg & 0xfffc); + return; + } + if ((seg&3) == CPL) + { + CS=seg; + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat[3]&0x40); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + cycles -= timing_iret_pm; + } + else /*Return to outer level*/ + { + oaddr = addr; + x86seg_log("Outer level\n"); + if (is32) + { + newsp=POPL(); + newss=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } + } + else + { + newsp=POPW(); + newss=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } + } + + x86seg_log("IRET load stack %04X:%04X\n",newss,newsp); + + if (!(newss&~3)) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } + if ((newss & 3) != (seg & 3)) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (DPL2 != (seg & 3)) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + ESP = oldsp; + x86np("IRET loading SS not present\n", newss & 0xfffc); + return; + } + SS=newss; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&cpu_state.seg_ss, segdat2); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + +#ifdef CS_ACCESSED + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ +#endif + cpl_override = 0; +#endif + /*Conforming segments don't change CPL, so CPL = RPL*/ + if (segdat[2]&0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + + CS=seg; + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat[3] & 0x40); + + check_seg_valid(&cpu_state.seg_ds); + check_seg_valid(&cpu_state.seg_es); + check_seg_valid(&cpu_state.seg_fs); + check_seg_valid(&cpu_state.seg_gs); + cycles -= timing_iret_pm_outer; + } + cpu_state.pc=newpc; + cpu_state.flags = (cpu_state.flags&~flagmask) | (tempflags&flagmask&0xFFD5)|2; + if (is32) cpu_state.eflags = tempflags>>16; +} + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) +{ + uint32_t base; + uint32_t limit; + uint32_t templ; + uint16_t tempw; + + uint32_t new_cr3=0; + uint16_t new_es,new_cs,new_ss,new_ds,new_fs,new_gs; + uint16_t new_ldt; + + uint32_t new_eax,new_ebx,new_ecx,new_edx,new_esp,new_ebp,new_esi,new_edi,new_pc,new_flags; + + uint32_t addr; + + uint16_t segdat2[4]; + + base=segdat[1]|((segdat[2]&0xFF)<<16); + limit=segdat[0]; + if(is386) + { + base |= (segdat[3]>>8)<<24; + limit |= (segdat[3]&0xF)<<16; + } + + if (is32) + { + if (limit < 103) + { + x86ts(NULL, seg); + return; + } + + if (optype==JMP || optype==CALL || optype==OPTYPE_INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); + else tempw=readmemw(gdt.base,(seg&~7)+4); + if (cpu_state.abrt) return; + tempw|=0x200; + if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); + else writememw(gdt.base,(seg&~7)+4,tempw); + } + if (cpu_state.abrt) return; + + if (optype==IRET) cpu_state.flags&=~NT_FLAG; + + cpu_386_flags_rebuild(); + writememl(tr.base,0x1C,cr3); + writememl(tr.base,0x20,cpu_state.pc); + writememl(tr.base,0x24,cpu_state.flags | (cpu_state.eflags<<16)); + + writememl(tr.base,0x28,EAX); + writememl(tr.base,0x2C,ECX); + writememl(tr.base,0x30,EDX); + writememl(tr.base,0x34,EBX); + writememl(tr.base,0x38,ESP); + writememl(tr.base,0x3C,EBP); + writememl(tr.base,0x40,ESI); + writememl(tr.base,0x44,EDI); + + writememl(tr.base,0x48,ES); + writememl(tr.base,0x4C,CS); + writememl(tr.base,0x50,SS); + writememl(tr.base,0x54,DS); + writememl(tr.base,0x58,FS); + writememl(tr.base,0x5C,GS); + + if (optype==JMP || optype==IRET) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); + else tempw=readmemw(gdt.base,(tr.seg&~7)+4); + if (cpu_state.abrt) return; + tempw&=~0x200; + if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); + else writememw(gdt.base,(tr.seg&~7)+4,tempw); + } + if (cpu_state.abrt) return; + + if (optype==OPTYPE_INT || optype==CALL) + { + writememl(base,0,tr.seg); + if (cpu_state.abrt) + return; + } + + + new_cr3=readmeml(base,0x1C); + new_pc=readmeml(base,0x20); + new_flags=readmeml(base,0x24); + if (optype == OPTYPE_INT || optype == CALL) + new_flags |= NT_FLAG; + + new_eax=readmeml(base,0x28); + new_ecx=readmeml(base,0x2C); + new_edx=readmeml(base,0x30); + new_ebx=readmeml(base,0x34); + new_esp=readmeml(base,0x38); + new_ebp=readmeml(base,0x3C); + new_esi=readmeml(base,0x40); + new_edi=readmeml(base,0x44); + + new_es=readmemw(base,0x48); + new_cs=readmemw(base,0x4C); + new_ss=readmemw(base,0x50); + new_ds=readmemw(base,0x54); + new_fs=readmemw(base,0x58); + new_gs=readmemw(base,0x5C); + new_ldt=readmemw(base,0x60); + + cr0 |= 8; + + cr3=new_cr3; + flushmmucache(); + + cpu_state.pc=new_pc; + cpu_state.flags = new_flags; + cpu_state.eflags = new_flags>>16; + cpu_386_flags_extract(); + + ldt.seg=new_ldt; + templ=(ldt.seg&~7)+gdt.base; + ldt.limit=readmemw(0,templ); + if (readmemb(0,templ+6)&0x80) + { + ldt.limit<<=12; + ldt.limit|=0xFFF; + } + ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); + + if (cpu_state.eflags & VM_FLAG) + { + loadcs(new_cs); + set_use32(0); + cpu_cur_status |= CPU_STATUS_V86; + } + else + { + if (!(new_cs&~3)) + { + x86ts(NULL,0); + return; + } + addr=new_cs&~7; + if (new_cs&4) + { + if (addr>=ldt.limit) + { + x86ts(NULL,new_cs&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86ts(NULL,new_cs&~3); + return; + } + addr+=gdt.base; + } + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + if (!(segdat2[2]&0x8000)) + { + x86np("TS loading CS not present\n", new_cs & 0xfffc); + return; + } + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((new_cs&3) != DPL2) + { + x86ts(NULL,new_cs&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((new_cs&3) < DPL2) + { + x86ts(NULL,new_cs&~3); + return; + } + break; + default: + x86ts(NULL,new_cs&~3); + return; + } + + CS=new_cs; + do_seg_load(&cpu_state.seg_cs, segdat2); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat2[3] & 0x40); + cpu_cur_status &= ~CPU_STATUS_V86; + } + + EAX=new_eax; + ECX=new_ecx; + EDX=new_edx; + EBX=new_ebx; + ESP=new_esp; + EBP=new_ebp; + ESI=new_esi; + EDI=new_edi; + + loadseg(new_es,&cpu_state.seg_es); + loadseg(new_ss,&cpu_state.seg_ss); + loadseg(new_ds,&cpu_state.seg_ds); + loadseg(new_fs,&cpu_state.seg_fs); + loadseg(new_gs,&cpu_state.seg_gs); + } + else + { + if (limit < 43) + { + x86ts(NULL, seg); + return; + } + + if (optype==JMP || optype==CALL || optype==OPTYPE_INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); + else tempw=readmemw(gdt.base,(seg&~7)+4); + if (cpu_state.abrt) return; + tempw|=0x200; + if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); + else writememw(gdt.base,(seg&~7)+4,tempw); + } + if (cpu_state.abrt) return; + + if (optype == IRET) + cpu_state.flags &= ~NT_FLAG; + + cpu_386_flags_rebuild(); + writememw(tr.base,0x0E,cpu_state.pc); + writememw(tr.base,0x10,cpu_state.flags); + + writememw(tr.base,0x12,AX); + writememw(tr.base,0x14,CX); + writememw(tr.base,0x16,DX); + writememw(tr.base,0x18,BX); + writememw(tr.base,0x1A,SP); + writememw(tr.base,0x1C,BP); + writememw(tr.base,0x1E,SI); + writememw(tr.base,0x20,DI); + + writememw(tr.base,0x22,ES); + writememw(tr.base,0x24,CS); + writememw(tr.base,0x26,SS); + writememw(tr.base,0x28,DS); + + if (optype==JMP || optype==IRET) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); + else tempw=readmemw(gdt.base,(tr.seg&~7)+4); + if (cpu_state.abrt) return; + tempw&=~0x200; + if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); + else writememw(gdt.base,(tr.seg&~7)+4,tempw); + } + if (cpu_state.abrt) return; + + if (optype==OPTYPE_INT || optype==CALL) + { + writememw(base,0,tr.seg); + if (cpu_state.abrt) + return; + } + + new_pc=readmemw(base,0x0E); + new_flags=readmemw(base,0x10); + if (optype == OPTYPE_INT || optype == CALL) + new_flags |= NT_FLAG; + + new_eax=readmemw(base,0x12); + new_ecx=readmemw(base,0x14); + new_edx=readmemw(base,0x16); + new_ebx=readmemw(base,0x18); + new_esp=readmemw(base,0x1A); + new_ebp=readmemw(base,0x1C); + new_esi=readmemw(base,0x1E); + new_edi=readmemw(base,0x20); + + new_es=readmemw(base,0x22); + new_cs=readmemw(base,0x24); + new_ss=readmemw(base,0x26); + new_ds=readmemw(base,0x28); + new_ldt=readmemw(base,0x2A); + + msw |= 8; + + cpu_state.pc=new_pc; + cpu_state.flags = new_flags; + cpu_386_flags_extract(); + + ldt.seg=new_ldt; + templ=(ldt.seg&~7)+gdt.base; + ldt.limit=readmemw(0,templ); + ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16); + if (is386) + { + if (readmemb(0,templ+6)&0x80) + { + ldt.limit<<=12; + ldt.limit|=0xFFF; + } + ldt.base|=(readmemb(0,templ+7)<<24); + } + + if (!(new_cs&~3)) + { + x86ts(NULL,0); + return; + } + addr=new_cs&~7; + if (new_cs&4) + { + if (addr>=ldt.limit) + { + x86ts(NULL,new_cs&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86ts(NULL,new_cs&~3); + return; + } + addr+=gdt.base; + } + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + if (!(segdat2[2]&0x8000)) + { + x86np("TS loading CS not present\n", new_cs & 0xfffc); + return; + } + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((new_cs&3) != DPL2) + { + x86ts(NULL,new_cs&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((new_cs&3) < DPL2) + { + x86ts(NULL,new_cs&~3); + return; + } + break; + default: + x86ts(NULL,new_cs&~3); + return; + } + + CS=new_cs; + do_seg_load(&cpu_state.seg_cs, segdat2); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(0); + + EAX=new_eax | 0xFFFF0000; + ECX=new_ecx | 0xFFFF0000; + EDX=new_edx | 0xFFFF0000; + EBX=new_ebx | 0xFFFF0000; + ESP=new_esp | 0xFFFF0000; + EBP=new_ebp | 0xFFFF0000; + ESI=new_esi | 0xFFFF0000; + EDI=new_edi | 0xFFFF0000; + + loadseg(new_es,&cpu_state.seg_es); + loadseg(new_ss,&cpu_state.seg_ss); + loadseg(new_ds,&cpu_state.seg_ds); + if (is386) + { + loadseg(0,&cpu_state.seg_fs); + loadseg(0,&cpu_state.seg_gs); + } + } + + tr.seg=seg; + tr.base=base; + tr.limit=limit; + tr.access=segdat[2]>>8; +} + diff --git a/src/memregs.h b/src/cpu_new/x86seg.h similarity index 50% rename from src/memregs.h rename to src/cpu_new/x86seg.h index c44cc21ed..4f12a8d65 100644 --- a/src/memregs.h +++ b/src/cpu_new/x86seg.h @@ -6,20 +6,13 @@ * * This file is part of the 86Box distribution. * - * Emulation of the memory I/O scratch registers on ports 0xE1 - * and 0xE2, used by just about any emulated machine. + * x86 CPU segment emulation. * - * Version: @(#)memregs.h 1.0.1 2017/08/23 + * Version: @(#)x86seg.h 1.0.1 2017/10/12 * * Author: Miran Grca, - * Copyright 2016,2017 Miran Grca. + * + * Copyright 2016-2017 Miran Grca. */ -#ifndef EMU_MEMREGS_H -# define EMU_MEMREGS_H - -extern void powermate_memregs_init(void); -extern void memregs_init(void); - - -#endif /*EMU_MEMREGS_H*/ +extern void do_seg_load(x86seg *s, uint16_t *segdat); diff --git a/src/cpu_new/x87.c b/src/cpu_new/x87.c new file mode 100644 index 000000000..367948656 --- /dev/null +++ b/src/cpu_new/x87.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#define fplog 0 +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" +#include "../pic.h" +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.h" +#include "386_common.h" + + +#ifdef ENABLE_FPU_LOG +int fpu_do_log = ENABLE_FPU_LOG; + + +static void +fpu_log(const char *fmt, ...) +{ + va_list ap; + + if (fpu_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define fpu_log(fmt, ...) +#endif + + +#define X87_TAG_VALID 0 +#define X87_TAG_ZERO 1 +#define X87_TAG_INVALID 2 +#define X87_TAG_EMPTY 3 + +uint16_t x87_gettag() +{ + uint16_t ret = 0; + int c; + + for (c = 0; c < 8; c++) + { + if (cpu_state.tag[c] == TAG_EMPTY) + ret |= X87_TAG_EMPTY << (c * 2); + else if (cpu_state.tag[c] & TAG_UINT64) + ret |= 2 << (c*2); + else if (cpu_state.ST[c] == 0.0 && !cpu_state.ismmx) + ret |= X87_TAG_ZERO << (c * 2); + else + ret |= X87_TAG_VALID << (c * 2); + } + + return ret; +} + +void x87_settag(uint16_t new_tag) +{ + int c; + + for (c = 0; c < 8; c++) + { + int tag = (new_tag >> (c * 2)) & 3; + + if (tag == X87_TAG_EMPTY) + cpu_state.tag[c] = TAG_EMPTY; + else if (tag == 2) + cpu_state.tag[c] = TAG_VALID | TAG_UINT64; + else + cpu_state.tag[c] = TAG_VALID; + } +} + + +#ifdef ENABLE_808X_LOG +void x87_dumpregs() +{ + if (cpu_state.ismmx) + { + fpu_log("MM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\n", cpu_state.MM[0].q, cpu_state.MM[1].q, cpu_state.MM[2].q, cpu_state.MM[3].q); + fpu_log("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", cpu_state.MM[4].q, cpu_state.MM[5].q, cpu_state.MM[6].q, cpu_state.MM[7].q); + } + else + { + fpu_log("ST(0)=%f\tST(1)=%f\tST(2)=%f\tST(3)=%f\t\n",cpu_state.ST[cpu_state.TOP],cpu_state.ST[(cpu_state.TOP+1)&7],cpu_state.ST[(cpu_state.TOP+2)&7],cpu_state.ST[(cpu_state.TOP+3)&7]); + fpu_log("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t\n",cpu_state.ST[(cpu_state.TOP+4)&7],cpu_state.ST[(cpu_state.TOP+5)&7],cpu_state.ST[(cpu_state.TOP+6)&7],cpu_state.ST[(cpu_state.TOP+7)&7]); + } + fpu_log("Status = %04X Control = %04X Tag = %04X\n", cpu_state.npxs, cpu_state.npxc, x87_gettag()); +} +#endif diff --git a/src/cpu_new/x87.h b/src/cpu_new/x87.h new file mode 100644 index 000000000..2d61c14ae --- /dev/null +++ b/src/cpu_new/x87.h @@ -0,0 +1,37 @@ +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +uint32_t x87_pc_off,x87_op_off; +uint16_t x87_pc_seg,x87_op_seg; + +static inline void x87_set_mmx() +{ + cpu_state.TOP = 0; + *(uint64_t *)cpu_state.tag = 0x0101010101010101ull; + cpu_state.ismmx = 1; +} + +static inline void x87_emms() +{ + *(uint64_t *)cpu_state.tag = 0; + cpu_state.ismmx = 0; +} + +uint16_t x87_gettag(); +void x87_settag(uint16_t new_tag); +void x87_dumpregs(); +void x87_reset(); + +#define TAG_EMPTY 0 +#define TAG_VALID (1 << 0) +/*Hack for FPU copy. If set then MM[].q contains the 64-bit integer loaded by FILD*/ +#define TAG_UINT64 (1 << 7) + +#define X87_ROUNDING_NEAREST 0 +#define X87_ROUNDING_DOWN 1 +#define X87_ROUNDING_UP 2 +#define X87_ROUNDING_CHOP 3 + +void codegen_set_rounding_mode(int mode); diff --git a/src/cpu_new/x87_ops.h b/src/cpu_new/x87_ops.h new file mode 100644 index 000000000..783a49382 --- /dev/null +++ b/src/cpu_new/x87_ops.h @@ -0,0 +1,1983 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * x87 FPU instructions core. + * + * Version: @(#)x87_ops.h 1.0.8 2019/06/11 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * leilei, + * Miran Grca, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 leilei. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. + */ +#include +#include +#ifdef _MSC_VER +# include +#endif + +#ifdef ENABLE_FPU_LOG +extern void fpu_log(const char *fmt, ...); +#else +#ifndef fpu_log +#define fpu_log(fmt, ...) +#endif +#endif + +static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO}; + +#define ST(x) cpu_state.ST[((cpu_state.TOP+(x))&7)] + +#define STATUS_ZERODIVIDE 4 + +#ifdef FPU_8087 +#define x87_div(dst, src1, src2) do \ + { \ + if (((double)src2) == 0.0) \ + { \ + cpu_state.npxs |= STATUS_ZERODIVIDE; \ + if (cpu_state.npxc & STATUS_ZERODIVIDE) \ + dst = src1 / (double)src2; \ + else \ + { \ + fpu_log("FPU : divide by zero\n"); \ + if (!(cpu_state.npxc & 0x80)) { \ + cpu_state.npxs |= 0x80; \ + nmi = 1; \ + } \ + return 1; \ + } \ + } \ + else \ + dst = src1 / (double)src2; \ + } while (0) +#else +#define x87_div(dst, src1, src2) do \ + { \ + if (((double)src2) == 0.0) \ + { \ + cpu_state.npxs |= STATUS_ZERODIVIDE; \ + if (cpu_state.npxc & STATUS_ZERODIVIDE) \ + dst = src1 / (double)src2; \ + else \ + { \ + fpu_log("FPU : divide by zero\n"); \ + picint(1 << 13); \ + return 1; \ + } \ + } \ + else \ + dst = src1 / (double)src2; \ + } while (0) +#endif + +static inline void x87_checkexceptions() +{ +} + +static inline void x87_push(double i) +{ + cpu_state.TOP--; + cpu_state.ST[cpu_state.TOP&7] = i; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; +} + +static inline void x87_push_u64(uint64_t i) +{ + union + { + double d; + uint64_t ll; + } td; + + td.ll = i; + + cpu_state.TOP--; + cpu_state.ST[cpu_state.TOP&7] = td.d; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; +} + +static inline double x87_pop() +{ + double t = cpu_state.ST[cpu_state.TOP&7]; + cpu_state.tag[cpu_state.TOP&7] = TAG_EMPTY; + cpu_state.TOP++; + return t; +} + +static inline int64_t x87_fround(double b) +{ + int64_t a, c; + + switch ((cpu_state.npxc >> 10) & 3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)floor(b); + case 2: /*Up*/ + return (int64_t)ceil(b); + case 3: /*Chop*/ + return (int64_t)b; + } + + return 0; +} +#define BIAS80 16383 +#define BIAS64 1023 + +static inline double x87_ld80() +{ + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + test.eind.ll = readmeml(easeg,cpu_state.eaaddr); + test.eind.ll |= (uint64_t)readmeml(easeg,cpu_state.eaaddr+4)<<32; + test.begin = readmemw(easeg,cpu_state.eaaddr+8); + + int64_t exp64 = (((test.begin&0x7fff) - BIAS80)); + int64_t blah = ((exp64 >0)?exp64:-exp64)&0x3ff; + int64_t exp64final = ((exp64 >0)?blah:-blah) +BIAS64; + + int64_t mant64 = (test.eind.ll >> 11) & (0xfffffffffffff); + int64_t sign = (test.begin&0x8000)?1:0; + + if ((test.begin & 0x7fff) == 0x7fff) + exp64final = 0x7ff; + if ((test.begin & 0x7fff) == 0) + exp64final = 0; + if (test.eind.ll & 0x400) + mant64++; + + test.eind.ll = (sign <<63)|(exp64final << 52)| mant64; + + return test.eind.d; +} + +static inline void x87_st80(double d) +{ + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + + test.eind.d=d; + + int64_t sign80 = (test.eind.ll&(0x8000000000000000))?1:0; + int64_t exp80 = test.eind.ll&(0x7ff0000000000000); + int64_t exp80final = (exp80>>52); + int64_t mant80 = test.eind.ll&(0x000fffffffffffff); + int64_t mant80final = (mant80 << 11); + + if (exp80final == 0x7ff) /*Infinity / Nan*/ + { + exp80final = 0x7fff; + mant80final |= (0x8000000000000000); + } + else if (d != 0){ //Zero is a special case + // Elvira wants the 8 and tcalc doesn't + mant80final |= (0x8000000000000000); + //Ca-cyber doesn't like this when result is zero. + exp80final += (BIAS80 - BIAS64); + } + test.begin = (((int16_t)sign80)<<15)| (int16_t)exp80final; + test.eind.ll = mant80final; + + writememl(easeg,cpu_state.eaaddr,test.eind.ll); + writememl(easeg,cpu_state.eaaddr+4,test.eind.ll>>32); + writememw(easeg,cpu_state.eaaddr+8,test.begin); +} + +static inline void x87_st_fsave(int reg) +{ + reg = (cpu_state.TOP + reg) & 7; + + if (cpu_state.tag[reg] & TAG_UINT64) + { + writememl(easeg, cpu_state.eaaddr, cpu_state.MM[reg].q & 0xffffffff); + writememl(easeg, cpu_state.eaaddr + 4, cpu_state.MM[reg].q >> 32); + writememw(easeg, cpu_state.eaaddr + 8, 0x5555); + } + else + x87_st80(cpu_state.ST[reg]); +} + +static inline void x87_ld_frstor(int reg) +{ + reg = (cpu_state.TOP + reg) & 7; + + cpu_state.MM[reg].q = readmemq(easeg, cpu_state.eaaddr); + cpu_state.MM_w4[reg] = readmemw(easeg, cpu_state.eaaddr + 8); + + if ((cpu_state.MM_w4[reg] == 0x5555) && (cpu_state.tag[reg] & TAG_UINT64)) + { + cpu_state.ST[reg] = (double)cpu_state.MM[reg].q; + } + else + { + cpu_state.tag[reg] &= ~TAG_UINT64; + cpu_state.ST[reg] = x87_ld80(); + } +} + +static inline void x87_ldmmx(MMX_REG *r, uint16_t *w4) +{ + r->l[0] = readmeml(easeg, cpu_state.eaaddr); + r->l[1] = readmeml(easeg, cpu_state.eaaddr + 4); + *w4 = readmemw(easeg, cpu_state.eaaddr + 8); +} + +static inline void x87_stmmx(MMX_REG r) +{ + writememl(easeg, cpu_state.eaaddr, r.l[0]); + writememl(easeg, cpu_state.eaaddr + 4, r.l[1]); + writememw(easeg, cpu_state.eaaddr + 8, 0xffff); +} + +#include + +static __inline uint16_t x87_compare(double a, double b) +{ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _M_IX86 || defined _M_X64 + uint32_t result; + double ea = a, eb = b; + const uint64_t ia = 0x3fec1a6ff866a936ull; + const uint64_t ib = 0x3fec1a6ff866a938ull; + + /* Hack to make CHKCOP happy. */ + if (!memcmp(&ea, &ia, 8) && !memcmp(&eb, &ib, 8)) + return C3; + + if (!is386 && !(cpu_state.npxc & 0x1000) && + ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) + eb = ea; + +#ifndef _MSC_VER + /* Memory barrier, to force GCC to write to the input parameters + * before the compare rather than after */ + __asm volatile ("" : : : "memory"); + + __asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fcompp\n" + "fnstsw %0\n" + : "=m" (result) + : "m" (ea), "m" (eb) + ); +#else + _ReadWriteBarrier(); + _asm + { + fld eb + fld ea + fclex + fcompp + fnstsw result + } +#endif + + return result & (C0|C2|C3); +#else + /* Generic C version is known to give incorrect results in some + * situations, eg comparison of infinity (Unreal) */ + uint32_t result = 0; + double ea = a, eb = b; + + if (!is386 && !(cpu_state.npxc & 0x1000) && + ((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) + eb = ea; + + if (ea == eb) + result |= C3; + else if (ea < eb) + result |= C0; + + return result; +#endif +} + +static inline uint16_t x87_ucompare(double a, double b) +{ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 || defined __amd64__ + uint32_t out; + + /* Memory barrier, to force GCC to write to the input parameters + * before the compare rather than after */ + asm volatile ("" : : : "memory"); + + asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fucompp\n" + "fnstsw %0\n" + : "=m" (out) + : "m" (a), "m" (b) + ); + + return out & (C0|C2|C3); +#else + /* Generic C version is known to give incorrect results in some + * situations, eg comparison of infinity (Unreal) */ + uint32_t out = 0; + + if (a == b) + out |= C3; + else if (a < b) + out |= C0; + + return out; +#endif +} + +typedef union +{ + float s; + uint32_t i; +} x87_ts; + +typedef union +{ + double d; + uint64_t i; +} x87_td; + +#ifdef FPU_8087 +#define FP_ENTER() { \ + fpucount++; \ + } +#else +#define FP_ENTER() do \ + { \ + if (cr0 & 0xc) \ + { \ + x86_int(7); \ + return 1; \ + } \ + fpucount++; \ + } while (0) +#endif + +#include "x87_ops_arith.h" +#include "x87_ops_misc.h" +#include "x87_ops_loadstore.h" + +#ifndef FPU_8087 +static int op_nofpu_a16(uint32_t fetchdat) +{ + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + else + { + fetch_ea_16(fetchdat); + return 0; + } +} +static int op_nofpu_a32(uint32_t fetchdat) +{ + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + else + { + fetch_ea_32(fetchdat); + return 0; + } +} +#endif + +#ifdef FPU_8087 +static int FPU_ILLEGAL_a16(uint32_t fetchdat) +{ + geteaw(); + wait(timing_rr, 0); + return 0; +} +#else +static int FPU_ILLEGAL_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int FPU_ILLEGAL_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} +#endif + +#define ILLEGAL_a16 FPU_ILLEGAL_a16 + +#ifdef FPU_8087 +const OpFn OP_TABLE(fpu_8087_d8)[32] = +{ + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; + +const OpFn OP_TABLE(fpu_8087_d9)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, ILLEGAL_a16, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a16, ILLEGAL_a16, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, ILLEGAL_a16, opFRNDINT, opFSCALE, ILLEGAL_a16, ILLEGAL_a16 +}; + +const OpFn OP_TABLE(fpu_8087_da)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; + +const OpFn OP_TABLE(fpu_8087_db)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFI, opFI, opFCLEX, opFINIT, ILLEGAL_a16, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; + +const OpFn OP_TABLE(fpu_8087_dc)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, ILLEGAL_a16, ILLEGAL_a16, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +const OpFn OP_TABLE(fpu_8087_dd)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; + +const OpFn OP_TABLE(fpu_8087_de)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_8087_df)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +#else +#define ILLEGAL_a32 FPU_ILLEGAL_a32 + +const OpFn OP_TABLE(fpu_d8_a16)[32] = +{ + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; +const OpFn OP_TABLE(fpu_d8_a32)[32] = +{ + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; + +const OpFn OP_TABLE(fpu_287_d9_a16)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, ILLEGAL_a16, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a16, ILLEGAL_a16, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, ILLEGAL_a16, opFRNDINT, opFSCALE, ILLEGAL_a16, ILLEGAL_a16 +}; + +const OpFn OP_TABLE(fpu_287_d9_a32)[256] = +{ + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a32, ILLEGAL_a32, opFTST, opFXAM, ILLEGAL_a32, ILLEGAL_a32, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a32, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a32, ILLEGAL_a32, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, ILLEGAL_a32, opFRNDINT, opFSCALE, ILLEGAL_a32, ILLEGAL_a32 +}; + +const OpFn OP_TABLE(fpu_d9_a16)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, ILLEGAL_a16, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a16, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +const OpFn OP_TABLE(fpu_d9_a32)[256] = +{ + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a32, ILLEGAL_a32, opFTST, opFXAM, ILLEGAL_a32, ILLEGAL_a32, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a32, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a32, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +const OpFn OP_TABLE(fpu_287_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_287_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFUCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, opFUCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_686_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, + opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, + opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, + opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFUCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_686_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, + opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, + opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, + opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, opFUCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_287_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_287_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_686_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_686_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_287_dc_a16)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, ILLEGAL_a16, ILLEGAL_a16, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; +const OpFn OP_TABLE(fpu_287_dc_a32)[32] = +{ + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDr, opFMULr, ILLEGAL_a32, ILLEGAL_a32, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +const OpFn OP_TABLE(fpu_dc_a16)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; +const OpFn OP_TABLE(fpu_dc_a32)[32] = +{ + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +const OpFn OP_TABLE(fpu_287_dd_a16)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_287_dd_a32)[256] = +{ + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_dd_a16)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_dd_a32)[256] = +{ + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_287_de_a16)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_287_de_a32)[256] = +{ + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, opFCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_de_a16)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, + ILLEGAL_a16, opFCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_de_a32)[256] = +{ + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, + ILLEGAL_a32, opFCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_287_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_287_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_686_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_686_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(nofpu_a16)[256] = +{ + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, +}; +const OpFn OP_TABLE(nofpu_a32)[256] = +{ + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, +}; +#endif + +#undef ILLEGAL diff --git a/src/cpu_new/x87_ops_arith.h b/src/cpu_new/x87_ops_arith.h new file mode 100644 index 000000000..26cab3ca6 --- /dev/null +++ b/src/cpu_new/x87_ops_arith.h @@ -0,0 +1,418 @@ +#define opFPU(name, optype, a_size, load_var, get, use_var) \ +static int opFADD ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + if ((cpu_state.npxc >> 10) & 3) \ + fesetround(rounding_modes[(cpu_state.npxc >> 10) & 3]); \ + ST(0) += use_var; \ + if ((cpu_state.npxc >> 10) & 3) \ + fesetround(FE_TONEAREST); \ + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; \ + CLOCK_CYCLES(8); \ + return 0; \ +} \ +static int opFCOM ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + cpu_state.npxs &= ~(C0|C2|C3); \ + cpu_state.npxs |= x87_compare(ST(0), (double)use_var); \ + CLOCK_CYCLES(4); \ + return 0; \ +} \ +static int opFCOMP ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + cpu_state.npxs &= ~(C0|C2|C3); \ + cpu_state.npxs |= x87_compare(ST(0), (double)use_var); \ + x87_pop(); \ + CLOCK_CYCLES(4); \ + return 0; \ +} \ +static int opFDIV ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + x87_div(ST(0), ST(0), use_var); \ + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; \ + CLOCK_CYCLES(73); \ + return 0; \ +} \ +static int opFDIVR ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + x87_div(ST(0), use_var, ST(0)); \ + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; \ + CLOCK_CYCLES(73); \ + return 0; \ +} \ +static int opFMUL ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + ST(0) *= use_var; \ + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; \ + CLOCK_CYCLES(11); \ + return 0; \ +} \ +static int opFSUB ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + ST(0) -= use_var; \ + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; \ + CLOCK_CYCLES(8); \ + return 0; \ +} \ +static int opFSUBR ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + ST(0) = use_var - ST(0); \ + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; \ + CLOCK_CYCLES(8); \ + return 0; \ +} + + +opFPU(s, x87_ts, 16, t.i, geteal, t.s) +#ifndef FPU_8087 +opFPU(s, x87_ts, 32, t.i, geteal, t.s) +#endif +opFPU(d, x87_td, 16, t.i, geteaq, t.d) +#ifndef FPU_8087 +opFPU(d, x87_td, 32, t.i, geteaq, t.d) +#endif + +opFPU(iw, uint16_t, 16, t, geteaw, (double)(int16_t)t) +#ifndef FPU_8087 +opFPU(iw, uint16_t, 32, t, geteaw, (double)(int16_t)t) +#endif +opFPU(il, uint32_t, 16, t, geteal, (double)(int32_t)t) +#ifndef FPU_8087 +opFPU(il, uint32_t, 32, t, geteal, (double)(int32_t)t) +#endif + + +static int opFADD(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = ST(0) + ST(fetchdat & 7); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(8); + return 0; +} +static int opFADDr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(8); + return 0; +} +static int opFADDP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFCOM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C2|C3); + if (ST(0) == ST(fetchdat & 7)) cpu_state.npxs |= C3; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.npxs |= C0; + CLOCK_CYCLES(4); + return 0; +} + +static int opFCOMP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C2|C3); + cpu_state.npxs |= x87_compare(ST(0), ST(fetchdat & 7)); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFCOMPP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C2|C3); + if (*(uint64_t *)&ST(0) == ((uint64_t)1 << 63) && *(uint64_t *)&ST(1) == 0) + cpu_state.npxs |= C0; /*Nasty hack to fix 80387 detection*/ + else + cpu_state.npxs |= x87_compare(ST(0), ST(1)); + + x87_pop(); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} +#ifndef FPU_8087 +static int opFUCOMPP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C2|C3); + cpu_state.npxs |= x87_ucompare(ST(0), ST(1)); + x87_pop(); + x87_pop(); + CLOCK_CYCLES(5); + return 0; +} + +static int opFCOMI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + flags_rebuild(); + cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; + CLOCK_CYCLES(4); + return 0; +} +static int opFCOMIP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + flags_rebuild(); + cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} +#endif + +static int opFDIV(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_div(ST(0), ST(0), ST(fetchdat & 7)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(73); + return 0; +} + +static int opFDIVR(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_div(ST(0), ST(fetchdat&7), ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVRr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVRP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(73); + return 0; +} + +static int opFMUL(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = ST(0) * ST(fetchdat & 7); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(16); + return 0; +} +static int opFMULr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(16); + return 0; +} +static int opFMULP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(16); + return 0; +} + +static int opFSUB(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = ST(0) - ST(fetchdat & 7); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFSUBR(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = ST(fetchdat & 7) - ST(0); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBRr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBRP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +#ifndef FPU_8087 +static int opFUCOM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C2|C3); + cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); + CLOCK_CYCLES(4); + return 0; +} + +static int opFUCOMP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C2|C3); + cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFUCOMI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + flags_rebuild(); + cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; + CLOCK_CYCLES(4); + return 0; +} +static int opFUCOMIP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + flags_rebuild(); + cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} +#endif diff --git a/src/cpu_new/x87_ops_loadstore.h b/src/cpu_new/x87_ops_loadstore.h new file mode 100644 index 000000000..ae7e8ae1a --- /dev/null +++ b/src/cpu_new/x87_ops_loadstore.h @@ -0,0 +1,492 @@ +static int opFILDiw_a16(uint32_t fetchdat) +{ + int16_t temp; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + x87_push((double)temp); + CLOCK_CYCLES(13); + return 0; +} +#ifndef FPU_8087 +static int opFILDiw_a32(uint32_t fetchdat) +{ + int16_t temp; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + temp = geteaw(); if (cpu_state.abrt) return 1; + x87_push((double)temp); + CLOCK_CYCLES(13); + return 0; +} +#endif + +static int opFISTiw_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); + CLOCK_CYCLES(29); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFISTiw_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); + CLOCK_CYCLES(29); + return cpu_state.abrt; +} +#endif + +static int opFISTPiw_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} +#ifndef FPU_8087 +static int opFISTPiw_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} +#endif + +static int opFILDiq_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + temp64 = geteaq(); if (cpu_state.abrt) return 1; + x87_push((double)temp64); + cpu_state.MM[cpu_state.TOP&7].q = temp64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID | TAG_UINT64; + + CLOCK_CYCLES(10); + return 0; +} +#ifndef FPU_8087 +static int opFILDiq_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + temp64 = geteaq(); if (cpu_state.abrt) return 1; + x87_push((double)temp64); + cpu_state.MM[cpu_state.TOP&7].q = temp64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID | TAG_UINT64; + + CLOCK_CYCLES(10); + return 0; +} +#endif + +static int FBSTP_a16(uint32_t fetchdat) +{ + double tempd; + int c; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + tempd = ST(0); + if (tempd < 0.0) + tempd = -tempd; + for (c = 0; c < 9; c++) + { + uint8_t tempc = (uint8_t)floor(fmod(tempd, 10.0)); + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + tempc |= ((uint8_t)floor(fmod(tempd, 10.0))) << 4; + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + writememb(easeg, cpu_state.eaaddr + c, tempc); + } + tempc = (uint8_t)floor(fmod(tempd, 10.0)); + if (ST(0) < 0.0) tempc |= 0x80; + writememb(easeg, cpu_state.eaaddr + 9, tempc); if (cpu_state.abrt) return 1; + x87_pop(); + return 0; +} +#ifndef FPU_8087 +static int FBSTP_a32(uint32_t fetchdat) +{ + double tempd; + int c; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + tempd = ST(0); + if (tempd < 0.0) + tempd = -tempd; + for (c = 0; c < 9; c++) + { + uint8_t tempc = (uint8_t)floor(fmod(tempd, 10.0)); + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + tempc |= ((uint8_t)floor(fmod(tempd, 10.0))) << 4; + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + writememb(easeg, cpu_state.eaaddr + c, tempc); + } + tempc = (uint8_t)floor(fmod(tempd, 10.0)); + if (ST(0) < 0.0) tempc |= 0x80; + writememb(easeg, cpu_state.eaaddr + 9, tempc); if (cpu_state.abrt) return 1; + x87_pop(); + return 0; +} +#endif + +static int FISTPiq_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + if (cpu_state.tag[cpu_state.TOP&7] & TAG_UINT64) + temp64 = cpu_state.MM[cpu_state.TOP&7].q; + else + temp64 = x87_fround(ST(0)); + seteaq(temp64); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} +#ifndef FPU_8087 +static int FISTPiq_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + if (cpu_state.tag[cpu_state.TOP&7] & TAG_UINT64) + temp64 = cpu_state.MM[cpu_state.TOP&7].q; + else + temp64 = x87_fround(ST(0)); + seteaq(temp64); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} +#endif + +static int opFILDil_a16(uint32_t fetchdat) +{ + int32_t templ; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + templ = geteal(); if (cpu_state.abrt) return 1; + x87_push((double)templ); + CLOCK_CYCLES(9); + return 0; +} +#ifndef FPU_8087 +static int opFILDil_a32(uint32_t fetchdat) +{ + int32_t templ; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + templ = geteal(); if (cpu_state.abrt) return 1; + x87_push((double)templ); + CLOCK_CYCLES(9); + return 0; +} +#endif + +static int opFISTil_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); + CLOCK_CYCLES(28); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFISTil_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); + CLOCK_CYCLES(28); + return cpu_state.abrt; +} +#endif + +static int opFISTPil_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(28); + return 0; +} +#ifndef FPU_8087 +static int opFISTPil_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(28); + return 0; +} +#endif + +static int opFLDe_a16(uint32_t fetchdat) +{ + double t; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + t=x87_ld80(); if (cpu_state.abrt) return 1; + x87_push(t); + CLOCK_CYCLES(6); + return 0; +} +#ifndef FPU_8087 +static int opFLDe_a32(uint32_t fetchdat) +{ + double t; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + t=x87_ld80(); if (cpu_state.abrt) return 1; + x87_push(t); + CLOCK_CYCLES(6); + return 0; +} +#endif + +static int opFSTPe_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + x87_st80(ST(0)); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(6); + return 0; +} +#ifndef FPU_8087 +static int opFSTPe_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + x87_st80(ST(0)); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(6); + return 0; +} +#endif + +static int opFLDd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + t.i = geteaq(); if (cpu_state.abrt) return 1; + x87_push(t.d); + CLOCK_CYCLES(3); + return 0; +} +#ifndef FPU_8087 +static int opFLDd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + t.i = geteaq(); if (cpu_state.abrt) return 1; + x87_push(t.d); + CLOCK_CYCLES(3); + return 0; +} +#endif + +static int opFSTd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + t.d = ST(0); + seteaq(t.i); + CLOCK_CYCLES(8); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFSTd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + t.d = ST(0); + seteaq(t.i); + CLOCK_CYCLES(8); + return cpu_state.abrt; +} +#endif + +static int opFSTPd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); + t.d = ST(0); + seteaq(t.i); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} +#ifndef FPU_8087 +static int opFSTPd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); + t.d = ST(0); + seteaq(t.i); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} +#endif + +static int opFLDs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + ts.i = geteal(); if (cpu_state.abrt) return 1; + x87_push((double)ts.s); + CLOCK_CYCLES(3); + return 0; +} +#ifndef FPU_8087 +static int opFLDs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + ts.i = geteal(); if (cpu_state.abrt) return 1; + x87_push((double)ts.s); + CLOCK_CYCLES(3); + return 0; +} +#endif + +static int opFSTs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + ts.s = (float)ST(0); + seteal(ts.i); + CLOCK_CYCLES(7); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFSTs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + ts.s = (float)ST(0); + seteal(ts.i); + CLOCK_CYCLES(7); + return cpu_state.abrt; +} +#endif + +static int opFSTPs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + ts.s = (float)ST(0); + seteal(ts.i); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(7); + return 0; +} +#ifndef FPU_8087 +static int opFSTPs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + ts.s = (float)ST(0); + seteal(ts.i); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(7); + return 0; +} +#endif diff --git a/src/cpu_new/x87_ops_misc.h b/src/cpu_new/x87_ops_misc.h new file mode 100644 index 000000000..6cccfd429 --- /dev/null +++ b/src/cpu_new/x87_ops_misc.h @@ -0,0 +1,861 @@ +#ifdef FPU_8087 +static int opFI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxc &= ~0x80; + if (rmdat == 0xe1) + cpu_state.npxc |= 0x80; + wait(3, 0); + return 0; +} +#else +static int opFSTSW_AX(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + AX = cpu_state.npxs; + CLOCK_CYCLES(3); + return 0; +} +#endif + + +static int opFNOP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + CLOCK_CYCLES(4); + return 0; +} + +static int opFCLEX(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= 0xff00; + CLOCK_CYCLES(4); + return 0; +} + +static int opFINIT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; +#ifdef FPU_8087 + cpu_state.npxc = 0x3FF; +#else + cpu_state.npxc = 0x37F; +#endif + codegen_set_rounding_mode(X87_ROUNDING_NEAREST); + cpu_state.npxs = 0; + *(uint64_t *)cpu_state.tag = 0; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + CLOCK_CYCLES(17); + CPU_BLOCK_END(); + return 0; +} + + +static int opFFREE(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_EMPTY; + CLOCK_CYCLES(3); + return 0; +} + +static int opFFREEP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + fpu_log("FFREE\n"); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3; if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(3); + return 0; +} + +static int opFST(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; + CLOCK_CYCLES(3); + return 0; +} + +static int opFSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(fetchdat & 7) = ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; + x87_pop(); + CLOCK_CYCLES(3); + return 0; +} + + + + +static int FSTOR() +{ + FP_ENTER(); + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + case 0x001: /*16-bit protected mode*/ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2); + x87_settag(readmemw(easeg, cpu_state.eaaddr+4)); + cpu_state.TOP = (cpu_state.npxs >> 11) & 7; + cpu_state.eaaddr += 14; + break; + case 0x100: /*32-bit real mode*/ + case 0x101: /*32-bit protected mode*/ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4); + x87_settag(readmemw(easeg, cpu_state.eaaddr+8)); + cpu_state.TOP = (cpu_state.npxs >> 11) & 7; + cpu_state.eaaddr += 28; + break; + } + x87_ld_frstor(0); cpu_state.eaaddr += 10; + x87_ld_frstor(1); cpu_state.eaaddr += 10; + x87_ld_frstor(2); cpu_state.eaaddr += 10; + x87_ld_frstor(3); cpu_state.eaaddr += 10; + x87_ld_frstor(4); cpu_state.eaaddr += 10; + x87_ld_frstor(5); cpu_state.eaaddr += 10; + x87_ld_frstor(6); cpu_state.eaaddr += 10; + x87_ld_frstor(7); + + cpu_state.ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + if (cpu_state.MM_w4[0] == 0xffff && cpu_state.MM_w4[1] == 0xffff && cpu_state.MM_w4[2] == 0xffff && cpu_state.MM_w4[3] == 0xffff && + cpu_state.MM_w4[4] == 0xffff && cpu_state.MM_w4[5] == 0xffff && cpu_state.MM_w4[6] == 0xffff && cpu_state.MM_w4[7] == 0xffff && + !cpu_state.TOP && (*(uint64_t *)cpu_state.tag == 0x0101010101010101ull)) + cpu_state.ismmx = 1; + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + return cpu_state.abrt; +} +static int opFSTOR_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + FSTOR(); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFSTOR_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + FSTOR(); + return cpu_state.abrt; +} +#endif + +static int FSAVE() +{ + FP_ENTER(); + cpu_state.npxs = (cpu_state.npxs & ~(7 << 11)) | ((cpu_state.TOP & 7) << 11); + + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+4,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+6,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+10,x87_op_off); + cpu_state.eaaddr+=14; + if (cpu_state.ismmx) + { + x87_stmmx(cpu_state.MM[0]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[1]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[2]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[3]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[4]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[5]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[6]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[7]); + } + else + { + x87_st_fsave(0); cpu_state.eaaddr+=10; + x87_st_fsave(1); cpu_state.eaaddr+=10; + x87_st_fsave(2); cpu_state.eaaddr+=10; + x87_st_fsave(3); cpu_state.eaaddr+=10; + x87_st_fsave(4); cpu_state.eaaddr+=10; + x87_st_fsave(5); cpu_state.eaaddr+=10; + x87_st_fsave(6); cpu_state.eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x001: /*16-bit protected mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+4,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+6,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+8,x87_pc_seg); + writememw(easeg,cpu_state.eaaddr+10,x87_op_off); + writememw(easeg,cpu_state.eaaddr+12,x87_op_seg); + cpu_state.eaaddr+=14; + if (cpu_state.ismmx) + { + x87_stmmx(cpu_state.MM[0]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[1]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[2]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[3]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[4]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[5]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[6]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[7]); + } + else + { + x87_st_fsave(0); cpu_state.eaaddr+=10; + x87_st_fsave(1); cpu_state.eaaddr+=10; + x87_st_fsave(2); cpu_state.eaaddr+=10; + x87_st_fsave(3); cpu_state.eaaddr+=10; + x87_st_fsave(4); cpu_state.eaaddr+=10; + x87_st_fsave(5); cpu_state.eaaddr+=10; + x87_st_fsave(6); cpu_state.eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x100: /*32-bit real mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+4,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+8,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+12,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+20,x87_op_off); + writememl(easeg,cpu_state.eaaddr+24,(x87_op_off>>16)<<12); + cpu_state.eaaddr+=28; + if (cpu_state.ismmx) + { + x87_stmmx(cpu_state.MM[0]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[1]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[2]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[3]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[4]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[5]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[6]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[7]); + } + else + { + x87_st_fsave(0); cpu_state.eaaddr+=10; + x87_st_fsave(1); cpu_state.eaaddr+=10; + x87_st_fsave(2); cpu_state.eaaddr+=10; + x87_st_fsave(3); cpu_state.eaaddr+=10; + x87_st_fsave(4); cpu_state.eaaddr+=10; + x87_st_fsave(5); cpu_state.eaaddr+=10; + x87_st_fsave(6); cpu_state.eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x101: /*32-bit protected mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+4,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+8,x87_gettag()); + writememl(easeg,cpu_state.eaaddr+12,x87_pc_off); + writememl(easeg,cpu_state.eaaddr+16,x87_pc_seg); + writememl(easeg,cpu_state.eaaddr+20,x87_op_off); + writememl(easeg,cpu_state.eaaddr+24,x87_op_seg); + cpu_state.eaaddr+=28; + if (cpu_state.ismmx) + { + x87_stmmx(cpu_state.MM[0]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[1]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[2]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[3]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[4]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[5]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[6]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[7]); + } + else + { + x87_st_fsave(0); cpu_state.eaaddr+=10; + x87_st_fsave(1); cpu_state.eaaddr+=10; + x87_st_fsave(2); cpu_state.eaaddr+=10; + x87_st_fsave(3); cpu_state.eaaddr+=10; + x87_st_fsave(4); cpu_state.eaaddr+=10; + x87_st_fsave(5); cpu_state.eaaddr+=10; + x87_st_fsave(6); cpu_state.eaaddr+=10; + x87_st_fsave(7); + } + break; + } + + cpu_state.npxc = 0x37F; + codegen_set_rounding_mode(X87_ROUNDING_NEAREST); + cpu_state.npxs = 0; + *(uint64_t *)cpu_state.tag = 0; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + return cpu_state.abrt; +} +static int opFSAVE_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + FSAVE(); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFSAVE_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + FSAVE(); + return cpu_state.abrt; +} +#endif + +static int opFSTSW_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw((cpu_state.npxs & 0xC7FF) | ((cpu_state.TOP & 7) << 11)); + CLOCK_CYCLES(3); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFSTSW_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw((cpu_state.npxs & 0xC7FF) | ((cpu_state.TOP & 7) << 11)); + CLOCK_CYCLES(3); + return cpu_state.abrt; +} +#endif + + +static int opFLD(uint32_t fetchdat) +{ + int old_tag; + uint64_t old_i64; + + FP_ENTER(); + cpu_state.pc++; + old_tag = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; + old_i64 = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; + x87_push(ST(fetchdat&7)); + cpu_state.tag[cpu_state.TOP&7] = old_tag; + cpu_state.MM[cpu_state.TOP&7].q = old_i64; + CLOCK_CYCLES(4); + return 0; +} + +static int opFXCH(uint32_t fetchdat) +{ + double td; + uint8_t old_tag; + uint64_t old_i64; + FP_ENTER(); + cpu_state.pc++; + td = ST(0); + ST(0) = ST(fetchdat&7); + ST(fetchdat&7) = td; + old_tag = cpu_state.tag[cpu_state.TOP&7]; + cpu_state.tag[cpu_state.TOP&7] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = old_tag; + old_i64 = cpu_state.MM[cpu_state.TOP&7].q; + cpu_state.MM[cpu_state.TOP&7].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; + cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q = old_i64; + + CLOCK_CYCLES(4); + return 0; +} + +static int opFCHS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = -ST(0); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(6); + return 0; +} + +static int opFABS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = fabs(ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(3); + return 0; +} + +static int opFTST(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C2|C3); + if (ST(0) == 0.0) cpu_state.npxs |= C3; + else if (ST(0) < 0.0) cpu_state.npxs |= C0; + CLOCK_CYCLES(4); + return 0; +} + +static int opFXAM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= ~(C0|C1|C2|C3); + if (cpu_state.tag[cpu_state.TOP&7] == TAG_EMPTY) cpu_state.npxs |= (C0|C3); + else if (ST(0) == 0.0) cpu_state.npxs |= C3; + else cpu_state.npxs |= C2; + if (ST(0) < 0.0) cpu_state.npxs |= C1; + CLOCK_CYCLES(8); + return 0; +} + +static int opFLD1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push(1.0); + CLOCK_CYCLES(4); + return 0; +} + +static int opFLDL2T(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push(3.3219280948873623); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDL2E(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push(1.4426950408889634); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDPI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push(3.141592653589793); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDEG2(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push(0.3010299956639812); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDLN2(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push_u64(0x3fe62e42fefa39f0ull); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDZ(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + x87_push(0.0); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(4); + return 0; +} + +static int opF2XM1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = pow(2.0, ST(0)) - 1.0; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(200); + return 0; +} + +static int opFYL2X(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(1) = ST(1) * (log(ST(0)) / log(2.0)); + cpu_state.tag[(cpu_state.TOP + 1) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFYL2XP1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(1) = ST(1) * (log(ST(0)+1.0) / log(2.0)); + cpu_state.tag[(cpu_state.TOP + 1) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFPTAN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = tan(ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + x87_push(1.0); + cpu_state.npxs &= ~C2; + CLOCK_CYCLES(235); + return 0; +} + +static int opFPATAN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(1) = atan2(ST(1), ST(0)); + cpu_state.tag[(cpu_state.TOP + 1) & 7] = TAG_VALID; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFDECSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.TOP--; + CLOCK_CYCLES(4); + return 0; +} + +static int opFINCSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.TOP++; + CLOCK_CYCLES(4); + return 0; +} + +static int opFPREM(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + temp64 = (int64_t)(ST(0) / ST(1)); + ST(0) = ST(0) - (ST(1) * (double)temp64); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + cpu_state.npxs &= ~(C0|C1|C2|C3); + if (temp64 & 4) cpu_state.npxs|=C0; + if (temp64 & 2) cpu_state.npxs|=C3; + if (temp64 & 1) cpu_state.npxs|=C1; + CLOCK_CYCLES(100); + return 0; +} +#ifndef FPU_8087 +static int opFPREM1(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + temp64 = (int64_t)(ST(0) / ST(1)); + ST(0) = ST(0) - (ST(1) * (double)temp64); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + cpu_state.npxs &= ~(C0|C1|C2|C3); + if (temp64 & 4) cpu_state.npxs|=C0; + if (temp64 & 2) cpu_state.npxs|=C3; + if (temp64 & 1) cpu_state.npxs|=C1; + CLOCK_CYCLES(100); + return 0; +} +#endif + +static int opFSQRT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = sqrt(ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(83); + return 0; +} + +#ifndef FPU_8087 +static int opFSINCOS(uint32_t fetchdat) +{ + double td; + FP_ENTER(); + cpu_state.pc++; + td = ST(0); + ST(0) = sin(td); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + x87_push(cos(td)); + cpu_state.npxs &= ~C2; + CLOCK_CYCLES(330); + return 0; +} +#endif + +static int opFRNDINT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = (double)x87_fround(ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(21); + return 0; +} + +static int opFSCALE(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + temp64 = (int64_t)ST(1); + ST(0) = ST(0) * pow(2.0, (double)temp64); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(30); + return 0; +} + +#ifndef FPU_8087 +static int opFSIN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = sin(ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + cpu_state.npxs &= ~C2; + CLOCK_CYCLES(300); + return 0; +} + +static int opFCOS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + ST(0) = cos(ST(0)); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + cpu_state.npxs &= ~C2; + CLOCK_CYCLES(300); + return 0; +} +#endif + + +static int FLDENV() +{ + FP_ENTER(); + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + case 0x001: /*16-bit protected mode*/ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2); + x87_settag(readmemw(easeg, cpu_state.eaaddr+4)); + cpu_state.TOP = (cpu_state.npxs >> 11) & 7; + break; + case 0x100: /*32-bit real mode*/ + case 0x101: /*32-bit protected mode*/ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4); + x87_settag(readmemw(easeg, cpu_state.eaaddr+8)); + cpu_state.TOP = (cpu_state.npxs >> 11) & 7; + break; + } + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + return cpu_state.abrt; +} + +static int opFLDENV_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + FLDENV(); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFLDENV_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + FLDENV(); + return cpu_state.abrt; +} +#endif + +static int opFLDCW_a16(uint32_t fetchdat) +{ + uint16_t tempw; + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + tempw = geteaw(); + if (cpu_state.abrt) return 1; + cpu_state.npxc = tempw; + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + CLOCK_CYCLES(4); + return 0; +} +#ifndef FPU_8087 +static int opFLDCW_a32(uint32_t fetchdat) +{ + uint16_t tempw; + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + tempw = geteaw(); + if (cpu_state.abrt) return 1; + cpu_state.npxc = tempw; + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + CLOCK_CYCLES(4); + return 0; +} +#endif + +static int FSTENV() +{ + FP_ENTER(); + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+4,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+6,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+10,x87_op_off); + break; + case 0x001: /*16-bit protected mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+4,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+6,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+8,x87_pc_seg); + writememw(easeg,cpu_state.eaaddr+10,x87_op_off); + writememw(easeg,cpu_state.eaaddr+12,x87_op_seg); + break; + case 0x100: /*32-bit real mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+4,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+8,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+12,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+20,x87_op_off); + writememl(easeg,cpu_state.eaaddr+24,(x87_op_off>>16)<<12); + break; + case 0x101: /*32-bit protected mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+4,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+8,x87_gettag()); + writememl(easeg,cpu_state.eaaddr+12,x87_pc_off); + writememl(easeg,cpu_state.eaaddr+16,x87_pc_seg); + writememl(easeg,cpu_state.eaaddr+20,x87_op_off); + writememl(easeg,cpu_state.eaaddr+24,x87_op_seg); + break; + } + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + return cpu_state.abrt; +} + +static int opFSTENV_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + FSTENV(); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFSTENV_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + FSTENV(); + return cpu_state.abrt; +} +#endif + +static int opFSTCW_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(cpu_state.npxc); + CLOCK_CYCLES(3); + return cpu_state.abrt; +} +#ifndef FPU_8087 +static int opFSTCW_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + seteaw(cpu_state.npxc); + CLOCK_CYCLES(3); + return cpu_state.abrt; +} +#endif + +#ifndef FPU_8087 +#define opFCMOV(condition) \ + static int opFCMOV ## condition(uint32_t fetchdat) \ + { \ + FP_ENTER(); \ + cpu_state.pc++; \ + if (cond_ ## condition) \ + { \ + cpu_state.tag[cpu_state.TOP&7] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; \ + cpu_state.MM[cpu_state.TOP&7].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; \ + ST(0) = ST(fetchdat & 7); \ + } \ + CLOCK_CYCLES(4); \ + return 0; \ + } + +#define cond_U ( PF_SET()) +#define cond_NU (!PF_SET()) + +opFCMOV(B) +opFCMOV(E) +opFCMOV(BE) +opFCMOV(U) +opFCMOV(NB) +opFCMOV(NE) +opFCMOV(NBE) +opFCMOV(NU) +#endif diff --git a/src/device.c b/src/device.c index 47810bb09..97318c50d 100644 --- a/src/device.c +++ b/src/device.c @@ -9,15 +9,15 @@ * Implementation of the generic device interface to handle * all devices attached to the emulator. * - * Version: @(#)device.c 1.0.23 2018/11/06 + * Version: @(#)device.c 1.0.24 2019/03/014 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -56,7 +56,7 @@ static device_t *devices[DEVICE_MAX]; static void *device_priv[DEVICE_MAX]; -static device_context_t device_current; +static device_context_t device_current, device_prev; #ifdef ENABLE_DEVICE_LOG @@ -99,12 +99,40 @@ device_set_context(device_context_t *c, const device_t *d, int inst) } -void * -device_add_common(const device_t *d, void *p, int inst) +static void +device_context_common(const device_t *d, int inst) +{ + memcpy(&device_prev, &device_current, sizeof(device_context_t)); + device_set_context(&device_current, d, inst); +} + + +void +device_context(const device_t *d) +{ + device_context_common(d, 0); +} + + +void +device_context_inst(const device_t *d, int inst) +{ + device_context_common(d, inst); +} + + +void +device_context_restore(void) +{ + memcpy(&device_current, &device_prev, sizeof(device_context_t)); +} + + +static void * +device_add_common(const device_t *d, const device_t *cd, void *p, int inst) { void *priv = NULL; int c; - device_context_t old; for (c = 0; c < 256; c++) { if (!inst && (devices[c] == (device_t *) d)) { @@ -121,8 +149,8 @@ device_add_common(const device_t *d, void *p, int inst) devices[c] = (device_t *)d; if (p == NULL) { - memcpy(&old, &device_current, sizeof(device_context_t)); - device_set_context(&device_current, d, inst); + memcpy(&device_prev, &device_current, sizeof(device_context_t)); + device_set_context(&device_current, cd, inst); if (d->init != NULL) { priv = d->init(d); @@ -139,7 +167,12 @@ device_add_common(const device_t *d, void *p, int inst) } } - memcpy(&device_current, &old, sizeof(device_context_t)); + if (d->name) + device_log("DEVICE: device '%s' init successful\n", d->name); + else + device_log("DEVICE: device init successful\n"); + + memcpy(&device_current, &device_prev, sizeof(device_context_t)); device_priv[c] = priv; } else device_priv[c] = p; @@ -151,7 +184,7 @@ device_add_common(const device_t *d, void *p, int inst) void * device_add(const device_t *d) { - return device_add_common(d, NULL, 0); + return device_add_common(d, d, NULL, 0); } @@ -159,14 +192,14 @@ device_add(const device_t *d) void device_add_ex(const device_t *d, void *priv) { - device_add_common(d, priv, 0); + device_add_common(d, d, priv, 0); } void * device_add_inst(const device_t *d, int inst) { - return device_add_common(d, NULL, inst); + return device_add_common(d, d, NULL, inst); } @@ -174,7 +207,39 @@ device_add_inst(const device_t *d, int inst) void device_add_inst_ex(const device_t *d, void *priv, int inst) { - device_add_common(d, priv, inst); + device_add_common(d, d, priv, inst); +} + + +/* These four are to add a device with another device's context - will be + used to add machines' internal devices. */ +void * +device_cadd(const device_t *d, const device_t *cd) +{ + return device_add_common(d, cd, NULL, 0); +} + + +/* For devices that do not have an init function (internal video etc.) */ +void +device_cadd_ex(const device_t *d, const device_t *cd, void *priv) +{ + device_add_common(d, cd, priv, 0); +} + + +void * +device_cadd_inst(const device_t *d, const device_t *cd, int inst) +{ + return device_add_common(d, cd, NULL, inst); +} + + +/* For devices that do not have an init function (internal video etc.) */ +void +device_cadd_inst_ex(const device_t *d, const device_t *cd, void *priv, int inst) +{ + device_add_common(d, cd, priv, inst); } @@ -462,7 +527,6 @@ device_is_valid(const device_t *device, int mflags) if ((device->flags & DEVICE_PCI) && !(mflags & MACHINE_PCI)) return(0); - if ((device->flags & DEVICE_PS2) && !(mflags & MACHINE_HDC_PS2)) return(0); if ((device->flags & DEVICE_AGP) && !(mflags & MACHINE_AGP)) return(0); return(1); diff --git a/src/device.h b/src/device.h index 3b103f11b..e59952205 100644 --- a/src/device.h +++ b/src/device.h @@ -8,15 +8,15 @@ * * Definitions for the device handler. * - * Version: @(#)device.h 1.0.11 2018/11/12 + * Version: @(#)device.h 1.0.12 2019/03/14 * * Authors: Fred N. van Kempen, * Miran Grca, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -121,15 +121,22 @@ extern "C" { extern void device_init(void); extern void device_set_context(device_context_t *c, const device_t *d, int inst); -extern void *device_add(const device_t *); +extern void device_context(const device_t *d); +extern void device_context_inst(const device_t *d, int inst); +extern void device_context_restore(void); +extern void *device_add(const device_t *d); extern void device_add_ex(const device_t *d, void *priv); -extern void *device_add_inst(const device_t *, int inst); +extern void *device_add_inst(const device_t *d, int inst); extern void device_add_inst_ex(const device_t *d, void *priv, int inst); +extern void *device_cadd(const device_t *d, const device_t *cd); +extern void device_cadd_ex(const device_t *d, const device_t *cd, void *priv); +extern void *device_cadd_inst(const device_t *d, const device_t *cd, int inst); +extern void device_cadd_inst_ex(const device_t *d, const device_t *cd, void *priv, int inst); extern void device_close_all(void); extern void device_reset_all(void); extern void device_reset_all_pci(void); -extern void *device_get_priv(const device_t *); -extern int device_available(const device_t *); +extern void *device_get_priv(const device_t *d); +extern int device_available(const device_t *d); extern void device_speed_changed(void); extern void device_force_redraw(void); diff --git a/src/disk/hdc.c b/src/disk/hdc.c index 84c71e765..4b1313cb1 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -104,14 +104,26 @@ static const struct { { "Internal Controller", "internal", &inthdc_device }, - { "[ISA] [MFM] IBM PC Fixed Disk Adapter", "mfm_xt", - &mfm_xt_xebec_device }, + { "[ISA] [MFM] IBM PC Fixed Disk Adapter", "st506_xt", + &st506_xt_xebec_device }, - { "[ISA] [MFM] DTC-5150X Fixed Disk Adapter", "mfm_dtc5150x", - &mfm_xt_dtc5150x_device }, + { "[ISA] [MFM] DTC-5150X Fixed Disk Adapter", "st506_xt_dtc5150x", + &st506_xt_dtc5150x_device }, - { "[ISA] [MFM] IBM PC/AT Fixed Disk Adapter", "mfm_at", - &mfm_at_wd1003_device }, + { "[ISA] [MFM] ST-11M Fixed Disk Adapter", "st506_xt_st11_m", + &st506_xt_st11_m_device }, + + { "[ISA] [MFM] WD1002A-WX1 Fixed Disk Adapter", "st506_xt_wd1002a_wx1", + &st506_xt_wd1002a_wx1_device }, + + { "[ISA] [MFM/RLL] IBM PC/AT Fixed Disk Adapter", "st506_at", + &st506_at_wd1003_device }, + + { "[ISA] [RLL] ST-11R Fixed Disk Adapter", "st506_xt_st11_r", + &st506_xt_st11_r_device }, + + { "[ISA] [RLL] WD1002A-27X Fixed Disk Adapter", "st506_xt_wd1002a_27x", + &st506_xt_wd1002a_27x_device }, { "[ISA] [ESDI] PC/AT ESDI Fixed Disk Adapter", "esdi_at", &esdi_at_wd1007vse1_device }, diff --git a/src/disk/hdc.h b/src/disk/hdc.h index 37b4af09f..c5e8d624c 100644 --- a/src/disk/hdc.h +++ b/src/disk/hdc.h @@ -8,13 +8,13 @@ * * Definitions for the common disk controller handler. * - * Version: @(#)hdc.h 1.0.10 2018/11/18 + * Version: @(#)hdc.h 1.0.11 2019/03/03 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_HDC_H # define EMU_HDC_H @@ -31,9 +31,13 @@ extern int hdc_current; -extern const device_t mfm_xt_xebec_device; /* mfm_xt_xebec */ -extern const device_t mfm_xt_dtc5150x_device; /* mfm_xt_dtc */ -extern const device_t mfm_at_wd1003_device; /* mfm_at_wd1003 */ +extern const device_t st506_xt_xebec_device; /* st506_xt_xebec */ +extern const device_t st506_xt_dtc5150x_device; /* st506_xt_dtc */ +extern const device_t st506_xt_st11_m_device; /* st506_xt_st11_m */ +extern const device_t st506_xt_st11_r_device; /* st506_xt_st11_m */ +extern const device_t st506_xt_wd1002a_wx1_device; /* st506_xt_wd1002a_wx1 */ +extern const device_t st506_xt_wd1002a_27x_device; /* st506_xt_wd1002a_27x */ +extern const device_t st506_at_wd1003_device; /* st506_at_wd1003 */ extern const device_t esdi_at_wd1007vse1_device; /* esdi_at */ extern const device_t esdi_ps2_device; /* esdi_mca */ diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index 2426e2a4c..e3bc9aa62 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -98,7 +98,8 @@ typedef struct { uint16_t buffer[256]; int irqstat; - int64_t callback; + uint64_t callback; + pc_timer_t timer; drive_t drives[2]; @@ -208,6 +209,21 @@ next_sector(esdi_t *esdi) } } +static void +esdi_set_callback(esdi_t *esdi, uint64_t callback) +{ + if (!esdi) { + return; + } + + if (callback) { + esdi->callback = callback; + timer_set_delay_u64(&esdi->timer, esdi->callback); + } else { + esdi->callback = 0; + timer_disable(&esdi->timer); + } +} static void esdi_writew(uint16_t port, uint16_t val, void *priv) @@ -220,10 +236,8 @@ esdi_writew(uint16_t port, uint16_t val, void *priv) if (esdi->pos >= 512) { esdi->pos = 0; esdi->status = STAT_BUSY; - timer_clock(); /* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */ - esdi->callback = (3125LL * TIMER_USEC) / 8LL; - timer_update_outstanding(); + esdi_set_callback(esdi, (3125 * TIMER_USEC) / 8); } } @@ -281,26 +295,20 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case CMD_RESTORE: esdi->command &= ~0x0f; /*mask off step rate*/ esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + esdi_set_callback(esdi, 200 * HDC_TIME); break; case CMD_SEEK: esdi->command &= ~0x0f; /*mask off step rate*/ esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + esdi_set_callback(esdi, 200 * HDC_TIME); break; default: switch (val) { case CMD_NOP: esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + esdi_set_callback(esdi, 200 * HDC_TIME); break; case CMD_READ: @@ -313,9 +321,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case 0xa0: esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + esdi_set_callback(esdi, 200 * HDC_TIME); break; case CMD_WRITE: @@ -333,9 +339,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case CMD_VERIFY+1: esdi->command &= ~0x01; esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + esdi_set_callback(esdi, 200 * HDC_TIME); break; case CMD_FORMAT: @@ -345,33 +349,25 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 30LL*HDC_TIME; - timer_update_outstanding(); + esdi_set_callback(esdi, 30 * HDC_TIME); break; case CMD_DIAGNOSE: /* Execute Drive Diagnostics */ esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + esdi_set_callback(esdi, 200 * HDC_TIME); break; case 0xe0: /*???*/ case CMD_READ_PARAMETERS: esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + esdi_set_callback(esdi, 200 * HDC_TIME); break; default: esdi_at_log("WD1007: bad command %02X\n", val); case 0xe8: /*???*/ esdi->status = STAT_BUSY; - timer_clock(); - esdi->callback = 200LL*HDC_TIME; - timer_update_outstanding(); + esdi_set_callback(esdi, 200 * HDC_TIME); break; } } @@ -379,18 +375,14 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case 0x3f6: /* Device control */ if ((esdi->fdisk & 0x04) && !(val & 0x04)) { - timer_clock(); - esdi->callback = 500LL*HDC_TIME; - timer_update_outstanding(); + esdi_set_callback(esdi, 500 * HDC_TIME); esdi->reset = 1; esdi->status = STAT_BUSY; } if (val & 0x04) { /*Drive held in reset*/ - timer_clock(); - esdi->callback = 0LL; - timer_update_outstanding(); + esdi_set_callback(esdi, 0); esdi->status = STAT_BUSY; } esdi->fdisk = val; @@ -419,10 +411,8 @@ esdi_readw(uint16_t port, void *priv) if (esdi->secount) { next_sector(esdi); esdi->status = STAT_BUSY; - timer_clock(); /* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */ - esdi->callback = (3125LL * TIMER_USEC) / 8LL; - timer_update_outstanding(); + esdi_set_callback(esdi, (3125 * TIMER_USEC) / 8); } else { ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 0); } @@ -487,7 +477,8 @@ esdi_callback(void *priv) drive_t *drive = &esdi->drives[esdi->drive_sel]; off64_t addr; - esdi->callback = 0LL; + esdi_set_callback(esdi, 0); + if (esdi->reset) { esdi->status = STAT_READY|STAT_DSC; esdi->error = 1; @@ -602,7 +593,7 @@ esdi_callback(void *priv) next_sector(esdi); esdi->secount = (esdi->secount - 1) & 0xff; if (esdi->secount) - esdi->callback = 6LL*HDC_TIME; + esdi_set_callback(esdi, 6 * HDC_TIME); else { esdi->pos = 0; esdi->status = STAT_READY|STAT_DSC; @@ -811,7 +802,7 @@ wd1007vse1_init(const device_t *info) io_sethandler(0x03f6, 1, NULL, NULL, NULL, esdi_write, NULL, NULL, esdi); - timer_add(esdi_callback, &esdi->callback, &esdi->callback, esdi); + timer_add(&esdi->timer, esdi_callback, esdi, 0); ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index f16c69ce6..f70dd7db7 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -90,7 +90,7 @@ #define BIOS_FILE_H L"roms/hdd/esdi/90x8970.bin" -#define ESDI_TIME (200LL*TIMER_USEC) +#define ESDI_TIME (200*TIMER_USEC) #define CMD_ADAPTER 0 @@ -134,7 +134,8 @@ typedef struct esdi { int cmd_state; int in_reset; - int64_t callback; + uint64_t callback; + pc_timer_t timer; uint32_t rba; @@ -188,6 +189,8 @@ typedef struct esdi { #define CMD_GET_DEV_STATUS 0x08 #define CMD_GET_DEV_CONFIG 0x09 #define CMD_GET_POS_INFO 0x0a +#define CMD_FORMAT_UNIT 0x16 +#define CMD_FORMAT_PREPARE 0x17 #define STATUS_LEN(x) ((x) << 8) #define STATUS_DEVICE(x) ((x) << 5) @@ -228,6 +231,21 @@ clear_irq(esdi_t *dev) picintc(1 << 14); } +static void +esdi_mca_set_callback(esdi_t *dev, uint64_t callback) +{ + if (!dev) { + return; + } + + if (callback) { + dev->callback = callback; + timer_set_delay_u64(&dev->timer, dev->callback); + } else { + dev->callback = 0; + timer_disable(&dev->timer); + } +} static void @@ -339,7 +357,7 @@ esdi_callback(void *priv) drive_t *drive; int val; - dev->callback = 0LL; + esdi_mca_set_callback(dev, 0); /* If we are returning from a RESET, handle this first. */ if (dev->in_reset) { @@ -377,13 +395,13 @@ esdi_callback(void *priv) set_irq(dev); dev->cmd_state = 1; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); dev->data_pos = 0; break; case 1: if (!(dev->basic_ctrl & CTRL_DMA_ENA)) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -399,7 +417,7 @@ esdi_callback(void *priv) val = dma_channel_write(dev->dma, dev->data[dev->data_pos]); if (val == DMA_NODATA) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -413,7 +431,7 @@ esdi_callback(void *priv) dev->status = STATUS_CMD_IN_PROGRESS; dev->cmd_state = 2; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); break; case 2: @@ -452,13 +470,13 @@ esdi_callback(void *priv) set_irq(dev); dev->cmd_state = 1; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); dev->data_pos = 0; break; case 1: if (! (dev->basic_ctrl & CTRL_DMA_ENA)) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -467,7 +485,7 @@ esdi_callback(void *priv) val = dma_channel_read(dev->dma); if (val == DMA_NODATA) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -487,7 +505,7 @@ esdi_callback(void *priv) dev->status = STATUS_CMD_IN_PROGRESS; dev->cmd_state = 2; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); break; case 2: @@ -630,13 +648,13 @@ esdi_callback(void *priv) set_irq(dev); dev->cmd_state = 1; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); dev->data_pos = 0; break; case 1: if (! (dev->basic_ctrl & CTRL_DMA_ENA)) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } while (dev->sector_pos < dev->sector_count) { @@ -644,7 +662,7 @@ esdi_callback(void *priv) val = dma_channel_read(dev->dma); if (val == DMA_NODATA) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -657,7 +675,7 @@ esdi_callback(void *priv) dev->status = STATUS_CMD_IN_PROGRESS; dev->cmd_state = 2; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); break; case 2: @@ -684,13 +702,13 @@ esdi_callback(void *priv) set_irq(dev); dev->cmd_state = 1; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); dev->data_pos = 0; break; case 1: if (! (dev->basic_ctrl & CTRL_DMA_ENA)) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -701,7 +719,7 @@ esdi_callback(void *priv) val = dma_channel_write(dev->dma, dev->data[dev->data_pos]); if (val == DMA_NODATA) { - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); return; } @@ -713,7 +731,7 @@ esdi_callback(void *priv) dev->status = STATUS_CMD_IN_PROGRESS; dev->cmd_state = 2; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); break; case 2: @@ -740,6 +758,59 @@ esdi_callback(void *priv) set_irq(dev); break; + case CMD_FORMAT_UNIT: + case CMD_FORMAT_PREPARE: + ESDI_DRIVE_ONLY(); + + if (! drive->present) { + device_not_present(dev); + return; + } + + switch (dev->cmd_state) { + case 0: + dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff; + + dev->sector_count = dev->cmd_data[1]; + + if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) { + rba_out_of_range(dev); + return; + } + + dev->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; + dev->irq_status = dev->cmd_dev | IRQ_DATA_TRANSFER_READY; + dev->irq_in_progress = 1; + set_irq(dev); + + dev->cmd_state = 1; + esdi_mca_set_callback(dev, ESDI_TIME); + break; + + case 1: + if (!(dev->basic_ctrl & CTRL_DMA_ENA)) { + esdi_mca_set_callback(dev, ESDI_TIME); + return; + } + + hdd_image_zero(drive->hdd_num, dev->rba, dev->sector_count); + ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1); + + dev->status = STATUS_CMD_IN_PROGRESS; + dev->cmd_state = 2; + esdi_mca_set_callback(dev, ESDI_TIME); + break; + + case 2: + complete_command_status(dev); + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + dev->irq_in_progress = 1; + set_irq(dev); + break; + } + break; + default: fatal("BAD COMMAND %02x %i\n", dev->command, dev->cmd_dev); } @@ -781,7 +852,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case 2: /*Basic control register*/ if ((dev->basic_ctrl & CTRL_RESET) && !(val & CTRL_RESET)) { dev->in_reset = 1; - dev->callback = ESDI_TIME * 50LL; + esdi_mca_set_callback(dev, ESDI_TIME * 50); dev->status = STATUS_BUSY; } dev->basic_ctrl = val; @@ -812,7 +883,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) case ATTN_RESET: dev->in_reset = 1; - dev->callback = ESDI_TIME * 50LL; + esdi_mca_set_callback(dev, ESDI_TIME * 50); dev->status = STATUS_BUSY; break; @@ -923,7 +994,7 @@ esdi_writew(uint16_t port, uint16_t val, void *priv) if ((dev->cmd_data[0] & CMD_DEVICE_SEL) != dev->cmd_dev) fatal("Command device mismatch with attn\n"); dev->command = dev->cmd_data[0] & CMD_MASK; - dev->callback = ESDI_TIME; + esdi_mca_set_callback(dev, ESDI_TIME); dev->status = STATUS_BUSY; dev->data_pos = 0; } @@ -1007,6 +1078,15 @@ esdi_mca_write(int port, uint8_t val, void *priv) } +static uint8_t +esdi_mca_feedb(void *priv) +{ + esdi_t *dev = (esdi_t *)priv; + + return (dev->pos_regs[2] & 1); +} + + static void * esdi_init(const device_t *info) { @@ -1059,15 +1139,15 @@ esdi_init(const device_t *info) dev->pos_regs[1] = 0xdd; /* Enable the device. */ - mca_add(esdi_mca_read, esdi_mca_write, dev); + mca_add(esdi_mca_read, esdi_mca_write, esdi_mca_feedb, dev); /* Mark for a reset. */ dev->in_reset = 1; - dev->callback = ESDI_TIME * 50LL; + esdi_mca_set_callback(dev, ESDI_TIME * 50); dev->status = STATUS_BUSY; /* Set the reply timer. */ - timer_add(esdi_callback, &dev->callback, &dev->callback, dev); + timer_add(&dev->timer, esdi_callback, dev, 0); return(dev); } diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 3ff2c3ea4..69a82093b 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -109,36 +109,32 @@ #define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd #define FEATURE_DISABLE_IRQ_SERVICE 0xde -#define IDE_PCI (PCI && !pio_override && (ide->board < 2)) +#define IDE_TIME 20.0 / 3.0 typedef struct { - int bit32, cur_dev, - irq; - int64_t callback; + int bit32, cur_dev, + irq, inited; + uint16_t base_main, side_main; + pc_timer_t timer; } ide_board_t; -static ide_board_t *ide_boards[4]; -static int pio_override = 0; +typedef struct { + int (*dma)(int channel, uint8_t *data, int transfer_length, int out, void *priv); + void (*set_irq)(int channel, void *priv); + void *priv; +} ide_bm_t; -ide_t *ide_drives[IDE_NUM]; -int (*ide_bus_master_dma)(int channel, uint8_t *data, int transfer_length, int out, void *priv); -void (*ide_bus_master_set_irq)(int channel, void *priv); -void *ide_bus_master_priv[2]; -int ide_inited = 0; -int ide_sec_optional = 0; +static ide_board_t *ide_boards[4] = { NULL, NULL, NULL, NULL }; +static ide_bm_t *ide_bm[4] = { NULL, NULL, NULL, NULL }; + +static ide_t *ide_drives[IDE_NUM]; int ide_ter_enabled = 0, ide_qua_enabled = 0; -static uint16_t ide_base_main[4] = { 0x1f0, 0x170, 0x168, 0x1e8 }; -static uint16_t ide_side_main[4] = { 0x3f6, 0x376, 0x36e, 0x3ee }; - static void ide_atapi_callback(ide_t *ide); static void ide_callback(void *priv); -#define IDE_TIME (20LL * TIMER_USEC) / 3LL - - #ifdef ENABLE_IDE_LOG int ide_do_log = ENABLE_IDE_LOG; @@ -165,7 +161,17 @@ getstat(ide_t *ide) { } -int64_t +ide_t * +ide_get_drive(int ch) +{ + if (ch >= 8) + return NULL; + + return ide_drives[ch]; +} + + +double ide_get_period(ide_t *ide, int size) { double period = 10.0 / 3.0; @@ -240,11 +246,9 @@ ide_get_period(ide_t *ide, int size) break; } - period *= 1048576.0; /* period * MB */ - period = 1000000.0 / period; - period *= (double) TIMER_USEC; - period *= (double) size; - return (int64_t) period; + period *= 1048576.0; /* period * MB - get bytes per second */ + period = ((double) size) / period; /* size / period to get seconds */ + return period * 1000000.0; /* return seconds * 1000000 to convert to us */ } @@ -276,21 +280,6 @@ ide_get_seek_time(ide_t *ide, uint32_t new_pos) #endif -int -ide_drive_is_atapi(ide_t *ide) -{ - int ch = ide->channel; - - if (ch >= 8) - return 0; - - if (ide->type == IDE_ATAPI) - return 1; - else - return 0; -} - - void ide_irq_raise(ide_t *ide) { @@ -300,14 +289,14 @@ ide_irq_raise(ide_t *ide) /* ide_log("Raising IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ if (!(ide->fdisk & 2) && (ide_boards[ide->board]->irq != -1)) { - if ((ide->board < 2) && ide_bus_master_set_irq) - ide_bus_master_set_irq(ide->board | 0x40, ide_bus_master_priv[ide->board]); + if (ide_bm[ide->board] && ide_bm[ide->board]->set_irq) + ide_bm[ide->board]->set_irq(ide->board | 0x40, ide_bm[ide->board]->priv); else picint(1 << ide_boards[ide->board]->irq); } - ide->irqstat=1; - ide->service=1; + ide->irqstat = 1; + ide->service = 1; } @@ -320,8 +309,8 @@ ide_irq_lower(ide_t *ide) /* ide_log("Lowering IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ if ((ide_boards[ide->board]->irq != -1) && ide->irqstat) { - if ((ide->board < 2) && ide_bus_master_set_irq) - ide_bus_master_set_irq(ide->board, ide_bus_master_priv[ide->board]); + if (ide_bm[ide->board] && ide_bm[ide->board]->set_irq) + ide_bm[ide->board]->set_irq(ide->board, ide_bm[ide->board]->priv); else picintc(1 << ide_boards[ide->board]->irq); } @@ -379,27 +368,27 @@ void ide_padstr8(uint8_t *buf, int buf_size, const char *src) static int ide_get_max(ide_t *ide, int type) { - if (ide_drive_is_atapi(ide)) - return ide->get_max(IDE_PCI, type); + if (ide->type == IDE_ATAPI) + return ide->get_max(ide_bm[ide->board] != NULL, type); switch(type) { case TYPE_PIO: /* PIO */ - if (IDE_PCI) + if (ide_bm[ide->board] != NULL) return 1; return 0; /* Maximum PIO 0 for legacy PIO-only drive. */ case TYPE_SDMA: /* SDMA */ - if (IDE_PCI) + if (ide_bm[ide->board] != NULL) return 2; return -1; case TYPE_MDMA: /* MDMA */ - if (IDE_PCI) + if (ide_bm[ide->board] != NULL) return 2; return -1; case TYPE_UDMA: /* UDMA */ - if (IDE_PCI) + if (ide_bm[ide->board] != NULL) return 2; return -1; @@ -413,17 +402,17 @@ ide_get_max(ide_t *ide, int type) static int ide_get_timings(ide_t *ide, int type) { - if (ide_drive_is_atapi(ide)) - return ide->get_timings(IDE_PCI, type); + if (ide->type == IDE_ATAPI) + return ide->get_timings(ide_bm[ide->board] != NULL, type); switch(type) { case TIMINGS_DMA: - if (IDE_PCI) + if (ide_bm[ide->board] != NULL) return 120; return 0; case TIMINGS_PIO: - if (IDE_PCI) + if (ide_bm[ide->board] != NULL) return 120; return 0; @@ -519,7 +508,7 @@ static void ide_hd_identify(ide_t *ide) ide_log("Current CHS translation: %i, %i, %i\n", ide->buffer[54], ide->buffer[55], ide->buffer[56]); } - if (IDE_PCI) { + if (ide_bm[ide->board]) { ide->buffer[47] = 32 | 0x8000; /*Max sectors on multiple transfer command*/ ide->buffer[80] = 0x1e; /*ATA-1 to ATA-4 supported*/ ide->buffer[81] = 0x18; /*ATA-4 revision 18 supported*/ @@ -539,8 +528,8 @@ ide_identify(ide_t *ide) memset(ide->buffer, 0, 512); - if (ide_drive_is_atapi(ide)) - ide->identify(ide, IDE_PCI); + if (ide->type == IDE_ATAPI) + ide->identify(ide, ide_bm[ide->board] != NULL); else if (ide->type != IDE_NONE) ide_hd_identify(ide); else { @@ -675,7 +664,7 @@ ide_set_signature(ide_t *ide) ide->sector=1; ide->head=0; - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->phase = 1; ide->sc->request_length = 0xEB14; ide->secount = ide->sc->phase; @@ -798,7 +787,8 @@ static void ide_zero(int d) { ide_t *dev; - ide_drives[d] = (ide_t *) malloc(sizeof(ide_t)); + if (ide_drives[d] == NULL) + ide_drives[d] = (ide_t *) malloc(sizeof(ide_t)); memset(ide_drives[d], 0, sizeof(ide_t)); dev = ide_drives[d]; dev->channel = d; @@ -810,44 +800,11 @@ ide_zero(int d) } -static void -ide_board_close(int board) -{ - ide_t *dev; - int c, d; - - /* Close hard disk image files (if previously open) */ - for (d = 0; d < 2; d++) { - c = (board << 1) + d; - dev = ide_drives[c]; - - if ((dev->type == IDE_HDD) && (dev->hdd_num != -1)) - hdd_image_close(dev->hdd_num); - - if (board < 4) { - if (ide_drive_is_atapi(dev)) - dev->sc->status = DRDY_STAT | DSC_STAT; - } - - if (dev->buffer) - free(dev->buffer); - - if (dev->sector_buffer) - free(dev->sector_buffer); - - if (dev) - free(dev); - } -} - - void ide_allocate_buffer(ide_t *dev) { - if (dev->buffer) - return; - - dev->buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); + if (dev->buffer == NULL) + dev->buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); memset(dev->buffer, 0, 65536 * sizeof(uint16_t)); } @@ -861,70 +818,14 @@ ide_atapi_attach(ide_t *ide) ide->type = IDE_ATAPI; ide_allocate_buffer(ide); ide_set_signature(ide); - ide->mdma_mode = (1 << ide->get_max(!IDE_PCI, TYPE_PIO)); + ide->mdma_mode = (1 << ide->get_max(!ide_bm[ide->board], TYPE_PIO)); ide->error = 1; ide->cfg_spt = ide->cfg_hpc = 0; } -static void -ide_board_init(int board) -{ - ide_t *dev; - int c, d; - int ch, is_ide, valid_ch; - int min_ch, max_ch; - - min_ch = (board << 1); - max_ch = min_ch + 1; - - ide_log("IDE: board %i: loading disks...\n", board); - for (d = 0; d < 2; d++) { - c = (board << 1) + d; - ide_zero(c); - } - - c = 0; - for (d = 0; d < HDD_NUM; d++) { - is_ide = (hdd[d].bus == HDD_BUS_IDE); - ch = hdd[d].ide_channel; - - if (board == 4) { - valid_ch = ((ch >= 0) && (ch <= 1)); - ch |= 8; - } else - valid_ch = ((ch >= min_ch) && (ch <= max_ch)); - - if (is_ide && valid_ch) { - ide_log("Found IDE hard disk on channel %i\n", ch); - loadhd(ide_drives[ch], d, hdd[d].fn); - ide_drives[ch]->sector_buffer = (uint8_t *) malloc(256*512); - memset(ide_drives[ch]->sector_buffer, 0, 256*512); - if (++c >= 2) break; - } - } - ide_log("IDE: board %i: done, loaded %d disks.\n", board, c); - - for (d = 0; d < 2; d++) { - c = (board << 1) + d; - dev = ide_drives[c]; - - if (dev->type == IDE_NONE) - continue; - - ide_allocate_buffer(dev); - - ide_set_signature(dev); - - dev->mdma_mode = (1 << ide_get_max(dev, TYPE_PIO)); - dev->error = 1; - dev->cfg_spt = dev->cfg_hpc = 0; - } -} - - void -ide_set_callback(uint8_t board, int64_t callback) +ide_set_callback(uint8_t board, double callback) { ide_board_t *dev = ide_boards[board]; @@ -935,10 +836,7 @@ ide_set_callback(uint8_t board, int64_t callback) return; } - if (callback) - dev->callback = callback; - else - dev->callback = 0LL; + timer_on_auto(&dev->timer, callback); } @@ -948,7 +846,7 @@ ide_atapi_command_bus(ide_t *ide) ide->sc->status = BUSY_STAT; ide->sc->phase = 1; ide->sc->pos = 0; - ide->sc->callback = 1LL * IDE_TIME; + ide->sc->callback = 1.0 * IDE_TIME; ide_set_callback(ide->board, ide->sc->callback); } @@ -968,7 +866,7 @@ ide_atapi_callback(ide_t *ide) ide->sc->status = BUSY_STAT | (ide->sc->status & ERR_STAT); if (ide->packet_command) { ide->packet_command(ide->sc, ide->sc->atapi_cdb); - if ((ide->sc->packet_status == PHASE_COMPLETE) && !ide->sc->callback) + if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) ide_atapi_callback(ide); } return; @@ -988,9 +886,16 @@ ide_atapi_callback(ide_t *ide) case PHASE_DATA_OUT_DMA: out = (ide->sc->packet_status & 0x01); - ret = ide_bus_master_dma(ide->board, - ide->sc->temp_buffer, ide->sc->packet_len, - out, ide_bus_master_priv[ide->board]); + if (ide_bm[ide->board] && ide_bm[ide->board]->dma) { + ret = ide_bm[ide->board]->dma(ide->board, + ide->sc->temp_buffer, ide->sc->packet_len, + out, ide_bm[ide->board]->priv); + } else { + /* DMA command without a bus master. */ + if (ide->bus_master_error) + ide->bus_master_error(ide->sc); + return; + } if (ret == 0) { if (ide->bus_master_error) @@ -1001,7 +906,7 @@ ide_atapi_callback(ide_t *ide) else if (!out && ide->command_stop) ide->command_stop(ide->sc); - if ((ide->sc->packet_status == PHASE_COMPLETE) && !ide->sc->callback) + if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) ide_atapi_callback(ide); } else if (ret == 2) ide_atapi_command_bus(ide); @@ -1036,7 +941,7 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) else if (!out && ide->command_stop) ide->command_stop(dev); - if ((ide->sc->packet_status == PHASE_COMPLETE) && !ide->sc->callback) + if ((ide->sc->packet_status == PHASE_COMPLETE) && (ide->sc->callback == 0.0)) ide_atapi_callback(ide); } else { ide_log("%i bytes %s, %i bytes are still left\n", dev->pos, @@ -1054,8 +959,7 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) dev->status = BSY_STAT; dev->phase = 1; ide_atapi_callback(ide); - dev->callback = 0LL; - ide_set_callback(ide->board >> 1, dev->callback); + ide_set_callback(ide->board >> 1, 0.0); dev->request_pos = 0; } @@ -1167,9 +1071,7 @@ ide_atapi_packet_write(ide_t *ide, uint32_t val, int length) dev->pos = 0; dev->status = BSY_STAT; dev->packet_status = PHASE_COMMAND; - timer_process(); ide_atapi_callback(ide); - timer_update_outstanding(); } return; } @@ -1186,12 +1088,8 @@ ide_write_data(ide_t *ide, uint32_t val, int length) if (ide->command == WIN_PACKETCMD) { ide->pos = 0; - if (!ide_drive_is_atapi(ide)) - return; - - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) ide_atapi_packet_write(ide, val, length); - return; } else { switch(length) { case 1: @@ -1210,15 +1108,13 @@ ide_write_data(ide_t *ide, uint32_t val, int length) return; } - if (ide->pos>=512) { + if (ide->pos >= 512) { ide->pos=0; ide->atastat = BSY_STAT; - timer_process(); if (ide->command == WIN_WRITE_MULTIPLE) ide_callback(ide_boards[ide->board]); else ide_set_callback(ide->board, ide_get_period(ide, 512)); - timer_update_outstanding(); } } } @@ -1292,26 +1188,22 @@ ide_write_devctl(uint16_t addr, uint8_t val, void *priv) ide_log("ide_write_devctl %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); if ((ide->fdisk & 4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) { - timer_process(); - if (ide_drive_is_atapi(ide)) - ide->sc->callback = 0LL; - ide_set_callback(ide->board, 500LL * IDE_TIME); - timer_update_outstanding(); + if (ide->type == IDE_ATAPI) + ide->sc->callback = 0.0; + ide_set_callback(ide->board, 500 * IDE_TIME); if (ide->type != IDE_NONE) ide->reset = 1; if (ide_other->type != IDE_NONE) ide->reset = 1; - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) ide->sc->status = BSY_STAT; ide->atastat = ide_other->atastat = BSY_STAT; } if (val & 4) { /*Drive held in reset*/ - timer_process(); - ide_set_callback(ide->board, 0LL); - timer_update_outstanding(); + ide_set_callback(ide->board, 0.0); ide->atastat = ide_other->atastat = BSY_STAT; } ide->fdisk = ide_other->fdisk = val; @@ -1345,25 +1237,25 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) /* Note to self: for ATAPI, bit 0 of this is DMA if set, PIO if clear. */ case 0x1: /* Features */ - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); ide->sc->features = val; } ide->cylprecomp = val; - if (ide_drive_is_atapi(ide_other)) + if (ide_other->type == IDE_ATAPI) ide_other->sc->features = val; ide_other->cylprecomp = val; return; case 0x2: /* Sector count */ - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide_log("Sector count write: %i\n", val); ide->sc->phase = val; } ide->secount = val; - if (ide_drive_is_atapi(ide_other)) { + if (ide_other->type == IDE_ATAPI) { ide_log("Other sector count write: %i\n", val); ide_other->sc->phase = val; } @@ -1378,14 +1270,14 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) return; case 0x4: /* Cylinder low */ - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->request_length &= 0xFF00; ide->sc->request_length |= val; } ide->cylinder = (ide->cylinder & 0xFF00) | val; ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); - if (ide_drive_is_atapi(ide_other)) { + if (ide_other->type == IDE_ATAPI) { ide_other->sc->request_length &= 0xFF00; ide_other->sc->request_length |= val; } @@ -1394,14 +1286,14 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) return; case 0x5: /* Cylinder high */ - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->request_length &= 0xFF; ide->sc->request_length |= (val << 8); } ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); - if (ide_drive_is_atapi(ide_other)) { + if (ide_other->type == IDE_ATAPI) { ide_other->sc->request_length &= 0xFF; ide_other->sc->request_length |= (val << 8); } @@ -1423,26 +1315,25 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->cylinder = ide_other->cylinder = 0; ide->reset = ide_other->reset = 0; - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->status = DRDY_STAT | DSC_STAT; ide->sc->error = 1; ide->sc->phase = 1; ide->sc->request_length = 0xEB14; - ide->sc->callback = 0LL; + ide->sc->callback = 0.0; ide->cylinder = 0xEB14; } - if (ide_drive_is_atapi(ide_other)) { + if (ide_other->type == IDE_ATAPI) { ide_other->sc->status = DRDY_STAT | DSC_STAT; ide_other->sc->error = 1; ide_other->sc->phase = 1; ide_other->sc->request_length = 0xEB14; - ide_other->sc->callback = 0LL; - ide->cylinder = 0xEB14; + ide_other->sc->callback = 0.0; + ide_other->cylinder = 0xEB14; } - ide_set_callback(ide->board, 0LL); - timer_update_outstanding(); + ide_set_callback(ide->board, 0.0); return; } @@ -1463,38 +1354,33 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) return; ide_irq_lower(ide); - ide->command=val; + ide->command = val; - ide->error=0; - if (ide_drive_is_atapi(ide)) + ide->error = 0; + if (ide->type == IDE_ATAPI) ide->sc->error = 0; if (((val >= WIN_RECAL) && (val <= 0x1F)) || ((val >= WIN_SEEK) && (val <= 0x7F))) { - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) ide->sc->status = DRDY_STAT; else ide->atastat = BSY_STAT; - timer_process(); - if (ide_drive_is_atapi(ide)) - ide->sc->callback = 100LL * IDE_TIME; - ide_set_callback(ide->board, 100LL * IDE_TIME); - timer_update_outstanding(); + if (ide->type == IDE_ATAPI) + ide->sc->callback = 100.0 * IDE_TIME; + ide_set_callback(ide->board, 100.0 * IDE_TIME); return; } switch (val) { case WIN_SRST: /* ATAPI Device Reset */ - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) { ide->sc->status = BSY_STAT; - else + ide->sc->callback = 100.0 * IDE_TIME; + } else ide->atastat = DRDY_STAT; - timer_process(); - - if (ide_drive_is_atapi(ide)) - ide->sc->callback = 100LL * IDE_TIME; - ide_set_callback(ide->board, 100LL * IDE_TIME); - timer_update_outstanding(); + + ide_set_callback(ide->board, 100.0 * IDE_TIME); return; case WIN_READ_MULTIPLE: @@ -1512,14 +1398,11 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_READ_NORETRY: case WIN_READ_DMA: case WIN_READ_DMA_ALT: - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) { ide->sc->status = BSY_STAT; - else + ide->sc->callback = 200.0 * IDE_TIME; + } else ide->atastat = BSY_STAT; - timer_process(); - - if (ide_drive_is_atapi(ide)) - ide->sc->callback = 200LL * IDE_TIME; if (ide->type == IDE_HDD) { if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { @@ -1527,16 +1410,17 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide_set_callback(ide->board, ide_get_period(ide, (int) ide->secount << 9)); else ide_set_callback(ide->board, ide_get_period(ide, 131072)); - } else + } else if (val == WIN_READ_MULTIPLE) + ide_set_callback(ide->board, 200.0 * IDE_TIME); + else ide_set_callback(ide->board, ide_get_period(ide, 512)); } else - ide_set_callback(ide->board, 200LL * IDE_TIME); - timer_update_outstanding(); + ide_set_callback(ide->board, 200.0 * IDE_TIME); ide->do_initial_read = 1; return; case WIN_WRITE_MULTIPLE: - if (!ide->blocksize && !ide_drive_is_atapi(ide)) + if (!ide->blocksize && (ide->type != IDE_ATAPI)) fatal("Write_MULTIPLE - blocksize = 0\n"); ide->blockcount = 0; /* Turn on the activity indicator *here* so that it gets turned on @@ -1545,7 +1429,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_WRITE: case WIN_WRITE_NORETRY: - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->status = DRQ_STAT | DSC_STAT | DRDY_STAT; ide->sc->pos = 0; } else { @@ -1561,14 +1445,12 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_IDENTIFY: /* Identify Device */ case WIN_SET_FEATURES: /* Set Features */ case WIN_READ_NATIVE_MAX: - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) { ide->sc->status = BSY_STAT; - else + ide->sc->callback = 200.0 * IDE_TIME; + } else ide->atastat = BSY_STAT; - timer_process(); - if (ide_drive_is_atapi(ide)) - ide->sc->callback = 200LL * IDE_TIME; if ((ide->type == IDE_HDD) && ((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) { if (ide->secount) @@ -1579,12 +1461,11 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ((val == WIN_VERIFY) || (val == WIN_VERIFY_ONCE))) ide_set_callback(ide->board, ide_get_period(ide, 512)); else - ide_set_callback(ide->board, 200LL * IDE_TIME); - timer_update_outstanding(); + ide_set_callback(ide->board, 200.0 * IDE_TIME); return; case WIN_FORMAT: - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) goto ide_bad_command; else { ide->atastat = DRQ_STAT; @@ -1593,34 +1474,28 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) return; case WIN_SPECIFY: /* Initialize Drive Parameters */ - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) { ide->sc->status = BSY_STAT; - else + ide->sc->callback = 30.0 * IDE_TIME; + } else ide->atastat = BSY_STAT; - timer_process(); - if (ide_drive_is_atapi(ide)) - ide->sc->callback = 30LL * IDE_TIME; - ide_set_callback(ide->board, 30LL * IDE_TIME); - timer_update_outstanding(); + ide_set_callback(ide->board, 30.0 * IDE_TIME); return; case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) { ide->sc->status = BSY_STAT; - else + ide->sc->callback = 200.0 * IDE_TIME; + } else ide->atastat = BSY_STAT; - if (ide_drive_is_atapi(ide_other)) + if (ide_other->type == IDE_ATAPI) ide_other->sc->status = BSY_STAT; else ide_other->atastat = BSY_STAT; - timer_process(); - if (ide_drive_is_atapi(ide)) - ide->sc->callback = 200LL * IDE_TIME; - ide_set_callback(ide->board, 200LL * IDE_TIME); - timer_update_outstanding(); + ide_set_callback(ide->board, 200.0 * IDE_TIME); return; case WIN_PIDENTIFY: /* Identify Packet Device */ @@ -1631,18 +1506,16 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_SETIDLE1: /* Idle */ case WIN_CHECKPOWERMODE1: case WIN_SLEEP1: - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) ide->sc->status = BSY_STAT; else ide->atastat = BSY_STAT; - timer_process(); ide_callback(dev); - timer_update_outstanding(); return; case WIN_PACKETCMD: /* ATAPI Packet */ /* Skip the command callback wait, and process immediately. */ - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->packet_status = PHASE_IDLE; ide->sc->pos = 0; ide->sc->phase = 1; @@ -1651,9 +1524,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide_irq_raise(ide); /* Interrupt DRQ, requires IRQ on any DRQ. */ } else { ide->atastat = BSY_STAT; - timer_process(); - ide_set_callback(ide->board, 200LL * IDE_TIME); - timer_update_outstanding(); + ide_set_callback(ide->board, 200.0 * IDE_TIME); ide->pos=0; } return; @@ -1661,7 +1532,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case 0xF0: default: ide_bad_command: - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->status = DRDY_STAT | ERR_STAT | DSC_STAT; ide->sc->error = ABRT_ERR; } else { @@ -1700,7 +1571,7 @@ ide_read_data(ide_t *ide, int length) if (ide->command == WIN_PACKETCMD) { ide->pos = 0; - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) temp = ide_atapi_packet_read(ide, length); else { ide_log("Drive not ATAPI (position: %i)\n", ide->pos); @@ -1727,7 +1598,7 @@ ide_read_data(ide_t *ide, int length) if ((ide->pos >= 512) && (ide->command != WIN_PACKETCMD)) { ide->pos = 0; ide->atastat = DRDY_STAT | DSC_STAT; - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->status = DRDY_STAT | DSC_STAT; ide->sc->packet_status = PHASE_IDLE; } @@ -1736,12 +1607,10 @@ ide_read_data(ide_t *ide, int length) if (ide->secount) { ide_next_sector(ide); ide->atastat = BSY_STAT; - timer_process(); if (ide->command == WIN_READ_MULTIPLE) ide_callback(ide_boards[ide->board]); else ide_set_callback(ide->board, ide_get_period(ide, 512)); - timer_update_outstanding(); } else if (ide->command != WIN_READ_MULTIPLE) ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); } @@ -1755,13 +1624,11 @@ static uint8_t ide_status(ide_t *ide, int ch) { if (ide->type == IDE_NONE) - return 0; - else { - if (ide_drive_is_atapi(ide)) - return (ide->sc->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); - else - return ide->atastat; - } + return 0x7F; /* Bit 7 pulled down, all other bits pulled up, per the spec. */ + else if (ide->type == IDE_ATAPI) + return (ide->sc->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + else + return ide->atastat; } @@ -1794,12 +1661,10 @@ ide_readb(uint16_t addr, void *priv) case 0x1: /* Error */ if (ide->type == IDE_NONE) temp = 0; - else { - if (ide_drive_is_atapi(ide)) - temp = ide->sc->error; - else - temp = ide->error; - } + else if (ide->type == IDE_ATAPI) + temp = ide->sc->error; + else + temp = ide->error; break; /* For ATAPI: @@ -1816,36 +1681,32 @@ ide_readb(uint16_t addr, void *priv) 0 1 0 Data from host 1 0 1 Status. */ case 0x2: /* Sector count */ - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) temp = ide->sc->phase; else temp = ide->secount; break; case 0x3: /* Sector */ - temp = (uint8_t)ide->sector; + temp = (uint8_t) ide->sector; break; case 0x4: /* Cylinder low */ if (ide->type == IDE_NONE) temp = 0xFF; - else { - if (ide_drive_is_atapi(ide)) - temp = ide->sc->request_length & 0xff; - else - temp = ide->cylinder & 0xff; - } + else if (ide->type == IDE_ATAPI) + temp = ide->sc->request_length & 0xff; + else + temp = ide->cylinder & 0xff; break; case 0x5: /* Cylinder high */ if (ide->type == IDE_NONE) temp = 0xFF; - else { - if (ide_drive_is_atapi(ide)) - temp = ide->sc->request_length >> 8; - else - temp = ide->cylinder >> 8; - } + else if (ide->type == IDE_ATAPI) + temp = ide->sc->request_length >> 8; + else + temp = ide->cylinder >> 8; break; case 0x6: /* Drive/Head */ @@ -1941,7 +1802,7 @@ static void ide_callback(void *priv) { ide_t *ide, *ide_other; - int snum, ret, ch; + int snum, ret = 0, ch; ide_board_t *dev = (ide_board_t *) priv; ch = dev->cur_dev; @@ -1949,8 +1810,6 @@ ide_callback(void *priv) ide = ide_drives[ch]; ide_other = ide_drives[ch ^ 1]; - ide_set_callback(ide->board, 0LL); - if (ide->reset) { ide_log("CALLBACK RESET %i %i\n", ide->reset,ch); @@ -1967,7 +1826,7 @@ ide_callback(void *priv) ide->reset = ide_other->reset = 0; ide_set_signature(ide); - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->status = DRDY_STAT | DSC_STAT; ide->sc->error = 1; if (ide->stop) @@ -1975,7 +1834,7 @@ ide_callback(void *priv) } ide_set_signature(ide_other); - if (ide_drive_is_atapi(ide_other)) { + if (ide_other->type == IDE_ATAPI) { ide_other->sc->status = DRDY_STAT | DSC_STAT; ide_other->sc->error = 1; if (ide_other->stop) @@ -2013,14 +1872,14 @@ ide_callback(void *priv) ide_set_signature(ide); - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->status = DRDY_STAT | DSC_STAT; ide->sc->error = 1; if (ide->device_reset) ide->device_reset(ide->sc); } ide_irq_raise(ide); - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) ide->service = 0; return; @@ -2028,7 +1887,7 @@ ide_callback(void *priv) case WIN_STANDBYNOW1: case WIN_IDLENOW1: case WIN_SETIDLE1: - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) ide->sc->status = DRDY_STAT | DSC_STAT; else ide->atastat = DRDY_STAT | DSC_STAT; @@ -2037,7 +1896,7 @@ ide_callback(void *priv) case WIN_CHECKPOWERMODE1: case WIN_SLEEP1: - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->phase = 0xFF; ide->sc->status = DRDY_STAT | DSC_STAT; } @@ -2048,7 +1907,7 @@ ide_callback(void *priv) case WIN_READ: case WIN_READ_NORETRY: - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide_set_signature(ide); goto abort_cmd; } @@ -2078,7 +1937,7 @@ ide_callback(void *priv) case WIN_READ_DMA: case WIN_READ_DMA_ALT: - if (ide_drive_is_atapi(ide) || !IDE_PCI) { + if ((ide->type == IDE_ATAPI) || !ide_bm[ide->board]) { ide_log("IDE %i: DMA read aborted (bad device or board)\n", ide->channel); goto abort_cmd; } @@ -2096,15 +1955,15 @@ ide_callback(void *priv) ide->pos=0; - if (ide_bus_master_dma) { + if (ide_bm[ide->board] && ide_bm[ide->board]->dma) { /* We should not abort - we should simply wait for the host to start DMA. */ - ret = ide_bus_master_dma(ide->board, - ide->sector_buffer, ide->sector_pos * 512, - 0, ide_bus_master_priv[ide->board]); + ret = ide_bm[ide->board]->dma(ide->board, + ide->sector_buffer, ide->sector_pos * 512, + 0, ide_bm[ide->board]->priv); if (ret == 2) { /* Bus master DMA disabled, simply wait for the host to enable DMA. */ ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; - ide_set_callback(ide->board, 6LL * IDE_TIME); + ide_set_callback(ide->board, 6.0 * IDE_TIME); return; } else if (ret == 1) { /*DMA successful*/ @@ -2132,7 +1991,7 @@ ide_callback(void *priv) command has been executed or when Read Multiple commands are disabled, the Read Multiple operation is rejected with an Aborted Com- mand error. */ - if (ide_drive_is_atapi(ide) || !ide->blocksize) + if ((ide->type == IDE_ATAPI) || !ide->blocksize) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2161,7 +2020,7 @@ ide_callback(void *priv) case WIN_WRITE: case WIN_WRITE_NORETRY: - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2181,7 +2040,7 @@ ide_callback(void *priv) case WIN_WRITE_DMA: case WIN_WRITE_DMA_ALT: - if (ide_drive_is_atapi(ide) || !IDE_PCI) { + if ((ide->type == IDE_ATAPI) || !ide_bm[ide->board]) { ide_log("IDE %i: DMA write aborted (bad device type or board)\n", ide->channel); goto abort_cmd; } @@ -2190,20 +2049,20 @@ ide_callback(void *priv) goto id_not_found; } - if (ide_bus_master_dma) { + if (ide_bm[ide->board] && ide_bm[ide->board]->dma) { if (ide->secount) ide->sector_pos = ide->secount; else ide->sector_pos = 256; - ret = ide_bus_master_dma(ide->board, - ide->sector_buffer, ide->sector_pos * 512, - 1, ide_bus_master_priv[ide->board]); + ret = ide_bm[ide->board]->dma(ide->board, + ide->sector_buffer, ide->sector_pos * 512, + 1, ide_bm[ide->board]->priv); if (ret == 2) { /* Bus master DMA disabled, simply wait for the host to enable DMA. */ ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; - ide_set_callback(ide->board, 6LL * IDE_TIME); + ide_set_callback(ide->board, 6.0 * IDE_TIME); return; } else if (ret == 1) { /*DMA successful*/ @@ -2228,7 +2087,7 @@ ide_callback(void *priv) return; case WIN_WRITE_MULTIPLE: - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2251,7 +2110,7 @@ ide_callback(void *priv) case WIN_VERIFY: case WIN_VERIFY_ONCE: - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2262,7 +2121,7 @@ ide_callback(void *priv) return; case WIN_FORMAT: - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) goto abort_cmd; if (ide->cfg_spt == 0) goto id_not_found; @@ -2278,7 +2137,7 @@ ide_callback(void *priv) ide_set_signature(ide); ide->error = 1; /*No error detected*/ - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->status = 0; ide->sc->error = 1; ide_irq_raise(ide); @@ -2291,7 +2150,7 @@ ide_callback(void *priv) ide_set_signature(ide_other); ide_other->error = 1; /*No error detected*/ - if (ide_drive_is_atapi(ide_other)) { + if (ide_other->type == IDE_ATAPI) { ide_other->sc->status = 0; ide_other->sc->error = 1; } else { @@ -2304,7 +2163,7 @@ ide_callback(void *priv) return; case WIN_SPECIFY: /* Initialize Drive Parameters */ - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) goto abort_cmd; if (ide->cfg_spt == 0) { /* Only accept after RESET or DIAG. */ @@ -2318,7 +2177,7 @@ ide_callback(void *priv) return; case WIN_PIDENTIFY: /* Identify Packet Device */ - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide_identify(ide); ide->pos = 0; ide->sc->phase = 2; @@ -2331,7 +2190,7 @@ ide_callback(void *priv) goto abort_cmd; case WIN_SET_MULTIPLE_MODE: - if (ide_drive_is_atapi(ide)) + if (ide->type == IDE_ATAPI) goto abort_cmd; ide->blocksize = ide->secount; ide->atastat = DRDY_STAT | DSC_STAT; @@ -2342,7 +2201,7 @@ ide_callback(void *priv) if ((ide->type == IDE_NONE) || !ide_set_features(ide)) goto abort_cmd; - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->status = DRDY_STAT | DSC_STAT; ide->sc->pos = 0; } @@ -2368,14 +2227,14 @@ ide_callback(void *priv) goto abort_cmd; } else { ide_identify(ide); - ide->pos=0; + ide->pos = 0; ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; ide_irq_raise(ide); } return; case WIN_PACKETCMD: /* ATAPI Packet */ - if (!ide_drive_is_atapi(ide)) + if (ide->type != IDE_ATAPI) goto abort_cmd; ide_atapi_callback(ide); @@ -2387,7 +2246,7 @@ ide_callback(void *priv) abort_cmd: ide->command = 0; - if (ide_drive_is_atapi(ide)) { + if (ide->type == IDE_ATAPI) { ide->sc->status = DRDY_STAT | ERR_STAT | DSC_STAT; ide->sc->error = ABRT_ERR; ide->sc->pos = 0; @@ -2410,25 +2269,28 @@ id_not_found: static void ide_set_handlers(uint8_t board) { - if (ide_base_main[board] & 0x300) { + if (ide_boards[board] == NULL) + return; + + if (ide_boards[board]->base_main & 0x300) { if (ide_boards[board]->bit32) { - io_sethandler(ide_base_main[board], 1, + io_sethandler(ide_boards[board]->base_main, 1, ide_readb, ide_readw, ide_readl, ide_writeb, ide_writew, ide_writel, ide_boards[board]); } else { - io_sethandler(ide_base_main[board], 1, + io_sethandler(ide_boards[board]->base_main, 1, ide_readb, ide_readw, NULL, ide_writeb, ide_writew, NULL, ide_boards[board]); } - io_sethandler(ide_base_main[board] + 1, 7, + io_sethandler(ide_boards[board]->base_main + 1, 7, ide_readb, NULL, NULL, ide_writeb, NULL, NULL, ide_boards[board]); } - if (ide_side_main[board] & 0x300) { - io_sethandler(ide_side_main[board], 1, + if (ide_boards[board]->side_main & 0x300) { + io_sethandler(ide_boards[board]->side_main, 1, ide_read_alt_status, NULL, NULL, ide_write_devctl, NULL, NULL, ide_boards[board]); @@ -2439,25 +2301,25 @@ ide_set_handlers(uint8_t board) static void ide_remove_handlers(uint8_t board) { - if (!ide_boards[board]) + if (ide_boards[board] == NULL) return; if (ide_boards[board]->bit32) { - io_removehandler(ide_base_main[board], 1, + io_removehandler(ide_boards[board]->base_main, 1, ide_readb, ide_readw, ide_readl, ide_writeb, ide_writew, ide_writel, ide_boards[board]); } else { - io_removehandler(ide_base_main[board], 1, + io_removehandler(ide_boards[board]->base_main, 1, ide_readb, ide_readw, NULL, ide_writeb, ide_writew, NULL, ide_boards[board]); } - io_removehandler(ide_base_main[board] + 1, 7, + io_removehandler(ide_boards[board]->base_main + 1, 7, ide_readb, NULL, NULL, ide_writeb, NULL, NULL, ide_boards[board]); - io_removehandler(ide_side_main[board], 1, + io_removehandler(ide_boards[board]->side_main, 1, ide_read_alt_status, NULL, NULL, ide_write_devctl, NULL, NULL, ide_boards[board]); @@ -2493,35 +2355,184 @@ ide_sec_disable(void) void -ide_set_base(int controller, uint16_t port) +ide_set_base(int board, uint16_t port) { - ide_base_main[controller] = port; + ide_log("ide_set_base(%i, %04X)\n", board, port); + + if (ide_boards[board] == NULL) + return; + + ide_boards[board]->base_main = port; } void -ide_set_side(int controller, uint16_t port) +ide_set_side(int board, uint16_t port) { - ide_side_main[controller] = port; + ide_log("ide_set_side(%i, %04X)\n", board, port); + + if (ide_boards[board] == NULL) + return; + + ide_boards[board]->side_main = port; +} + + +static void +ide_clear_bus_master(int board) +{ + if (ide_bm[board]) { + free(ide_bm[board]); + ide_bm[board] = NULL; + } +} + + +static void +ide_board_close(int board) +{ + ide_t *dev; + int c, d; + + ide_log("ide_board_close(%i)\n", board); + + if ((ide_boards[board] == NULL)|| !ide_boards[board]->inited) + return; + + ide_log("IDE: Closing board %i...\n", board); + + timer_stop(&ide_boards[board]->timer); + + ide_clear_bus_master(board); + + /* Close hard disk image files (if previously open) */ + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + dev = ide_drives[c]; + + if (dev == NULL) + continue; + + if ((dev->type == IDE_HDD) && (dev->hdd_num != -1)) + hdd_image_close(dev->hdd_num); + + if (dev->type == IDE_ATAPI) + dev->sc->status = DRDY_STAT | DSC_STAT; + + if (dev->buffer) { + free(dev->buffer); + dev->buffer = NULL; + } + + if (dev->sector_buffer) { + free(dev->sector_buffer); + dev->buffer = NULL; + } + + if (dev) { + free(dev); + ide_drives[c] = NULL; + } + } + + free(ide_boards[board]); + ide_boards[board] = NULL; +} + + +static void +ide_board_setup(int board) +{ + ide_t *dev; + int c, d; + int ch, is_ide, valid_ch; + int min_ch, max_ch; + + min_ch = (board << 1); + max_ch = min_ch + 1; + + ide_log("IDE: board %i: loading disks...\n", board); + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + ide_zero(c); + } + + c = 0; + for (d = 0; d < HDD_NUM; d++) { + is_ide = (hdd[d].bus == HDD_BUS_IDE); + ch = hdd[d].ide_channel; + + if (board == 4) { + valid_ch = ((ch >= 0) && (ch <= 1)); + ch |= 8; + } else + valid_ch = ((ch >= min_ch) && (ch <= max_ch)); + + if (is_ide && valid_ch) { + ide_log("Found IDE hard disk on channel %i\n", ch); + loadhd(ide_drives[ch], d, hdd[d].fn); + if (ide_drives[ch]->sector_buffer == NULL) + ide_drives[ch]->sector_buffer = (uint8_t *) malloc(256*512); + memset(ide_drives[ch]->sector_buffer, 0, 256*512); + if (++c >= 2) break; + } + } + ide_log("IDE: board %i: done, loaded %d disks.\n", board, c); + + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + dev = ide_drives[c]; + + if (dev->type == IDE_NONE) + continue; + + ide_allocate_buffer(dev); + + ide_set_signature(dev); + + dev->mdma_mode = (1 << ide_get_max(dev, TYPE_PIO)); + dev->error = 1; + dev->cfg_spt = dev->cfg_hpc = 0; + } +} + + +static void +ide_board_init(int board, int irq, int base_main, int side_main, int type) +{ + ide_log("ide_board_init(%i, %i, %04X, %04X, %i)\n", board, irq, base_main, side_main, type); + + if ((ide_boards[board] != NULL) && ide_boards[board]->inited) + return; + + ide_log("IDE: Initializing board %i...\n", board); + + ide_boards[board] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[board], 0, sizeof(ide_board_t)); + ide_boards[board]->irq = irq; + ide_boards[board]->cur_dev = board << 1; + if (type & 6) + ide_boards[board]->bit32 = 1; + if (base_main != -1) + ide_boards[board]->base_main = base_main; + if (side_main != -1) + ide_boards[board]->side_main = side_main; + ide_set_handlers(board); + + timer_add(&ide_boards[board]->timer, ide_callback, ide_boards[board], 0); + + ide_board_setup(board); + + ide_boards[board]->inited = 1; } static void * ide_ter_init(const device_t *info) { - ide_boards[2] = (ide_board_t *) malloc(sizeof(ide_board_t)); - memset(ide_boards[2], 0, sizeof(ide_board_t)); + ide_board_init(2, device_get_config_int("irq"), 0x168, 0x36e, info->local); - ide_boards[2]->irq = device_get_config_int("irq"); - ide_boards[2]->cur_dev = 4; - - ide_set_handlers(2); - - timer_add(ide_callback, &ide_boards[2]->callback, &ide_boards[2]->callback, ide_boards[2]); - - ide_board_init(2); - - return(ide_drives); + return(ide_boards[2]); } @@ -2529,31 +2540,16 @@ ide_ter_init(const device_t *info) static void ide_ter_close(void *priv) { - if (ide_boards[2]) { - free(ide_boards[2]); - ide_boards[2] = NULL; - - ide_board_close(2); - } + ide_board_close(2); } static void * ide_qua_init(const device_t *info) { - ide_boards[3] = (ide_board_t *) malloc(sizeof(ide_board_t)); - memset(ide_boards[3], 0, sizeof(ide_board_t)); + ide_board_init(3, device_get_config_int("irq"), 0x1e8, 0x3ee, info->local); - ide_boards[3]->irq = device_get_config_int("irq"); - ide_boards[3]->cur_dev = 6; - - ide_set_handlers(3); - - timer_add(ide_callback, &ide_boards[3]->callback, &ide_boards[3]->callback, ide_boards[3]); - - ide_board_init(3); - - return(ide_drives); + return(ide_boards[3]); } @@ -2561,40 +2557,14 @@ ide_qua_init(const device_t *info) static void ide_qua_close(void *priv) { - if (ide_boards[3]) { - free(ide_boards[3]); - ide_boards[3] = NULL; - - ide_board_close(3); - } -} - - -static void -ide_clear_bus_master(void) -{ - ide_bus_master_dma = NULL; - ide_bus_master_set_irq = NULL; - ide_bus_master_priv[0] = ide_bus_master_priv[1] = NULL; + ide_board_close(3); } void * ide_xtide_init(void) { - ide_clear_bus_master(); - - if (!ide_boards[0]) { - ide_boards[0] = (ide_board_t *) malloc(sizeof(ide_board_t)); - memset(ide_boards[0], 0, sizeof(ide_board_t)); - ide_boards[0]->cur_dev = 0; - - timer_add(ide_callback, &ide_boards[0]->callback, &ide_boards[0]->callback, - ide_boards[0]); - - ide_board_init(0); - } - ide_boards[0]->irq = -1; + ide_board_init(0, -1, -1, -1, 0); return ide_boards[0]; } @@ -2603,34 +2573,21 @@ ide_xtide_init(void) void ide_xtide_close(void) { - if (ide_boards[0]) { - free(ide_boards[0]); - ide_boards[0] = NULL; - - ide_board_close(0); - } + ide_board_close(0); } void -ide_set_bus_master(int (*dma)(int channel, uint8_t *data, int transfer_length, int out, void *priv), - void (*set_irq)(int channel, void *priv), - void *priv0, void *priv1) +ide_set_bus_master(int board, + int (*dma)(int channel, uint8_t *data, int transfer_length, int out, void *priv), + void (*set_irq)(int channel, void *priv), void *priv) { - ide_bus_master_dma = dma; - ide_bus_master_set_irq = set_irq; - ide_bus_master_priv[0] = priv0; - ide_bus_master_priv[1] = priv1; -} + if (ide_bm[board] == NULL) + ide_bm[board] = (ide_bm_t *) malloc(sizeof(ide_bm_t)); - -void -secondary_ide_check(void) -{ - /* If secondary IDE is optional and the secondary master is not present or not ATAPI, - disable secondary IDE. */ - if (ide_sec_optional && (!ide_drives[4] || (ide_drives[4]->type != IDE_ATAPI))) - ide_remove_handlers(1); + ide_bm[board]->dma = dma; + ide_bm[board]->set_irq = set_irq; + ide_bm[board]->priv = priv; } @@ -2641,58 +2598,15 @@ ide_init(const device_t *info) switch(info->local) { case 0: /* ISA, single-channel */ - case 2: /* ISA, dual-channel */ - case 3: /* ISA, dual-channel, optional 2nd channel */ - case 4: /* VLB, single-channel */ - case 6: /* VLB, dual-channel */ - case 8: /* PCI, single-channel */ - case 10: /* PCI, dual-channel */ - if (!ide_inited) { - pio_override = 0; + case 1: /* ISA, dual-channel */ + case 2: /* VLB, single-channel */ + case 3: /* VLB, dual-channel */ + case 4: /* PCI, single-channel */ + case 5: /* PCI, dual-channel */ + ide_board_init(0, 14, 0x1f0, 0x3f6, info->local); - if (!(info->local & 8)) - ide_clear_bus_master(); - } - - if (!(ide_inited & 1)) { - ide_boards[0] = (ide_board_t *) malloc(sizeof(ide_board_t)); - memset(ide_boards[0], 0, sizeof(ide_board_t)); - ide_boards[0]->irq = 14; - ide_boards[0]->cur_dev = 0; - if (info->local & 8) - ide_boards[0]->bit32 = 1; - ide_base_main[0] = 0x1f0; - ide_side_main[0] = 0x3f6; - ide_set_handlers(0); - timer_add(ide_callback, &ide_boards[0]->callback, &ide_boards[0]->callback, - ide_boards[0]); - ide_log("Callback 0 pointer: %08X\n", &ide_boards[0]->callback); - - ide_board_init(0); - - ide_inited |= 1; - } - - if ((info->local & 3) && !(ide_inited & 2)) { - ide_boards[1] = (ide_board_t *) malloc(sizeof(ide_board_t)); - memset(ide_boards[1], 0, sizeof(ide_board_t)); - ide_boards[1]->irq = 15; - ide_boards[1]->cur_dev = 2; - if (info->local & 8) - ide_boards[1]->bit32 = 1; - ide_base_main[1] = 0x170; - ide_side_main[1] = 0x376; - ide_set_handlers(1); - timer_add(ide_callback, &ide_boards[1]->callback, &ide_boards[1]->callback, - ide_boards[1]); - ide_log("Callback 1 pointer: %08X\n", &ide_boards[1]->callback); - - ide_board_init(1); - - ide_sec_optional = (info->local & 1); - - ide_inited |= 2; - } + if (info->local & 1) + ide_board_init(1, 15, 0x170, 0x376, info->local); break; } @@ -2700,16 +2614,11 @@ ide_init(const device_t *info) } -void -ide_enable_pio_override(void) -{ - pio_override = 1; -} - - static void ide_drive_reset(int d) { + ide_log("Resetting IDE drive %i...\n", d); + ide_drives[d]->channel = d; ide_drives[d]->atastat = DRDY_STAT | DSC_STAT; ide_drives[d]->service = 0; @@ -2717,7 +2626,7 @@ ide_drive_reset(int d) if (ide_boards[d >> 1]) { ide_boards[d >> 1]->cur_dev = d & ~1; - ide_boards[d >> 1]->callback = 0LL; + timer_stop(&ide_boards[d >> 1]->timer); } ide_set_signature(ide_drives[d]); @@ -2730,23 +2639,31 @@ ide_drive_reset(int d) } +static void +ide_board_reset(int board) +{ + int d, min, max; + + ide_log("Resetting IDE board %i...\n", board); + + timer_stop(&ide_boards[board]->timer); + + min = (board << 1); + max = min + 2; + + for (d = min; d < max; d++) + ide_drive_reset(d); +} + + /* Reset a standalone IDE unit. */ static void ide_reset(void *p) { - int d; - ide_log("Resetting IDE...\n"); - if (ide_inited & 1) { - for (d = 0; d < 2; d++) - ide_drive_reset(d); - } - - if (ide_inited & 2) { - for (d = 2; d < 4; d++) - ide_drive_reset(d); - } + ide_board_reset(0); + ide_board_reset(1); } @@ -2756,21 +2673,8 @@ ide_close(void *priv) { ide_log("Closing IDE...\n"); - if ((ide_inited & 1) && (ide_boards[0])) { - free(ide_boards[0]); - ide_boards[0] = NULL; - - ide_board_close(0); - } - - if ((ide_inited & 2) && (ide_boards[1])) { - free(ide_boards[1]); - ide_boards[1] = NULL; - - ide_board_close(1); - } - - ide_inited = 0; + ide_board_close(0); + ide_board_close(1); } @@ -2785,15 +2689,7 @@ const device_t ide_isa_device = { const device_t ide_isa_2ch_device = { "ISA PC/AT IDE Controller (Dual-Channel)", DEVICE_ISA | DEVICE_AT, - 2, - ide_init, ide_close, ide_reset, - NULL, NULL, NULL, NULL -}; - -const device_t ide_isa_2ch_opt_device = { - "ISA PC/AT IDE Controller (Single/Dual)", - DEVICE_ISA | DEVICE_AT, - 3, + 1, ide_init, ide_close, ide_reset, NULL, NULL, NULL, NULL }; @@ -2801,7 +2697,7 @@ const device_t ide_isa_2ch_opt_device = { const device_t ide_vlb_device = { "VLB IDE Controller", DEVICE_VLB | DEVICE_AT, - 4, + 2, ide_init, ide_close, ide_reset, NULL, NULL, NULL, NULL }; @@ -2809,7 +2705,7 @@ const device_t ide_vlb_device = { const device_t ide_vlb_2ch_device = { "VLB IDE Controller (Dual-Channel)", DEVICE_VLB | DEVICE_AT, - 6, + 3, ide_init, ide_close, ide_reset, NULL, NULL, NULL, NULL }; @@ -2817,7 +2713,7 @@ const device_t ide_vlb_2ch_device = { const device_t ide_pci_device = { "PCI IDE Controller", DEVICE_PCI | DEVICE_AT, - 8, + 4, ide_init, ide_close, ide_reset, NULL, NULL, NULL, NULL }; @@ -2825,7 +2721,7 @@ const device_t ide_pci_device = { const device_t ide_pci_2ch_device = { "PCI IDE Controller (Dual-Channel)", DEVICE_PCI | DEVICE_AT, - 10, + 5, ide_init, ide_close, ide_reset, NULL, NULL, NULL, NULL }; diff --git a/src/disk/hdc_ide.h b/src/disk/hdc_ide.h index 9bcd01d19..b2f96807a 100644 --- a/src/disk/hdc_ide.h +++ b/src/disk/hdc_ide.h @@ -94,16 +94,11 @@ enum { }; -extern int ideboard; extern int ide_ter_enabled, ide_qua_enabled; -#ifdef SCSI_DEVICE_H -extern ide_t *ide_drives[IDE_NUM]; -#endif -extern int64_t idecallback[5]; - #ifdef SCSI_DEVICE_H +extern ide_t * ide_get_drive(int ch); extern void ide_irq_raise(ide_t *ide); extern void ide_irq_lower(ide_t *ide); extern void ide_allocate_buffer(ide_t *dev); @@ -120,23 +115,22 @@ extern uint8_t ide_readb(uint16_t addr, void *priv); extern uint8_t ide_read_alt_status(uint16_t addr, void *priv); extern uint16_t ide_readw(uint16_t addr, void *priv); -extern void ide_set_bus_master(int (*dmna)(int channel, uint8_t *data, int transfer_length, int out, void *priv), - void (*set_irq)(int channel, void *priv), - void *priv0, void *priv1); +extern void ide_set_bus_master(int board, + int (*dma)(int channel, uint8_t *data, int transfer_length, int out, void *priv), + void (*set_irq)(int channel, void *priv), void *priv); extern void win_cdrom_eject(uint8_t id); extern void win_cdrom_reload(uint8_t id); -extern void ide_set_base(int controller, uint16_t port); -extern void ide_set_side(int controller, uint16_t port); +extern void ide_set_base(int board, uint16_t port); +extern void ide_set_side(int board, uint16_t port); extern void ide_pri_enable(void); extern void ide_pri_disable(void); extern void ide_sec_enable(void); extern void ide_sec_disable(void); -extern void ide_set_callback(uint8_t channel, int64_t callback); -extern void secondary_ide_check(void); +extern void ide_set_callback(uint8_t channel, double callback); extern void ide_padstr(char *str, const char *src, int len); extern void ide_padstr8(uint8_t *buf, int buf_size, const char *src); @@ -145,7 +139,5 @@ extern int (*ide_bus_master_dma)(int channel, uint8_t *data, int transfer_length extern void (*ide_bus_master_set_irq)(int channel, void *priv); extern void *ide_bus_master_priv[2]; -extern void ide_enable_pio_override(void); - #endif /*EMU_IDE_H*/ diff --git a/src/disk/hdc_ide_sff8038i.c b/src/disk/hdc_ide_sff8038i.c new file mode 100644 index 000000000..ffa6a8a0c --- /dev/null +++ b/src/disk/hdc_ide_sff8038i.c @@ -0,0 +1,471 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the SFF-8038i IDE Bus Master. + * + * PRD format : + * word 0 - base address + * word 1 - bits 1-15 = byte count, bit 31 = end of transfer + * + * Version: @(#)hdc_ide_sff8038i.c 1.0.0 2019/05/12 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cdrom/cdrom.h" +#include "../scsi/scsi_device.h" +#include "../scsi/scsi_cdrom.h" +#include "../dma.h" +#include "../io.h" +#include "../device.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../pci.h" +#include "../pic.h" +#include "hdc.h" +#include "hdc_ide.h" +#include "hdc_ide_sff8038i.h" +#include "zip.h" + + +static int next_id = 0; + + +static uint8_t sff_bus_master_read(uint16_t port, void *priv); +static uint16_t sff_bus_master_readw(uint16_t port, void *priv); +static uint32_t sff_bus_master_readl(uint16_t port, void *priv); +static void sff_bus_master_write(uint16_t port, uint8_t val, void *priv); +static void sff_bus_master_writew(uint16_t port, uint16_t val, void *priv); +static void sff_bus_master_writel(uint16_t port, uint32_t val, void *priv); + + +#ifdef ENABLE_SFF_LOG +int sff_do_log = ENABLE_SFF_LOG; + + +static void +sff_log(const char *fmt, ...) +{ + va_list ap; + + if (sff_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define sff_log(fmt, ...) +#endif + + +void +sff_bus_master_handlers(sff8038i_t *dev, uint16_t old_base, uint16_t new_base, int enabled) +{ + io_removehandler(old_base, 0x08, + sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl, + sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel, + dev); + + if (enabled && new_base) { + io_sethandler(new_base, 0x08, + sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl, + sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel, + dev); + } + + dev->enabled = enabled; +} + + +static void +sff_bus_master_next_addr(sff8038i_t *dev) +{ + DMAPageRead(dev->ptr_cur, (uint8_t *)&(dev->addr), 4); + DMAPageRead(dev->ptr_cur + 4, (uint8_t *)&(dev->count), 4); + sff_log("SFF-8038i Bus master DWORDs: %08X %08X\n", dev->addr, dev->count); + dev->eot = dev->count >> 31; + dev->count &= 0xfffe; + if (!dev->count) + dev->count = 65536; + dev->addr &= 0xfffffffe; + dev->ptr_cur += 8; +} + + +static void +sff_bus_master_write(uint16_t port, uint8_t val, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; +#ifdef ENABLE_SFF_LOG + int channel = (port & 8) ? 1 : 0; +#endif + + sff_log("SFF-8038i Bus master BYTE write: %04X %02X\n", port, val); + + switch (port & 7) { + case 0: + sff_log("sff Cmd : val = %02X, old = %02X\n", val, dev->command); + if ((val & 1) && !(dev->command & 1)) { /*Start*/ + sff_log("sff Bus Master start on channel %i\n", channel); + dev->ptr_cur = dev->ptr; + sff_bus_master_next_addr(dev); + dev->status |= 1; + } + if (!(val & 1) && (dev->command & 1)) { /*Stop*/ + sff_log("sff Bus Master stop on channel %i\n", channel); + dev->status &= ~1; + } + + dev->command = val; + break; + case 2: + sff_log("sff Status: val = %02X, old = %02X\n", val, dev->status); + dev->status &= 0x07; + dev->status |= (val & 0x60); + if (val & 0x04) + dev->status &= ~0x04; + if (val & 0x02) + dev->status &= ~0x02; + break; + case 4: + dev->ptr = (dev->ptr & 0xffffff00) | (val & 0xfc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val; + break; + case 5: + dev->ptr = (dev->ptr & 0xffff00fc) | (val << 8); + dev->ptr %= (mem_size * 1024); + break; + case 6: + dev->ptr = (dev->ptr & 0xff00fffc) | (val << 16); + dev->ptr %= (mem_size * 1024); + break; + case 7: + dev->ptr = (dev->ptr & 0x00fffffc) | (val << 24); + dev->ptr %= (mem_size * 1024); + break; + } +} + + +static void +sff_bus_master_writew(uint16_t port, uint16_t val, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; + + sff_log("SFF-8038i Bus master WORD write: %04X %04X\n", port, val); + + switch (port & 7) { + case 0: + case 2: + sff_bus_master_write(port, val & 0xff, priv); + break; + case 4: + dev->ptr = (dev->ptr & 0xffff0000) | (val & 0xfffc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val & 0xff; + break; + case 6: + dev->ptr = (dev->ptr & 0x0000fffc) | (val << 16); + dev->ptr %= (mem_size * 1024); + break; + } +} + + +static void +sff_bus_master_writel(uint16_t port, uint32_t val, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; + + sff_log("SFF-8038i Bus master DWORD write: %04X %08X\n", port, val); + + switch (port & 7) { + case 0: + case 2: + sff_bus_master_write(port, val & 0xff, priv); + break; + case 4: + dev->ptr = (val & 0xfffffffc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val & 0xff; + break; + } +} + + +static uint8_t +sff_bus_master_read(uint16_t port, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; + + uint8_t ret = 0xff; + + switch (port & 7) { + case 0: + ret = dev->command; + break; + case 2: + ret = dev->status & 0x67; + break; + case 4: + ret = dev->ptr0; + break; + case 5: + ret = dev->ptr >> 8; + break; + case 6: + ret = dev->ptr >> 16; + break; + case 7: + ret = dev->ptr >> 24; + break; + } + + sff_log("SFF-8038i Bus master BYTE read : %04X %02X\n", port, ret); + + return ret; +} + + +static uint16_t +sff_bus_master_readw(uint16_t port, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; + + uint16_t ret = 0xffff; + + switch (port & 7) { + case 0: + case 2: + ret = (uint16_t) sff_bus_master_read(port, priv); + break; + case 4: + ret = dev->ptr0 | (dev->ptr & 0xff00); + break; + case 6: + ret = dev->ptr >> 16; + break; + } + + sff_log("SFF-8038i Bus master WORD read : %04X %04X\n", port, ret); + + return ret; +} + + +static uint32_t +sff_bus_master_readl(uint16_t port, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; + + uint32_t ret = 0xffffffff; + + switch (port & 7) { + case 0: + case 2: + ret = (uint32_t) sff_bus_master_read(port, priv); + break; + case 4: + ret = dev->ptr0 | (dev->ptr & 0xffffff00); + break; + } + + sff_log("sff Bus master DWORD read : %04X %08X\n", port, ret); + + return ret; +} + + +static int +sff_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; +#ifdef ENABLE_SFF_LOG + char *sop; +#endif + + int force_end = 0, buffer_pos = 0; + +#ifdef ENABLE_SFF_LOG + sop = out ? "Read" : "Writ"; +#endif + + if (!(dev->status & 1)) + return 2; /*DMA disabled*/ + + sff_log("SFF-8038i Bus master %s: %i bytes\n", out ? "write" : "read", transfer_length); + + while (1) { + if (dev->count <= transfer_length) { + sff_log("%sing %i bytes to %08X\n", sop, dev->count, dev->addr); + if (out) + DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); + else + DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); + transfer_length -= dev->count; + buffer_pos += dev->count; + } else { + sff_log("%sing %i bytes to %08X\n", sop, transfer_length, dev->addr); + if (out) + DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); + else + DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); + /* Increase addr and decrease count so that resumed transfers do not mess up. */ + dev->addr += transfer_length; + dev->count -= transfer_length; + transfer_length = 0; + force_end = 1; + } + + if (force_end) { + sff_log("Total transfer length smaller than sum of all blocks, partial block\n"); + dev->status &= ~2; + return 1; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ + } else { + if (!transfer_length && !dev->eot) { + sff_log("Total transfer length smaller than sum of all blocks, full block\n"); + dev->status &= ~2; + return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */ + } else if (transfer_length && dev->eot) { + sff_log("Total transfer length greater than sum of all blocks\n"); + dev->status |= 2; + return 0; /* There is data left to transfer but we have reached EOT - return with error. */ + } else if (dev->eot) { + sff_log("Regular EOT\n"); + dev->status &= ~3; + return 1; /* We have regularly reached EOT - clear status and break. */ + } else { + /* We have more to transfer and there are blocks left, get next block. */ + sff_bus_master_next_addr(dev); + } + } + } + + return 1; +} + + +void +sff_bus_master_set_irq(int channel, void *priv) +{ + sff8038i_t *dev = (sff8038i_t *) priv; + dev->status &= ~4; + dev->status |= (channel >> 4); + + channel &= 0x01; + if (dev->status & 0x04) { + if (channel && pci_use_mirq(0)) + pci_set_mirq(0); + else + picint(1 << (14 + channel)); + } else { + if ((channel & 1) && pci_use_mirq(0)) + pci_clear_mirq(0); + else + picintc(1 << (14 + channel)); + } +} + + +void +sff_bus_master_reset(sff8038i_t *dev, uint16_t old_base) +{ + if (dev->enabled) { + io_removehandler(old_base, 0x08, + sff_bus_master_read, sff_bus_master_readw, sff_bus_master_readl, + sff_bus_master_write, sff_bus_master_writew, sff_bus_master_writel, + dev); + + dev->enabled = 0; + } + + dev->command = 0x00; + dev->status = 0x00; + dev->ptr = dev->ptr_cur = 0x00000000; + dev->addr = 0x00000000; + dev->ptr0 = 0x00; + dev->count = dev->eot = 0x00000000; + + ide_pri_disable(); + ide_sec_disable(); +} + + +static void +sff_reset(void *p) +{ + int i = 0; + + for (i = 0; i < CDROM_NUM; i++) { + if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && + (cdrom[i].ide_channel < 4) && cdrom[i].priv) + scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv); + } + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && + (zip_drives[i].ide_channel < 4) && zip_drives[i].priv) + zip_reset((scsi_common_t *) zip_drives[i].priv); + } +} + + +static void +sff_close(void *p) +{ + sff8038i_t *dev = (sff8038i_t *)p; + + free(dev); + + next_id--; + if (next_id < 0) + next_id = 0; +} + + +static void +*sff_init(const device_t *info) +{ + sff8038i_t *dev = (sff8038i_t *) malloc(sizeof(sff8038i_t)); + memset(dev, 0, sizeof(sff8038i_t)); + + /* Make sure to only add IDE once. */ + if (next_id == 0) + device_add(&ide_pci_2ch_device); + + ide_set_bus_master(next_id, sff_bus_master_dma, sff_bus_master_set_irq, dev); + + next_id++; + + return dev; +} + + +const device_t sff8038i_device = +{ + "SFF-8038i IDE Bus Master", + DEVICE_PCI, + 0, + sff_init, + sff_close, + sff_reset, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/disk/hdc_ide_sff8038i.h b/src/disk/hdc_ide_sff8038i.h new file mode 100644 index 000000000..0be341eff --- /dev/null +++ b/src/disk/hdc_ide_sff8038i.h @@ -0,0 +1,38 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the SFF-8038i IDE Bus Master. + * + * Emulation core dispatcher. + * + * Version: @(#)hdc_ide_sff8038i.h 1.0.0 2019/05/12 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +typedef struct +{ + uint8_t command, status, + ptr0, enabled; + uint32_t ptr, ptr_cur, + addr; + int count, eot; +} sff8038i_t; + + +extern const device_t sff8038i_device; + +extern void sff_bus_master_handlers(sff8038i_t *dev, uint16_t old_base, uint16_t new_base, int enabled); + +extern int sff_bus_master_dma_read(int channel, uint8_t *data, int transfer_length, void *priv); +extern int sff_bus_master_dma_write(int channel, uint8_t *data, int transfer_length, void *priv); + +extern void sff_bus_master_set_irq(int channel, void *priv); + +extern void sff_bus_master_reset(sff8038i_t *dev, uint16_t old_base); diff --git a/src/disk/hdc_mfm_xt.c b/src/disk/hdc_mfm_xt.c deleted file mode 100644 index d1adb1005..000000000 --- a/src/disk/hdc_mfm_xt.c +++ /dev/null @@ -1,949 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Driver for the IBM PC-XT Fixed Disk controller. - * - * The original controller shipped by IBM was made by Xebec, and - * several variations had been made: - * - * #1 Original, single drive (ST412), 10MB, 2 heads. - * #2 Update, single drive (ST412) but with option for a - * switch block that can be used to 'set' the actual - * drive type. Four switches are define, where switches - * 1 and 2 define drive0, and switches 3 and 4 drive1. - * - * 0 ON ON 306 2 0 - * 1 ON OFF 375 8 0 - * 2 OFF ON 306 6 256 - * 3 OFF OFF 306 4 0 - * - * The latter option is the default, in use on boards - * without the switch block option. - * - * #3 Another updated board, mostly to accomodate the new - * 20MB disk now being shipped. The controller can have - * up to 2 drives, the type of which is set using the - * switch block: - * - * SW1 SW2 CYLS HD SPT WPC - * 0 ON ON 306 4 17 0 - * 1 ON OFF 612 4 17 0 (type 16) - * 2 OFF ON 615 4 17 300 (Seagate ST-225, 2) - * 3 OFF OFF 306 8 17 128 (IBM WD25, 13) - * - * Examples of #3 are IBM/Xebec, WD10004A-WX1 and ST11R. - * - * Since all controllers (including the ones made by DTC) use - * (mostly) the same API, we keep them all in this module. - * - * Version: @(#)hdc_mfm_xt.c 1.0.18 2018/10/17 - * - * Authors: Sarah Walker, - * Fred N. van Kempen, - * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2017,2018 Fred N. van Kempen. - */ -#define __USE_LARGEFILE64 -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include "../86box.h" -#include "../device.h" -#include "../dma.h" -#include "../io.h" -#include "../mem.h" -#include "../pic.h" -#include "../rom.h" -#include "../timer.h" -#include "../plat.h" -#include "../ui.h" -#include "hdc.h" -#include "hdd.h" - - -// #define MFM_TIME (2000LL*TIMER_USEC) -#define MFM_TIME (50LL*TIMER_USEC) -#define XEBEC_BIOS_FILE L"roms/hdd/mfm_xebec/ibm_xebec_62x0822_1985.bin" -#define DTC_BIOS_FILE L"roms/hdd/mfm_xebec/dtc_cxd21a.bin" - - -enum { - STATE_IDLE, - STATE_RECEIVE_COMMAND, - STATE_START_COMMAND, - STATE_RECEIVE_DATA, - STATE_RECEIVED_DATA, - STATE_SEND_DATA, - STATE_SENT_DATA, - STATE_COMPLETION_BYTE, - STATE_DUNNO -}; - - -typedef struct { - int spt, hpc; - int tracks; - int cfg_spt; - int cfg_hpc; - int cfg_cyl; - int current_cylinder; - int present; - int hdd_num; -} drive_t; - -typedef struct { - rom_t bios_rom; - int64_t callback; - int state; - uint8_t status; - uint8_t command[6]; - int command_pos; - uint8_t data[512]; - int data_pos, data_len; - uint8_t sector_buf[512]; - uint8_t irq_dma_mask; - uint8_t completion_byte; - uint8_t error; - int drive_sel; - drive_t drives[2]; - int sector, head, cylinder; - int sector_count; - uint8_t switches; -} mfm_t; - -#define STAT_IRQ 0x20 -#define STAT_DRQ 0x10 -#define STAT_BSY 0x08 -#define STAT_CD 0x04 -#define STAT_IO 0x02 -#define STAT_REQ 0x01 - -#define IRQ_ENA 0x02 -#define DMA_ENA 0x01 - -#define CMD_TEST_DRIVE_READY 0x00 -#define CMD_RECALIBRATE 0x01 -#define CMD_READ_STATUS 0x03 -#define CMD_VERIFY_SECTORS 0x05 -#define CMD_FORMAT_TRACK 0x06 -#define CMD_READ_SECTORS 0x08 -#define CMD_WRITE_SECTORS 0x0a -#define CMD_SEEK 0x0b -#define CMD_INIT_DRIVE_PARAMS 0x0c -#define CMD_WRITE_SECTOR_BUFFER 0x0f -#define CMD_BUFFER_DIAGNOSTIC 0xe0 -#define CMD_CONTROLLER_DIAGNOSTIC 0xe4 -#define CMD_DTC_GET_DRIVE_PARAMS 0xfb -#define CMD_DTC_SET_STEP_RATE 0xfc -#define CMD_DTC_SET_GEOMETRY 0xfe -#define CMD_DTC_GET_GEOMETRY 0xff - -#define ERR_NOT_READY 0x04 -#define ERR_SEEK_ERROR 0x15 -#define ERR_ILLEGAL_SECTOR_ADDRESS 0x21 - - -#ifdef ENABLE_MFM_XT_LOG -int mfm_xt_do_log = ENABLE_MFM_XT_LOG; - - -static void -mfm_xt_log(const char *fmt, ...) -{ - va_list ap; - - if (mfm_xt_do_log) { - va_start(ap, fmt); - pclog_ex(fmt, ap); - va_end(ap); - } -} -#else -#define mfm_xt_log(fmt, ...) -#endif - - -static uint8_t -mfm_read(uint16_t port, void *priv) -{ - mfm_t *mfm = (mfm_t *)priv; - uint8_t temp = 0xff; - - switch (port) { - case 0x320: /*Read data*/ - mfm->status &= ~STAT_IRQ; - switch (mfm->state) { - case STATE_COMPLETION_BYTE: - if ((mfm->status & 0xf) != (STAT_CD | STAT_IO | STAT_REQ | STAT_BSY)) - fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", mfm->status); - - temp = mfm->completion_byte; - mfm->status = 0; - mfm->state = STATE_IDLE; - break; - - case STATE_SEND_DATA: - if ((mfm->status & 0xf) != (STAT_IO | STAT_REQ | STAT_BSY)) - fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", mfm->status); - if (mfm->data_pos >= mfm->data_len) - fatal("Data write with full data!\n"); - temp = mfm->data[mfm->data_pos++]; - if (mfm->data_pos == mfm->data_len) { - mfm->status = STAT_BSY; - mfm->state = STATE_SENT_DATA; - mfm->callback = MFM_TIME; - } - break; - - default: - fatal("Read data register - %i, %02x\n", mfm->state, mfm->status); - } - break; - - case 0x321: /*Read status*/ - temp = mfm->status; - break; - - case 0x322: /*Read option jumpers*/ - temp = mfm->switches; - break; - } - - return(temp); -} - - -static void -mfm_write(uint16_t port, uint8_t val, void *priv) -{ - mfm_t *mfm = (mfm_t *)priv; - - switch (port) { - case 0x320: /*Write data*/ - switch (mfm->state) { - case STATE_RECEIVE_COMMAND: - if ((mfm->status & 0xf) != (STAT_BSY | STAT_CD | STAT_REQ)) - fatal("Bad write data state - STATE_START_COMMAND, status=%02x\n", mfm->status); - if (mfm->command_pos >= 6) - fatal("Command write with full command!\n"); - /*Command data*/ - mfm->command[mfm->command_pos++] = val; - if (mfm->command_pos == 6) { - mfm->status = STAT_BSY; - mfm->state = STATE_START_COMMAND; - mfm->callback = MFM_TIME; - } - break; - - case STATE_RECEIVE_DATA: - if ((mfm->status & 0xf) != (STAT_BSY | STAT_REQ)) - fatal("Bad write data state - STATE_RECEIVE_DATA, status=%02x\n", mfm->status); - if (mfm->data_pos >= mfm->data_len) - fatal("Data write with full data!\n"); - /*Command data*/ - mfm->data[mfm->data_pos++] = val; - if (mfm->data_pos == mfm->data_len) { - mfm->status = STAT_BSY; - mfm->state = STATE_RECEIVED_DATA; - mfm->callback = MFM_TIME; - } - break; - - default: - fatal("Write data unknown state - %i %02x\n", mfm->state, mfm->status); - } - break; - - case 0x321: /*Controller reset*/ - mfm->status = 0; - break; - - case 0x322: /*Generate controller-select-pulse*/ - mfm->status = STAT_BSY | STAT_CD | STAT_REQ; - mfm->command_pos = 0; - mfm->state = STATE_RECEIVE_COMMAND; - break; - - case 0x323: /*DMA/IRQ mask register*/ - mfm->irq_dma_mask = val; - break; - } -} - - -static void mfm_complete(mfm_t *mfm) -{ - mfm->status = STAT_REQ | STAT_CD | STAT_IO | STAT_BSY; - mfm->state = STATE_COMPLETION_BYTE; - - if (mfm->irq_dma_mask & IRQ_ENA) { - mfm->status |= STAT_IRQ; - picint(1 << 5); - } -} - - -static void -mfm_error(mfm_t *mfm, uint8_t error) -{ - mfm->completion_byte |= 0x02; - mfm->error = error; - - mfm_xt_log("mfm_error - %02x\n", mfm->error); -} - - -static int -get_sector(mfm_t *mfm, off64_t *addr) -{ - drive_t *drive = &mfm->drives[mfm->drive_sel]; - int heads = drive->cfg_hpc; - - if (drive->current_cylinder != mfm->cylinder) { - mfm_xt_log("mfm_get_sector: wrong cylinder\n"); - mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; - return(1); - } - if (mfm->head > heads) { - mfm_xt_log("mfm_get_sector: past end of configured heads\n"); - mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; - return(1); - } - if (mfm->head > drive->hpc) { - mfm_xt_log("mfm_get_sector: past end of heads\n"); - mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; - return(1); - } - if (mfm->sector >= 17) { - mfm_xt_log("mfm_get_sector: past end of sectors\n"); - mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; - return(1); - } - - *addr = ((((off64_t) mfm->cylinder * heads) + mfm->head) * - 17) + mfm->sector; - - return(0); -} - - -static void -next_sector(mfm_t *mfm) -{ - drive_t *drive = &mfm->drives[mfm->drive_sel]; - - mfm->sector++; - if (mfm->sector >= 17) { - mfm->sector = 0; - mfm->head++; - if (mfm->head >= drive->cfg_hpc) { - mfm->head = 0; - mfm->cylinder++; - drive->current_cylinder++; - if (drive->current_cylinder >= drive->cfg_cyl) - drive->current_cylinder = drive->cfg_cyl-1; - } - } -} - - -static void -mfm_callback(void *priv) -{ - mfm_t *mfm = (mfm_t *)priv; - drive_t *drive; - off64_t addr; - - mfm->callback = 0LL; - - mfm->drive_sel = (mfm->command[1] & 0x20) ? 1 : 0; - mfm->completion_byte = mfm->drive_sel & 0x20; - drive = &mfm->drives[mfm->drive_sel]; - - switch (mfm->command[0]) { - case CMD_TEST_DRIVE_READY: - if (!drive->present) - mfm_error(mfm, ERR_NOT_READY); - mfm_complete(mfm); - break; - - case CMD_RECALIBRATE: - if (!drive->present) - mfm_error(mfm, ERR_NOT_READY); - else { - mfm->cylinder = 0; - drive->current_cylinder = 0; - } - mfm_complete(mfm); - break; - - case CMD_READ_STATUS: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->state = STATE_SEND_DATA; - mfm->data_pos = 0; - mfm->data_len = 4; - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - mfm->data[0] = mfm->error; - mfm->data[1] = mfm->drive_sel ? 0x20 : 0; - mfm->data[2] = mfm->data[3] = 0; - mfm->error = 0; - break; - - case STATE_SENT_DATA: - mfm_complete(mfm); - break; - } - break; - - case CMD_VERIFY_SECTORS: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; - mfm->head = mfm->command[1] & 0x1f; - mfm->sector = mfm->command[2] & 0x1f; - mfm->sector_count = mfm->command[4]; - do { - if (get_sector(mfm, &addr)) { - mfm_xt_log("get_sector failed\n"); - mfm_error(mfm, mfm->error); - mfm_complete(mfm); - return; - } - - next_sector(mfm); - - mfm->sector_count = (mfm->sector_count-1) & 0xff; - } while (mfm->sector_count); - - mfm_complete(mfm); - - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); - break; - - default: - fatal("CMD_VERIFY_SECTORS: bad state %i\n", mfm->state); - } - break; - - case CMD_FORMAT_TRACK: - mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; - mfm->head = mfm->command[1] & 0x1f; - - if (get_sector(mfm, &addr)) { - mfm_xt_log("get_sector failed\n"); - mfm_error(mfm, mfm->error); - mfm_complete(mfm); - return; - } - - hdd_image_zero(drive->hdd_num, addr, 17); - - mfm_complete(mfm); - break; - - case CMD_READ_SECTORS: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; - mfm->head = mfm->command[1] & 0x1f; - mfm->sector = mfm->command[2] & 0x1f; - mfm->sector_count = mfm->command[4]; - mfm->state = STATE_SEND_DATA; - mfm->data_pos = 0; - mfm->data_len = 512; - - if (get_sector(mfm, &addr)) { - mfm_error(mfm, mfm->error); - mfm_complete(mfm); - return; - } - - hdd_image_read(drive->hdd_num, addr, 1, - (uint8_t *) mfm->sector_buf); - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; - else { - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - memcpy(mfm->data, mfm->sector_buf, 512); - } - break; - - case STATE_SEND_DATA: - mfm->status = STAT_BSY; - if (mfm->irq_dma_mask & DMA_ENA) { - for (; mfm->data_pos < 512; mfm->data_pos++) { - int val = dma_channel_write(3, mfm->sector_buf[mfm->data_pos]); - - if (val == DMA_NODATA) { - mfm_xt_log("CMD_READ_SECTORS out of data!\n"); - mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; - mfm->callback = MFM_TIME; - return; - } - } - mfm->state = STATE_SENT_DATA; - mfm->callback = MFM_TIME; - } else - fatal("Read sectors no DMA! - shouldn't get here\n"); - break; - - case STATE_SENT_DATA: - next_sector(mfm); - - mfm->data_pos = 0; - - mfm->sector_count = (mfm->sector_count-1) & 0xff; - - if (mfm->sector_count) { - if (get_sector(mfm, &addr)) { - mfm_error(mfm, mfm->error); - mfm_complete(mfm); - return; - } - - hdd_image_read(drive->hdd_num, addr, 1, - (uint8_t *) mfm->sector_buf); - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - - mfm->state = STATE_SEND_DATA; - - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; - else { - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - memcpy(mfm->data, mfm->sector_buf, 512); - } - } else { - mfm_complete(mfm); - ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); - } - break; - - default: - fatal("CMD_READ_SECTORS: bad state %i\n", mfm->state); - } - break; - - case CMD_WRITE_SECTORS: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; - mfm->head = mfm->command[1] & 0x1f; - mfm->sector = mfm->command[2] & 0x1f; - mfm->sector_count = mfm->command[4]; - mfm->state = STATE_RECEIVE_DATA; - mfm->data_pos = 0; - mfm->data_len = 512; - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; - else - mfm->status = STAT_BSY | STAT_REQ; - break; - - case STATE_RECEIVE_DATA: - mfm->status = STAT_BSY; - if (mfm->irq_dma_mask & DMA_ENA) { - for (; mfm->data_pos < 512; mfm->data_pos++) { - int val = dma_channel_read(3); - - if (val == DMA_NODATA) { - mfm_xt_log("CMD_WRITE_SECTORS out of data!\n"); - mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; - mfm->callback = MFM_TIME; - return; - } - - mfm->sector_buf[mfm->data_pos] = val & 0xff; - } - - mfm->state = STATE_RECEIVED_DATA; - mfm->callback = MFM_TIME; - } else - fatal("Write sectors no DMA! - should never get here\n"); - break; - - case STATE_RECEIVED_DATA: - if (! (mfm->irq_dma_mask & DMA_ENA)) - memcpy(mfm->sector_buf, mfm->data, 512); - - if (get_sector(mfm, &addr)) - { - mfm_error(mfm, mfm->error); - mfm_complete(mfm); - return; - } - - hdd_image_write(drive->hdd_num, addr, 1, - (uint8_t *) mfm->sector_buf); - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - - next_sector(mfm); - mfm->data_pos = 0; - mfm->sector_count = (mfm->sector_count-1) & 0xff; - - if (mfm->sector_count) { - mfm->state = STATE_RECEIVE_DATA; - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; - else - mfm->status = STAT_BSY | STAT_REQ; - } else - mfm_complete(mfm); - break; - - default: - fatal("CMD_WRITE_SECTORS: bad state %i\n", mfm->state); - } - break; - - case CMD_SEEK: - if (! drive->present) - mfm_error(mfm, ERR_NOT_READY); - else { - int cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); - - drive->current_cylinder = (cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : cylinder; - - if (cylinder != drive->current_cylinder) - mfm_error(mfm, ERR_SEEK_ERROR); - } - mfm_complete(mfm); - break; - - case CMD_INIT_DRIVE_PARAMS: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->state = STATE_RECEIVE_DATA; - mfm->data_pos = 0; - mfm->data_len = 8; - mfm->status = STAT_BSY | STAT_REQ; - break; - - case STATE_RECEIVED_DATA: - drive->cfg_cyl = mfm->data[1] | (mfm->data[0] << 8); - drive->cfg_hpc = mfm->data[2]; - mfm_xt_log("Drive %i: cylinders=%i, heads=%i\n", mfm->drive_sel, drive->cfg_cyl, drive->cfg_hpc); - mfm_complete(mfm); - break; - - default: - fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", mfm->state); - } - break; - - case CMD_WRITE_SECTOR_BUFFER: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->state = STATE_RECEIVE_DATA; - mfm->data_pos = 0; - mfm->data_len = 512; - if (mfm->irq_dma_mask & DMA_ENA) - mfm->callback = MFM_TIME; - else - mfm->status = STAT_BSY | STAT_REQ; - break; - - case STATE_RECEIVE_DATA: - if (mfm->irq_dma_mask & DMA_ENA) { - mfm->status = STAT_BSY; - - for (; mfm->data_pos < 512; mfm->data_pos++) { - int val = dma_channel_read(3); - - if (val == DMA_NODATA) { - mfm_xt_log("CMD_WRITE_SECTOR_BUFFER out of data!\n"); - mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; - mfm->callback = MFM_TIME; - return; - } - - mfm->data[mfm->data_pos] = val & 0xff; - } - - mfm->state = STATE_RECEIVED_DATA; - mfm->callback = MFM_TIME; - } else - fatal("CMD_WRITE_SECTOR_BUFFER - should never get here!\n"); - break; - - case STATE_RECEIVED_DATA: - memcpy(mfm->sector_buf, mfm->data, 512); - mfm_complete(mfm); - break; - - default: - fatal("CMD_WRITE_SECTOR_BUFFER bad state %i\n", mfm->state); - } - break; - - case CMD_BUFFER_DIAGNOSTIC: - case CMD_CONTROLLER_DIAGNOSTIC: - mfm_complete(mfm); - break; - - case 0xfa: - mfm_complete(mfm); - break; - - case CMD_DTC_SET_STEP_RATE: - mfm_complete(mfm); - break; - - case CMD_DTC_GET_DRIVE_PARAMS: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->state = STATE_SEND_DATA; - mfm->data_pos = 0; - mfm->data_len = 4; - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - memset(mfm->data, 0, 4); - mfm->data[0] = drive->tracks & 0xff; - mfm->data[1] = 17 | ((drive->tracks >> 2) & 0xc0); - mfm->data[2] = drive->hpc-1; - mfm_xt_log("Get drive params %02x %02x %02x %i\n", mfm->data[0], mfm->data[1], mfm->data[2], drive->tracks); - break; - - case STATE_SENT_DATA: - mfm_complete(mfm); - break; - - default: - fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", mfm->state); - } - break; - - case CMD_DTC_GET_GEOMETRY: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->state = STATE_SEND_DATA; - mfm->data_pos = 0; - mfm->data_len = 16; - mfm->status = STAT_BSY | STAT_IO | STAT_REQ; - memset(mfm->data, 0, 16); - mfm->data[0x4] = drive->tracks & 0xff; - mfm->data[0x5] = (drive->tracks >> 8) & 0xff; - mfm->data[0xa] = drive->hpc; - break; - - case STATE_SENT_DATA: - mfm_complete(mfm); - break; - } - break; - - case CMD_DTC_SET_GEOMETRY: - switch (mfm->state) { - case STATE_START_COMMAND: - mfm->state = STATE_RECEIVE_DATA; - mfm->data_pos = 0; - mfm->data_len = 16; - mfm->status = STAT_BSY | STAT_REQ; - break; - - case STATE_RECEIVED_DATA: - /*Bit of a cheat here - we always report the actual geometry of the drive in use*/ - mfm_complete(mfm); - break; - } - break; - - default: - fatal("Unknown Xebec command - %02x %02x %02x %02x %02x %02x\n", - mfm->command[0], mfm->command[1], - mfm->command[2], mfm->command[3], - mfm->command[4], mfm->command[5]); - } -} - - -static void -loadhd(mfm_t *mfm, int c, int d, const wchar_t *fn) -{ - drive_t *drive = &mfm->drives[d]; - - if (! hdd_image_load(c)) { - drive->present = 0; - return; - } - - drive->spt = hdd[c].spt; - drive->hpc = hdd[c].hpc; - drive->tracks = hdd[c].tracks; - drive->hdd_num = c; - drive->present = 1; -} - - -static struct { - int tracks, hpc; -} hd_types[4] = { - { 306, 4 }, /* Type 0 */ - { 612, 4 }, /* Type 16 */ - { 615, 4 }, /* Type 2 */ - { 306, 8 } /* Type 13 */ -}; - - -static void -mfm_set_switches(mfm_t *mfm) -{ - int c, d; - - mfm->switches = 0; - - for (d=0; d<2; d++) { - drive_t *drive = &mfm->drives[d]; - - if (! drive->present) continue; - - for (c=0; c<4; c++) { - if (drive->spt == 17 && - drive->hpc == hd_types[c].hpc && - drive->tracks == hd_types[c].tracks) { - mfm->switches |= (c << (d ? 0 : 2)); - break; - } - } - - if (c == 4) - mfm_xt_log("WARNING: Drive %c: has format not supported by Fixed Disk Adapter", d ? 'D' : 'C'); - } -} - - -static void * -xebec_init(const device_t *info) -{ - int i, c = 0; - - mfm_t *xebec = malloc(sizeof(mfm_t)); - memset(xebec, 0x00, sizeof(mfm_t)); - - mfm_xt_log("MFM: looking for disks..\n"); - for (i=0; i MFM_NUM) break; - } - } - mfm_xt_log("MFM: %d disks loaded.\n", c); - - mfm_set_switches(xebec); - - rom_init(&xebec->bios_rom, XEBEC_BIOS_FILE, - 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - - io_sethandler(0x0320, 4, - mfm_read, NULL, NULL, mfm_write, NULL, NULL, xebec); - - timer_add(mfm_callback, &xebec->callback, &xebec->callback, xebec); - - return(xebec); -} - - -static void -mfm_close(void *priv) -{ - mfm_t *mfm = (mfm_t *)priv; - int d; - - for (d=0; d<2; d++) { - drive_t *drive = &mfm->drives[d]; - - hdd_image_close(drive->hdd_num); - } - - free(mfm); -} - - -static int -xebec_available(void) -{ - return(rom_present(XEBEC_BIOS_FILE)); -} - - -const device_t mfm_xt_xebec_device = { - "IBM PC Fixed Disk Adapter", - DEVICE_ISA, - 0, - xebec_init, mfm_close, NULL, - xebec_available, NULL, NULL, NULL -}; - - -static void * -dtc5150x_init(const device_t *info) -{ - int i, c = 0; - - mfm_t *dtc = malloc(sizeof(mfm_t)); - memset(dtc, 0x00, sizeof(mfm_t)); - - mfm_xt_log("MFM: looking for disks..\n"); - for (i=0; i MFM_NUM) break; - } - } - mfm_xt_log("MFM: %d disks loaded.\n", c); - - dtc->switches = 0xff; - - dtc->drives[0].cfg_cyl = dtc->drives[0].tracks; - dtc->drives[0].cfg_hpc = dtc->drives[0].hpc; - dtc->drives[1].cfg_cyl = dtc->drives[1].tracks; - dtc->drives[1].cfg_hpc = dtc->drives[1].hpc; - - rom_init(&dtc->bios_rom, DTC_BIOS_FILE, - 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - - io_sethandler(0x0320, 4, - mfm_read, NULL, NULL, mfm_write, NULL, NULL, dtc); - - timer_add(mfm_callback, &dtc->callback, &dtc->callback, dtc); - - return(dtc); -} - - -static int -dtc5150x_available(void) -{ - return(rom_present(DTC_BIOS_FILE)); -} - - -const device_t mfm_xt_dtc5150x_device = { - "DTC 5150X", - DEVICE_ISA, - 0, - dtc5150x_init, mfm_close, NULL, - dtc5150x_available, NULL, NULL, NULL -}; diff --git a/src/disk/hdc_mfm_at.c b/src/disk/hdc_st506_at.c similarity index 78% rename from src/disk/hdc_mfm_at.c rename to src/disk/hdc_st506_at.c index 8de6a6210..5db99b806 100644 --- a/src/disk/hdc_mfm_at.c +++ b/src/disk/hdc_st506_at.c @@ -12,13 +12,13 @@ * based design. Most cards were WD1003-WA2 or -WAH, where the * -WA2 cards had a floppy controller as well (to save space.) * - * Version: @(#)hdc_mfm_at.c 1.0.18 2018/10/17 + * Version: @(#)hdc_st506_at.c 1.0.19 2019/03/03 * * Authors: Sarah Walker, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. */ #define __USE_LARGEFILE64 #define _LARGEFILE_SOURCE @@ -43,7 +43,15 @@ #include "hdd.h" -#define MFM_TIME (TIMER_USEC*10LL) +#define MFM_TIME (TIMER_USEC*10) + +/*Rough estimate - MFM drives spin at 3600 RPM, with 17 sectors per track, + meaning (3600/60)*17 = 1020 sectors per second, or 980us per sector. + + This is required for OS/2 on slow 286 systems, as the hard drive formatter + will crash with 'internal processing error' if write sector interrupts are too + close in time*/ +#define SECTOR_TIME (TIMER_USEC * 980) #define STAT_ERR 0x01 #define STAT_INDEX 0x02 @@ -104,7 +112,8 @@ typedef struct { pad; int pos; /* offset within data buffer */ - int64_t callback; /* callback delay timer */ + uint64_t callback; /* callback delay timer */ + pc_timer_t timer; uint16_t buffer[256]; /* data buffer (16b wide) */ @@ -112,23 +121,23 @@ typedef struct { } mfm_t; -#ifdef ENABLE_MFM_AT_LOG -int mfm_at_do_log = ENABLE_MFM_AT_LOG; +#ifdef ENABLE_ST506_AT_LOG +int mfm_at_do_log = ENABLE_ST506_AT_LOG; static void -mfm_at_log(const char *fmt, ...) +st506_at_log(const char *fmt, ...) { va_list ap; - if (mfm_at_do_log) { + if (st506_at_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } } #else -#define mfm_at_log(fmt, ...) +#define st506_at_log(fmt, ...) #endif @@ -172,31 +181,31 @@ get_sector(mfm_t *mfm, off64_t *addr) drive_t *drive = &mfm->drives[mfm->drvsel]; if (drive->curcyl != mfm->cylinder) { - mfm_at_log("WD1003(%d) sector: wrong cylinder\n"); + st506_at_log("WD1003(%d) sector: wrong cylinder\n"); return(1); } if (mfm->head > drive->cfg_hpc) { - mfm_at_log("WD1003(%d) get_sector: past end of configured heads\n", - mfm->drvsel); + st506_at_log("WD1003(%d) get_sector: past end of configured heads\n", + mfm->drvsel); return(1); } if (mfm->sector >= drive->cfg_spt+1) { - mfm_at_log("WD1003(%d) get_sector: past end of configured sectors\n", - mfm->drvsel); + st506_at_log("WD1003(%d) get_sector: past end of configured sectors\n", + mfm->drvsel); return(1); } #if 1 /* We should check this in the SET_DRIVE_PARAMETERS command! --FvK */ if (mfm->head > drive->hpc) { - mfm_at_log("WD1003(%d) get_sector: past end of heads\n", mfm->drvsel); + st506_at_log("WD1003(%d) get_sector: past end of heads\n", mfm->drvsel); return(1); } if (mfm->sector >= drive->spt+1) { - mfm_at_log("WD1003(%d) get_sector: past end of sectors\n", mfm->drvsel); + st506_at_log("WD1003(%d) get_sector: past end of sectors\n", mfm->drvsel); return(1); } #endif @@ -225,6 +234,20 @@ next_sector(mfm_t *mfm) } } +static void +mfm_set_callback(mfm_t *mfm, uint64_t callback) +{ + if (!mfm) + return; + + if (callback) { + mfm->callback = callback; + timer_set_delay_u64(&mfm->timer, mfm->callback); + } else { + mfm->callback = 0ULL; + timer_disable(&mfm->timer); + } +} static void mfm_cmd(mfm_t *mfm, uint8_t val) @@ -233,14 +256,11 @@ mfm_cmd(mfm_t *mfm, uint8_t val) if (! drive->present) { /* This happens if sofware polls all drives. */ - mfm_at_log("WD1003(%d) command %02x on non-present drive\n", - mfm->drvsel, val); + st506_at_log("WD1003(%d) command %02x on non-present drive\n", + mfm->drvsel, val); mfm->command = 0xff; mfm->status = STAT_BUSY; - timer_clock(); - mfm->callback = 200LL*MFM_TIME; - timer_update_outstanding(); - + mfm_set_callback(mfm, 200 * MFM_TIME); return; } @@ -251,8 +271,8 @@ mfm_cmd(mfm_t *mfm, uint8_t val) switch (val & 0xf0) { case CMD_RESTORE: drive->steprate = (val & 0x0f); - mfm_at_log("WD1003(%d) restore, step=%d\n", - mfm->drvsel, drive->steprate); + st506_at_log("WD1003(%d) restore, step=%d\n", + mfm->drvsel, drive->steprate); drive->curcyl = 0; mfm->status = STAT_READY|STAT_DSC; mfm->command &= 0xf0; @@ -263,9 +283,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) drive->steprate = (val & 0x0f); mfm->command &= 0xf0; mfm->status = STAT_BUSY; - timer_clock(); - mfm->callback = 200LL*MFM_TIME; - timer_update_outstanding(); + mfm_set_callback(mfm, 200 * MFM_TIME); break; default: @@ -275,23 +293,21 @@ mfm_cmd(mfm_t *mfm, uint8_t val) case CMD_READ+1: case CMD_READ+2: case CMD_READ+3: - mfm_at_log("WD1003(%d) read, opt=%d\n", - mfm->drvsel, val&0x03); + st506_at_log("WD1003(%d) read, opt=%d\n", + mfm->drvsel, val&0x03); mfm->command &= 0xfc; if (val & 2) fatal("WD1003: READ with ECC\n"); mfm->status = STAT_BUSY; - timer_clock(); - mfm->callback = 200LL*MFM_TIME; - timer_update_outstanding(); + mfm_set_callback(mfm, 200 * MFM_TIME); break; case CMD_WRITE: case CMD_WRITE+1: case CMD_WRITE+2: case CMD_WRITE+3: - mfm_at_log("WD1003(%d) write, opt=%d\n", - mfm->drvsel, val & 0x03); + st506_at_log("WD1003(%d) write, opt=%d\n", + mfm->drvsel, val & 0x03); mfm->command &= 0xfc; if (val & 2) fatal("WD1003: WRITE with ECC\n"); @@ -303,9 +319,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) case CMD_VERIFY+1: mfm->command &= 0xfe; mfm->status = STAT_BUSY; - timer_clock(); - mfm->callback = 200LL*MFM_TIME; - timer_update_outstanding(); + mfm_set_callback(mfm, 200 * MFM_TIME); break; case CMD_FORMAT: @@ -315,9 +329,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) case CMD_DIAGNOSE: mfm->status = STAT_BUSY; - timer_clock(); - mfm->callback = 200LL*MFM_TIME; - timer_update_outstanding(); + mfm_set_callback(mfm, 200 * MFM_TIME); break; case CMD_SET_PARAMETERS: @@ -341,13 +353,13 @@ mfm_cmd(mfm_t *mfm, uint8_t val) /* Only accept after RESET or DIAG. */ drive->cfg_spt = mfm->secount; drive->cfg_hpc = mfm->head+1; - mfm_at_log("WD1003(%d) parameters: tracks=%d, spt=%i, hpc=%i\n", - mfm->drvsel, drive->tracks, - drive->cfg_spt, drive->cfg_hpc); + st506_at_log("WD1003(%d) parameters: tracks=%d, spt=%i, hpc=%i\n", + mfm->drvsel, drive->tracks, + drive->cfg_spt, drive->cfg_hpc); } else { - mfm_at_log("WD1003(%d) parameters: tracks=%d,spt=%i,hpc=%i (IGNORED)\n", - mfm->drvsel, drive->tracks, - drive->cfg_spt, drive->cfg_hpc); + st506_at_log("WD1003(%d) parameters: tracks=%d,spt=%i,hpc=%i (IGNORED)\n", + mfm->drvsel, drive->tracks, + drive->cfg_spt, drive->cfg_hpc); } mfm->command = 0x00; mfm->status = STAT_READY|STAT_DSC; @@ -356,11 +368,9 @@ mfm_cmd(mfm_t *mfm, uint8_t val) break; default: - mfm_at_log("WD1003: bad command %02X\n", val); + st506_at_log("WD1003: bad command %02X\n", val); mfm->status = STAT_BUSY; - timer_clock(); - mfm->callback = 200LL*MFM_TIME; - timer_update_outstanding(); + mfm_set_callback(mfm, 200 * MFM_TIME); break; } } @@ -378,11 +388,7 @@ mfm_writew(uint16_t port, uint16_t val, void *priv) if (mfm->pos >= 512) { mfm->pos = 0; mfm->status = STAT_BUSY; - timer_clock(); - /* 781.25 us per sector at 5 Mbit/s = 640 kB/s. */ - mfm->callback = ((3125LL * TIMER_USEC) / 4LL); - /* mfm->callback = 10LL * MFM_TIME; */ - timer_update_outstanding(); + mfm_set_callback(mfm, SECTOR_TIME); } } @@ -392,7 +398,7 @@ mfm_write(uint16_t port, uint8_t val, void *priv) { mfm_t *mfm = (mfm_t *)priv; - mfm_at_log("WD1003 write(%04x, %02x)\n", port, val); + st506_at_log("WD1003 write(%04x, %02x)\n", port, val); switch (port) { case 0x01f0: /* data */ @@ -435,18 +441,14 @@ mfm_write(uint16_t port, uint8_t val, void *priv) case 0x03f6: /* device control */ val &= 0x0f; if ((mfm->fdisk & 0x04) && !(val & 0x04)) { - timer_clock(); - mfm->callback = 500LL*MFM_TIME; - timer_update_outstanding(); + mfm_set_callback(mfm, 500 * MFM_TIME); mfm->reset = 1; mfm->status = STAT_BUSY; } if (val & 0x04) { /* Drive held in reset. */ - timer_clock(); - mfm->callback = 0LL; - timer_update_outstanding(); + mfm_set_callback(mfm, 0); mfm->status = STAT_BUSY; } mfm->fdisk = val; @@ -474,14 +476,9 @@ mfm_readw(uint16_t port, void *priv) if (mfm->secount) { next_sector(mfm); mfm->status = STAT_BUSY; - timer_clock(); - /* 781.25 us per sector at 5 Mbit/s = 640 kB/s. */ - mfm->callback = ((3125LL * TIMER_USEC) / 4LL); - /* mfm->callback = 10LL * MFM_TIME; */ - timer_update_outstanding(); - } else { + mfm_set_callback(mfm, SECTOR_TIME); + } else ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); - } } } @@ -533,7 +530,7 @@ mfm_read(uint16_t port, void *priv) break; } - mfm_at_log("WD1003 read(%04x) = %02x\n", port, ret); + st506_at_log("WD1003 read(%04x) = %02x\n", port, ret); return(ret); } @@ -544,8 +541,8 @@ do_seek(mfm_t *mfm) { drive_t *drive = &mfm->drives[mfm->drvsel]; - mfm_at_log("WD1003(%d) seek(%d) max=%d\n", - mfm->drvsel,mfm->cylinder,drive->tracks); + st506_at_log("WD1003(%d) seek(%d) max=%d\n", + mfm->drvsel,mfm->cylinder,drive->tracks); if (mfm->cylinder < drive->tracks) drive->curcyl = mfm->cylinder; @@ -561,9 +558,9 @@ do_callback(void *priv) drive_t *drive = &mfm->drives[mfm->drvsel]; off64_t addr; - mfm->callback = 0LL; + mfm_set_callback(mfm, 0); if (mfm->reset) { - mfm_at_log("WD1003(%d) reset\n", mfm->drvsel); + st506_at_log("WD1003(%d) reset\n", mfm->drvsel); mfm->status = STAT_READY|STAT_DSC; mfm->error = 1; @@ -584,16 +581,16 @@ do_callback(void *priv) switch (mfm->command) { case CMD_SEEK: - mfm_at_log("WD1003(%d) seek, step=%d\n", - mfm->drvsel, drive->steprate); + st506_at_log("WD1003(%d) seek, step=%d\n", + mfm->drvsel, drive->steprate); do_seek(mfm); mfm->status = STAT_READY|STAT_DSC; irq_raise(mfm); break; case CMD_READ: - mfm_at_log("WD1003(%d) read(%d,%d,%d)\n", - mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); + st506_at_log("WD1003(%d) read(%d,%d,%d)\n", + mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); do_seek(mfm); if (get_sector(mfm, &addr)) { mfm->error = ERR_ID_NOT_FOUND; @@ -611,8 +608,8 @@ do_callback(void *priv) break; case CMD_WRITE: - mfm_at_log("WD1003(%d) write(%d,%d,%d)\n", - mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); + st506_at_log("WD1003(%d) write(%d,%d,%d)\n", + mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); do_seek(mfm); if (get_sector(mfm, &addr)) { mfm->error = ERR_ID_NOT_FOUND; @@ -637,8 +634,8 @@ do_callback(void *priv) break; case CMD_VERIFY: - mfm_at_log("WD1003(%d) verify(%d,%d,%d)\n", - mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); + st506_at_log("WD1003(%d) verify(%d,%d,%d)\n", + mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); do_seek(mfm); mfm->pos = 0; mfm->status = STAT_READY|STAT_DSC; @@ -647,8 +644,8 @@ do_callback(void *priv) break; case CMD_FORMAT: - mfm_at_log("WD1003(%d) format(%d,%d)\n", - mfm->drvsel, mfm->cylinder, mfm->head); + st506_at_log("WD1003(%d) format(%d,%d)\n", + mfm->drvsel, mfm->cylinder, mfm->head); do_seek(mfm); if (get_sector(mfm, &addr)) { mfm->error = ERR_ID_NOT_FOUND; @@ -665,7 +662,7 @@ do_callback(void *priv) break; case CMD_DIAGNOSE: - mfm_at_log("WD1003(%d) diag\n", mfm->drvsel); + st506_at_log("WD1003(%d) diag\n", mfm->drvsel); drive->steprate = 0x0f; mfm->error = 1; mfm->status = STAT_READY|STAT_DSC; @@ -673,8 +670,8 @@ do_callback(void *priv) break; default: - mfm_at_log("WD1003(%d) callback on unknown command %02x\n", - mfm->drvsel, mfm->command); + st506_at_log("WD1003(%d) callback on unknown command %02x\n", + mfm->drvsel, mfm->command); mfm->status = STAT_READY|STAT_ERR|STAT_DSC; mfm->error = ERR_ABRT; irq_raise(mfm); @@ -708,7 +705,7 @@ mfm_init(const device_t *info) mfm_t *mfm; int c, d; - mfm_at_log("WD1003: ISA MFM/RLL Fixed Disk Adapter initializing ...\n"); + st506_at_log("WD1003: ISA MFM/RLL Fixed Disk Adapter initializing ...\n"); mfm = malloc(sizeof(mfm_t)); memset(mfm, 0x00, sizeof(mfm_t)); @@ -717,8 +714,8 @@ mfm_init(const device_t *info) if ((hdd[d].bus == HDD_BUS_MFM) && (hdd[d].mfm_channel < MFM_NUM)) { loadhd(mfm, hdd[d].mfm_channel, d, hdd[d].fn); - mfm_at_log("WD1003(%d): (%ls) geometry %d/%d/%d\n", c, hdd[d].fn, - (int)hdd[d].tracks, (int)hdd[d].hpc, (int)hdd[d].spt); + st506_at_log("WD1003(%d): (%ls) geometry %d/%d/%d\n", c, hdd[d].fn, + (int)hdd[d].tracks, (int)hdd[d].hpc, (int)hdd[d].spt); if (++c >= MFM_NUM) break; } @@ -734,7 +731,7 @@ mfm_init(const device_t *info) io_sethandler(0x03f6, 1, NULL, NULL, NULL, mfm_write, NULL, NULL, mfm); - timer_add(do_callback, &mfm->callback, &mfm->callback, mfm); + timer_add(&mfm->timer, do_callback, mfm, 0); ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); @@ -760,7 +757,7 @@ mfm_close(void *priv) } -const device_t mfm_at_wd1003_device = { +const device_t st506_at_wd1003_device = { "WD1003 AT MFM/RLL Controller", DEVICE_ISA | DEVICE_AT, 0, diff --git a/src/disk/hdc_st506_xt.c b/src/disk/hdc_st506_xt.c new file mode 100644 index 000000000..cdeb5e517 --- /dev/null +++ b/src/disk/hdc_st506_xt.c @@ -0,0 +1,1919 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Driver for the IBM PC-XT Fixed Disk controller. + * + * The original controller shipped by IBM was made by Xebec, and + * several variations had been made: + * + * #1 Original, single drive (ST412), 10MB, 2 heads. + * #2 Update, single drive (ST412) but with option for a + * switch block that can be used to 'set' the actual + * drive type. Four switches are defined, where switches + * 1 and 2 define drive0, and switches 3 and 4 drive1. + * + * 0 ON ON 306 2 0 + * 1 ON OFF 375 8 0 + * 2 OFF ON 306 6 256 + * 3 OFF OFF 306 4 0 + * + * The latter option is the default, in use on boards + * without the switch block option. + * + * #3 Another updated board, mostly to accomodate the new + * 20MB disk now being shipped. The controller can have + * up to 2 drives, the type of which is set using the + * switch block: + * + * SW1 SW2 CYLS HD SPT WPC + * 0 ON ON 306 4 17 0 + * 1 ON OFF 612 4 17 0 (type 16) + * 2 OFF ON 615 4 17 300 (Seagate ST-225, 2) + * 3 OFF OFF 306 8 17 128 (IBM WD25, 13) + * + * Examples of #3 are IBM/Xebec, WD10004A-WX1 and ST11R. + * + * Since all controllers (including the ones made by DTC) use + * (mostly) the same API, we keep them all in this module. + * + * Version: @(#)hdc_st506_xt.c 1.0.16 2019/03/02 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../ui.h" +#include "../plat.h" +#include "../dma.h" +#include "../pic.h" +#include "hdc.h" +#include "hdd.h" + + +#define XEBEC_BIOS_FILE L"roms/hdd/st506/ibm_xebec_62x0822_1985.bin" +#define DTC_BIOS_FILE L"roms/hdd/st506/dtc_cxd21a.bin" +#define ST11_BIOS_FILE L"roms/hdd/st506/st11_bios_vers_1.7.bin" +#define WD1002A_WX1_BIOS_FILE L"roms/hdd/st506/wd1002a_wx1-62-000094-032.bin" +#define WD1002A_27X_BIOS_FILE L"roms/hdd/st506/wd1002a_27x-62-000215-060.bin" + + +#define ST506_TIME (50 * TIMER_USEC) +#define ST506_TIME_MS (1000 * TIMER_USEC) + +/* MFM and RLL use different sectors/track. */ +#define SECTOR_SIZE 512 +#define MFM_SECTORS 17 +#define RLL_SECTORS 26 + + +/* Status register. */ +#define STAT_REQ 0x01 /* controller ready */ +#define STAT_IO 0x02 /* input, data to host */ +#define STAT_CD 0x04 /* command mode (else data) */ +#define STAT_BSY 0x08 /* controller is busy */ +#define STAT_DRQ 0x10 /* controller needs DMA */ +#define STAT_IRQ 0x20 /* interrupt, we have info */ + +/* DMA/IRQ enable register. */ +#define DMA_ENA 0x01 /* DMA operation enabled */ +#define IRQ_ENA 0x02 /* IRQ operation enabled */ + +/* Error codes in sense report. */ +#define ERR_BV 0x80 +#define ERR_TYPE_MASK 0x30 +#define ERR_TYPE_SHIFT 4 +# define ERR_TYPE_DRIVE 0x00 +# define ERR_TYPE_CONTROLLER 0x01 +# define ERR_TYPE_COMMAND 0x02 +# define ERR_TYPE_MISC 0x03 + +/* No, um, errors.. */ +#define ERR_NONE 0x00 + +/* Group 0: drive errors. */ +#define ERR_NO_SEEK 0x02 /* no seek_complete */ +#define ERR_WR_FAULT 0x03 /* write fault */ +#define ERR_NOT_READY 0x04 /* drive not ready */ +#define ERR_NO_TRACK0 0x06 /* track 0 not found */ +#define ERR_STILL_SEEKING 0x08 /* drive is still seeking */ +#define ERR_NOT_AVAILABLE 0x09 /* drive not available */ + +/* Group 1: controller errors. */ +#define ERR_ID_FAULT 0x10 /* could not read ID field */ +#define ERR_UNC_ERR 0x11 /* uncorrectable data */ +#define ERR_SECTOR_ADDR 0x12 /* sector address */ +#define ERR_DATA_ADDR 0x13 /* data mark not found */ +#define ERR_TARGET_SECTOR 0x14 /* target sector not found */ +#define ERR_SEEK_ERROR 0x15 /* seek error- cyl not found */ +#define ERR_CORR_ERR 0x18 /* correctable data */ +#define ERR_BAD_TRACK 0x19 /* track is flagged as bad */ +#define ERR_ALT_TRACK_FLAGGED 0x1c /* alt trk not flagged as alt */ +#define ERR_ALT_TRACK_ACCESS 0x1e /* illegal access to alt trk */ +#define ERR_NO_RECOVERY 0x1f /* recovery mode not avail */ + +/* Group 2: command errors. */ +#define ERR_BAD_COMMAND 0x20 /* invalid command */ +#define ERR_ILLEGAL_ADDR 0x21 /* address beyond disk size */ +#define ERR_BAD_PARAMETER 0x22 /* invalid command parameter */ + +/* Group 3: misc errors. */ +#define ERR_BAD_RAM 0x30 /* controller has bad RAM */ +#define ERR_BAD_ROM 0x31 /* ROM failed checksum test */ +#define ERR_CRC_FAIL 0x32 /* CRC circuit failed test */ + +/* Controller commands. */ +#define CMD_TEST_DRIVE_READY 0x00 +#define CMD_RECALIBRATE 0x01 +/* reserved 0x02 */ +#define CMD_STATUS 0x03 +#define CMD_FORMAT_DRIVE 0x04 +#define CMD_VERIFY 0x05 +#define CMD_FORMAT_TRACK 0x06 +#define CMD_FORMAT_BAD_TRACK 0x07 +#define CMD_READ 0x08 +#define CMD_REASSIGN 0x09 +#define CMD_WRITE 0x0a +#define CMD_SEEK 0x0b +#define CMD_SPECIFY 0x0c +#define CMD_READ_ECC_BURST_LEN 0x0d +#define CMD_READ_BUFFER 0x0e +#define CMD_WRITE_BUFFER 0x0f +#define CMD_ALT_TRACK 0x11 +#define CMD_INQUIRY_ST11 0x12 /* ST-11 BIOS */ +#define CMD_RAM_DIAGNOSTIC 0xe0 +/* reserved 0xe1 */ +/* reserved 0xe2 */ +#define CMD_DRIVE_DIAGNOSTIC 0xe3 +#define CMD_CTRLR_DIAGNOSTIC 0xe4 +#define CMD_READ_LONG 0xe5 +#define CMD_WRITE_LONG 0xe6 + +#define CMD_FORMAT_DRIVE_ST11 0xf6 /* ST-11 BIOS */ +#define CMD_GET_GEOMETRY_ST11 0xf8 /* ST-11 BIOS */ +#define CMD_SET_GEOMETRY_ST11 0xfa /* ST-11 BIOS */ + +#define CMD_GET_DRIVE_PARAMS_DTC 0xfb /* DTC */ +#define CMD_SET_STEP_RATE_DTC 0xfc /* DTC */ +#define CMD_SET_GEOMETRY_DTC 0xfe /* DTC */ +#define CMD_GET_GEOMETRY_DTC 0xff /* DTC */ + + +enum { + STATE_IDLE, + STATE_RECEIVE_COMMAND, + STATE_START_COMMAND, + STATE_RECEIVE_DATA, + STATE_RECEIVED_DATA, + STATE_SEND_DATA, + STATE_SENT_DATA, + STATE_COMPLETION_BYTE, + STATE_DONE +}; + + +typedef struct { + int8_t present; + uint8_t hdd_num; + + uint8_t interleave; /* default interleave */ + char pad; + + uint16_t cylinder; /* current cylinder */ + + uint8_t spt, /* physical parameters */ + hpc; + uint16_t tracks; + + uint8_t cfg_spt, /* configured parameters */ + cfg_hpc; + uint16_t cfg_cyl; +} drive_t; + + +typedef struct { + uint8_t type; /* controller type */ + + uint8_t spt; /* sectors-per-track for controller */ + + uint16_t base; /* controller configuration */ + int8_t irq, + dma; + uint8_t switches; + uint8_t misc; + uint32_t bios_addr, + bios_size, + bios_ram; + rom_t bios_rom; + + int state; /* operational data */ + uint8_t irq_dma; + uint8_t error; + uint8_t status; + int8_t cyl_off; /* for ST-11, cylinder0 offset */ + uint64_t callback; + pc_timer_t timer; + + uint8_t command[6]; /* current command request */ + int drive_sel; + int sector, + head, + cylinder, + count; + uint8_t compl; /* current request completion code */ + + int buff_pos, /* pointers to the RAM buffer */ + buff_cnt; + + drive_t drives[MFM_NUM]; /* the attached drives */ + uint8_t scratch[64]; /* ST-11 scratchpad RAM */ + uint8_t buff[SECTOR_SIZE + 4]; /* sector buffer RAM (+ ECC bytes) */ +} hdc_t; + + +/* Supported drives table for the Xebec controller. */ +typedef struct { + uint16_t tracks; + uint8_t hpc; + uint8_t spt; +} hd_type_t; + +hd_type_t hd_types[4] = { + { 306, 4, MFM_SECTORS }, /* type 0 */ + { 612, 4, MFM_SECTORS }, /* type 16 */ + { 615, 4, MFM_SECTORS }, /* type 2 */ + { 306, 8, MFM_SECTORS } /* type 13 */ +}; + +hd_type_t wd1002a_hd_types[4] = { + { 981, 5, RLL_SECTORS }, /* type 0 */ + { 987, 7, RLL_SECTORS }, /* type 16 */ + { 612, 4, RLL_SECTORS }, /* type 2 */ + { 615, 4, RLL_SECTORS } /* type 13 */ +}; + + +#ifdef ENABLE_ST506_XT_LOG +int st506_xt_do_log = ENABLE_ST506_XT_LOG; + + +static void +st506_xt_log(const char *fmt, ...) +{ + va_list ap; + + if (st506_xt_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define st506_xt_log(fmt, ...) +#endif + + +static void +st506_complete(hdc_t *dev) +{ + dev->status = STAT_REQ | STAT_CD | STAT_IO | STAT_BSY; + dev->state = STATE_COMPLETION_BYTE; + + if (dev->irq_dma & DMA_ENA) + dma_set_drq(dev->dma, 0); + + if (dev->irq_dma & IRQ_ENA) { + dev->status |= STAT_IRQ; + picint(1 << dev->irq); + } +} + + +static void +st506_error(hdc_t *dev, uint8_t err) +{ + dev->compl |= 0x02; + dev->error = err; +} + + +static int +get_sector(hdc_t *dev, drive_t *drive, off64_t *addr) +{ + if (! drive->present) { + /* No need to log this. */ + dev->error = ERR_NOT_AVAILABLE; + return(0); + } + + if (drive->cylinder != dev->cylinder) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: get_sector: wrong cylinder\n"); +#endif + dev->error = ERR_ILLEGAL_ADDR; + return(0); + } + + if (dev->head >= drive->cfg_hpc) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: get_sector: past end of configured heads\n"); +#endif + dev->error = ERR_ILLEGAL_ADDR; + return(0); + } + if (dev->sector >= drive->cfg_spt) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: get_sector: past end of configured sectors\n"); +#endif + dev->error = ERR_ILLEGAL_ADDR; + return(0); + } + + *addr = ((((off64_t)dev->cylinder * drive->cfg_hpc) + dev->head) * drive->cfg_spt) + dev->sector; + + return(1); +} + + +static void +next_sector(hdc_t *dev, drive_t *drive) +{ + if (++dev->sector >= drive->cfg_spt) { + dev->sector = 0; + if (++dev->head >= drive->cfg_hpc) { + dev->head = 0; + if (++drive->cylinder >= drive->cfg_cyl) { + /* + * This really is an error, we cannot move + * past the end of the drive, which should + * result in an ERR_ILLEGAL_ADDR. --FvK + */ + drive->cylinder = drive->cfg_cyl - 1; + } else + dev->cylinder++; + } + } +} + + +/* Extract the CHS info from a command block. */ +static int +get_chs(hdc_t *dev, drive_t *drive) +{ + dev->cylinder = dev->command[3] | ((dev->command[2] & 0xc0) << 2); + dev->head = dev->command[1] & 0x1f; + dev->sector = dev->command[2] & 0x1f; /* 0x3f on some */ + dev->count = dev->command[4]; + dev->cylinder += dev->cyl_off; /* for ST-11 */ + + if (dev->cylinder >= drive->cfg_cyl) { + /* + * This really is an error, we cannot move + * past the end of the drive, which should + * result in an ERR_ILLEGAL_ADDR. --FvK + */ + drive->cylinder = drive->cfg_cyl - 1; + return(0); + } + + drive->cylinder = dev->cylinder; + + return(1); +} + +static void +st506_set_callback(hdc_t *dev, uint64_t callback) +{ + if (!dev) { + return; + } + + if (callback) { + dev->callback = callback; + timer_set_delay_u64(&dev->timer, dev->callback); + } else { + dev->callback = 0; + timer_disable(&dev->timer); + } +} + +static void +st506_callback(void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + drive_t *drive; + off64_t addr; + int val; + + /* Cancel the timer for now. */ + st506_set_callback(dev, 0); + + /* Get the drive info. Note that the API supports up to 8 drives! */ + dev->drive_sel = (dev->command[1] >> 5) & 0x07; + drive = &dev->drives[dev->drive_sel]; + + /* Preset the completion byte to "No error" and the selected drive. */ + dev->compl = (dev->drive_sel << 5) | ERR_NONE; + + switch (dev->command[0]) { + case CMD_TEST_DRIVE_READY: + st506_xt_log("ST506: TEST_READY(%i) = %i\n", + dev->drive_sel, drive->present); + if (! drive->present) + st506_error(dev, ERR_NOT_AVAILABLE); + st506_complete(dev); + break; + + case CMD_RECALIBRATE: + switch (dev->state) { + case STATE_START_COMMAND: + st506_xt_log("ST506: RECALIBRATE(%i) [%i]\n", + dev->drive_sel, drive->present); + if (! drive->present) { + st506_error(dev, ERR_NOT_AVAILABLE); + st506_complete(dev); + break; + } + + /* Wait 20msec. */ + st506_set_callback(dev, ST506_TIME_MS * 20); + + dev->cylinder = dev->cyl_off; + drive->cylinder = dev->cylinder; + dev->state = STATE_DONE; + + break; + + case STATE_DONE: + st506_complete(dev); + break; + } + break; + + case CMD_STATUS: + switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + case STATE_START_COMMAND: +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: STATUS\n"); +#endif + dev->buff_pos = 0; + dev->buff_cnt = 4; + dev->buff[0] = ERR_BV | dev->error; + dev->error = 0; + + /* Give address of last operation. */ + dev->buff[1] = (dev->drive_sel ? 0x20 : 0) | + dev->head; + dev->buff[2] = ((dev->cylinder & 0x0300) >> 2) | + dev->sector; + dev->buff[3] = (dev->cylinder & 0xff); + + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + dev->state = STATE_SEND_DATA; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } + break; + + case CMD_FORMAT_DRIVE: + case CMD_FORMAT_DRIVE_ST11: + switch (dev->state) { + case STATE_START_COMMAND: + (void)get_chs(dev, drive); + st506_xt_log("ST506: FORMAT_DRIVE%s(%i) interleave=%i\n", + (dev->command[0] == CMD_FORMAT_DRIVE_ST11) ? "_ST11" : "", + dev->drive_sel, dev->command[4]); + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + st506_set_callback(dev, ST506_TIME); + dev->state = STATE_SEND_DATA; + break; + + case STATE_SEND_DATA: /* wrong, but works */ + if (! get_sector(dev, drive, &addr)) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + + /* FIXME: should be drive->capac, not ->spt */ + hdd_image_zero(drive->hdd_num, + addr, drive->cfg_spt); + + /* Wait 5msec per cylinder. */ + st506_set_callback(dev, ST506_TIME_MS * 5 * drive->cfg_cyl); + + dev->state = STATE_SENT_DATA; + break; + + case STATE_SENT_DATA: + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_complete(dev); + break; + } + break; + + case CMD_VERIFY: + switch (dev->state) { + case STATE_START_COMMAND: + (void)get_chs(dev, drive); + st506_xt_log("ST506: VERIFY(%i, %i/%i/%i, %i)\n", + dev->drive_sel, dev->cylinder, + dev->head, dev->sector, dev->count); + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + st506_set_callback(dev, ST506_TIME); + dev->state = STATE_SEND_DATA; + break; + + case STATE_SEND_DATA: + if (dev->count-- == 0) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_complete(dev); + } + + if (! get_sector(dev, drive, &addr)) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + + next_sector(dev, drive); + + st506_set_callback(dev, ST506_TIME); + break; + } + break; + + case CMD_FORMAT_TRACK: + case CMD_FORMAT_BAD_TRACK: + switch (dev->state) { + case STATE_START_COMMAND: + (void)get_chs(dev, drive); + st506_xt_log("ST506: FORMAT_%sTRACK(%i, %i/%i)\n", + (dev->command[0] == CMD_FORMAT_BAD_TRACK) ? "BAD_" : "", + dev->drive_sel, dev->cylinder, dev->head); + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + st506_set_callback(dev, ST506_TIME); + dev->state = STATE_SEND_DATA; + break; + + case STATE_SEND_DATA: /* wrong, but works */ + if (! get_sector(dev, drive, &addr)) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + + hdd_image_zero(drive->hdd_num, + addr, drive->cfg_spt); + + /* Wait 5msec per cylinder. */ + st506_set_callback(dev, ST506_TIME_MS * 5); + + dev->state = STATE_SENT_DATA; + break; + + case STATE_SENT_DATA: + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_complete(dev); + break; + } + break; + + case CMD_READ: +#if 0 + case CMD_READ_LONG: +#endif + switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + case STATE_START_COMMAND: + (void)get_chs(dev, drive); + st506_xt_log("ST506: READ%s(%i, %i/%i/%i, %i)\n", + (dev->command[0] == CMD_READ_LONG) ? "_LONG" : "", + dev->drive_sel, dev->cylinder, + dev->head, dev->sector, dev->count); + + if (! get_sector(dev, drive, &addr)) { + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + + /* Read data from the image. */ + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *)dev->buff); + + /* Set up the data transfer. */ + dev->buff_pos = 0; + dev->buff_cnt = SECTOR_SIZE; + if (dev->command[0] == CMD_READ_LONG) + dev->buff_cnt += 4; + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + if (dev->irq_dma & DMA_ENA) { + st506_set_callback(dev, ST506_TIME); + dma_set_drq(dev->dma, 1); + } + dev->state = STATE_SEND_DATA; + break; + + case STATE_SEND_DATA: + for (; dev->buff_pos < dev->buff_cnt; dev->buff_pos++) { + val = dma_channel_write(dev->dma, dev->buff[dev->buff_pos]); + if (val == DMA_NODATA) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: CMD_READ out of data!\n"); +#endif + st506_error(dev, ERR_NO_RECOVERY); + st506_complete(dev); + return; + } + } + dma_set_drq(dev->dma, 0); + st506_set_callback(dev, ST506_TIME); + dev->state = STATE_SENT_DATA; + break; + + case STATE_SENT_DATA: + if (--dev->count == 0) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_complete(dev); + break; + } + + next_sector(dev, drive); + + if (! get_sector(dev, drive, &addr)) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + + /* Read data from the image. */ + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *)dev->buff); + + /* Set up the data transfer. */ + dev->buff_pos = 0; + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + if (dev->irq_dma & DMA_ENA) { + st506_set_callback(dev, ST506_TIME); + dma_set_drq(dev->dma, 1); + } + dev->state = STATE_SEND_DATA; + break; + } + break; + + case CMD_WRITE: +#if 0 + case CMD_WRITE_LONG: +#endif + switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + case STATE_START_COMMAND: + (void)get_chs(dev, drive); + st506_xt_log("ST506: WRITE%s(%i, %i/%i/%i, %i)\n", + (dev->command[0] == CMD_WRITE_LONG) ? "_LONG" : "", + dev->drive_sel, dev->cylinder, + dev->head, dev->sector, dev->count); + + if (! get_sector(dev, drive, &addr)) { + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + + /* Set up the data transfer. */ + dev->buff_pos = 0; + dev->buff_cnt = SECTOR_SIZE; + if (dev->command[0] == CMD_WRITE_LONG) + dev->buff_cnt += 4; + dev->status = STAT_BSY | STAT_REQ; + if (dev->irq_dma & DMA_ENA) { + st506_set_callback(dev, ST506_TIME); + dma_set_drq(dev->dma, 1); + } + dev->state = STATE_RECEIVE_DATA; + break; + + case STATE_RECEIVE_DATA: + for (; dev->buff_pos < dev->buff_cnt; dev->buff_pos++) { + val = dma_channel_read(dev->dma); + if (val == DMA_NODATA) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: CMD_WRITE out of data!\n"); +#endif + st506_error(dev, ERR_NO_RECOVERY); + st506_complete(dev); + return; + } + dev->buff[dev->buff_pos] = val & 0xff; + } + + dma_set_drq(dev->dma, 0); + st506_set_callback(dev, ST506_TIME); + dev->state = STATE_RECEIVED_DATA; + break; + + case STATE_RECEIVED_DATA: + if (! get_sector(dev, drive, &addr)) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_error(dev, dev->error); + st506_complete(dev); + return; + } + + /* Write data to image. */ + hdd_image_write(drive->hdd_num, addr, 1, + (uint8_t *)dev->buff); + + if (--dev->count == 0) { + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + st506_complete(dev); + break; + } + + next_sector(dev, drive); + + /* Set up the data transfer. */ + dev->buff_pos = 0; + dev->status = STAT_BSY | STAT_REQ; + if (dev->irq_dma & DMA_ENA) { + st506_set_callback(dev, ST506_TIME); + dma_set_drq(dev->dma, 1); + } + dev->state = STATE_RECEIVE_DATA; + break; + } + break; + + case CMD_SEEK: + if (drive->present) { + val = get_chs(dev, drive); + st506_xt_log("ST506: SEEK(%i, %i) [%i]\n", + dev->drive_sel, drive->cylinder, val); + if (! val) + st506_error(dev, ERR_SEEK_ERROR); + } else + st506_error(dev, ERR_NOT_AVAILABLE); + st506_complete(dev); + break; + + case CMD_SPECIFY: + switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + case STATE_START_COMMAND: + dev->buff_pos = 0; + dev->buff_cnt = 8; + dev->status = STAT_BSY | STAT_REQ; + dev->state = STATE_RECEIVE_DATA; + break; + + case STATE_RECEIVED_DATA: + drive->cfg_cyl = dev->buff[1] | (dev->buff[0] << 8); + drive->cfg_hpc = dev->buff[2]; + st506_xt_log("ST506: drive%i: cyls=%i, heads=%i\n", + dev->drive_sel, drive->cfg_cyl, drive->cfg_hpc); + st506_complete(dev); + break; + } + break; + + case CMD_READ_ECC_BURST_LEN: + switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + case STATE_START_COMMAND: +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: READ_ECC_BURST_LEN\n"); +#endif + dev->buff_pos = 0; + dev->buff_cnt = 1; + dev->buff[0] = 0; /* 0 bits */ + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + dev->state = STATE_SEND_DATA; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } + break; + + case CMD_READ_BUFFER: + switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + case STATE_START_COMMAND: + dev->buff_pos = 0; + dev->buff_cnt = SECTOR_SIZE; + st506_xt_log("ST506: READ_BUFFER (%i)\n", + dev->buff_cnt); + + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + if (dev->irq_dma & DMA_ENA) { + st506_set_callback(dev, ST506_TIME); + dma_set_drq(dev->dma, 1); + } + dev->state = STATE_SEND_DATA; + break; + + case STATE_SEND_DATA: + for (; dev->buff_pos < dev->buff_cnt; dev->buff_pos++) { + val = dma_channel_write(dev->dma, dev->buff[dev->buff_pos]); + if (val == DMA_NODATA) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: CMD_READ_BUFFER out of data!\n"); +#endif + st506_error(dev, ERR_NO_RECOVERY); + st506_complete(dev); + return; + } + } + + dma_set_drq(dev->dma, 0); + st506_set_callback(dev, ST506_TIME); + dev->state = STATE_SENT_DATA; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } + break; + + case CMD_WRITE_BUFFER: + switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + case STATE_START_COMMAND: + dev->buff_pos = 0; + dev->buff_cnt = SECTOR_SIZE; + st506_xt_log("ST506: WRITE_BUFFER (%i)\n", + dev->buff_cnt); + + dev->status = STAT_BSY | STAT_REQ; + if (dev->irq_dma & DMA_ENA) { + st506_set_callback(dev, ST506_TIME); + dma_set_drq(dev->dma, 1); + } + dev->state = STATE_RECEIVE_DATA; + break; + + case STATE_RECEIVE_DATA: + for (; dev->buff_pos < dev->buff_cnt; dev->buff_pos++) { + val = dma_channel_read(dev->dma); + if (val == DMA_NODATA) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: CMD_WRITE_BUFFER out of data!\n"); +#endif + st506_error(dev, ERR_NO_RECOVERY); + st506_complete(dev); + return; + } + dev->buff[dev->buff_pos] = val & 0xff; + } + + dma_set_drq(dev->dma, 0); + st506_set_callback(dev, ST506_TIME); + dev->state = STATE_RECEIVED_DATA; + break; + + case STATE_RECEIVED_DATA: + st506_complete(dev); + break; + } + break; + + case CMD_INQUIRY_ST11: + if (dev->type == 11 || dev->type == 12) switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + case STATE_START_COMMAND: + st506_xt_log("ST506: INQUIRY (type=%i)\n", dev->type); + dev->buff_pos = 0; + dev->buff_cnt = 2; + dev->buff[0] = 0x80; /* "ST-11" */ + dev->buff[1] = dev->misc; /* revision */ + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + dev->state = STATE_SEND_DATA; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } else { + st506_error(dev, ERR_BAD_COMMAND); + st506_complete(dev); + } + break; + + case CMD_RAM_DIAGNOSTIC: +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: RAM_DIAG\n"); +#endif + st506_complete(dev); + break; + + case CMD_CTRLR_DIAGNOSTIC: +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: CTRLR_DIAG\n"); +#endif + st506_complete(dev); + break; + + case CMD_GET_GEOMETRY_ST11: + if (dev->type == 11 || dev->type == 12) switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + /* + * [0] = 0xda; // magic + * [1] = 0xbe; // magic + * [2] = cyl_hi + * [3] = cyl_lo + * [4] = heads + * [5] = sectors + * [6] = interleave + * [7] = 00 // ?? + * [8] = 01 // ?? + * [9] = 03 // ?? + * [10] = landing_hi + * [11] = landing_lo + * [12] = 'SEAGATESTxxxxxx' // magic + * [29] .. = 00 + * [41] = 02 // ?? + * + * This is the data block written to cylinder 0 + * somewhere by the ST-11 BIOS, and which we + * read back here, and then send to the caller. + * + * We do not yet know where this block is, so + * for now, we just fake it. Of course, since + * we do not with real drives, we could simply + * write it anywhere on that cylinder, but OK.. + */ + case STATE_START_COMMAND: + /* Send geometry data. */ + dev->buff_pos = 0; + dev->buff_cnt = SECTOR_SIZE; + memset(dev->buff, 0x00, dev->buff_cnt); + dev->buff[0] = 0xda; + dev->buff[1] = 0xbe; + dev->buff[2] = (drive->tracks >> 8) & 0xff; + dev->buff[3] = drive->tracks & 0xff; + dev->buff[4] = drive->hpc; + dev->buff[5] = drive->spt; + dev->buff[6] = drive->interleave; + dev->buff[7] = 0x00; + dev->buff[8] = 0x01; + dev->buff[9] = 0x03; + dev->buff[10] = (drive->tracks >> 8) & 0xff; + dev->buff[11] = drive->tracks & 0xff; + memcpy(&dev->buff[12], "SEAGATESTxxxxxx", 15); + dev->buff[41] = 0x02; + dev->state = STATE_SEND_DATA; + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } else { + st506_error(dev, ERR_BAD_COMMAND); + st506_complete(dev); + } + break; + + case CMD_SET_GEOMETRY_ST11: + if (dev->type == 11 || dev->type == 12) switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + case STATE_START_COMMAND: + dev->buff_pos = 0; + dev->buff_cnt = 512; // 42 + memset(dev->buff, 0x00, dev->buff_cnt); + dev->state = STATE_RECEIVE_DATA; + dev->status = STAT_BSY | STAT_REQ; + break; + + case STATE_RECEIVED_DATA: + /* + * See above as well. + * + * This is the data block written to cylinder 0 + * somewhere by the ST-11 BIOS, and which we + * read back here, and then send to the caller. + * + * We do not yet know where this block is, so + * for now, we just fake it. Of course, since + * we do not with real drives, we could simply + * write it anywhere on that cylinder, but OK.. + */ + st506_xt_log("ST506: GEO data for drive %i:\n", + dev->drive_sel); + st506_xt_log("ST506: [ %02x %02x %02x %02x %02x %02x %02x %02x ]\n", + dev->buff[0], dev->buff[1], dev->buff[2], dev->buff[3], + dev->buff[4], dev->buff[5], dev->buff[6], dev->buff[7]); + st506_complete(dev); + break; + } else if (dev->type == 1) { + /* DTC sends this.. */ + st506_complete(dev); + } else { + st506_error(dev, ERR_BAD_COMMAND); + st506_complete(dev); + } + break; + + case CMD_SET_STEP_RATE_DTC: + st506_complete(dev); + break; + + case CMD_GET_DRIVE_PARAMS_DTC: + switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + case STATE_START_COMMAND: + dev->buff_pos = 0; + dev->buff_cnt = 4; + memset(dev->buff, 0x00, dev->buff_cnt); + dev->buff[0] = drive->tracks & 0xff; + dev->buff[1] = 17 | ((drive->tracks >> 2) & 0xc0); + dev->buff[2] = drive->hpc - 1; + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + dev->state = STATE_SEND_DATA; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } + break; + + case CMD_SET_GEOMETRY_DTC: + switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + case STATE_START_COMMAND: + val = dev->command[1] & 0x01; + st506_xt_log("ST506: DTC_GET_GEOMETRY(%i) %i\n", + dev->drive_sel, val); + dev->buff_pos = 0; + dev->buff_cnt = 16; + dev->status = STAT_BSY | STAT_REQ; + dev->state = STATE_RECEIVE_DATA; + break; + + case STATE_RECEIVED_DATA: + /* FIXME: ignore the results. */ + st506_complete(dev); + break; + } + break; + + case CMD_GET_GEOMETRY_DTC: + switch (dev->state) { + case STATE_RECEIVE_COMMAND: + dev->status |= STAT_REQ; + break; + + case STATE_START_COMMAND: + val = dev->command[1] & 0x01; + st506_xt_log("ST506: DTC_GET_GEOMETRY(%i) %i\n", + dev->drive_sel, val); + dev->buff_pos = 0; + dev->buff_cnt = 16; + memset(dev->buff, 0x00, dev->buff_cnt); + dev->buff[4] = drive->tracks & 0xff; + dev->buff[5] = (drive->tracks >> 8) & 0xff; + dev->buff[10] = drive->hpc; + dev->status = STAT_BSY | STAT_IO | STAT_REQ; + dev->state = STATE_SEND_DATA; + break; + + case STATE_SENT_DATA: + st506_complete(dev); + break; + } + break; + + default: + if (dev->state == STATE_RECEIVE_COMMAND) + break; + +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: unknown command:\n"); +#endif + st506_xt_log("ST506: %02x %02x %02x %02x %02x %02x\n", + dev->command[0], dev->command[1], dev->command[2], + dev->command[3], dev->command[4], dev->command[5]); + st506_error(dev, ERR_BAD_COMMAND); + st506_complete(dev); + } +} + + +/* Read from one of the registers. */ +static uint8_t +st506_read(uint16_t port, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + uint8_t ret = 0xff; + + switch (port & 3) { + case 0: /* read data */ + dev->status &= ~STAT_IRQ; + switch (dev->state) { + case STATE_COMPLETION_BYTE: + ret = dev->compl; + dev->status = 0x00; + dev->state = STATE_IDLE; + break; + + case STATE_SEND_DATA: + ret = dev->buff[dev->buff_pos++]; + if (dev->buff_pos == dev->buff_cnt) { + dev->buff_pos = 0; + dev->buff_cnt = 0; + dev->status = STAT_BSY; + dev->state = STATE_SENT_DATA; + st506_set_callback(dev, ST506_TIME); + } + break; + } + break; + + case 1: /* read status */ + ret = dev->status; + if ((dev->irq_dma & DMA_ENA) && dma_get_drq(dev->dma)) + ret |= STAT_DRQ; + break; + + case 2: /* read option jumpers */ + ret = dev->switches; + break; + } + st506_xt_log("ST506: read(%04x) = %02x\n", port, ret); + + return(ret); +} + + +/* Write to one of the registers. */ +static void +st506_write(uint16_t port, uint8_t val, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + + st506_xt_log("ST506: write(%04x, %02x)\n", port, val); + switch (port & 3) { + case 0: /* write data */ + switch (dev->state) { + case STATE_RECEIVE_COMMAND: /* command data */ + dev->buff[dev->buff_pos++] = val; + if (dev->buff_pos == dev->buff_cnt) { + /* We have a new command. */ + memcpy(dev->command, dev->buff, dev->buff_cnt); + dev->buff_pos = 0; + dev->buff_cnt = 0; + dev->status = STAT_BSY; + st506_callback(dev); + dev->state = STATE_START_COMMAND; + st506_set_callback(dev, ST506_TIME); + } + break; + + case STATE_RECEIVE_DATA: /* data */ + dev->buff[dev->buff_pos++] = val; + if (dev->buff_pos == dev->buff_cnt) { + dev->buff_pos = 0; + dev->buff_cnt = 0; + dev->status = STAT_BSY; + dev->state = STATE_RECEIVED_DATA; + st506_set_callback(dev, ST506_TIME); + } + break; + } + break; + + case 1: /* controller reset */ + dev->status = 0x00; + break; + + case 2: /* generate controller-select-pulse */ + dev->status = STAT_BSY | STAT_CD | STAT_REQ; + dev->buff_pos = 0; + dev->buff_cnt = sizeof(dev->command); + dev->state = STATE_RECEIVE_COMMAND; + break; + + case 3: /* DMA/IRQ enable register */ + dev->irq_dma = val; + + if (!(dev->irq_dma & DMA_ENA)) + dma_set_drq(dev->dma, 0); + + if (!(dev->irq_dma & IRQ_ENA)) { + dev->status &= ~STAT_IRQ; + picintc(1 << dev->irq); + } + break; + } +} + + +/* Write to ROM (or scratchpad RAM.) */ +static void +mem_write(uint32_t addr, uint8_t val, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + uint32_t ptr, mask = 0; + + /* Ignore accesses to anything below the configured address, + needed because of the emulator's 16k mapping granularity. */ + if (addr < dev->bios_addr) + return; + + addr &= dev->bios_rom.mask; + + switch(dev->type) { + case 11: /* ST-11M */ + case 12: /* ST-11R */ + mask = 0x1fff; /* ST-11 decodes RAM on each 8K block */ + break; + + default: + break; + } + + ptr = (dev->bios_rom.mask & mask) - dev->bios_ram; + if (mask && ((addr & mask) > ptr) && + ((addr & mask) < (ptr + dev->bios_ram))) { + dev->scratch[addr & (dev->bios_ram - 1)] = val; + } +} + + +static uint8_t +mem_read(uint32_t addr, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + uint32_t ptr, mask = 0; + uint8_t ret = 0xff; + + /* Ignore accesses to anything below the configured address, + needed because of the emulator's 16k mapping granularity. */ + if (addr < dev->bios_addr) + return 0xff; + + addr &= dev->bios_rom.mask; + + switch(dev->type) { + case 0: /* Xebec */ + if (addr >= 0x001000) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: Xebec ROM access(0x%06lx)\n", addr); +#endif + return 0xff; + } + break; + + case 1: /* DTC */ + default: + if (addr >= 0x002000) { +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: DTC-5150X ROM access(0x%06lx)\n", addr); +#endif + return 0xff; + } + break; + + case 11: /* ST-11M */ + case 12: /* ST-11R */ + mask = 0x1fff; /* ST-11 decodes RAM on each 8K block */ + break; + + /* default: + break; */ + } + + ptr = (dev->bios_rom.mask & mask) - dev->bios_ram; + if (mask && ((addr & mask) > ptr) && + ((addr & mask) < (ptr + dev->bios_ram))) { + ret = dev->scratch[addr & (dev->bios_ram - 1)]; + } else + ret = dev->bios_rom.rom[addr]; + + return(ret); +} + + +/* + * Set up and load the ROM BIOS for this controller. + * + * This is straightforward for most, but some (like the ST-11x) + * map part of the area as scratchpad RAM, so we cannot use the + * standard 'rom_init' function here. + */ +static void +loadrom(hdc_t *dev, const wchar_t *fn) +{ + uint32_t size; + FILE *fp; + + if ((fp = rom_fopen((wchar_t *) fn, L"rb")) == NULL) { + st506_xt_log("ST506: BIOS ROM '%ls' not found!\n", fn); + return; + } + + /* Initialize the ROM entry. */ + memset(&dev->bios_rom, 0x00, sizeof(rom_t)); + + /* Manually load and process the ROM image. */ + (void)fseek(fp, 0L, SEEK_END); + size = ftell(fp); + (void)fseek(fp, 0L, SEEK_SET); + +#if 1 + /* + * The Xebec and DTC-5150X ROMs seem to be probing for + * (other) ROMs at addresses between their own size and + * 16K, at 2K blocks. So, we must enable all of that.. + */ + // if (dev->type < 2) + if ((dev->type != 11) && (dev->type != 12)) + size = 16384; +#endif + + /* Load the ROM data. */ + dev->bios_rom.rom = (uint8_t *)malloc(size); + memset(dev->bios_rom.rom, 0xff, size); + (void)fread(dev->bios_rom.rom, size, 1, fp); + (void)fclose(fp); + + /* Set up an address mask for this memory. */ + dev->bios_size = size; + dev->bios_rom.mask = (size - 1); + + /* Map this system into the memory map. */ + mem_mapping_add(&dev->bios_rom.mapping, dev->bios_addr, size, + mem_read,NULL,NULL, mem_write,NULL,NULL, + dev->bios_rom.rom, MEM_MAPPING_EXTERNAL, dev); +} + + +static void +loadhd(hdc_t *dev, int c, int d, const wchar_t *fn) +{ + drive_t *drive = &dev->drives[c]; + + if (! hdd_image_load(d)) { + drive->present = 0; + return; + } + + /* Make sure we can do this. */ + if (hdd[d].spt != dev->spt) { + /* + * Uh-oh, MFM/RLL mismatch. + * + * Although this would be no issue in the code itself, + * most of the BIOSes were hardwired to whatever their + * native SPT setting was, so, do not allow this here. + */ + st506_xt_log("ST506: drive%i: MFM/RLL mismatch (%i/%i)\n", + c, hdd[d].spt, dev->spt); + hdd_image_close(d); + drive->present = 0; + return; + } + + drive->spt = (uint8_t)hdd[d].spt; + drive->hpc = (uint8_t)hdd[d].hpc; + drive->tracks = (uint16_t)hdd[d].tracks; + + drive->hdd_num = d; + drive->present = 1; +} + + +/* Set the "drive type" switches for the IBM Xebec controller. */ +static void +set_switches(hdc_t *dev) +{ + drive_t *drive; + int c, d; + + dev->switches = 0x00; + + for (d = 0; d < MFM_NUM; d++) { + drive = &dev->drives[d]; + + if (! drive->present) continue; + + for (c = 0; c < 4; c++) { + if (dev->type == 21) { + if ((drive->hpc == wd1002a_hd_types[c].hpc) && + (drive->tracks == wd1002a_hd_types[c].tracks)) { + dev->switches |= (c << (d ? 0 : 2)); + break; + } + + if (drive->spt == RLL_SECTORS) + dev->switches |= 0x20; + } else { + if ((drive->spt == hd_types[c].spt) && + (drive->hpc == hd_types[c].hpc) && + (drive->tracks == hd_types[c].tracks)) { + dev->switches |= (c << (d ? 0 : 2)); + break; + } + } + } + +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: "); + if (c == 4) + st506_xt_log("*WARNING* drive%i unsupported", d); + else + st506_xt_log("drive%i is type %i", d, c); + st506_xt_log(" (%i/%i/%i)\n", drive->tracks, drive->hpc, drive->spt); +#endif + } + + if (dev->type == 21) { + if (dev->irq == 5) + dev->switches |= 0x40; + } +} + + +static void * +st506_init(const device_t *info) +{ + wchar_t *fn = NULL; + hdc_t *dev; + int i, c; + + dev = (hdc_t *)malloc(sizeof(hdc_t)); + memset(dev, 0x00, sizeof(hdc_t)); + dev->type = info->local & 255; + + /* Set defaults for the controller. */ + dev->spt = MFM_SECTORS; + dev->base = 0x0320; + dev->irq = 5; + dev->dma = 3; + dev->bios_addr = 0xc8000; + + switch(dev->type) { + case 0: /* Xebec (MFM) */ + fn = XEBEC_BIOS_FILE; + break; + + case 1: /* DTC5150 (MFM) */ + fn = DTC_BIOS_FILE; + dev->switches = 0xff; + break; + + case 12: /* Seagate ST-11R (RLL) */ + dev->spt = RLL_SECTORS; + /*FALLTHROUGH*/ + + case 11: /* Seagate ST-11M (MFM) */ + fn = ST11_BIOS_FILE; + dev->switches = 0x01; /* fixed */ + dev->misc = device_get_config_int("revision"); + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->bios_addr = device_get_config_hex20("bios_addr"); + dev->bios_ram = 64; /* scratch RAM size */ + + /* + * Industrial Madness Alert. + * + * With the ST-11 controller, Seagate decided to act + * like they owned the industry, and reserved the + * first cylinder of a drive for the controller. So, + * when the host accessed cylinder 0, that would be + * the actual cylinder 1 on the drive, and so on. + */ + dev->cyl_off = 1; + break; + + case 21: /* Western Digital WD1002A-WX1 (MFM) */ + fn = WD1002A_WX1_BIOS_FILE; + dev->switches = 0x10; /* autobios */ + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->bios_addr = device_get_config_hex20("bios_addr"); + break; + + case 22: /* Western Digital WD1002A-27X (RLL) */ + fn = WD1002A_27X_BIOS_FILE; + dev->switches = 0x10; /* autobios */ + dev->spt = RLL_SECTORS; + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->bios_addr = device_get_config_hex20("bios_addr"); + break; + } + + /* Load the ROM BIOS. */ + loadrom(dev, fn); + + /* Set up the I/O region. */ + io_sethandler(dev->base, 4, + st506_read,NULL,NULL, st506_write,NULL,NULL, dev); + + /* Add the timer. */ + timer_add(&dev->timer, st506_callback, dev, 0); + + st506_xt_log("ST506: %s (I/O=%03X, IRQ=%i, DMA=%i, BIOS @0x%06lX, size %lu)\n", + info->name,dev->base,dev->irq,dev->dma, dev->bios_addr,dev->bios_size); + + /* Load any drives configured for us. */ +#ifdef ENABLE_ST506_XT_LOG + st506_xt_log("ST506: looking for disks...\n"); +#endif + for (c = 0, i = 0; i < HDD_NUM; i++) { + if ((hdd[i].bus == HDD_BUS_MFM) && (hdd[i].mfm_channel < MFM_NUM)) { + st506_xt_log("ST506: disk '%ls' on channel %i\n", + hdd[i].fn, hdd[i].mfm_channel); + loadhd(dev, hdd[i].mfm_channel, i, hdd[i].fn); + + if (++c > MFM_NUM) break; + } + } + st506_xt_log("ST506: %i disks loaded.\n", c); + + /* For the Xebec, set the switches now. */ + if ((dev->type == 0) || (dev->type == 21)) + set_switches(dev); + + /* Initial "active" drive parameters. */ + for (c = 0; c < MFM_NUM; c++) { + dev->drives[c].cfg_cyl = dev->drives[c].tracks; + dev->drives[c].cfg_hpc = dev->drives[c].hpc; + dev->drives[c].cfg_spt = dev->drives[c].spt; + } + + return(dev); +} + + +static void +st506_close(void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + drive_t *drive; + int d; + + for (d = 0; d < MFM_NUM; d++) { + drive = &dev->drives[d]; + + hdd_image_close(drive->hdd_num); + } + + if (dev->bios_rom.rom != NULL) { + free(dev->bios_rom.rom); + dev->bios_rom.rom = NULL; + } + + free(dev); +} + + +static int +xebec_available(void) +{ + return(rom_present(XEBEC_BIOS_FILE)); +} + + +static int +dtc5150x_available(void) +{ + return(rom_present(DTC_BIOS_FILE)); +} + +static int +st11_m_available(void) +{ + return(rom_present(ST11_BIOS_FILE)); +} + +static int +st11_r_available(void) +{ + return(rom_present(ST11_BIOS_FILE)); +} + +static int +wd1002a_wx1_available(void) +{ + return(rom_present(WD1002A_WX1_BIOS_FILE)); +} + +static int +wd1002a_27x_available(void) +{ + return(rom_present(WD1002A_27X_BIOS_FILE)); +} + + +static const device_config_t dtc_config[] = { + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0xc8000, + { + { + "Disabled", 0x00000 + }, + { + "C800H", 0xc8000 + }, + { + "CA00H", 0xca000 + }, + { + "D800H", 0xd8000 + }, + { + "F400H", 0xf4000 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t st11_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x0320, + { + { + "320H", 0x0320 + }, + { + "324H", 0x0324 + }, + { + "328H", 0x0328 + }, + { + "32CH", 0x032c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 2", 2 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0xc8000, + { + { + "Disabled", 0x00000 + }, + { + "C800H", 0xc8000 + }, + { + "D000H", 0xd0000 + }, + { + "D800H", 0xd8000 + }, + { + "E000H", 0xe0000 + }, + { + "" + } + } + }, + { + "revision", "Board Revision", CONFIG_SELECTION, "", 5, + { + { + "Rev. 00", 0 + }, + { + "Rev. 01", 1 + }, + { + "Rev. 05", 5 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t wd_config[] = { + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0xc8000, + { + { + "Disabled", 0x00000 + }, + { + "C800H", 0xc8000 + }, + { + "" + } + } + }, + { + "base", "Address", CONFIG_HEX16, "", 0x0320, + { + { + "320H", 0x0320 + }, + { + "324H", 0x0324 + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 2", 2 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t st506_xt_xebec_device = { + "IBM PC Fixed Disk Adapter", + DEVICE_ISA, + (HDD_BUS_MFM << 8) | 0, + st506_init, st506_close, NULL, + xebec_available, + NULL, NULL, + NULL +}; + +const device_t st506_xt_dtc5150x_device = { + "DTC 5150X Fixed Disk Adapter", + DEVICE_ISA, + (HDD_BUS_MFM << 8) | 1, + st506_init, st506_close, NULL, + dtc5150x_available, + NULL, NULL, + dtc_config +}; + +const device_t st506_xt_st11_m_device = { + "ST-11M Fixed Disk Adapter", + DEVICE_ISA, + (HDD_BUS_MFM << 8) | 11, + st506_init, st506_close, NULL, + st11_m_available, + NULL, NULL, + st11_config +}; + +const device_t st506_xt_st11_r_device = { + "ST-11R RLL Fixed Disk Adapter", + DEVICE_ISA, + (HDD_BUS_MFM << 8) | 12, + st506_init, st506_close, NULL, + st11_r_available, + NULL, NULL, + st11_config +}; + +const device_t st506_xt_wd1002a_wx1_device = { + "WD1002A-WX1 Fixed Disk Adapter", + DEVICE_ISA, + (HDD_BUS_MFM << 8) | 21, + st506_init, st506_close, NULL, + wd1002a_wx1_available, + NULL, NULL, + wd_config +}; + +const device_t st506_xt_wd1002a_27x_device = { + "WD1002A-27X RLL Fixed Disk Adapter", + DEVICE_ISA, + (HDD_BUS_MFM << 8) | 22, + st506_init, st506_close, NULL, + wd1002a_27x_available, + NULL, NULL, + wd_config +}; diff --git a/src/disk/hdc_xta.c b/src/disk/hdc_xta.c index a99d987b9..9aa8f8faf 100644 --- a/src/disk/hdc_xta.c +++ b/src/disk/hdc_xta.c @@ -257,7 +257,8 @@ typedef struct { uint8_t sense; /* current SENSE ERROR value */ uint8_t status; /* current operational status */ uint8_t intr; - int64_t callback; + uint64_t callback; + pc_timer_t timer; /* Data transfer. */ int16_t buf_idx, /* buffer index and pointer */ @@ -357,6 +358,22 @@ next_sector(hdc_t *dev, drive_t *drive) } } +static void +xta_set_callback(hdc_t *dev, uint64_t callback) +{ + if (!dev) { + return; + } + + if (callback) { + dev->callback = callback; + timer_set_delay_u64(&dev->timer, dev->callback); + } else { + dev->callback = 0; + timer_disable(&dev->timer); + } +} + /* Perform the seek operation. */ static void @@ -456,7 +473,7 @@ hdc_callback(void *priv) int val; /* Cancel timer. */ - dev->callback = 0; + xta_set_callback(dev, 0); drive = &dev->drives[dcb->drvsel]; dev->comp = (dcb->drvsel) ? COMP_DRIVE : 0x00; @@ -553,12 +570,12 @@ do_send: dev->buf_idx = 0; if (no_data) { /* Delay a bit, no actual transfer. */ - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } else { if (dev->intr & DMA_ENA) { /* DMA enabled. */ dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } else { /* Copy from sector to data. */ memcpy(dev->data, @@ -581,14 +598,14 @@ do_send: xta_log("%s: CMD_READ_SECTORS out of data (idx=%d, len=%d)!\n", dev->name, dev->buf_idx, dev->buf_len); dev->status |= (STAT_CD | STAT_IO| STAT_REQ); - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); return; } dev->buf_ptr++; dev->buf_idx++; } } - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); dev->state = STATE_SDONE; break; @@ -651,12 +668,12 @@ do_recv: dev->buf_idx = 0; if (no_data) { /* Delay a bit, no actual transfer. */ - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } else { if (dev->intr & DMA_ENA) { /* DMA enabled. */ dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } else { /* No DMA, do PIO. */ dev->buf_ptr = dev->data; @@ -676,7 +693,7 @@ do_recv: xta_log("%s: CMD_WRITE_SECTORS out of data!\n", dev->name); dev->status |= (STAT_CD | STAT_IO | STAT_REQ); - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); return; } @@ -684,7 +701,7 @@ do_recv: dev->buf_idx++; } dev->state = STATE_RDONE; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } break; @@ -783,7 +800,7 @@ do_recv: dev->state = STATE_RDATA; if (dev->intr & DMA_ENA) { dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } else { dev->buf_ptr = dev->data; dev->status |= STAT_REQ; @@ -798,7 +815,7 @@ do_recv: if (val == DMA_NODATA) { xta_log("%s: CMD_WRITE_BUFFER out of data!\n", dev->name); dev->status |= (STAT_CD | STAT_IO | STAT_REQ); - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); return; } @@ -806,7 +823,7 @@ do_recv: dev->buf_idx++; } dev->state = STATE_RDONE; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } break; @@ -823,7 +840,7 @@ do_recv: switch(dev->state) { case STATE_IDLE: dev->state = STATE_RDONE; - dev->callback = 5*HDC_TIME; + xta_set_callback(dev, 5 * HDC_TIME); break; case STATE_RDONE: @@ -837,7 +854,7 @@ do_recv: case STATE_IDLE: if (drive->present) { dev->state = STATE_RDONE; - dev->callback = 5*HDC_TIME; + xta_set_callback(dev, 5 * HDC_TIME); } else { dev->comp |= COMP_ERR; dev->sense = ERR_NOTRDY; @@ -855,7 +872,7 @@ do_recv: switch(dev->state) { case STATE_IDLE: dev->state = STATE_RDONE; - dev->callback = 10*HDC_TIME; + xta_set_callback(dev, 10 * HDC_TIME); break; case STATE_RDONE: @@ -898,7 +915,7 @@ hdc_read(uint16_t port, void *priv) /* All data sent. */ dev->status &= ~STAT_REQ; dev->state = STATE_SDONE; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } } else if (dev->state == STATE_COMPL) { xta_log("DCB=%02X status=%02X comp=%02X\n", dev->dcb.cmd, dev->status, dev->comp); @@ -954,7 +971,7 @@ hdc_write(uint16_t port, uint8_t val, void *priv) else dev->state = STATE_IDLE; dev->status &= ~STAT_CD; - dev->callback = HDC_TIME; + xta_set_callback(dev, HDC_TIME); } } break; @@ -981,6 +998,13 @@ hdc_write(uint16_t port, uint8_t val, void *priv) } +static int +xta_available(void) +{ + return(rom_present(WD_BIOS_FILE)); +} + + static void * xta_init(const device_t *info) { @@ -1063,7 +1087,7 @@ xta_init(const device_t *info) dev->rom_addr, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); /* Create a timer for command delays. */ - timer_add(hdc_callback, &dev->callback, &dev->callback, dev); + timer_add(&dev->timer, hdc_callback, dev, 0); return(dev); } @@ -1146,7 +1170,7 @@ const device_t xta_wdxt150_device = { DEVICE_ISA, 0, xta_init, xta_close, NULL, - NULL, NULL, NULL, + xta_available, NULL, NULL, wdxt150_config }; diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index a558a3318..3a6cf6656 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -276,7 +276,7 @@ const device_t xtide_acculogic_device = { const device_t xtide_at_ps2_device = { "XTIDE (AT) (1.1.5)", - DEVICE_ISA | DEVICE_PS2, + DEVICE_AT, 0, xtide_at_ps2_init, xtide_at_close, NULL, xtide_at_ps2_available, NULL, NULL, diff --git a/src/disk/hdd.c b/src/disk/hdd.c index 805618a75..46bd9e262 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -24,6 +24,7 @@ #include "../plat.h" #include "../ui.h" #include "hdd.h" +#include "../cdrom/cdrom.h" hard_disk_t hdd[HDD_NUM]; @@ -92,6 +93,9 @@ no_cdrom: if (! strcmp(str, "scsi")) return(HDD_BUS_SCSI); + if (! strcmp(str, "scsi_chinon")) + return(CDROM_BUS_SCSI_CHINON); + if (! strcmp(str, "usb")) ui_msgbox(MBX_ERROR, (wchar_t *)IDS_4110); @@ -128,6 +132,10 @@ hdd_bus_to_string(int bus, int cdrom) case HDD_BUS_SCSI: s = "scsi"; break; + + case CDROM_BUS_SCSI_CHINON: + s = "scsi_chinon"; + break; } return(s); diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index d8bc070d8..a34f2b5cb 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -748,9 +748,17 @@ hdd_image_seek(uint8_t id, uint32_t sector) void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { - hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); - fread(buffer, 1, count << 9, hdd_images[id].file); + int i; + + fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET); + + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; + + hdd_images[id].pos = sector + i; + fread(buffer + (i << 9), 1, 512, hdd_images[id].file); + } } @@ -782,9 +790,17 @@ hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) { - hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); - fwrite(buffer, count << 9, 1, hdd_images[id].file); + int i; + + fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET); + + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; + + hdd_images[id].pos = sector + i; + fwrite(buffer + (i << 9), 512, 1, hdd_images[id].file); + } } @@ -810,11 +826,17 @@ hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) { uint32_t i = 0; - hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); memset(empty_sector, 0, 512); - for (i = 0; i < count; i++) + + fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET); + + for (i = 0; i < count; i++) { + if (feof(hdd_images[id].file)) + break; + + hdd_images[id].pos = sector + i; fwrite(empty_sector, 512, 1, hdd_images[id].file); + } } diff --git a/src/disk/zip.c b/src/disk/zip.c index 6447ecc37..2ff5b4e52 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -23,6 +23,7 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../config.h" #include "../timer.h" #include "../device.h" @@ -857,16 +858,15 @@ static void zip_command_common(zip_t *dev) { double bytes_per_second, period; - double dusec; dev->status = BUSY_STAT; dev->phase = 1; dev->pos = 0; if (dev->packet_status == PHASE_COMPLETE) - dev->callback = 0LL; + dev->callback = 0.0; else { if (dev->drv->bus_type == ZIP_BUS_SCSI) { - dev->callback = -1LL; /* Speed depends on SCSI controller */ + dev->callback = -1.0; /* Speed depends on SCSI controller */ return; } else { if (zip_current_mode(dev) == 2) @@ -876,9 +876,7 @@ zip_command_common(zip_t *dev) } period = 1000000.0 / bytes_per_second; - dusec = (double) TIMER_USEC; - dusec = dusec * period * (double) (dev->packet_len); - dev->callback = ((int64_t) dusec); + dev->callback = period * (double) (dev->packet_len); } zip_set_callback(dev); @@ -998,7 +996,7 @@ zip_cmd_error(zip_t *dev) dev->phase = 3; dev->pos = 0; dev->packet_status = PHASE_ERROR; - dev->callback = 50LL * ZIP_TIME; + dev->callback = 50.0 * ZIP_TIME; zip_set_callback(dev); zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", dev->id, dev->current_cdb[0], zip_sense_key, zip_asc, zip_ascq); } @@ -1015,7 +1013,7 @@ zip_unit_attention(zip_t *dev) dev->phase = 3; dev->pos = 0; dev->packet_status = PHASE_ERROR; - dev->callback = 50LL * ZIP_TIME; + dev->callback = 50.0 * ZIP_TIME; zip_set_callback(dev); zip_log("ZIP %i: UNIT ATTENTION\n", dev->id); } @@ -1138,6 +1136,7 @@ static int zip_blocks(zip_t *dev, int32_t *len, int first_batch, int out) { *len = 0; + int i; if (!dev->sector_len) { zip_command_complete(dev); @@ -1154,11 +1153,17 @@ zip_blocks(zip_t *dev, int32_t *len, int first_batch, int out) *len = dev->requested_blocks << 9; - fseek(dev->drv->f, dev->drv->base + (dev->sector_pos << 9), SEEK_SET); - if (out) - fwrite(dev->buffer, 1, *len, dev->drv->f); - else - fread(dev->buffer, 1, *len, dev->drv->f); + for (i = 0; i < dev->requested_blocks; i++) { + fseek(dev->drv->f, dev->drv->base + (dev->sector_pos << 9) + (i << 9), SEEK_SET); + + if (feof(dev->drv->f)) + break; + + if (out) + fwrite(dev->buffer + (i << 9), 1, 512, dev->drv->f); + else + fread(dev->buffer + (i << 9), 1, 512, dev->drv->f); + } zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); @@ -1286,7 +1291,7 @@ zip_reset(scsi_common_t *sc) zip_rezero(dev); dev->status = 0; - dev->callback = 0LL; + dev->callback = 0.0; zip_set_callback(dev); dev->phase = 1; dev->request_length = 0xEB14; @@ -1481,7 +1486,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) if (!max_len) { zip_set_phase(dev, SCSI_PHASE_STATUS); dev->packet_status = PHASE_COMPLETE; - dev->callback = 20LL * ZIP_TIME; + dev->callback = 20.0 * ZIP_TIME; zip_set_callback(dev); break; } @@ -1533,7 +1538,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) zip_set_phase(dev, SCSI_PHASE_STATUS); /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ dev->packet_status = PHASE_COMPLETE; - dev->callback = 20LL * ZIP_TIME; + dev->callback = 20.0 * ZIP_TIME; zip_set_callback(dev); break; } @@ -1550,7 +1555,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) if (ret <= 0) { zip_set_phase(dev, SCSI_PHASE_STATUS); dev->packet_status = PHASE_COMPLETE; - dev->callback = 20LL * ZIP_TIME; + dev->callback = 20.0 * ZIP_TIME; zip_set_callback(dev); zip_buf_free(dev); return; @@ -1594,6 +1599,8 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_VERIFY_6: case GPCMD_WRITE_6: dev->sector_len = cdb[4]; + if (dev->sector_len == 0) + dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); break; case GPCMD_VERIFY_10: @@ -1611,8 +1618,8 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) break; } - if ((dev->sector_pos >= dev->drv->medium_size) || - ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)) { + if ((dev->sector_pos >= dev->drv->medium_size)/* || + ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)*/) { zip_lba_out_of_range(dev); return; } @@ -1621,7 +1628,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) zip_set_phase(dev, SCSI_PHASE_STATUS); /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ dev->packet_status = PHASE_COMPLETE; - dev->callback = 20LL * ZIP_TIME; + dev->callback = 20.0 * ZIP_TIME; zip_set_callback(dev); break; } @@ -1663,8 +1670,8 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - if ((dev->sector_pos >= dev->drv->medium_size) || - ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)) { + if ((dev->sector_pos >= dev->drv->medium_size)/* || + ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)*/) { zip_lba_out_of_range(dev); return; } @@ -1673,7 +1680,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb) zip_set_phase(dev, SCSI_PHASE_STATUS); /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ dev->packet_status = PHASE_COMPLETE; - dev->callback = 20LL * ZIP_TIME; + dev->callback = 20.0 * ZIP_TIME; zip_set_callback(dev); break; } @@ -2307,7 +2314,7 @@ zip_drive_reset(int c) sd->type = SCSI_REMOVABLE_DISK; } else if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) { /* ATAPI CD-ROM, attach to the IDE bus. */ - id = ide_drives[zip_drives[c].ide_channel]; + id = ide_get_drive(zip_drives[c].ide_channel); /* If the IDE channel is initialized, we attach to it, otherwise, we do nothing - it's going to be a drive that's not attached to anything. */ diff --git a/src/disk/zip.h b/src/disk/zip.h index d01cb061e..b36b7e6bd 100644 --- a/src/disk/zip.h +++ b/src/disk/zip.h @@ -23,7 +23,7 @@ #define BUF_SIZE 32768 -#define ZIP_TIME (5LL * 100LL * (1LL << TIMER_SHIFT)) +#define ZIP_TIME 500.0 #define ZIP_SECTORS (96*2048) @@ -85,7 +85,7 @@ typedef struct { uint32_t sector_pos, sector_len, packet_len, pos; - int64_t callback; + double callback; } zip_t; diff --git a/src/dma.c b/src/dma.c index 6f9bfea8a..1ed1bced2 100644 --- a/src/dma.c +++ b/src/dma.c @@ -41,8 +41,13 @@ #include #include #include "86box.h" +#ifdef USE_NEW_DYNAREC +#include "cpu_new/cpu.h" +#include "cpu_new/x86.h" +#else #include "cpu/cpu.h" #include "cpu/x86.h" +#endif #include "machine/machine.h" #include "mca.h" #include "mem.h" @@ -61,6 +66,7 @@ static int dma_wp, static uint8_t dma_m; static uint8_t dma_stat; static uint8_t dma_stat_rq; +static uint8_t dma_stat_rq_pc; static uint8_t dma_command, dma16_command; static struct { @@ -83,6 +89,22 @@ static struct { static void dma_ps2_run(int channel); +int +dma_get_drq(int channel) +{ + return !!(dma_stat_rq_pc & (1 << channel)); +} + + +void +dma_set_drq(int channel, int set) +{ + dma_stat_rq_pc &= ~(1 << channel); + if (set) + dma_stat_rq_pc |= (1 << channel); +} + + static uint8_t dma_read(uint16_t addr, void *priv) { @@ -111,11 +133,13 @@ dma_read(uint16_t addr, void *priv) return(temp); case 8: /*Status register*/ - temp = dma_stat & 0xf; + temp = dma_stat_rq_pc & 0xf; + temp <<= 4; + temp |= dma_stat & 0xf; dma_stat &= ~0xf; return(temp); - case 0xd: + case 0xd: /*Temporary register*/ return(0); } @@ -156,8 +180,18 @@ dma_write(uint16_t addr, uint8_t val, void *priv) case 8: /*Control register*/ dma_command = val; + if (val & 0x01) + fatal("Memory-to-memory enable\n"); return; + case 9: /*Request register */ + channel = (val & 3); + if (val & 4) + dma_stat_rq_pc |= (1 << channel); + else + dma_stat_rq_pc &= ~(1 << channel); + break; + case 0xa: /*Mask*/ if (val & 4) dma_m |= (1 << (val & 3)); @@ -186,6 +220,11 @@ dma_write(uint16_t addr, uint8_t val, void *priv) case 0xd: /*Master clear*/ dma_wp = 0; dma_m |= 0xf; + dma_stat_rq_pc &= ~0x0f; + return; + + case 0xe: /*Clear mask*/ + dma_m &= 0xf0; return; case 0xf: /*Mask write*/ @@ -387,7 +426,8 @@ dma16_read(uint16_t addr, void *priv) return(temp); case 8: /*Status register*/ - temp = dma_stat >> 4; + temp = (dma_stat_rq_pc & 0xf0); + temp |= dma_stat >> 4; dma_stat &= ~0xf0; return(temp); } @@ -438,6 +478,14 @@ dma16_write(uint16_t addr, uint8_t val, void *priv) case 8: /*Control register*/ return; + case 9: /*Request register */ + channel = (val & 3) + 4; + if (val & 4) + dma_stat_rq_pc |= (1 << channel); + else + dma_stat_rq_pc &= ~(1 << channel); + break; + case 0xa: /*Mask*/ if (val & 4) dma_m |= (0x10 << (val & 3)); @@ -466,6 +514,11 @@ dma16_write(uint16_t addr, uint8_t val, void *priv) case 0xd: /*Master clear*/ dma16_wp = 0; dma_m |= 0xf0; + dma_stat_rq_pc &= ~0xf0; + return; + + case 0xe: /*Clear mask*/ + dma_m &= 0x0f; return; case 0xf: /*Mask write*/ @@ -557,12 +610,18 @@ dma_reset(void) dma[c].cb = 0; dma[c].size = (c & 4) ? 1 : 0; } + + dma_stat = 0x00; + dma_stat_rq = 0x00; + dma_stat_rq_pc = 0x00; } void dma_init(void) { + dma_reset(); + io_sethandler(0x0000, 16, dma_read,NULL,NULL, dma_write,NULL,NULL, NULL); io_sethandler(0x0080, 8, @@ -574,6 +633,8 @@ dma_init(void) void dma16_init(void) { + dma_reset(); + io_sethandler(0x00C0, 32, dma16_read,NULL,NULL, dma16_write,NULL,NULL, NULL); io_sethandler(0x0088, 8, @@ -614,6 +675,8 @@ dma_alias_remove_piix(void) void ps2_dma_init(void) { + dma_reset(); + io_sethandler(0x0018, 1, dma_ps2_read,NULL,NULL, dma_ps2_write,NULL,NULL, NULL); io_sethandler(0x001a, 1, @@ -659,8 +722,10 @@ dma_channel_read(int channel) if ((dma_c->mode & 0xC) != 8) return(DMA_NODATA); - if (!AT) + if (!AT && !channel) refreshread(); + /* if (!AT && channel) + pclog("DMA refresh read on channel %i\n", channel); */ if (! dma_c->size) { temp = _dma_read(dma_c->ac); @@ -730,8 +795,10 @@ dma_channel_write(int channel, uint16_t val) if ((dma_c->mode & 0xC) != 4) return(DMA_NODATA); - if (!AT) + /* if (!AT) refreshread(); + if (!AT) + pclog("DMA refresh write on channel %i\n", channel); */ if (! dma_c->size) { _dma_write(dma_c->ac, val & 0xff); diff --git a/src/dma.h b/src/dma.h index 32f90c4e7..75f923e66 100644 --- a/src/dma.h +++ b/src/dma.h @@ -78,6 +78,9 @@ extern int readdma3(void); extern void writedma2(uint8_t temp); +extern int dma_get_drq(int channel); +extern void dma_set_drq(int channel, int set); + extern int dma_channel_read(int channel); extern int dma_channel_write(int channel, uint16_t val); diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index 8eac08f4d..06c0592df 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -9,7 +9,7 @@ * Implementation of the NEC uPD-765 and compatible floppy disk * controller. * - * Version: @(#)fdc.c 1.0.15 2019/01/26 + * Version: @(#)fdc.c 1.0.18 2019/03/23 * * Authors: Miran Grca, * Sarah Walker, @@ -47,8 +47,6 @@ #include "../cpu/cpu.h" #include "../machine/machine.h" #include "../io.h" -#include "../mem.h" -#include "../rom.h" #include "../dma.h" #include "../pic.h" #include "../timer.h" @@ -57,7 +55,7 @@ #include "fdc.h" -extern int64_t motoron[FDD_NUM]; +extern uint64_t motoron[FDD_NUM]; const int command_has_drivesel[256] = { @@ -100,10 +98,10 @@ const int command_has_drivesel[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -uint8_t current_drive = 0; + +static uint8_t current_drive = 0; static void fdc_callback(void *priv); -int timetolive; int lastbyte=0; int floppymodified[4]; @@ -131,16 +129,9 @@ fdc_log(const char *fmt, ...) uint8_t -fdc_ps1_525(void) +fdc_get_current_drive(void) { - switch (romset) { - case ROM_IBMPS1_2011: - case ROM_IBMPS1_2121: - case ROM_IBMPS1_2121_ISA: - return fdd_is_525(current_drive) ? 0x40 : 0x00; - default: - return 0x00; - } + return current_drive; } @@ -156,7 +147,7 @@ fdc_ctrl_reset(void *p) fdc->head = 0; fdc->abort = 0; fdc->step = 0; - if (!(fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_PS1)) + if (!(fdc->flags & FDC_FLAG_AT)) fdc->rate = 2; } @@ -354,9 +345,8 @@ fdc_watchdog_poll(void *priv) fdc->watchdog_count--; if (fdc->watchdog_count) - fdc->watchdog_timer += 1000LL * TIMER_USEC; + timer_advance_u64(&fdc->watchdog_timer, 1000 * TIMER_USEC); else { - fdc->watchdog_timer = 0LL; if (fdc->dor & 0x20) picint(1 << fdc->irq); } @@ -579,7 +569,6 @@ static void fdc_rate(fdc_t *fdc, int drive) { fdc_update_rate(fdc, drive); - fdd_set_rate(drive, fdc->drvrate[drive], fdc->rate); fdc_log("FDD %c: Setting rate: %i, %i, %i (%i, %i)\n", 0x41 + drive, fdc->drvrate[drive], fdc->rate, fdc_get_densel(fdc, drive), fdc->rwc[drive], fdc->densel_force); fdd_set_densel(fdc_get_densel(fdc, drive)); } @@ -599,8 +588,6 @@ void fdc_seek(fdc_t *fdc, int drive, int params) { fdd_seek(real_drive(fdc, drive), params); - fdc->time = 2048LL * (1 << TIMER_SHIFT); - fdc->stat |= (1 << fdc->drive); } @@ -622,9 +609,7 @@ fdc_bad_command(fdc_t *fdc) { fdc->stat = 0x10; fdc->interrupt = 0xfc; - timer_process(); - fdc->time = 200LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc->timer, 100 * TIMER_USEC); } @@ -641,8 +626,7 @@ fdc_io_command_phase1(fdc_t *fdc, int out) fdc->dtl = fdc->params[7]; fdc_implied_seek(fdc); fdc->rw_track = fdc->params[1]; - fdc->time = 0LL; - ui_sb_update_icon(SB_FLOPPY | fdc->drive, 1); + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); fdc->stat = out ? 0x90 : 0x50; if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) fdc->stat |= 0x20; @@ -663,7 +647,7 @@ fdc_sis(fdc_t *fdc) if (fdc->reset_stat) { drive_num = real_drive(fdc, 4 - fdc->reset_stat); - if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) { + if ((drive_num < FDD_NUM) && fdd_get_flags(drive_num)) { fdd_stop(drive_num); fdd_set_head(drive_num, 0); fdc->res[9] = 0xc0 | (4 - fdc->reset_stat) | (fdd_get_head(drive_num) ? 4 : 0); @@ -698,8 +682,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_log("Write FDC %04X %02X\n", addr, val); - cycles -= ISA_CYCLES(8); - // pclog("fdc_write(): cycles -= ISA_CYCLES(8);\n"); + sub_cycles(ISA_CYCLES(8)); switch (addr&7) { case 0: @@ -709,25 +692,20 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) case 2: /*DOR*/ if (fdc->flags & FDC_FLAG_PCJR) { if ((fdc->dor & 0x40) && !(val & 0x40)) { - fdc->watchdog_timer = 1000LL * TIMER_USEC; - fdc->watchdog_count = 1000LL; + timer_set_delay_u64(&fdc->watchdog_timer, 1000 * TIMER_USEC); + fdc->watchdog_count = 1000; picintc(1 << fdc->irq); } if ((val & 0x80) && !(fdc->dor & 0x80)) { - timer_process(); - fdc->time = 128LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); fdc->interrupt = -1; ui_sb_update_icon(SB_FLOPPY | 0, 0); fdc_ctrl_reset(fdc); fdd_changed[0] = 1; - fdd_changed[1] = 1; - fdd_changed[2] = 1; - fdd_changed[3] = 1; } if (!fdd_get_flags(0)) val &= 0xfe; - motoron[0] = val & 0x01; + fdd_set_motor_enable(0, val & 0x01); fdc->st0 &= ~0x07; fdc->st0 |= (fdd_get_head(0) ? 4 : 0); } else { @@ -745,9 +723,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->pnum = fdc->ptot = 0; } if ((val&4) && !(fdc->dor&4)) { - timer_process(); - fdc->time = 128LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); fdc->interrupt = -1; fdc->perp &= 0xfc; @@ -756,18 +732,16 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_ctrl_reset(fdc); } - timer_process(); - timer_update_outstanding(); /* We can now simplify this since each motor now spins separately. */ for (i = 0; i < FDD_NUM; i++) { drive_num = real_drive(fdc, i); if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) val &= ~(0x10 << drive_num); else - motoron[i] = (val & (0x10 << drive_num)); + fdd_set_motor_enable(i, (val & (0x10 << drive_num))); } drive_num = real_drive(fdc, val & 0x03); - current_drive = real_drive(fdc, val & 0x03); + current_drive = drive_num; fdc->st0 &= ~0x07; fdc->st0 |= real_drive(fdc, drive_num); fdc->st0 |= (fdd_get_head(drive_num) ? 4 : 0); @@ -782,9 +756,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) return; case 4: if (val & 0x80) { - timer_process(); - fdc->time = 128LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); fdc->interrupt = -1; fdc->perp &= 0xfc; fdc_ctrl_reset(fdc); @@ -802,7 +774,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } break; } - if (fdc->pnum==fdc->ptot) { + if (fdc->pnum == fdc->ptot) { if ((fdc->stat & 0xf0) != 0x80) { /* If bit 4 of the MSR is set, or the MSR is 0x00, the fdc_t is NOT in the command phase, therefore @@ -963,15 +935,39 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->stat |= (1 << real_drive(fdc, fdc->drive)); } } - if (fdc->pnum==fdc->ptot) { + if (fdc->pnum == fdc->ptot) { fdc_log("Got all params %02X\n", fdc->command); fdc->interrupt = fdc->command & 0x1F; - timer_process(); - fdc->time = 1024LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); fdc->reset_stat = 0; + /* Disable timer if enabled. */ + timer_disable(&fdc->timer); + /* Start timer if needed at this point. */ switch (fdc->interrupt & 0x1F) { - case 2: /*Read a track*/ + case 0x02: /* Read a track */ + case 0x03: /* Specify */ + case 0x0a: /* Read sector ID */ + case 0x05: /* Write data */ + case 0x06: /* Read data */ + case 0x09: /* Write deleted data */ + case 0x0c: /* Read deleted data */ + case 0x11: /* Scan equal */ + case 0x12: /* Perpendicular mode */ + case 0x16: /* Verify */ + case 0x19: /* Scan low or equal */ + case 0x1d: /* Scan high or equal */ + /* Do nothing. */ + break; + case 0x07: /* Recalibrate */ + case 0x0f: /* Seek */ + timer_set_delay_u64(&fdc->timer, 2048 * TIMER_USEC); + break; + default: + timer_set_delay_u64(&fdc->timer, 256 * TIMER_USEC); + break; + } + /* Process the firt phase of the command. */ + switch (fdc->interrupt & 0x1F) { + case 0x02: /* Read a track */ fdc_io_command_phase1(fdc, 0); fdc->read_track_sector.id.c = fdc->params[1]; fdc->read_track_sector.id.h = fdc->params[2]; @@ -983,28 +979,17 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } fdd_readsector(real_drive(fdc, fdc->drive), SECTOR_FIRST, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); break; - case 3: /*Specify*/ - fdc->stat=0x80; + case 0x03: /* Specify */ + fdc->stat = 0x80; fdc->specify[0] = fdc->params[0]; fdc->specify[1] = fdc->params[1]; fdc->dma = (fdc->specify[1] & 1) ^ 1; - fdc->time = 0LL; break; - case 0x12: - fdc->stat=0x80; - if (fdc->params[0] & 0x80) - fdc->perp = fdc->params[0] & 0x3f; - else { - fdc->perp &= 0xfc; - fdc->perp |= (fdc->params[0] & 0x03); - } - fdc->time = 0LL; - return; - case 4: + case 0x04: /*Sense drive status*/ fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); break; - case 5: /*Write data*/ - case 9: /*Write deleted data*/ + case 0x05: /* Write data */ + case 0x09: /* Write deleted data */ fdc_io_command_phase1(fdc, 1); if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { fdc_noidam(fdc); @@ -1012,9 +997,9 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } fdd_writesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); break; - case 0x11: /*Scan equal*/ - case 0x19: /*Scan low or equal*/ - case 0x1D: /*Scan high or equal*/ + case 0x11: /* Scan equal */ + case 0x19: /* Scan low or equal */ + case 0x1d: /* Scan high or equal */ fdc_io_command_phase1(fdc, 1); if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { fdc_noidam(fdc); @@ -1022,11 +1007,11 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } fdd_comparesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); break; - case 0x16: /*Verify*/ + case 0x16: /* Verify */ if (fdc->params[0] & 0x80) fdc->sc = fdc->params[7]; - case 6: /*Read data*/ - case 0xC: /*Read deleted data*/ + case 0x06: /* Read data */ + case 0x0c: /* Read deleted data */ fdc_io_command_phase1(fdc, 0); fdc_log("Reading sector (drive %i) (%i) (%i %i %i %i) (%i %i %i)\n", fdc->drive, fdc->params[0], fdc->params[1], fdc->params[2], fdc->params[3], fdc->params[4], fdc->params[5], fdc->params[6], fdc->params[7]); if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { @@ -1042,12 +1027,12 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdd_readsector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); break; - case 7: /*Recalibrate*/ + case 0x07: /* Recalibrate */ + fdc->rw_drive = fdc->params[0] & 3; fdc->stat = (1 << real_drive(fdc, fdc->drive)) | 0x80; - fdc->st0 = fdc->drive & 0x03; + fdc->st0 = fdc->params[0] & 3; fdc->st0 |= fdd_get_head(real_drive(fdc, fdc->drive)) ? 0x04 : 0x00; fdc->st0 |= 0x80; - fdc->time = 0LL; drive_num = real_drive(fdc, fdc->drive); /* Three conditions under which the command should fail. */ if (!fdd_get_flags(drive_num) || (drive_num >= FDD_NUM) || !motoron[drive_num] || fdd_track0(drive_num)) { @@ -1058,18 +1043,28 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->st0 = 0x20 | (fdc->params[0] & 3); fdc->pcn[fdc->params[0] & 3] = 0; fdc->interrupt = -3; - timer_process(); - fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); break; } if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) fdc_seek(fdc, fdc->drive, -fdc->max_track); fdc_log("Recalibrating...\n"); - fdc->time = 2048LL * (1 << TIMER_SHIFT); fdc->seek_dir = fdc->step = 1; break; - case 0x0d: /*Format*/ + case 0x0a: /* Read sector ID */ + fdc_rate(fdc, fdc->drive); + fdc->head = (fdc->params[0] & 4) ? 1 : 0; + fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); + if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) { + fdd_readaddress(real_drive(fdc, fdc->drive), fdc->head, fdc->rate); + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) + fdc->stat = 0x70; + else + fdc->stat = 0x50; + } + else + fdc_noidam(fdc); + break; + case 0x0d: /* Format */ fdc_rate(fdc, fdc->drive); fdc->head = (fdc->params[0] & 4) ? 1 : 0; fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); @@ -1081,14 +1076,14 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->pos = 0; fdc->stat = 0x10; break; - case 0xf: /*Seek*/ + case 0x0f: /* Seek */ + fdc->rw_drive = fdc->params[0] & 3; fdc->stat = (1 << fdc->drive) | 0x80; fdc->head = (fdc->params[0] & 4) ? 1 : 0; - fdc->st0 = fdc->drive & 0x03; + fdc->st0 = fdc->params[0] & 0x03; fdc->st0 |= (fdc->params[0] & 4); fdc->st0 |= 0x80; fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); - fdc->time = 0LL; drive_num = real_drive(fdc, fdc->drive); /* Three conditions under which the command should fail. */ if (!fdd_get_flags(drive_num) || (drive_num >= FDD_NUM) || !motoron[drive_num]) { @@ -1102,9 +1097,6 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) } else fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; fdc->interrupt = -3; - timer_process(); - fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); break; } if (fdc->command & 0x80) { @@ -1120,14 +1112,10 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_seek(fdc, fdc->drive, -fdc->params[1]); fdc->pcn[fdc->params[0] & 3] -= fdc->params[1]; } - fdc->time = 2048LL * (1 << TIMER_SHIFT); fdc->step = 1; } else { fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; - timer_process(); - fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); break; } } else { @@ -1136,9 +1124,6 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_log("Failed seek\n"); fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; - timer_process(); - fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); break; } if (fdc->params[1] > fdc->pcn[fdc->params[0] & 3]) @@ -1147,26 +1132,19 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->seek_dir = 1; fdc_seek(fdc, fdc->drive, fdc->params[1] - fdc->pcn[fdc->params[0] & 3]); fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; - fdc->time = 2048LL * (1 << TIMER_SHIFT); fdc->step = 1; fdc_log("fdc->time = %i\n", fdc->time); } break; - case 10: /*Read sector ID*/ - fdc_rate(fdc, fdc->drive); - fdc->time = 0LL; - fdc->head = (fdc->params[0] & 4) ? 1 : 0; - fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); - if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) { - fdd_readaddress(real_drive(fdc, fdc->drive), fdc->head, fdc->rate); - if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) - fdc->stat = 0x70; - else - fdc->stat = 0x50; + case 0x12: /* Perpendicular mode */ + fdc->stat = 0x80; + if (fdc->params[0] & 0x80) + fdc->perp = fdc->params[0] & 0x3f; + else { + fdc->perp &= 0xfc; + fdc->perp |= (fdc->params[0] & 0x03); } - else - fdc_noidam(fdc); - break; + return; } } else fdc->stat = 0x90 | (fdc->stat & 0xf); @@ -1190,8 +1168,7 @@ fdc_read(uint16_t addr, void *priv) uint8_t ret; int drive; - cycles -= ISA_CYCLES(8); - // pclog("fdc_read(): cycles -= ISA_CYCLES(8);\n"); + sub_cycles(ISA_CYCLES(8)); switch (addr & 7) { case 0: /* STA */ @@ -1240,13 +1217,13 @@ fdc_read(uint16_t addr, void *priv) break; } } else { - if (is486) + if (is486 || !fdc->enable_3f1) return 0xff; - drive = real_drive(fdc, fdc->dor & 3); - if (!fdc->enable_3f1) - ret = 0xff; ret = 0x70; + + drive = real_drive(fdc, fdc->dor & 3); + if (drive) ret &= ~0x40; else @@ -1322,7 +1299,6 @@ fdc_read(uint16_t addr, void *priv) drive = real_drive(fdc, fdc->dor & 3); if (fdc->flags & FDC_FLAG_PS1) { - fdc->step = 0; if (fdc->dor & (0x10 << drive)) { ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x00 : 0x80; ret |= (fdc->dor & 0x08); @@ -1342,10 +1318,11 @@ fdc_read(uint16_t addr, void *priv) ret ^= 0x80; /* 0 = ????, 1 = Ext. FDD off, 2 = Ext. FDD = FDD A, 3 = Ext. FDD = FDD B */ - if (fdc->flags & FDC_FLAG_TOSHIBA) + if (fdc->flags & FDC_FLAG_TOSHIBA) { ret |= (3 << 5); - - ret |= 0x01; + ret |= 0x01; + } else + ret |= 0x7F; } fdc->step = 0; @@ -1399,7 +1376,7 @@ fdc_poll_common_finish(fdc_t *fdc, int compare, int st5) fdc->res[9]=fdc->sector; fdc->res[10]=fdc->params[4]; fdc_log("Read/write finish (%02X %02X %02X %02X %02X %02X %02X)\n" , fdc->res[4], fdc->res[5], fdc->res[6], fdc->res[7], fdc->res[8], fdc->res[9], fdc->res[10]); - ui_sb_update_icon(SB_FLOPPY | fdc->drive, 0); + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); fdc->paramstogo = 7; } @@ -1417,7 +1394,7 @@ fdc_poll_readwrite_finish(fdc_t *fdc, int compare) static void fdc_no_dma_end(fdc_t *fdc, int compare) { - fdc->time = 0LL; + timer_disable(&fdc->timer); fdc_poll_common_finish(fdc, compare, 0x80); } @@ -1430,7 +1407,6 @@ fdc_callback(void *priv) int compare = 0; int drive_num = 0; int old_sector = 0; - fdc->time = 0LL; fdc_log("fdc_callback(): %i\n", fdc->interrupt); switch (fdc->interrupt) { case -3: /*End of command with interrupt*/ @@ -1446,12 +1422,12 @@ fdc_callback(void *priv) memset(fdc->pcn, 0, 4 * sizeof(int)); fdc->reset_stat = 4; return; - case 1: /*Mode*/ + case 0x01: /* Mode */ fdc->stat=0x80; fdc->densel_force = (fdc->params[2] & 0xC0) >> 6; return; - case 2: /*Read track*/ - ui_sb_update_icon(SB_FLOPPY | fdc->drive, 1); + case 0x02: /* Read track */ + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); fdc->eot[fdc->drive]--; fdc->read_track_sector.id.r++; if (!fdc->eot[fdc->drive] || fdc->tc) { @@ -1466,7 +1442,7 @@ fdc_callback(void *priv) } fdc->inread = 1; return; - case 4: /*Sense drive status*/ + case 0x04: /* Sense drive status */ fdc->res[10] = (fdc->params[0] & 7) | 0x20; if (fdd_is_double_sided(real_drive(fdc, fdc->drive))) fdc->res[10] |= 0x08; @@ -1480,16 +1456,15 @@ fdc_callback(void *priv) fdc->stat = (fdc->stat & 0xf) | 0xd0; fdc->paramstogo = 1; fdc->interrupt = 0; - fdc->time = 0LL; return; - case 5: /*Write data*/ - case 9: /*Write deleted data*/ - case 6: /*Read data*/ - case 0xC: /*Read deleted data*/ - case 0x11: /*Scan equal*/ - case 0x19: /*Scan low or equal*/ - case 0x1C: /*Verify*/ - case 0x1D: /*Scan high or equal*/ + case 0x05: /* Write data */ + case 0x09: /* Write deleted data */ + case 0x06: /* Read data */ + case 0x0c: /* Read deleted data */ + case 0x11: /* Scan equal */ + case 0x19: /* Scan low or equal */ + case 0x1c: /* Verify */ + case 0x1d: /* Scan high or equal */ if ((fdc->interrupt == 0x11) || (fdc->interrupt == 0x19) || (fdc->interrupt == 0x1D)) compare = 1; else @@ -1572,7 +1547,7 @@ fdc_callback(void *priv) } } else if (fdc->sector < fdc->params[5]) fdc->sector++; - ui_sb_update_icon(SB_FLOPPY | fdc->drive, 1); + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 1); switch (fdc->interrupt) { case 5: case 9: @@ -1603,24 +1578,20 @@ fdc_callback(void *priv) } fdc->inread = 1; return; - case 7: /*Recalibrate*/ + case 0x07: /* Recalibrate */ fdc->pcn[fdc->params[0] & 3] = 0; drive_num = real_drive(fdc, fdc->rw_drive); fdc->st0 = 0x20 | (fdc->params[0] & 3); if (!fdd_track0(drive_num)) fdc->st0 |= 0x50; fdc->interrupt = -3; - timer_process(); - fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); - fdc->stat = 0x80 | (1 << fdc->drive); + timer_set_delay_u64(&fdc->timer, 2048 * TIMER_USEC); + fdc->stat = 0x80 | (1 << fdc->rw_drive); return; case 0x0d: /*Format track*/ if (fdc->format_state == 1) { fdc->format_state = 2; - timer_process(); - fdc->time = 128LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc->timer, 8 * TIMER_USEC); } else if (fdc->format_state == 2) { fdd_format(real_drive(fdc, fdc->drive), fdc->head, fdc->rate, fdc->params[4]); fdc->format_state = 3; @@ -1655,16 +1626,11 @@ fdc_callback(void *priv) fdc->res[10] = fdc->pretrk; fdc->paramstogo = 10; fdc->interrupt = 0; - fdc->time = 0LL; return; case 0x0f: /*Seek*/ - drive_num = real_drive(fdc, fdc->rw_drive); fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; - /* timer_process(); - fdc->time = 2048LL * (1LL << TIMER_SHIFT); - timer_update_outstanding(); */ - fdc->stat = 0x80 | (1 << fdc->drive); + fdc->stat = 0x80 | (1 << fdc->rw_drive); fdc_callback(fdc); return; case 0x10: /*Version*/ @@ -1673,7 +1639,6 @@ fdc_callback(void *priv) fdc->res[10] = (fdc->interrupt & 0x08) ? 0x73 : 0x90; fdc->paramstogo = 1; fdc->interrupt = 0; - fdc->time = 0LL; return; case 0x13: /*Configure*/ fdc->config = fdc->params[1]; @@ -1681,7 +1646,6 @@ fdc_callback(void *priv) fdc->fifo = (fdc->params[1] & 0x20) ? 0 : 1; fdc->tfifo = (fdc->params[1] & 0xF); fdc->stat = 0x80; - fdc->time = 0LL; return; case 0x14: /*Unlock*/ case 0x94: /*Lock*/ @@ -1690,7 +1654,6 @@ fdc_callback(void *priv) fdc->res[10] = (fdc->interrupt & 0x80) ? 0x10 : 0x00; fdc->paramstogo = 1; fdc->interrupt = 0; - fdc->time = 0LL; return; case 0xfc: /*Invalid*/ fdc->dat = fdc->st0 = 0x80; @@ -1698,7 +1661,6 @@ fdc_callback(void *priv) fdc->res[10] = fdc->st0; fdc->paramstogo = 1; fdc->interrupt = 0; - fdc->time = 0LL; return; } } @@ -1707,7 +1669,7 @@ fdc_callback(void *priv) void fdc_error(fdc_t *fdc, int st5, int st6) { - fdc->time = 0LL; + timer_disable(&fdc->timer); fdc_int(fdc); if (!(fdc->flags & FDC_FLAG_PS1)) @@ -1741,7 +1703,7 @@ fdc_error(fdc_t *fdc, int st5, int st6) fdc->res[10]=0; break; } - ui_sb_update_icon(SB_FLOPPY | fdc->drive, 0); + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); fdc->paramstogo = 7; } @@ -1979,7 +1941,7 @@ fdc_sectorid(fdc_t *fdc, uint8_t track, uint8_t side, uint8_t sector, uint8_t si fdc->res[8] = side; fdc->res[9] = sector; fdc->res[10] = size; - ui_sb_update_icon(SB_FLOPPY | fdc->drive, 0); + ui_sb_update_icon(SB_FLOPPY | real_drive(fdc, fdc->drive), 0); fdc->paramstogo = 7; } @@ -2034,15 +1996,19 @@ fdc_set_base(fdc_t *fdc, int base) { int super_io = (fdc->flags & FDC_FLAG_SUPERIO); - if (fdc->flags & FDC_FLAG_AT) { + if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { io_sethandler(base + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); io_sethandler(base + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); } else { - io_sethandler(base + 0x0002, 0x0001, NULL, NULL, NULL, fdc_write, NULL, NULL, fdc); - io_sethandler(base + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); - io_sethandler(base + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); - if (fdc->flags & FDC_FLAG_TOSHIBA) - io_sethandler(base + 0x0007, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + if (fdc->flags & FDC_FLAG_PCJR) + io_sethandler(base, 0x0010, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + else { + io_sethandler(base + 0x0002, 0x0001, NULL, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_sethandler(base + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); + io_sethandler(base + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + if (fdc->flags & FDC_FLAG_TOSHIBA) + io_sethandler(base + 0x0007, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } } fdc->base_address = base; fdc_log("fdc_t Base address set%s (%04X)\n", super_io ? " for Super I/O" : "", fdc->base_address); @@ -2055,15 +2021,19 @@ fdc_remove(fdc_t *fdc) int super_io = (fdc->flags & FDC_FLAG_SUPERIO); fdc_log("fdc_t Removed (%04X)\n", fdc->base_address); - if (fdc->flags & FDC_FLAG_AT) { + if ((fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_AMSTRAD)) { io_removehandler(fdc->base_address + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); io_removehandler(fdc->base_address + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); } else { - io_removehandler(fdc->base_address + 0x0002, 0x0001, NULL, NULL, NULL, fdc_write, NULL, NULL, fdc); - io_removehandler(fdc->base_address + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); - io_removehandler(fdc->base_address + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); - if (fdc->flags & FDC_FLAG_TOSHIBA) - io_removehandler(fdc->base_address + 0x0007, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + if (fdc->flags & FDC_FLAG_PCJR) + io_removehandler(fdc->base_address, 0x0010, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + else { + io_removehandler(fdc->base_address + 0x0002, 0x0001, NULL, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + if (fdc->flags & FDC_FLAG_TOSHIBA) + io_removehandler(fdc->base_address + 0x0007, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } } } @@ -2138,11 +2108,8 @@ fdc_close(void *priv) fdc_reset(fdc); /* Stop timers. */ - fdc->watchdog_timer = 0; fdc->watchdog_count = 0; - fdc->time = 0; - free(fdc); } @@ -2159,13 +2126,13 @@ fdc_init(const device_t *info) fdc->irq = 6; if (fdc->flags & FDC_FLAG_PCJR) - timer_add(fdc_watchdog_poll, &fdc->watchdog_timer, &fdc->watchdog_timer, fdc); + timer_add(&fdc->watchdog_timer, fdc_watchdog_poll, fdc, 0); else fdc->dma_ch = 2; fdc_log("FDC added: %04X (flags: %08X)\n", fdc->base_address, fdc->flags); - timer_add(fdc_callback, &fdc->time, &fdc->time, fdc); + timer_add(&fdc->timer, fdc_callback, fdc, 0); d86f_set_fdc(fdc); fdi_set_fdc(fdc); @@ -2198,7 +2165,7 @@ const device_t fdc_xt_device = { }; const device_t fdc_xt_t1x00_device = { - "PC/XT Floppy Drive Controller", + "PC/XT Floppy Drive Controller (Toshiba)", 0, FDC_FLAG_TOSHIBA, fdc_init, @@ -2207,6 +2174,17 @@ const device_t fdc_xt_t1x00_device = { NULL, NULL, NULL }; +const device_t fdc_xt_amstrad_device = { + "PC/XT Floppy Drive Controller (Amstrad)", + 0, + FDC_FLAG_DISKCHG_ACTLOW | FDC_FLAG_AMSTRAD, + fdc_init, + fdc_close, + fdc_reset, + NULL, NULL, NULL +}; + + const device_t fdc_pcjr_device = { "PCjr Floppy Drive Controller", 0, diff --git a/src/floppy/fdc.h b/src/floppy/fdc.h index 9158e57d8..5acc1d883 100644 --- a/src/floppy/fdc.h +++ b/src/floppy/fdc.h @@ -9,7 +9,7 @@ * Implementation of the NEC uPD-765 and compatible floppy disk * controller. * - * Version: @(#)fdc.h 1.0.5 2018/09/22 + * Version: @(#)fdc.h 1.0.6 2019/03/23 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -50,6 +50,7 @@ #define FDC_FLAG_MORE_TRACKS 0x40 /* W83877F, W83977F, PC87306, PC87309 */ #define FDC_FLAG_NSC 0x80 /* PC87306, PC87309 */ #define FDC_FLAG_TOSHIBA 0x100 /* T1000, T1200 */ +#define FDC_FLAG_AMSTRAD 0x200 /* Non-AT Amstrad machines */ typedef struct { @@ -99,8 +100,9 @@ typedef struct { sector_id_t read_track_sector; - int64_t time; - int64_t watchdog_timer, watchdog_count; + uint64_t watchdog_count; + + pc_timer_t timer, watchdog_timer; } fdc_t; @@ -180,11 +182,12 @@ extern void fdc_sectorid(fdc_t *fdc, uint8_t track, uint8_t side, extern uint8_t fdc_read(uint16_t addr, void *priv); extern void fdc_reset(void *priv); -extern uint8_t fdc_ps1_525(void); +extern uint8_t fdc_get_current_drive(void); #ifdef EMU_DEVICE_H extern const device_t fdc_xt_device; extern const device_t fdc_xt_t1x00_device; +extern const device_t fdc_xt_amstrad_device; extern const device_t fdc_pcjr_device; extern const device_t fdc_at_device; extern const device_t fdc_at_actlow_device; diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 64558ad7e..02d4ed837 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -8,7 +8,7 @@ * * Implementation of the floppy drive emulation. * - * Version: @(#)fdd.c 1.0.13 2018/11/12 + * Version: @(#)fdd.c 1.0.14 2019/02/11 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -57,96 +57,6 @@ #include "fdc.h" -extern int driveempty[4]; - -wchar_t floppyfns[4][512]; - -int64_t fdd_poll_time[FDD_NUM] = { 16LL, 16LL, 16LL, 16LL }; - -int fdd_cur_track[FDD_NUM]; -int writeprot[FDD_NUM], fwriteprot[FDD_NUM]; - -DRIVE drives[FDD_NUM]; -int drive_type[FDD_NUM]; - -int curdrive = 0; - -int defaultwriteprot = 0; - -int fdc_ready; - -int drive_empty[FDD_NUM] = {1, 1, 1, 1}; -int fdd_changed[FDD_NUM]; - -int motorspin; -int64_t motoron[FDD_NUM]; - -int fdc_indexcount = 52; - -fdc_t *fdd_fdc; - -d86f_handler_t d86f_handler[FDD_NUM]; - -static const struct -{ - wchar_t *ext; - void (*load)(int drive, wchar_t *fn); - void (*close)(int drive); - int size; -} loaders[]= -{ - {L"001", img_load, img_close, -1}, - {L"002", img_load, img_close, -1}, - {L"003", img_load, img_close, -1}, - {L"004", img_load, img_close, -1}, - {L"005", img_load, img_close, -1}, - {L"006", img_load, img_close, -1}, - {L"007", img_load, img_close, -1}, - {L"008", img_load, img_close, -1}, - {L"009", img_load, img_close, -1}, - {L"010", img_load, img_close, -1}, - {L"12", img_load, img_close, -1}, - {L"144", img_load, img_close, -1}, - {L"360", img_load, img_close, -1}, - {L"720", img_load, img_close, -1}, - {L"86F", d86f_load, d86f_close, -1}, - {L"BIN", img_load, img_close, -1}, - {L"CQ", img_load, img_close, -1}, - {L"CQM", img_load, img_close, -1}, - {L"DDI", img_load, img_close, -1}, - {L"DSK", img_load, img_close, -1}, - {L"FDI", fdi_load, fdi_close, -1}, - {L"FDF", img_load, img_close, -1}, - {L"FLP", img_load, img_close, -1}, - {L"HDM", img_load, img_close, -1}, - {L"IMA", img_load, img_close, -1}, - {L"IMD", imd_load, imd_close, -1}, - {L"IMG", img_load, img_close, -1}, - {L"JSON", json_load, json_close, -1}, - {L"MFM", mfm_load, mfm_close, -1}, - {L"TD0", td0_load, td0_close, -1}, - {L"VFD", img_load, img_close, -1}, - {L"XDF", img_load, img_close, -1}, - {0,0,0} -}; - -static int driveloaders[4]; - - -typedef struct { - int type; - int track; - int densel; - int head; - int turbo; - int check_bpb; -} fdd_t; - - -fdd_t fdd[FDD_NUM]; -int ui_writeprot[FDD_NUM] = {0, 0, 0, 0}; - - /* Flags: Bit 0: 300 rpm supported; Bit 1: 360 rpm supported; @@ -160,8 +70,8 @@ int ui_writeprot[FDD_NUM] = {0, 0, 0, 0}; Bit 9: ignore DENSEL; Bit 10: drive is a PS/2 drive; */ -#define FLAG_RPM_300 1 -#define FLAG_RPM_360 2 +#define FLAG_RPM_300 1 +#define FLAG_RPM_360 2 #define FLAG_525 4 #define FLAG_DS 8 #define FLAG_HOLE0 16 @@ -172,61 +82,139 @@ int ui_writeprot[FDD_NUM] = {0, 0, 0, 0}; #define FLAG_IGNORE_DENSEL 512 #define FLAG_PS2 1024 + +typedef struct { + int type; + int track; + int densel; + int head; + int turbo; + int check_bpb; +} fdd_t; + + +fdd_t fdd[FDD_NUM]; + +wchar_t floppyfns[FDD_NUM][512]; + +pc_timer_t fdd_poll_time[FDD_NUM]; + +static int fdd_notfound = 0, + driveloaders[FDD_NUM]; + +int writeprot[FDD_NUM], fwriteprot[FDD_NUM], + fdd_changed[FDD_NUM], ui_writeprot[FDD_NUM] = {0, 0, 0, 0}, + drive_empty[FDD_NUM] = {1, 1, 1, 1}; + +DRIVE drives[FDD_NUM]; + +uint64_t motoron[FDD_NUM]; + +fdc_t *fdd_fdc; + +d86f_handler_t d86f_handler[FDD_NUM]; + + static const struct { - int max_track; - int flags; - char name[64]; - char internal_name[24]; + wchar_t *ext; + void (*load)(int drive, wchar_t *fn); + void (*close)(int drive); + int size; +} loaders[]= +{ + {L"001", img_load, img_close, -1}, + {L"002", img_load, img_close, -1}, + {L"003", img_load, img_close, -1}, + {L"004", img_load, img_close, -1}, + {L"005", img_load, img_close, -1}, + {L"006", img_load, img_close, -1}, + {L"007", img_load, img_close, -1}, + {L"008", img_load, img_close, -1}, + {L"009", img_load, img_close, -1}, + {L"010", img_load, img_close, -1}, + {L"12", img_load, img_close, -1}, + {L"144", img_load, img_close, -1}, + {L"360", img_load, img_close, -1}, + {L"720", img_load, img_close, -1}, + {L"86F", d86f_load, d86f_close, -1}, + {L"BIN", img_load, img_close, -1}, + {L"CQ", img_load, img_close, -1}, + {L"CQM", img_load, img_close, -1}, + {L"DDI", img_load, img_close, -1}, + {L"DSK", img_load, img_close, -1}, + {L"FDI", fdi_load, fdi_close, -1}, + {L"FDF", img_load, img_close, -1}, + {L"FLP", img_load, img_close, -1}, + {L"HDM", img_load, img_close, -1}, + {L"IMA", img_load, img_close, -1}, + {L"IMD", imd_load, imd_close, -1}, + {L"IMG", img_load, img_close, -1}, + {L"JSON", json_load, json_close, -1}, + {L"MFM", mfm_load, mfm_close, -1}, + {L"TD0", td0_load, td0_close, -1}, + {L"VFD", img_load, img_close, -1}, + {L"XDF", img_load, img_close, -1}, + {0, 0, 0, 0} +}; + + +static const struct +{ + int max_track; + int flags; + const char *name; + const char *internal_name; } drive_types[] = { - { /*None*/ - 0, 0, "None", "none" - }, - { /*5.25" 1DD*/ - 43, FLAG_RPM_300 | FLAG_525 | FLAG_HOLE0, "5.25\" 180k", "525_1dd" - }, - { /*5.25" DD*/ - 43, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0, "5.25\" 360k", "525_2dd" - }, - { /*5.25" QD*/ - 86, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "5.25\" 720k", "525_2qd" - }, - { /*5.25" HD PS/2*/ - 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2, "5.25\" 1.2M PS/2", "525_2hd_ps2" - }, - { /*5.25" HD*/ - 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M", "525_2hd" - }, - { /*5.25" HD Dual RPM*/ - 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M 300/360 RPM", "525_2hd_dualrpm" - }, - { /*3.5" 1DD*/ - 86, FLAG_RPM_300 | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 360k", "35_1dd" - }, - { /*3.5" DD*/ - 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 720k", "35_2dd" - }, - { /*3.5" HD PS/2*/ - 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2, "3.5\" 1.44M PS/2", "35_2hd_ps2" - }, - { /*3.5" HD*/ - 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M", "35_2hd" - }, - { /*3.5" HD PC-98*/ - 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL, "3.5\" 1.25M PC-98", "35_2hd_nec" - }, - { /*3.5" HD 3-Mode*/ - 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M 300/360 RPM", "35_2hd_3mode" - }, - { /*3.5" ED*/ - 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 | FLAG_DOUBLE_STEP, "3.5\" 2.88M", "35_2ed" - }, - { /*End of list*/ - -1, -1, "", "" - } + { /*None*/ + 0, 0, "None", "none" + }, + { /*5.25" 1DD*/ + 43, FLAG_RPM_300 | FLAG_525 | FLAG_HOLE0, "5.25\" 180k", "525_1dd" + }, + { /*5.25" DD*/ + 43, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0, "5.25\" 360k", "525_2dd" + }, + { /*5.25" QD*/ + 86, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "5.25\" 720k", "525_2qd" + }, + { /*5.25" HD PS/2*/ + 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2, "5.25\" 1.2M PS/2", "525_2hd_ps2" + }, + { /*5.25" HD*/ + 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M", "525_2hd" + }, + { /*5.25" HD Dual RPM*/ + 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M 300/360 RPM", "525_2hd_dualrpm" + }, + { /*3.5" 1DD*/ + 86, FLAG_RPM_300 | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 360k", "35_1dd" + }, + { /*3.5" DD*/ + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 720k", "35_2dd" + }, + { /*3.5" HD PS/2*/ + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2, "3.5\" 1.44M PS/2", "35_2hd_ps2" + }, + { /*3.5" HD*/ + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M", "35_2hd" + }, + { /*3.5" HD PC-98*/ + 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL, "3.5\" 1.25M PC-98", "35_2hd_nec" + }, + { /*3.5" HD 3-Mode*/ + 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M 300/360 RPM", "35_2hd_3mode" + }, + { /*3.5" ED*/ + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 | FLAG_DOUBLE_STEP, "3.5\" 2.88M", "35_2ed" + }, + { /*End of list*/ + -1, -1, "", "" + } }; + #ifdef ENABLE_FDD_LOG int fdd_do_log = ENABLE_FDD_LOG; @@ -248,493 +236,494 @@ fdd_log(const char *fmt, ...) #endif -char *fdd_getname(int type) +char * +fdd_getname(int type) { - return (char *)drive_types[type].name; + return (char *)drive_types[type].name; } -char *fdd_get_internal_name(int type) + +char * +fdd_get_internal_name(int type) { - return (char *)drive_types[type].internal_name; + return (char *)drive_types[type].internal_name; } -int fdd_get_from_internal_name(char *s) + +int +fdd_get_from_internal_name(char *s) { - int c = 0; - - while (strlen(drive_types[c].internal_name)) - { - if (!strcmp((char *)drive_types[c].internal_name, s)) - return c; - c++; - } - - return 0; + int c = 0; + + while (strlen(drive_types[c].internal_name)) { + if (!strcmp((char *)drive_types[c].internal_name, s)) + return c; + c++; + } + + return 0; } + /* This is needed for the dump as 86F feature. */ -void fdd_do_seek(int drive, int track) +void +fdd_do_seek(int drive, int track) { - if (drives[drive].seek) { - drives[drive].seek(drive, track); - } + if (drives[drive].seek) + drives[drive].seek(drive, track); } -void fdd_forced_seek(int drive, int track_diff) + +void +fdd_forced_seek(int drive, int track_diff) { - fdd[drive].track += track_diff; - - if (fdd[drive].track < 0) - fdd[drive].track = 0; + fdd[drive].track += track_diff; - if (fdd[drive].track > drive_types[fdd[drive].type].max_track) - fdd[drive].track = drive_types[fdd[drive].type].max_track; + if (fdd[drive].track < 0) + fdd[drive].track = 0; - fdd_do_seek(drive, fdd[drive].track); + if (fdd[drive].track > drive_types[fdd[drive].type].max_track) + fdd[drive].track = drive_types[fdd[drive].type].max_track; + + fdd_do_seek(drive, fdd[drive].track); } -void fdd_seek(int drive, int track_diff) + +void +fdd_seek(int drive, int track_diff) { - if (!track_diff) - return; + if (!track_diff) + return; - fdd[drive].track += track_diff; + fdd[drive].track += track_diff; - if (fdd[drive].track < 0) - fdd[drive].track = 0; + if (fdd[drive].track < 0) + fdd[drive].track = 0; - if (fdd[drive].track > drive_types[fdd[drive].type].max_track) - fdd[drive].track = drive_types[fdd[drive].type].max_track; + if (fdd[drive].track > drive_types[fdd[drive].type].max_track) + fdd[drive].track = drive_types[fdd[drive].type].max_track; - fdd_changed[drive] = 0; + fdd_changed[drive] = 0; - fdd_do_seek(drive, fdd[drive].track); + fdd_do_seek(drive, fdd[drive].track); } -int fdd_track0(int drive) -{ - /* If drive is disabled, TRK0 never gets set. */ - if (!drive_types[fdd[drive].type].max_track) return 0; - return !fdd[drive].track; +int +fdd_track0(int drive) +{ + /* If drive is disabled, TRK0 never gets set. */ + if (!drive_types[fdd[drive].type].max_track) return 0; + + return !fdd[drive].track; } -int fdd_current_track(int drive) + +int +fdd_current_track(int drive) { - return fdd[drive].track; + return fdd[drive].track; } -void fdd_set_densel(int densel) + +void +fdd_set_densel(int densel) { - int i = 0; + int i = 0; - for (i = 0; i < 4; i++) - { - if (drive_types[fdd[i].type].flags & FLAG_INVERT_DENSEL) - { - fdd[i].densel = densel ^ 1; - } - else - { - fdd[i].densel = densel; - } - } -} - -int fdd_getrpm(int drive) -{ - int hole = fdd_hole(drive); - - int densel = 0; - - densel = fdd[drive].densel; - - if (drive_types[fdd[drive].type].flags & FLAG_INVERT_DENSEL) - { - densel ^= 1; - } - - if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_360)) return 300; - if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_300)) return 360; - - if (drive_types[fdd[drive].type].flags & FLAG_525) - { - return densel ? 360 : 300; - } + for (i = 0; i < 4; i++) { + if (drive_types[fdd[i].type].flags & FLAG_INVERT_DENSEL) + fdd[i].densel = densel ^ 1; else - { - /* fdd_hole(drive) returns 0 for double density media, 1 for high density, and 2 for extended density. */ - if (hole == 1) - { - return densel ? 300 : 360; - } - else - { - return 300; - } - } + fdd[i].densel = densel; + } } -int fdd_can_read_medium(int drive) + +int +fdd_getrpm(int drive) { - int hole = fdd_hole(drive); + int densel = 0; + int hole; - hole = 1 << (hole + 4); + hole = fdd_hole(drive); + densel = fdd[drive].densel; - return (drive_types[fdd[drive].type].flags & hole) ? 1 : 0; -} + if (drive_types[fdd[drive].type].flags & FLAG_INVERT_DENSEL) + densel ^= 1; -int fdd_doublestep_40(int drive) -{ - return (drive_types[fdd[drive].type].flags & FLAG_DOUBLE_STEP) ? 1 : 0; -} + if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_360)) + return 300; + if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_300)) + return 360; -void fdd_set_type(int drive, int type) -{ - int old_type = fdd[drive].type; - fdd[drive].type = type; - if ((drive_types[old_type].flags ^ drive_types[type].flags) & FLAG_INVERT_DENSEL) - { - fdd[drive].densel ^= 1; - } -} - -int fdd_get_type(int drive) -{ - return fdd[drive].type; -} - -int fdd_get_flags(int drive) -{ - return drive_types[fdd[drive].type].flags; -} - -int fdd_is_525(int drive) -{ - return drive_types[fdd[drive].type].flags & FLAG_525; -} - -int fdd_is_dd(int drive) -{ - return (drive_types[fdd[drive].type].flags & 0x70) == 0x10; -} - -int fdd_is_ed(int drive) -{ - return drive_types[fdd[drive].type].flags & FLAG_HOLE2; -} - -int fdd_is_double_sided(int drive) -{ - return drive_types[fdd[drive].type].flags & FLAG_DS; -} - -void fdd_set_head(int drive, int head) -{ - if (head && !fdd_is_double_sided(drive)) - fdd[drive].head = 0; + if (drive_types[fdd[drive].type].flags & FLAG_525) + return densel ? 360 : 300; + else { + /* fdd_hole(drive) returns 0 for double density media, 1 for high density, and 2 for extended density. */ + if (hole == 1) + return densel ? 300 : 360; else - fdd[drive].head = head; + return 300; + } } -int fdd_get_head(int drive) + +int +fdd_can_read_medium(int drive) { - if (!fdd_is_double_sided(drive)) - return 0; - return fdd[drive].head; + int hole = fdd_hole(drive); + + hole = 1 << (hole + 4); + + return !!(drive_types[fdd[drive].type].flags & hole); } -void fdd_set_turbo(int drive, int turbo) + +int +fdd_doublestep_40(int drive) { - fdd[drive].turbo = turbo; + return !!(drive_types[fdd[drive].type].flags & FLAG_DOUBLE_STEP); } -int fdd_get_turbo(int drive) + +void +fdd_set_type(int drive, int type) { - return fdd[drive].turbo; + int old_type = fdd[drive].type; + fdd[drive].type = type; + if ((drive_types[old_type].flags ^ drive_types[type].flags) & FLAG_INVERT_DENSEL) + fdd[drive].densel ^= 1; } + +int +fdd_get_type(int drive) +{ + return fdd[drive].type; +} + + +int +fdd_get_flags(int drive) +{ + return drive_types[fdd[drive].type].flags; +} + + +int +fdd_is_525(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_525; +} + + +int +fdd_is_dd(int drive) +{ + return (drive_types[fdd[drive].type].flags & 0x70) == 0x10; +} + + +int +fdd_is_ed(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_HOLE2; +} + + +int +fdd_is_double_sided(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_DS; +} + + +void +fdd_set_head(int drive, int head) +{ + if (head && !fdd_is_double_sided(drive)) + fdd[drive].head = 0; + else + fdd[drive].head = head; +} + + +int +fdd_get_head(int drive) +{ + if (!fdd_is_double_sided(drive)) + return 0; + return fdd[drive].head; +} + + +void +fdd_set_turbo(int drive, int turbo) +{ + fdd[drive].turbo = turbo; +} + + +int +fdd_get_turbo(int drive) +{ + return fdd[drive].turbo; +} + + void fdd_set_check_bpb(int drive, int check_bpb) { - fdd[drive].check_bpb = check_bpb; + fdd[drive].check_bpb = check_bpb; } -int fdd_get_check_bpb(int drive) + +int +fdd_get_check_bpb(int drive) { - return fdd[drive].check_bpb; + return fdd[drive].check_bpb; } -int fdd_get_densel(int drive) + +int +fdd_get_densel(int drive) { - return fdd[drive].densel; + return fdd[drive].densel; } -void fdd_load(int drive, wchar_t *fn) + +void +fdd_load(int drive, wchar_t *fn) { - int c = 0, size; - wchar_t *p; - FILE *f; + int c = 0, size; + wchar_t *p; + FILE *f; - fdd_log("FDD: loading drive %d with '%ls'\n", drive, fn); + fdd_log("FDD: loading drive %d with '%ls'\n", drive, fn); - if (!fn) return; - p = plat_get_extension(fn); - if (!p) return; - f = plat_fopen(fn, L"rb"); - if (!f) return; - fseek(f, -1, SEEK_END); - size = ftell(f) + 1; - fclose(f); - while (loaders[c].ext) - { - if (!wcscasecmp(p, loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) - { - driveloaders[drive] = c; - memcpy(floppyfns[drive], fn, (wcslen(fn) << 1) + 2); - d86f_setup(drive); - loaders[c].load(drive, floppyfns[drive]); - drive_empty[drive] = 0; - fdd_forced_seek(drive, 0); - fdd_changed[drive] = 1; - return; - } - c++; - } - fdd_log("FDD: could not load '%ls' %s\n",fn,p); - drive_empty[drive] = 1; - fdd_set_head(drive, 0); - memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); - ui_sb_update_icon_state(drive, 1); -} - -void fdd_close(int drive) -{ - fdd_log("FDD: closing drive %d\n", drive); - - d86f_stop(drive); /* Call this first of all to make sure the 86F poll is back to idle state. */ - if (loaders[driveloaders[drive]].close) loaders[driveloaders[drive]].close(drive); - drive_empty[drive] = 1; - fdd_set_head(drive, 0); - floppyfns[drive][0] = 0; - drives[drive].hole = NULL; - drives[drive].poll = NULL; - drives[drive].seek = NULL; - drives[drive].readsector = NULL; - drives[drive].writesector = NULL; - drives[drive].comparesector = NULL; - drives[drive].readaddress = NULL; - drives[drive].format = NULL; - drives[drive].byteperiod = NULL; - drives[drive].stop = NULL; - d86f_destroy(drive); - ui_sb_update_icon_state(drive, 1); -} - -int fdd_notfound = 0; -static int fdd_period = 32; - -int fdd_hole(int drive) -{ - if (drives[drive].hole) - { - return drives[drive].hole(drive); + if (!fn) + return; + p = plat_get_extension(fn); + if (!p) + return; + f = plat_fopen(fn, L"rb"); + if (!f) + return; + fseek(f, -1, SEEK_END); + size = ftell(f) + 1; + fclose(f); + while (loaders[c].ext) { + if (!wcscasecmp(p, (wchar_t *) loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) { + driveloaders[drive] = c; + memcpy(floppyfns[drive], fn, (wcslen(fn) << 1) + 2); + d86f_setup(drive); + loaders[c].load(drive, floppyfns[drive]); + drive_empty[drive] = 0; + fdd_forced_seek(drive, 0); + fdd_changed[drive] = 1; + return; } - else - { - return 0; - } -} - -double fdd_byteperiod(int drive) -{ - if (drives[drive].byteperiod) - { - return drives[drive].byteperiod(drive); - } - else - { - return 32.0; - } -} - -double fdd_real_period(int drive) -{ - double ddbp; - double dusec; - - ddbp = fdd_byteperiod(drive); - - dusec = (double) TIMER_USEC; - - /* This is a giant hack but until the timings become even more correct, this is needed to make floppies work right on that BIOS. */ - if (fdd_get_turbo(drive)) - { - return (32.0 * dusec); - } - - return (ddbp * dusec); -} - -void fdd_poll(int drive) -{ - if (drive >= FDD_NUM) - { - fatal("Attempting to poll floppy drive %i that is not supposed to be there\n", drive); - } - - fdd_poll_time[drive] += (int64_t) fdd_real_period(drive); - - if (drives[drive].poll) - drives[drive].poll(drive); - - if (fdd_notfound) - { - fdd_notfound--; - if (!fdd_notfound) - fdc_noidam(fdd_fdc); - } -} - -void fdd_poll_0(void *priv) -{ - fdd_poll(0); -} - -void fdd_poll_1(void *priv) -{ - fdd_poll(1); -} - -void fdd_poll_2(void *priv) -{ - fdd_poll(2); -} - -void fdd_poll_3(void *priv) -{ - fdd_poll(3); -} - -int fdd_get_bitcell_period(int rate) -{ - int bit_rate = 250; - - switch (rate) - { - case 0: /*High density*/ - bit_rate = 500; - break; - case 1: /*Double density (360 rpm)*/ - bit_rate = 300; - break; - case 2: /*Double density*/ - bit_rate = 250; - break; - case 3: /*Extended density*/ - bit_rate = 1000; - break; - } - - return 1000000 / bit_rate*2; /*Bitcell period in ns*/ + c++; + } + fdd_log("FDD: could not load '%ls' %s\n",fn,p); + drive_empty[drive] = 1; + fdd_set_head(drive, 0); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + ui_sb_update_icon_state(drive, 1); } -void fdd_set_rate(int drive, int drvden, int rate) +void +fdd_close(int drive) { - switch (rate) - { - case 0: /*High density*/ - fdd_period = 16; - break; - case 1: - switch(drvden) - { - case 0: /*Double density (360 rpm)*/ - fdd_period = 26; - break; - case 1: /*High density (360 rpm)*/ - fdd_period = 16; - break; - case 2: - fdd_period = 4; - break; - } - case 2: /*Double density*/ - fdd_period = 32; - break; - case 3: /*Extended density*/ - fdd_period = 8; - break; - } + fdd_log("FDD: closing drive %d\n", drive); + + d86f_stop(drive); /* Call this first of all to make sure the 86F poll is back to idle state. */ + if (loaders[driveloaders[drive]].close) + loaders[driveloaders[drive]].close(drive); + drive_empty[drive] = 1; + fdd_set_head(drive, 0); + floppyfns[drive][0] = 0; + drives[drive].hole = NULL; + drives[drive].poll = NULL; + drives[drive].seek = NULL; + drives[drive].readsector = NULL; + drives[drive].writesector = NULL; + drives[drive].comparesector = NULL; + drives[drive].readaddress = NULL; + drives[drive].format = NULL; + drives[drive].byteperiod = NULL; + drives[drive].stop = NULL; + d86f_destroy(drive); + ui_sb_update_icon_state(drive, 1); } -void fdd_reset() + +int +fdd_hole(int drive) { - curdrive = 0; - fdd_period = 32; - timer_add(fdd_poll_0, &(fdd_poll_time[0]), &(motoron[0]), NULL); - timer_add(fdd_poll_1, &(fdd_poll_time[1]), &(motoron[1]), NULL); - timer_add(fdd_poll_2, &(fdd_poll_time[2]), &(motoron[2]), NULL); - timer_add(fdd_poll_3, &(fdd_poll_time[3]), &(motoron[3]), NULL); + if (drives[drive].hole) + return drives[drive].hole(drive); + else + return 0; } -int oldtrack[FDD_NUM] = {0, 0, 0, 0}; -void fdd_readsector(int drive, int sector, int track, int side, int density, int sector_size) +uint64_t +fdd_byteperiod(int drive) { - if (drives[drive].readsector) - drives[drive].readsector(drive, sector, track, side, density, sector_size); - else - fdd_notfound = 1000; + if (!fdd_get_turbo(drive) && drives[drive].byteperiod) + return drives[drive].byteperiod(drive); + else + return 32ULL * TIMER_USEC; } -void fdd_writesector(int drive, int sector, int track, int side, int density, int sector_size) + +void +fdd_set_motor_enable(int drive, int motor_enable) { - if (drives[drive].writesector) - drives[drive].writesector(drive, sector, track, side, density, sector_size); - else - fdd_notfound = 1000; + /* I think here is where spin-up and spin-down should be implemented. */ + if (motor_enable && !motoron[drive]) + timer_set_delay_u64(&fdd_poll_time[drive], fdd_byteperiod(drive)); + else if (!motor_enable) + timer_disable(&fdd_poll_time[drive]); + motoron[drive] = motor_enable; } -void fdd_comparesector(int drive, int sector, int track, int side, int density, int sector_size) + +static void +fdd_poll(void *priv) { - if (drives[drive].comparesector) - drives[drive].comparesector(drive, sector, track, side, density, sector_size); - else - fdd_notfound = 1000; + int drive; + DRIVE *drv = (DRIVE *) priv; + + drive = drv->id; + + if (drive >= FDD_NUM) + fatal("Attempting to poll floppy drive %i that is not supposed to be there\n", drive); + + timer_advance_u64(&fdd_poll_time[drive], fdd_byteperiod(drive)); + + if (drv->poll) + drv->poll(drive); + + if (fdd_notfound) { + fdd_notfound--; + if (!fdd_notfound) + fdc_noidam(fdd_fdc); + } } -void fdd_readaddress(int drive, int side, int density) + +int +fdd_get_bitcell_period(int rate) { - if (drives[drive].readaddress) - drives[drive].readaddress(drive, side, density); + int bit_rate = 250; + + switch (rate) { + case 0: /*High density*/ + bit_rate = 500; + break; + case 1: /*Double density (360 rpm)*/ + bit_rate = 300; + break; + case 2: /*Double density*/ + bit_rate = 250; + break; + case 3: /*Extended density*/ + bit_rate = 1000; + break; + } + + return 1000000 / bit_rate*2; /*Bitcell period in ns*/ } -void fdd_format(int drive, int side, int density, uint8_t fill) + +void +fdd_reset(void) { - if (drives[drive].format) - drives[drive].format(drive, side, density, fill); - else - fdd_notfound = 1000; + int i; + + for (i = 0; i < 4; i++) { + drives[i].id = i; + timer_add(&(fdd_poll_time[i]), fdd_poll, &drives[i], 0); + } } -void fdd_stop(int drive) + +void +fdd_readsector(int drive, int sector, int track, int side, int density, int sector_size) { - if (drives[drive].stop) - drives[drive].stop(drive); + if (drives[drive].readsector) + drives[drive].readsector(drive, sector, track, side, density, sector_size); + else + fdd_notfound = 1000; } -void fdd_set_fdc(void *fdc) + +void +fdd_writesector(int drive, int sector, int track, int side, int density, int sector_size) { - fdd_fdc = (fdc_t *) fdc; + if (drives[drive].writesector) + drives[drive].writesector(drive, sector, track, side, density, sector_size); + else + fdd_notfound = 1000; } -void fdd_init(void) + +void +fdd_comparesector(int drive, int sector, int track, int side, int density, int sector_size) { - drives[0].poll = drives[1].poll = drives[2].poll = drives[3].poll = 0; - drives[0].seek = drives[1].seek = drives[2].seek = drives[3].seek = 0; - drives[0].readsector = drives[1].readsector = drives[2].readsector = drives[3].readsector = 0; - fdd_reset(); + if (drives[drive].comparesector) + drives[drive].comparesector(drive, sector, track, side, density, sector_size); + else + fdd_notfound = 1000; +} + + +void +fdd_readaddress(int drive, int side, int density) +{ + if (drives[drive].readaddress) + drives[drive].readaddress(drive, side, density); +} + + +void +fdd_format(int drive, int side, int density, uint8_t fill) +{ + if (drives[drive].format) + drives[drive].format(drive, side, density, fill); + else + fdd_notfound = 1000; +} + + +void +fdd_stop(int drive) +{ + if (drives[drive].stop) + drives[drive].stop(drive); +} + + +void +fdd_set_fdc(void *fdc) +{ + fdd_fdc = (fdc_t *) fdc; +} + + +void +fdd_init(void) +{ + int i; + + for (i = 0; i < 4; i++) { + drives[i].poll = 0; + drives[i].seek = 0; + drives[i].readsector = 0; + } img_init(); d86f_init(); diff --git a/src/floppy/fdd.h b/src/floppy/fdd.h index 31a7786ef..722bb98f0 100644 --- a/src/floppy/fdd.h +++ b/src/floppy/fdd.h @@ -8,7 +8,7 @@ * * Definitions for the floppy drive emulation. * - * Version: @(#)fdd.h 1.0.5 2018/11/12 + * Version: @(#)fdd.h 1.0.6 2019/02/11 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -50,7 +50,7 @@ extern "C" { extern int fdd_swap; - +extern void fdd_set_motor_enable(int drive, int motor_enable); extern void fdd_do_seek(int drive, int track); extern void fdd_forced_seek(int drive, int track_diff); extern void fdd_seek(int drive, int track_diff); @@ -85,6 +85,8 @@ extern int fdd_current_track(int drive); typedef struct { + int id; + void (*seek)(int drive, int track); void (*readsector)(int drive, int sector, int track, int side, int density, int sector_size); @@ -95,17 +97,16 @@ typedef struct { void (*readaddress)(int drive, int side, int density); void (*format)(int drive, int side, int density, uint8_t fill); int (*hole)(int drive); - double (*byteperiod)(int drive); + uint64_t (*byteperiod)(int drive); void (*stop)(int drive); void (*poll)(int drive); } DRIVE; -extern DRIVE drives[FDD_NUM]; -extern wchar_t floppyfns[FDD_NUM][512]; -extern int driveempty[FDD_NUM]; -extern int64_t fdd_poll_time[FDD_NUM]; -extern int ui_writeprot[FDD_NUM]; +extern DRIVE drives[FDD_NUM]; +extern wchar_t floppyfns[FDD_NUM][512]; +extern pc_timer_t fdd_poll_time[FDD_NUM]; +extern int ui_writeprot[FDD_NUM]; extern int curdrive; @@ -118,11 +119,6 @@ extern void fdd_new(int drive, char *fn); extern void fdd_close(int drive); extern void fdd_init(void); extern void fdd_reset(void); -extern void fdd_poll(int drive); -extern void fdd_poll_0(void* priv); -extern void fdd_poll_1(void* priv); -extern void fdd_poll_2(void* priv); -extern void fdd_poll_3(void* priv); extern void fdd_seek(int drive, int track); extern void fdd_readsector(int drive, int sector, int track, int side, int density, int sector_size); @@ -133,12 +129,10 @@ extern void fdd_comparesector(int drive, int sector, int track, extern void fdd_readaddress(int drive, int side, int density); extern void fdd_format(int drive, int side, int density, uint8_t fill); extern int fdd_hole(int drive); -extern double fdd_byteperiod(int drive); extern void fdd_stop(int drive); -extern void fdd_set_rate(int drive, int drvden, int rate); extern int motorspin; -extern int64_t motoron[FDD_NUM]; +extern uint64_t motoron[FDD_NUM]; extern int swwp; extern int disable_write; @@ -146,10 +140,8 @@ extern int disable_write; extern int defaultwriteprot; extern int writeprot[FDD_NUM], fwriteprot[FDD_NUM]; -extern int fdd_cur_track[FDD_NUM]; extern int fdd_changed[FDD_NUM]; extern int drive_empty[FDD_NUM]; -extern int drive_type[FDD_NUM]; /*Used in the Read A Track command. Only valid for fdd_readsector(). */ #define SECTOR_FIRST -2 diff --git a/src/floppy/fdd_86f - Cópia.c b/src/floppy/fdd_86f - Cópia.c new file mode 100644 index 000000000..560a6090b --- /dev/null +++ b/src/floppy/fdd_86f - Cópia.c @@ -0,0 +1,3924 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the 86F floppy image format (stores the + * data in the form of FM/MFM-encoded transitions) which also + * forms the core of the emulator's floppy disk emulation. + * + * Version: @(#)fdd_86f.c 1.0.17 2018/11/12 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../timer.h" +#include "../dma.h" +#include "../nvr.h" +#include "../random.h" +#include "../plat.h" +#include "../ui.h" +#include "fdd.h" +#include "fdc.h" +#include "fdd_86f.h" +#ifdef D86F_COMPRESS +#include "lzf/lzf.h" +#endif + + +/* + * Let's give this some more logic: + * + * Bits 4,3 = Read/write (0 = read, 1 = write, 2 = scan, 3 = verify) + * Bits 6,5 = Sector/track (0 = ID, 1 = sector, 2 = deleted sector, 3 = track) + * Bit 7 = State type (0 = idle states, 1 = active states) + */ +enum { + /* 0 ?? ?? ??? */ + STATE_IDLE = 0x00, + STATE_SECTOR_NOT_FOUND, + + /* 1 00 00 ??? */ + STATE_0A_FIND_ID = 0x80, /* READ SECTOR ID */ + STATE_0A_READ_ID, + + /* 1 01 00 ??? */ + STATE_06_FIND_ID = 0xA0, /* READ DATA */ + STATE_06_READ_ID, + STATE_06_FIND_DATA, + STATE_06_READ_DATA, + + /* 1 01 01 ??? */ + STATE_05_FIND_ID = 0xA8, /* WRITE DATA */ + STATE_05_READ_ID, + STATE_05_FIND_DATA, + STATE_05_WRITE_DATA, + + /* 1 01 10 ??? */ + STATE_11_FIND_ID = 0xB0, /* SCAN EQUAL,SCAN LOW/EQUAL,SCAN HIGH/EQUAL */ + STATE_11_READ_ID, + STATE_11_FIND_DATA, + STATE_11_SCAN_DATA, + + /* 1 01 11 ??? */ + STATE_16_FIND_ID = 0xB8, /* VERIFY */ + STATE_16_READ_ID, + STATE_16_FIND_DATA, + STATE_16_VERIFY_DATA, + + /* 1 10 00 ??? */ + STATE_0C_FIND_ID = 0xC0, /* READ DELETED DATA */ + STATE_0C_READ_ID, + STATE_0C_FIND_DATA, + STATE_0C_READ_DATA, + + /* 1 10 01 ??? */ + STATE_09_FIND_ID = 0xC8, /* WRITE DELETED DATA */ + STATE_09_READ_ID, + STATE_09_FIND_DATA, + STATE_09_WRITE_DATA, + + /* 1 11 00 ??? */ + STATE_02_SPIN_TO_INDEX = 0xE0, /* READ TRACK */ + STATE_02_FIND_ID, + STATE_02_READ_ID, + STATE_02_FIND_DATA, + STATE_02_READ_DATA, + + /* 1 11 01 ??? */ + STATE_0D_SPIN_TO_INDEX = 0xE8, /* FORMAT TRACK */ + STATE_0D_FORMAT_TRACK, + + /* 1 11 11 ??? */ + STATE_0D_NOP_SPIN_TO_INDEX = 0xF8, /* FORMAT TRACK */ + STATE_0D_NOP_FORMAT_TRACK +}; + +enum { + FMT_PRETRK_GAP0, + FMT_PRETRK_SYNC, + FMT_PRETRK_IAM, + FMT_PRETRK_GAP1, + + FMT_SECTOR_ID_SYNC, + FMT_SECTOR_IDAM, + FMT_SECTOR_ID, + FMT_SECTOR_ID_CRC, + FMT_SECTOR_GAP2, + FMT_SECTOR_DATA_SYNC, + FMT_SECTOR_DATAAM, + FMT_SECTOR_DATA, + FMT_SECTOR_DATA_CRC, + FMT_SECTOR_GAP3, + + FMT_POSTTRK_CHECK, + FMT_POSTTRK_GAP4 +}; + + +typedef struct { + uint8_t buffer[10]; + uint32_t pos; + uint32_t len; +} sliding_buffer_t; + +typedef struct { + uint32_t sync_marks; + uint32_t bits_obtained; + uint32_t bytes_obtained; + uint32_t sync_pos; +} find_t; + +typedef struct { + unsigned nibble0 :4; + unsigned nibble1 :4; +} split_byte_t; + +typedef union { + uint8_t byte; + split_byte_t nibbles; +} decoded_t; + +typedef struct { + uint8_t c, h, r, n; + void *prev; +} sector_t; + +/* Disk flags: + * Bit 0 Has surface data (1 = yes, 0 = no) + * Bits 2, 1 Hole (3 = ED + 2000 kbps, 2 = ED, 1 = HD, 0 = DD) + * Bit 3 Sides (1 = 2 sides, 0 = 1 side) + * Bit 4 Write protect (1 = yes, 0 = no) + * Bits 6, 5 RPM slowdown (3 = 2%, 2 = 1.5%, 1 = 1%, 0 = 0%) + * Bit 7 Bitcell mode (1 = Extra bitcells count specified after + * disk flags, 0 = No extra bitcells) + * The maximum number of extra bitcells is 1024 (which + * after decoding translates to 64 bytes) + * Bit 8 Disk type (1 = Zoned, 0 = Fixed RPM) + * Bits 10, 9 Zone type (3 = Commodore 64 zoned, 2 = Apple zoned, + * 1 = Pre-Apple zoned #2, 0 = Pre-Apple zoned #1) + * Bit 11 Data and surface bits are stored in reverse byte endianness + * Bit 12 If bits 6, 5 are not 0, they specify % of speedup instead + * of slowdown; + * If bits 6, 5 are 0, and bit 7 is 1, the extra bitcell count + * specifies the entire bitcell count + */ +typedef struct { + FILE *f; + uint16_t version; + uint16_t disk_flags; + int32_t extra_bit_cells[2]; + uint16_t track_encoded_data[2][53048]; + uint16_t *track_surface_data[2]; + uint16_t thin_track_encoded_data[2][2][53048]; + uint16_t *thin_track_surface_data[2][2]; + uint16_t side_flags[2]; + uint32_t index_hole_pos[2]; + uint32_t track_offset[512]; + uint32_t file_size; + sector_id_t format_sector_id; + sector_id_t last_sector; + sector_id_t req_sector; + uint32_t index_count; + uint8_t state; + uint8_t fill; + uint32_t track_pos; + uint32_t datac; + uint32_t id_pos; + uint16_t last_word[2]; + find_t id_find; + find_t data_find; + crc_t calc_crc; + crc_t track_crc; + uint8_t sector_count; + uint8_t format_state; + uint16_t satisfying_bytes; + uint16_t preceding_bit[2]; + uint16_t current_byte[2]; + uint16_t current_bit[2]; + int cur_track; + uint32_t error_condition; +#ifdef D86F_COMPRESS + int is_compressed; +#endif + int id_found; + wchar_t original_file_name[2048]; + uint8_t *filebuf; + uint8_t *outbuf; + uint32_t dma_over; + int turbo_pos; + sector_t *last_side_sector[2]; +} d86f_t; + + +static const uint8_t encoded_fm[64] = { + 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, + 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff, + 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, + 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff, + 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, + 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff, + 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, + 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff +}; +static const uint8_t encoded_mfm[64] = { + 0xaa, 0xa9, 0xa4, 0xa5, 0x92, 0x91, 0x94, 0x95, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55, + 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55, + 0xaa, 0xa9, 0xa4, 0xa5, 0x92, 0x91, 0x94, 0x95, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55, + 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55 +}; + +static d86f_t *d86f[FDD_NUM]; +static uint16_t CRCTable[256]; +static fdc_t *d86f_fdc; +uint64_t poly = 0x42F0E1EBA9EA3693ll; /* ECMA normal */ +uint64_t table[256]; + + +uint16_t d86f_side_flags(int drive); +int d86f_is_mfm(int drive); +void d86f_writeback(int drive); +uint8_t d86f_poll_read_data(int drive, int side, uint16_t pos); +void d86f_poll_write_data(int drive, int side, uint16_t pos, uint8_t data); +int d86f_format_conditions(int drive); + + +#ifdef ENABLE_D86F_LOG +int d86f_do_log = ENABLE_D86F_LOG; + + +static void +d86f_log(const char *fmt, ...) +{ + va_list ap; + + if (d86f_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define d86f_log(fmt, ...) +#endif + + +static void +setup_crc(uint16_t poly) +{ + int c = 256, bc; + uint16_t temp; + + while(c--) { + temp = c << 8; + bc = 8; + + while (bc--) { + if (temp & 0x8000) + temp = (temp << 1) ^ poly; + else + temp <<= 1; + + CRCTable[c] = temp; + } + } +} + + +void +d86f_destroy_linked_lists(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + sector_t *s, *t; + + if (dev == NULL) return; + + if (dev->last_side_sector[side]) { + s = dev->last_side_sector[side]; + while (s) { + t = s->prev; + free(s); + s = NULL; + if (! t) + break; + s = t; + } + dev->last_side_sector[side] = NULL; + } +} + + +static int +d86f_has_surface_desc(int drive) +{ + return (d86f_handler[drive].disk_flags(drive) & 1); +} + + +int +d86f_get_sides(int drive) +{ + return ((d86f_handler[drive].disk_flags(drive) >> 3) & 1) + 1; +} + + +int +d86f_get_rpm_mode(int drive) +{ + return (d86f_handler[drive].disk_flags(drive) & 0x60) >> 5; +} + + +int +d86f_get_speed_shift_dir(int drive) +{ + return (d86f_handler[drive].disk_flags(drive) & 0x1000) >> 12; +} + + +int +d86f_reverse_bytes(int drive) +{ + return (d86f_handler[drive].disk_flags(drive) & 0x800) >> 11; +} + + +uint16_t +d86f_disk_flags(int drive) +{ + d86f_t *dev = d86f[drive]; + + return dev->disk_flags; +} + + +uint32_t +d86f_index_hole_pos(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + return dev->index_hole_pos[side]; +} + + +uint32_t +null_index_hole_pos(int drive, int side) +{ + return 0; +} + + +uint16_t +null_disk_flags(int drive) +{ + return 0x09; +} + + +uint16_t +null_side_flags(int drive) +{ + return 0x0A; +} + + +void +null_writeback(int drive) +{ + return; +} + + +void +null_set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + return; +} + + +void +null_write_data(int drive, int side, uint16_t pos, uint8_t data) +{ + return; +} + + +int +null_format_conditions(int drive) +{ + return 0; +} + + +int32_t +d86f_extra_bit_cells(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + return dev->extra_bit_cells[side]; +} + + +int32_t +null_extra_bit_cells(int drive, int side) +{ + return 0; +} + + +uint16_t* +common_encoded_data(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + return dev->track_encoded_data[side]; +} + + +void +common_read_revolution(int drive) +{ + return; +} + + +uint16_t +d86f_side_flags(int drive) +{ + d86f_t *dev = d86f[drive]; + int side; + + side = fdd_get_head(drive); + + return dev->side_flags[side]; +} + + +uint16_t +d86f_track_flags(int drive) +{ + uint16_t dr, rr, tf; + + tf = d86f_handler[drive].side_flags(drive); + rr = tf & 0x67; + dr = fdd_get_flags(drive) & 7; + tf &= ~0x67; + + switch (rr) { + case 0x02: + case 0x21: + /* 1 MB unformatted medium, treat these two as equivalent. */ + switch (dr) { + case 0x06: + /* 5.25" Single-RPM HD drive, treat as 300 kbps, 360 rpm. */ + tf |= 0x21; + break; + + default: + /* Any other drive, treat as 250 kbps, 300 rpm. */ + tf |= 0x02; + break; + } + break; + + default: + tf |= rr; + break; + } + + return tf; +} + + +uint32_t +common_get_raw_size(int drive, int side) +{ + double rate = 0.0; + double rpm, rpm_diff; + double size = 100000.0; + int mfm; + int rm, ssd; + uint32_t extra_bc = 0; + + mfm = d86f_is_mfm(drive); + rpm = ((d86f_track_flags(drive) & 0xE0) == 0x20) ? 360.0 : 300.0; + rpm_diff = 1.0; + rm = d86f_get_rpm_mode(drive); + ssd = d86f_get_speed_shift_dir(drive); + + /* 0% speed shift and shift direction 1: special case where extra bit cells are the entire track size. */ + if (!rm && ssd) + extra_bc = d86f_handler[drive].extra_bit_cells(drive, side); + + if (extra_bc) + return extra_bc; + + switch (rm) { + case 1: + rpm_diff = 1.01; + break; + + case 2: + rpm_diff = 1.015; + break; + + case 3: + rpm_diff = 1.02; + break; + + default: + rpm_diff = 1.0; + break; + } + + if (ssd) + rpm_diff = 1.0 / rpm_diff; + + switch (d86f_track_flags(drive) & 7) { + case 0: + rate = 500.0; + break; + + case 1: + rate = 300.0; + break; + + case 2: + rate = 250.0; + break; + + case 3: + rate = 1000.0; + break; + + case 5: + rate = 2000.0; + break; + + default: + rate = 250.0; + break; + } + + if (! mfm) rate /= 2.0; + + size = (size / 250.0) * rate; + size = (size * 300.0) / rpm; + size *= rpm_diff; + + /* + * Round down to a multiple of 16 and add the extra bit cells, + * then return. + */ + return ((((uint32_t) size) >> 4) << 4) + d86f_handler[drive].extra_bit_cells(drive, side); +} + + +void +d86f_set_version(int drive, uint16_t version) +{ + d86f_t *dev = d86f[drive]; + + dev->version = version; +} + + +void +d86f_unregister(int drive) +{ + d86f_t *dev = d86f[drive]; + + if (dev == NULL) return; + + d86f_handler[drive].disk_flags = null_disk_flags; + d86f_handler[drive].side_flags = null_side_flags; + d86f_handler[drive].writeback = null_writeback; + d86f_handler[drive].set_sector = null_set_sector; + d86f_handler[drive].write_data = null_write_data; + d86f_handler[drive].format_conditions = null_format_conditions; + d86f_handler[drive].extra_bit_cells = null_extra_bit_cells; + d86f_handler[drive].encoded_data = common_encoded_data; + d86f_handler[drive].read_revolution = common_read_revolution; + d86f_handler[drive].index_hole_pos = null_index_hole_pos; + d86f_handler[drive].get_raw_size = common_get_raw_size; + d86f_handler[drive].check_crc = 0; + + dev->version = 0x0063; /* Proxied formats report as version 0.99. */ +} + + +void +d86f_register_86f(int drive) +{ + d86f_handler[drive].disk_flags = d86f_disk_flags; + d86f_handler[drive].side_flags = d86f_side_flags; + d86f_handler[drive].writeback = d86f_writeback; + d86f_handler[drive].set_sector = null_set_sector; + d86f_handler[drive].write_data = null_write_data; + d86f_handler[drive].format_conditions = d86f_format_conditions; + d86f_handler[drive].extra_bit_cells = d86f_extra_bit_cells; + d86f_handler[drive].encoded_data = common_encoded_data; + d86f_handler[drive].read_revolution = common_read_revolution; + d86f_handler[drive].index_hole_pos = d86f_index_hole_pos; + d86f_handler[drive].get_raw_size = common_get_raw_size; + d86f_handler[drive].check_crc = 1; +} + + +int +d86f_get_array_size(int drive, int side, int words) +{ + int array_size; + int hole, rm; + int ssd; + + rm = d86f_get_rpm_mode(drive); + ssd = d86f_get_speed_shift_dir(drive); + hole = (d86f_handler[drive].disk_flags(drive) & 6) >> 1; + + if (!rm && ssd) /* Special case - extra bit cells size specifies entire array size. */ + array_size = 0; + else switch (hole) { + case 0: + case 1: + default: + array_size = 12500; + switch (rm) { + case 1: + array_size = ssd ? 12376 : 12625; + break; + + case 2: + array_size = ssd ? 12315 : 12687; + break; + + case 3: + array_size = ssd ? 12254 : 12750; + break; + + default: + break; + } + break; + + case 2: + array_size = 25000; + switch (rm) { + case 1: + array_size = ssd ? 24752 : 25250; + break; + + case 2: + array_size = ssd ? 24630 : 25375; + break; + + case 3: + array_size = ssd ? 24509 : 25500; + break; + + default: + break; + } + break; + + case 3: + array_size = 50000; + switch (rm) { + case 1: + array_size = ssd ? 49504 : 50500; + break; + + case 2: + array_size = ssd ? 49261 : 50750; + break; + + case 3: + array_size = ssd ? 49019 : 51000; + break; + + default: + break; + } + break; + } + + array_size <<= 4; + array_size += d86f_handler[drive].extra_bit_cells(drive, side); + + if (array_size & 15) + array_size = (array_size >> 4) + 1; + else + array_size = (array_size >> 4); + + if (!words) + array_size <<= 1; + + return array_size; +} + + +int +d86f_valid_bit_rate(int drive) +{ + int hole, rate; + + rate = fdc_get_bit_rate(d86f_fdc); + hole = (d86f_handler[drive].disk_flags(drive) & 6) >> 1; + switch (hole) { + case 0: /* DD */ + if (!rate && (fdd_get_flags(drive) & 0x10)) return 1; + if ((rate < 1) || (rate > 2)) return 0; + return 1; + + case 1: /* HD */ + if (rate != 0) return 0; + return 1; + + case 2: /* ED */ + if (rate != 3) return 0; + return 1; + + case 3: /* ED with 2000 kbps support */ + if (rate < 3) return 0; + return 1; + + default: + break; + } + + return 0; +} + + +int +d86f_hole(int drive) +{ + if (((d86f_handler[drive].disk_flags(drive) >> 1) & 3) == 3) + return 2; + + return (d86f_handler[drive].disk_flags(drive) >> 1) & 3; +} + + +uint8_t +d86f_get_encoding(int drive) +{ + return (d86f_track_flags(drive) & 0x18) >> 3; +} + + +uint64_t +d86f_byteperiod(int drive) +{ + double dusec = (double) TIMER_USEC; + double p = 2.0; + + switch (d86f_track_flags(drive) & 0x0f) { + case 0x02: /* 125 kbps, FM */ + p = 4.0; + break; + case 0x01: /* 150 kbps, FM */ + p = 20.0 / 6.0; + break; + case 0x0a: /* 250 kbps, MFM */ + case 0x00: /* 250 kbps, FM */ + default: + p = 2.0; + break; + case 0x09: /* 300 kbps, MFM */ + p = 10.0 / 6.0; + break; + case 0x08: /* 500 kbps, MFM */ + p = 1.0; + break; + case 0x0b: /* 1000 kbps, MFM */ + p = 0.5; + break; + case 0x0d: /* 2000 kbps, MFM */ + p = 0.25; + break; + } + + return (uint64_t) (p * dusec); +} + + +int +d86f_is_mfm(int drive) +{ + return (d86f_track_flags(drive) & 8) ? 1 : 0; +} + + +uint32_t +d86f_get_data_len(int drive) +{ + d86f_t *dev = d86f[drive]; + + if (dev->req_sector.id.n) { + if (dev->req_sector.id.n == 8) return 32768; + return (128 << ((uint32_t) dev->req_sector.id.n)); + } else { + if (fdc_get_dtl(d86f_fdc) < 128) + return fdc_get_dtl(d86f_fdc); + else + return (128 << ((uint32_t) dev->req_sector.id.n)); + } +} + + +uint32_t +d86f_has_extra_bit_cells(int drive) +{ + return (d86f_handler[drive].disk_flags(drive) >> 7) & 1; +} + + +uint32_t +d86f_header_size(int drive) +{ + return 8; +} + + +static uint16_t +d86f_encode_get_data(uint8_t dat) +{ + uint16_t temp; + temp = 0; + + if (dat & 0x01) temp |= 1; + if (dat & 0x02) temp |= 4; + if (dat & 0x04) temp |= 16; + if (dat & 0x08) temp |= 64; + if (dat & 0x10) temp |= 256; + if (dat & 0x20) temp |= 1024; + if (dat & 0x40) temp |= 4096; + if (dat & 0x80) temp |= 16384; + + return temp; +} + + +static uint16_t +d86f_encode_get_clock(uint8_t dat) +{ + uint16_t temp; + temp = 0; + + if (dat & 0x01) temp |= 2; + if (dat & 0x02) temp |= 8; + if (dat & 0x40) temp |= 32; + if (dat & 0x08) temp |= 128; + if (dat & 0x10) temp |= 512; + if (dat & 0x20) temp |= 2048; + if (dat & 0x40) temp |= 8192; + if (dat & 0x80) temp |= 32768; + + return temp; +} + + +int +d86f_format_conditions(int drive) +{ + return d86f_valid_bit_rate(drive); +} + + +int +d86f_wrong_densel(int drive) +{ + int is_3mode = 0; + + if ((fdd_get_flags(drive) & 7) == 3) + is_3mode = 1; + + switch (d86f_hole(drive)) { + case 0: + default: + if (fdd_is_dd(drive)) + return 0; + if (fdd_get_densel(drive)) + return 1; + else + return 0; + break; + + case 1: + if (fdd_is_dd(drive)) + return 1; + if (fdd_get_densel(drive)) + return 0; + else { + if (is_3mode) + return 0; + else + return 1; + } + break; + + case 2: + if (fdd_is_dd(drive) || !fdd_is_ed(drive)) + return 1; + if (fdd_get_densel(drive)) + return 0; + else + return 1; + break; + } +} + + +int +d86f_can_format(int drive) +{ + int temp; + + temp = !writeprot[drive]; + temp = temp && !fdc_get_swwp(d86f_fdc); + temp = temp && fdd_can_read_medium(real_drive(d86f_fdc, drive)); + temp = temp && d86f_handler[drive].format_conditions(drive); /* Allows proxied formats to add their own extra conditions to formatting. */ + temp = temp && !d86f_wrong_densel(drive); + + return temp; +} + + +uint16_t +d86f_encode_byte(int drive, int sync, decoded_t b, decoded_t prev_b) +{ + uint8_t encoding = d86f_get_encoding(drive); + uint8_t bits89AB = prev_b.nibbles.nibble0; + uint8_t bits7654 = b.nibbles.nibble1; + uint8_t bits3210 = b.nibbles.nibble0; + uint16_t encoded_7654, encoded_3210, result; + + if (encoding > 1) return 0xff; + + if (sync) { + result = d86f_encode_get_data(b.byte); + if (encoding) { + switch(b.byte) { + case 0xa1: + return result | d86f_encode_get_clock(0x0a); + + case 0xc2: + return result | d86f_encode_get_clock(0x14); + + case 0xf8: + return result | d86f_encode_get_clock(0x03); + + case 0xfb: + case 0xfe: + return result | d86f_encode_get_clock(0x00); + + case 0xfc: + return result | d86f_encode_get_clock(0x01); + } + } else { + switch(b.byte) { + case 0xf8: + case 0xfb: + case 0xfe: + return result | d86f_encode_get_clock(0xc7); + + case 0xfc: + return result | d86f_encode_get_clock(0xd7); + } + } + } + + bits3210 += ((bits7654 & 3) << 4); + bits7654 += ((bits89AB & 3) << 4); + encoded_3210 = (encoding == 1) ? encoded_mfm[bits3210] : encoded_fm[bits3210]; + encoded_7654 = (encoding == 1) ? encoded_mfm[bits7654] : encoded_fm[bits7654]; + result = (encoded_7654 << 8) | encoded_3210; + + return result; +} + + +static int +d86f_get_bitcell_period(int drive) +{ + double rate = 0.0; + int mfm = 0; + int tflags = 0; + double rpm = 0; + double size = 8000.0; + + tflags = d86f_track_flags(drive); + + mfm = (tflags & 8) ? 1 : 0; + rpm = ((tflags & 0xE0) == 0x20) ? 360.0 : 300.0; + + switch (tflags & 7) { + case 0: + rate = 500.0; + break; + + case 1: + rate = 300.0; + break; + + case 2: + rate = 250.0; + break; + + case 3: + rate = 1000.0; + break; + + case 5: + rate = 2000.0; + break; + } + + if (! mfm) + rate /= 2.0; + size = (size * 250.0) / rate; + size = (size * 300.0) / rpm; + size = (size * fdd_getrpm(real_drive(d86f_fdc, drive))) / 300.0; + + return (int)size; +} + + +int +d86f_can_read_address(int drive) +{ + int temp; + + temp = (fdc_get_bitcell_period(d86f_fdc) == d86f_get_bitcell_period(drive)); + temp = temp && fdd_can_read_medium(real_drive(d86f_fdc, drive)); + temp = temp && (fdc_is_mfm(d86f_fdc) == d86f_is_mfm(drive)); + temp = temp && (d86f_get_encoding(drive) <= 1); + + return temp; +} + + +void +d86f_get_bit(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + uint32_t track_word; + uint32_t track_bit; + uint16_t encoded_data; + uint16_t surface_data = 0; + uint16_t current_bit; + uint16_t surface_bit; + + track_word = dev->track_pos >> 4; + + /* We need to make sure we read the bits from MSB to LSB. */ + track_bit = 15 - (dev->track_pos & 15); + + if (d86f_reverse_bytes(drive)) { + /* Image is in reverse endianness, read the data as is. */ + encoded_data = d86f_handler[drive].encoded_data(drive, side)[track_word]; + } else { + /* We store the words as big endian, so we need to convert them to little endian when reading. */ + encoded_data = (d86f_handler[drive].encoded_data(drive, side)[track_word] & 0xFF) << 8; + encoded_data |= (d86f_handler[drive].encoded_data(drive, side)[track_word] >> 8); + } + + /* In some cases, misindentification occurs so we need to make sure the surface data array is not + not NULL. */ + if (d86f_has_surface_desc(drive) && dev->track_surface_data[side]) { + if (d86f_reverse_bytes(drive)) { + surface_data = dev->track_surface_data[side][track_word] & 0xFF; + } else { + surface_data = (dev->track_surface_data[side][track_word] & 0xFF) << 8; + surface_data |= (dev->track_surface_data[side][track_word] >> 8); + } + } + + current_bit = (encoded_data >> track_bit) & 1; + dev->last_word[side] <<= 1; + + if (d86f_has_surface_desc(drive) && dev->track_surface_data[side]) { + surface_bit = (surface_data >> track_bit) & 1; + if (! surface_bit) + dev->last_word[side] |= current_bit; + else { + if (current_bit) { + /* Bit is 1 and is set to fuzzy, we randomly generate it. */ + dev->last_word[side] |= (random_generate() & 1); + } + } + } else + dev->last_word[side] |= current_bit; +} + + +void +d86f_put_bit(int drive, int side, int bit) +{ + d86f_t *dev = d86f[drive]; + uint32_t track_word; + uint32_t track_bit; + uint16_t encoded_data; + uint16_t surface_data = 0; + uint16_t current_bit; + uint16_t surface_bit; + + if (fdc_get_diswr(d86f_fdc)) + return; + + track_word = dev->track_pos >> 4; + + /* We need to make sure we read the bits from MSB to LSB. */ + track_bit = 15 - (dev->track_pos & 15); + + if (d86f_reverse_bytes(drive)) { + /* Image is in reverse endianness, read the data as is. */ + encoded_data = d86f_handler[drive].encoded_data(drive, side)[track_word]; + } else { + /* We store the words as big endian, so we need to convert them to little endian when reading. */ + encoded_data = (d86f_handler[drive].encoded_data(drive, side)[track_word] & 0xFF) << 8; + encoded_data |= (d86f_handler[drive].encoded_data(drive, side)[track_word] >> 8); + } + + if (d86f_has_surface_desc(drive)) { + if (d86f_reverse_bytes(drive)) { + surface_data = dev->track_surface_data[side][track_word] & 0xFF; + } else { + surface_data = (dev->track_surface_data[side][track_word] & 0xFF) << 8; + surface_data |= (dev->track_surface_data[side][track_word] >> 8); + } + } + + current_bit = (encoded_data >> track_bit) & 1; + dev->last_word[side] <<= 1; + + 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; + } + } else { + if (current_bit) { + /* Bit is 1 and is set to fuzzy, we overwrite it with a non-fuzzy bit. */ + dev->last_word[side] |= bit; + current_bit = bit; + surface_bit = 0; + } + } + + surface_data &= ~(1 << track_bit); + surface_data |= (surface_bit << track_bit); + if (d86f_reverse_bytes(drive)) { + dev->track_surface_data[side][track_word] = surface_data; + } else { + dev->track_surface_data[side][track_word] = (surface_data & 0xFF) << 8; + dev->track_surface_data[side][track_word] |= (surface_data >> 8); + } + } else { + dev->last_word[side] |= bit; + current_bit = bit; + } + + encoded_data &= ~(1 << track_bit); + encoded_data |= (current_bit << track_bit); + + if (d86f_reverse_bytes(drive)) { + d86f_handler[drive].encoded_data(drive, side)[track_word] = encoded_data; + } else { + d86f_handler[drive].encoded_data(drive, side)[track_word] = (encoded_data & 0xFF) << 8; + d86f_handler[drive].encoded_data(drive, side)[track_word] |= (encoded_data >> 8); + } +} + + +static uint8_t +decodefm(int drive, uint16_t dat) +{ + uint8_t temp = 0; + + /* + * We write the encoded bytes in big endian, so we + * process the two 8-bit halves swapped here. + */ + if (dat & 0x0001) temp |= 1; + if (dat & 0x0004) temp |= 2; + if (dat & 0x0010) temp |= 4; + if (dat & 0x0040) temp |= 8; + if (dat & 0x0100) temp |= 16; + if (dat & 0x0400) temp |= 32; + if (dat & 0x1000) temp |= 64; + if (dat & 0x4000) temp |= 128; + + return temp; +} + + +void +fdd_calccrc(uint8_t byte, crc_t *crc_var) +{ + crc_var->word = (crc_var->word << 8) ^ + CRCTable[(crc_var->word >> 8)^byte]; +} + + +static void +d86f_calccrc(d86f_t *dev, uint8_t byte) +{ + fdd_calccrc(byte, &(dev->calc_crc)); +} + + +int +d86f_word_is_aligned(int drive, int side, uint32_t base_pos) +{ + d86f_t *dev = d86f[drive]; + uint32_t adjusted_track_pos = dev->track_pos; + + if (base_pos == 0xFFFFFFFF) return 0; + + /* + * This is very important, it makes sure alignment is detected + * correctly even across the index hole of a track whose length + * is not divisible by 16. + */ + if (adjusted_track_pos < base_pos) { + adjusted_track_pos += d86f_handler[drive].get_raw_size(drive, side); + } + + if ((adjusted_track_pos & 15) == (base_pos & 15)) return 1; + + return 0; +} + + +/* State 1: Find sector ID */ +void +d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t wrong_am, uint16_t ignore_other_am) +{ + d86f_t *dev = d86f[drive]; + + d86f_get_bit(drive, side); + + if (dev->last_word[side] == req_am) { + dev->calc_crc.word = 0xFFFF; + fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + dev->preceding_bit[side] = dev->last_word[side] & 1; + dev->state++; + return; + } + + if ((wrong_am) && (dev->last_word[side] == wrong_am)) { + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_nodataam(d86f_fdc); + return; + } + + if ((ignore_other_am & 2) && (dev->last_word[side] == other_am)) { + dev->calc_crc.word = 0xFFFF; + fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + if (ignore_other_am & 1) { + /* Skip mode, let's go back to finding ID. */ + dev->state -= 2; + } else { + /* Not skip mode, process the sector anyway. */ + fdc_set_wrong_am(d86f_fdc); + dev->preceding_bit[side] = dev->last_word[side] & 1; + dev->state++; + } + } +} + + +/* When writing in FM mode, we find the beginning of the address mark by looking for 352 (22 * 16) set bits (gap fill = 0xFF, 0xFFFF FM-encoded). */ +void +d86f_write_find_address_mark_fm(int drive, int side, find_t *find) +{ + d86f_t *dev = d86f[drive]; + + d86f_get_bit(drive, side); + + if (dev->last_word[side] & 1) { + find->sync_marks++; + if (find->sync_marks == 352) { + dev->calc_crc.word = 0xFFFF; + dev->preceding_bit[side] = 1; + find->sync_marks = 0; + dev->state++; + return; + } + } + + /* If we hadn't found enough set bits but have found a clear bit, null the counter of set bits. */ + if (!(dev->last_word[side] & 1)) { + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + } +} + + +void +d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t wrong_am, uint16_t ignore_other_am) +{ + d86f_t *dev = d86f[drive]; + + d86f_get_bit(drive, side); + + if (dev->last_word[side] == 0x4489) { + find->sync_marks++; + find->sync_pos = dev->track_pos; + return; + } + + if ((wrong_am) && (dev->last_word[side] == wrong_am) && (find->sync_marks >= 3)) { + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_nodataam(d86f_fdc); + return; + } + + if ((dev->last_word[side] == req_am) && (find->sync_marks >= 3)) { + if (d86f_word_is_aligned(drive, side, find->sync_pos)) { + dev->calc_crc.word = 0xCDB4; + fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + dev->preceding_bit[side] = dev->last_word[side] & 1; + dev->state++; + return; + } + } + + if ((ignore_other_am & 2) && (dev->last_word[side] == other_am) && (find->sync_marks >= 3)) { + if (d86f_word_is_aligned(drive, side, find->sync_pos)) { + dev->calc_crc.word = 0xCDB4; + fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + if (ignore_other_am & 1) { + /* Skip mode, let's go back to finding ID. */ + dev->state -= 2; + } else { + /* Not skip mode, process the sector anyway. */ + fdc_set_wrong_am(d86f_fdc); + dev->preceding_bit[side] = dev->last_word[side] & 1; + dev->state++; + } + return; + } + } + + if (dev->last_word[side] != 0x4489) { + if (d86f_word_is_aligned(drive, side, find->sync_pos)) { + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + } + } +} + + +/* When writing in MFM mode, we find the beginning of the address mark by looking for 3 0xA1 sync bytes. */ +void +d86f_write_find_address_mark_mfm(int drive, int side, find_t *find) +{ + d86f_t *dev = d86f[drive]; + + d86f_get_bit(drive, side); + + if (dev->last_word[side] == 0x4489) { + find->sync_marks++; + find->sync_pos = dev->track_pos; + if (find->sync_marks == 3) { + dev->calc_crc.word = 0xCDB4; + dev->preceding_bit[side] = 1; + find->sync_marks = 0; + dev->state++; + return; + } + } + + /* If we hadn't found enough address mark sync marks, null the counter. */ + if (dev->last_word[side] != 0x4489) { + if (d86f_word_is_aligned(drive, side, find->sync_pos)) { + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + } + } +} + + +/* State 2: Read sector ID and CRC*/ +void +d86f_read_sector_id(int drive, int side, int match) +{ + d86f_t *dev = d86f[drive]; + + if (dev->id_find.bits_obtained) { + if (! (dev->id_find.bits_obtained & 15)) { + /* We've got a byte. */ + if (dev->id_find.bytes_obtained < 4) { + dev->last_sector.byte_array[dev->id_find.bytes_obtained] = decodefm(drive, dev->last_word[side]); + fdd_calccrc(dev->last_sector.byte_array[dev->id_find.bytes_obtained], &(dev->calc_crc)); + } else if ((dev->id_find.bytes_obtained >= 4) && (dev->id_find.bytes_obtained < 6)) { + dev->track_crc.bytes[(dev->id_find.bytes_obtained & 1) ^ 1] = decodefm(drive, dev->last_word[side]); + } + dev->id_find.bytes_obtained++; + + if (dev->id_find.bytes_obtained == 6) { + /* We've got the ID. */ + if ((dev->calc_crc.word != dev->track_crc.word) && (dev->last_sector.dword == dev->req_sector.dword)) { + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; + d86f_log("86F: ID CRC error: %04X != %04X (%08X)\n", dev->track_crc.word, dev->calc_crc.word, dev->last_sector.dword); + if ((dev->state != STATE_02_READ_ID) && (dev->state != STATE_0A_READ_ID)) { + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_headercrcerror(d86f_fdc); + } else if (dev->state == STATE_0A_READ_ID) + dev->state--; + else { + dev->error_condition |= 1; /* Mark that there was an ID CRC error. */ + dev->state++; + } + } else if ((dev->calc_crc.word == dev->track_crc.word) && (dev->state == STATE_0A_READ_ID)) { + /* CRC is valid and this is a read sector ID command. */ + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; + fdc_sectorid(d86f_fdc, dev->last_sector.id.c, dev->last_sector.id.h, dev->last_sector.id.r, dev->last_sector.id.n, 0, 0); + dev->state = STATE_IDLE; + } else { + /* CRC is valid. */ + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; + dev->id_found++; + if ((dev->last_sector.dword == dev->req_sector.dword) || !match) { + d86f_handler[drive].set_sector(drive, side, dev->last_sector.id.c, dev->last_sector.id.h, dev->last_sector.id.r, dev->last_sector.id.n); + if (dev->state == STATE_02_READ_ID) { + /* READ TRACK command, we need some special handling here. */ + /* Code corrected: Only the C, H, and N portions of the sector ID are compared, the R portion (the sector number) is ignored. */ + if ((dev->last_sector.id.c != fdc_get_read_track_sector(d86f_fdc).id.c) || (dev->last_sector.id.h != fdc_get_read_track_sector(d86f_fdc).id.h) || (dev->last_sector.id.n != fdc_get_read_track_sector(d86f_fdc).id.n)) { + dev->error_condition |= 4; /* Mark that the sector ID is not the one expected by the FDC. */ + /* Make sure we use the sector size from the FDC. */ + dev->last_sector.id.n = fdc_get_read_track_sector(d86f_fdc).id.n; + } + + /* If the two ID's are identical, then we do not need to do anything regarding the sector size. */ + } + dev->state++; + } else { + if (dev->last_sector.id.c != dev->req_sector.id.c) { + if (dev->last_sector.id.c == 0xFF) { + dev->error_condition |= 8; + } else { + dev->error_condition |= 0x10; + } + } + + dev->state--; + } + } + } + } + } + + d86f_get_bit(drive, side); + + dev->id_find.bits_obtained++; +} + + +uint8_t +d86f_get_data(int drive, int base) +{ + d86f_t *dev = d86f[drive]; + int data; + + if (dev->data_find.bytes_obtained < (d86f_get_data_len(drive) + base)) { + data = fdc_getdata(d86f_fdc, dev->data_find.bytes_obtained == (d86f_get_data_len(drive) + base - 1)); + if ((data & DMA_OVER) || (data == -1)) { + dev->dma_over++; + if (data == -1) + data = 0; + else + data &= 0xff; + } + } else { + data = 0; + } + + return data; +} + + +void +d86f_compare_byte(int drive, uint8_t received_byte, uint8_t disk_byte) +{ + d86f_t *dev = d86f[drive]; + + switch(fdc_get_compare_condition(d86f_fdc)) { + case 0: /* SCAN EQUAL */ + if ((received_byte == disk_byte) || (received_byte == 0xFF)) + dev->satisfying_bytes++; + break; + + case 1: /* SCAN LOW OR EQUAL */ + if ((received_byte <= disk_byte) || (received_byte == 0xFF)) + dev->satisfying_bytes++; + break; + + case 2: /* SCAN HIGH OR EQUAL */ + if ((received_byte >= disk_byte) || (received_byte == 0xFF)) + dev->satisfying_bytes++; + break; + } +} + + +/* State 4: Read sector data and CRC*/ +void +d86f_read_sector_data(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + int data = 0; + int recv_data = 0; + int read_status = 0; + uint32_t sector_len = dev->last_sector.id.n; + uint32_t crc_pos = 0; + sector_len = 1 << (7 + sector_len); + crc_pos = sector_len + 2; + + if (dev->data_find.bits_obtained) { + if (!(dev->data_find.bits_obtained & 15)) { + /* We've got a byte. */ + d86f_log("86F: We've got a byte.\n"); + if (dev->data_find.bytes_obtained < sector_len) { + data = decodefm(drive, dev->last_word[side]); + if (dev->state == STATE_11_SCAN_DATA) { + /* Scan/compare command. */ + recv_data = d86f_get_data(drive, 0); + d86f_compare_byte(drive, recv_data, data); + } else { + if (dev->data_find.bytes_obtained < d86f_get_data_len(drive)) { + if (dev->state != STATE_16_VERIFY_DATA) { + read_status = fdc_data(d86f_fdc, data); + if (read_status == -1) + dev->dma_over++; + } + } + } + fdd_calccrc(data, &(dev->calc_crc)); + } else if (dev->data_find.bytes_obtained < crc_pos) + dev->track_crc.bytes[(dev->data_find.bytes_obtained - sector_len) ^ 1] = decodefm(drive, dev->last_word[side]); + dev->data_find.bytes_obtained++; + + if (dev->data_find.bytes_obtained == (crc_pos + fdc_get_gap(d86f_fdc))) { + /* We've got the data. */ + if ((dev->calc_crc.word != dev->track_crc.word) && (dev->state != STATE_02_READ_DATA)) { + d86f_log("86F: Data CRC error: %04X != %04X (%08X)\n", dev->track_crc.word, dev->calc_crc.word, dev->last_sector.dword); + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_datacrcerror(d86f_fdc); + } else if ((dev->calc_crc.word != dev->track_crc.word) && (dev->state == STATE_02_READ_DATA)) { + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition |= 2; /* Mark that there was a data error. */ + dev->state = STATE_IDLE; + fdc_track_finishread(d86f_fdc, dev->error_condition); + } else { + /* CRC is valid. */ + d86f_log("86F: Data CRC OK: %04X != %04X (%08X)\n", dev->track_crc.word, dev->calc_crc.word, dev->last_sector.dword); + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + if (dev->state == STATE_11_SCAN_DATA) + fdc_sector_finishcompare(d86f_fdc, (dev->satisfying_bytes == ((128 << ((uint32_t) dev->last_sector.id.n)) - 1)) ? 1 : 0); + else + fdc_sector_finishread(d86f_fdc); + } + } + } + } + + d86f_get_bit(drive, side); + + dev->data_find.bits_obtained++; +} + + +void +d86f_write_sector_data(int drive, int side, int mfm, uint16_t am) +{ + d86f_t *dev = d86f[drive]; + uint16_t bit_pos; + uint16_t temp; + uint32_t sector_len = dev->last_sector.id.n; + uint32_t crc_pos = 0; + sector_len = (1 << (7 + sector_len)) + 1; + crc_pos = sector_len + 2; + + if (! (dev->data_find.bits_obtained & 15)) { + if (dev->data_find.bytes_obtained < crc_pos) { + if (! dev->data_find.bytes_obtained) { + /* We're writing the address mark. */ + dev->current_byte[side] = am; + } else if (dev->data_find.bytes_obtained < sector_len) { + /* We're in the data field of the sector, read byte from FDC and request new byte. */ + dev->current_byte[side] = d86f_get_data(drive, 1); + if (! fdc_get_diswr(d86f_fdc)) + d86f_handler[drive].write_data(drive, side, dev->data_find.bytes_obtained - 1, dev->current_byte[side]); + } else { + /* We're in the data field of the sector, use a CRC byte. */ + dev->current_byte[side] = dev->calc_crc.bytes[(dev->data_find.bytes_obtained & 1)]; + } + + dev->current_bit[side] = (15 - (dev->data_find.bits_obtained & 15)) >> 1; + + /* Write the bit. */ + temp = (dev->current_byte[side] >> dev->current_bit[side]) & 1; + if ((!temp && !dev->preceding_bit[side]) || !mfm) { + temp |= 2; + } + + /* This is an even bit, so write the clock. */ + if (! dev->data_find.bytes_obtained) { + /* Address mark, write bit directly. */ + d86f_put_bit(drive, side, am >> 15); + } else { + d86f_put_bit(drive, side, temp >> 1); + } + + if (dev->data_find.bytes_obtained < sector_len) { + /* This is a data byte, so CRC it. */ + if (! dev->data_find.bytes_obtained) { + fdd_calccrc(decodefm(drive, am), &(dev->calc_crc)); + } else { + fdd_calccrc(dev->current_byte[side], &(dev->calc_crc)); + } + } + } + } else { + if (dev->data_find.bytes_obtained < crc_pos) { + /* Encode the bit. */ + bit_pos = 15 - (dev->data_find.bits_obtained & 15); + dev->current_bit[side] = bit_pos >> 1; + + temp = (dev->current_byte[side] >> dev->current_bit[side]) & 1; + if ((!temp && !dev->preceding_bit[side]) || !mfm) { + temp |= 2; + } + + if (! dev->data_find.bytes_obtained) { + /* Address mark, write directly. */ + d86f_put_bit(drive, side, am >> bit_pos); + if (! (bit_pos & 1)) { + dev->preceding_bit[side] = am >> bit_pos; + } + } else { + if (bit_pos & 1) { + /* Clock bit */ + d86f_put_bit(drive, side, temp >> 1); + } else { + /* Data bit */ + d86f_put_bit(drive, side, temp & 1); + dev->preceding_bit[side] = temp & 1; + } + } + } + + if ((dev->data_find.bits_obtained & 15) == 15) { + dev->data_find.bytes_obtained++; + + if (dev->data_find.bytes_obtained == (crc_pos + fdc_get_gap(d86f_fdc))) { + /* We've written the data. */ + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + d86f_handler[drive].writeback(drive); + fdc_sector_finishread(d86f_fdc); + return; + } + } + } + + dev->data_find.bits_obtained++; +} + + +void d86f_advance_bit(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + dev->track_pos++; + dev->track_pos %= d86f_handler[drive].get_raw_size(drive, side); + + if (dev->track_pos == d86f_handler[drive].index_hole_pos(drive, side)) { + d86f_handler[drive].read_revolution(drive); + + if (dev->state != STATE_IDLE) + dev->index_count++; + } +} + + +void +d86f_advance_word(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + dev->track_pos += 16; + dev->track_pos %= d86f_handler[drive].get_raw_size(drive, side); + + if ((dev->track_pos == d86f_handler[drive].index_hole_pos(drive, side)) && (dev->state != STATE_IDLE)) + dev->index_count++; +} + + +void +d86f_spin_to_index(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + d86f_get_bit(drive, side); + d86f_get_bit(drive, side ^ 1); + + d86f_advance_bit(drive, side); + + if (dev->track_pos == d86f_handler[drive].index_hole_pos(drive, side)) { + if ((dev->state == STATE_0D_SPIN_TO_INDEX) || (dev->state == STATE_0D_NOP_SPIN_TO_INDEX)) { + /* When starting format, reset format state to the beginning. */ + dev->preceding_bit[side] = 1; + dev->format_state = FMT_PRETRK_GAP0; + } + + /* This is to make sure both READ TRACK and FORMAT TRACK command don't end prematurely. */ + dev->index_count = 0; + dev->state++; + } +} + + +void +d86f_write_direct_common(int drive, int side, uint16_t byte, uint8_t type, uint32_t pos) +{ + d86f_t *dev = d86f[drive]; + uint16_t encoded_byte = 0, mask_data, mask_surface, mask_hole, mask_fuzzy; + decoded_t dbyte, dpbyte; + + if (fdc_get_diswr(d86f_fdc)) return; + + dbyte.byte = byte & 0xff; + dpbyte.byte = dev->preceding_bit[side] & 0xff; + + if (type == 0) { + /* Byte write. */ + encoded_byte = d86f_encode_byte(drive, 0, dbyte, dpbyte); + if (! d86f_reverse_bytes(drive)) { + mask_data = encoded_byte >> 8; + encoded_byte &= 0xFF; + encoded_byte <<= 8; + encoded_byte |= mask_data; + } + } else { + /* Word write. */ + encoded_byte = byte; + if (d86f_reverse_bytes(drive)) { + mask_data = encoded_byte >> 8; + encoded_byte &= 0xFF; + encoded_byte <<= 8; + encoded_byte |= mask_data; + } + } + + dev->preceding_bit[side] = encoded_byte & 1; + + if (d86f_has_surface_desc(drive)) { + mask_data = dev->track_encoded_data[side][pos] ^= 0xFFFF; + mask_surface = dev->track_surface_data[side][pos]; + mask_hole = (mask_surface & mask_data) ^ 0xFFFF; /* This will retain bits that are both fuzzy and 0, therefore physical holes. */ + encoded_byte &= mask_hole; /* Filter out physical hole bits from the encoded data. */ + mask_data ^= 0xFFFF; /* Invert back so bits 1 are 1 again. */ + mask_fuzzy = (mask_surface & mask_data) ^ 0xFFFF; /* All fuzzy bits are 0. */ + dev->track_surface_data[side][pos] &= mask_fuzzy; /* Remove fuzzy bits (but not hole bits) from the surface mask, making them regular again. */ + } + + dev->track_encoded_data[side][pos] = encoded_byte; + dev->last_word[side] = encoded_byte; +} + + +void +d86f_write_direct(int drive, int side, uint16_t byte, uint8_t type) +{ + d86f_t *dev = d86f[drive]; + + d86f_write_direct_common(drive, side, byte, type, dev->track_pos >> 4); +} + + +uint16_t +endian_swap(uint16_t word) +{ + uint16_t temp; + + temp = word & 0xff; + temp <<= 8; + temp |= (word >> 8); + + return temp; +} + + +void +d86f_format_finish(int drive, int side, int mfm, uint16_t sc, uint16_t gap_fill, int do_write) +{ + d86f_t *dev = d86f[drive]; + + if (mfm && do_write) { + if (do_write && (dev->track_pos == d86f_handler[drive].index_hole_pos(drive, side))) { + d86f_write_direct_common(drive, side, gap_fill, 0, 0); + } + } + + dev->state = STATE_IDLE; + + if (do_write) + d86f_handler[drive].writeback(drive); + + dev->error_condition = 0; + dev->datac = 0; + fdc_sector_finishread(d86f_fdc); +} + + +void +d86f_format_turbo_finish(int drive, int side, int do_write) +{ + d86f_t *dev = d86f[drive]; + + dev->state = STATE_IDLE; + + if (do_write) + d86f_handler[drive].writeback(drive); + + dev->error_condition = 0; + dev->datac = 0; + fdc_sector_finishread(d86f_fdc); +} + + +void +d86f_format_track(int drive, int side, int do_write) +{ + d86f_t *dev = d86f[drive]; + int data; + uint16_t max_len; + + int mfm; + uint16_t sc = 0; + uint16_t dtl = 0; + int gap_sizes[4] = { 0, 0, 0, 0 }; + int am_len = 0; + int sync_len = 0; + uint16_t iam_mfm[4] = { 0x2452, 0x2452, 0x2452, 0x5255 }; + uint16_t idam_mfm[4] = { 0x8944, 0x8944, 0x8944, 0x5455 }; + uint16_t dataam_mfm[4] = { 0x8944, 0x8944, 0x8944, 0x4555 }; + uint16_t iam_fm = 0xFAF7; + uint16_t idam_fm = 0x7EF5; + uint16_t dataam_fm = 0x6FF5; + uint16_t gap_fill = 0x4E; + + mfm = d86f_is_mfm(drive); + am_len = mfm ? 4 : 1; + gap_sizes[0] = mfm ? 80 : 40; + gap_sizes[1] = mfm ? 50 : 26; + gap_sizes[2] = fdc_get_gap2(d86f_fdc, real_drive(d86f_fdc, drive)); + gap_sizes[3] = fdc_get_gap(d86f_fdc); + sync_len = mfm ? 12 : 6; + sc = fdc_get_format_sectors(d86f_fdc); + dtl = 128 << fdc_get_format_n(d86f_fdc); + gap_fill = mfm ? 0x4E : 0xFF; + + switch(dev->format_state) { + case FMT_POSTTRK_GAP4: + max_len = 60000; + if (do_write) + d86f_write_direct(drive, side, gap_fill, 0); + break; + + case FMT_PRETRK_GAP0: + max_len = gap_sizes[0]; + if (do_write) + d86f_write_direct(drive, side, gap_fill, 0); + break; + + case FMT_SECTOR_ID_SYNC: + max_len = sync_len; + if (dev->datac <= 3) { + data = fdc_getdata(d86f_fdc, 0); + if (data != -1) + data &= 0xff; + if ((data == -1) && (dev->datac < 3)) + data = 0; + dev->format_sector_id.byte_array[dev->datac] = data & 0xff; + if (dev->datac == 3) + fdc_stop_id_request(d86f_fdc); + } + /*FALLTHROUGH*/ + + case FMT_PRETRK_SYNC: + case FMT_SECTOR_DATA_SYNC: + max_len = sync_len; + if (do_write) + d86f_write_direct(drive, side, 0x00, 0); + break; + + case FMT_PRETRK_IAM: + max_len = am_len; + if (do_write) { + if (mfm) + d86f_write_direct(drive, side, iam_mfm[dev->datac], 1); + else + d86f_write_direct(drive, side, iam_fm, 1); + } + break; + + case FMT_PRETRK_GAP1: + max_len = gap_sizes[1]; + if (do_write) + d86f_write_direct(drive, side, gap_fill, 0); + break; + + case FMT_SECTOR_IDAM: + max_len = am_len; + if (mfm) { + if (do_write) + d86f_write_direct(drive, side, idam_mfm[dev->datac], 1); + d86f_calccrc(dev, (dev->datac < 3) ? 0xA1 : 0xFE); + } else { + if (do_write) + d86f_write_direct(drive, side, idam_fm, 1); + d86f_calccrc(dev, 0xFE); + } + break; + + case FMT_SECTOR_ID: + max_len = 4; + if (do_write) { + d86f_write_direct(drive, side, dev->format_sector_id.byte_array[dev->datac], 0); + d86f_calccrc(dev, dev->format_sector_id.byte_array[dev->datac]); + } else { + if (dev->datac == 3) { + d86f_handler[drive].set_sector(drive, side, dev->format_sector_id.id.c, dev->format_sector_id.id.h, dev->format_sector_id.id.r, dev->format_sector_id.id.n); + } + } + break; + + case FMT_SECTOR_ID_CRC: + case FMT_SECTOR_DATA_CRC: + max_len = 2; + if (do_write) + d86f_write_direct(drive, side, dev->calc_crc.bytes[dev->datac ^ 1], 0); + break; + + case FMT_SECTOR_GAP2: + max_len = gap_sizes[2]; + if (do_write) + d86f_write_direct(drive, side, gap_fill, 0); + break; + + case FMT_SECTOR_DATAAM: + max_len = am_len; + if (mfm) { + if (do_write) + d86f_write_direct(drive, side, dataam_mfm[dev->datac], 1); + d86f_calccrc(dev, (dev->datac < 3) ? 0xA1 : 0xFB); + } else { + if (do_write) + d86f_write_direct(drive, side, dataam_fm, 1); + d86f_calccrc(dev, 0xFB); + } + break; + + case FMT_SECTOR_DATA: + max_len = dtl; + if (do_write) { + d86f_write_direct(drive, side, dev->fill, 0); + d86f_handler[drive].write_data(drive, side, dev->datac, dev->fill); + } + d86f_calccrc(dev, dev->fill); + break; + + case FMT_SECTOR_GAP3: + max_len = gap_sizes[3]; + if (do_write) + d86f_write_direct(drive, side, gap_fill, 0); + break; + + default: + max_len = 0; + break; + } + + dev->datac++; + + d86f_advance_word(drive, side); + + if ((dev->index_count) && ((dev->format_state < FMT_SECTOR_ID_SYNC) || (dev->format_state > FMT_SECTOR_GAP3))) { + d86f_format_finish(drive, side, mfm, sc, gap_fill, do_write); + return; + } + + if (dev->datac >= max_len) { + dev->datac = 0; + dev->format_state++; + + switch (dev->format_state) { + case FMT_SECTOR_ID_SYNC: + fdc_request_next_sector_id(d86f_fdc); + break; + + case FMT_SECTOR_IDAM: + case FMT_SECTOR_DATAAM: + dev->calc_crc.word = 0xffff; + break; + + case FMT_POSTTRK_CHECK: + if (dev->index_count) { + d86f_format_finish(drive, side, mfm, sc, gap_fill, do_write); + return; + } + dev->sector_count++; + if (dev->sector_count < sc) { + /* Sector within allotted amount, change state to SECTOR_ID_SYNC. */ + dev->format_state = FMT_SECTOR_ID_SYNC; + fdc_request_next_sector_id(d86f_fdc); + break; + } else { + dev->format_state = FMT_POSTTRK_GAP4; + dev->sector_count = 0; + break; + } + break; + } + } +} + + +void +d86f_format_track_normal(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + d86f_format_track(drive, side, (dev->version == D86FVER)); +} + + +void +d86f_format_track_nop(int drive, int side) +{ + d86f_format_track(drive, side, 0); +} + + +void +d86f_initialize_last_sector_id(int drive, int c, int h, int r, int n) +{ + d86f_t *dev = d86f[drive]; + + dev->last_sector.id.c = c; + dev->last_sector.id.h = h; + dev->last_sector.id.r = r; + dev->last_sector.id.n = n; +} + + +void +d86f_turbo_read(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + uint8_t dat = 0; + int recv_data = 0; + int read_status = 0; + + dat = d86f_handler[drive].read_data(drive, side, dev->turbo_pos); + dev->turbo_pos++; + + if (dev->state == STATE_11_SCAN_DATA) { + /* Scan/compare command. */ + recv_data = d86f_get_data(drive, 0); + d86f_compare_byte(drive, recv_data, dat); + } else { + if (dev->data_find.bytes_obtained < (128UL << dev->last_sector.id.n)) { + if (dev->state != STATE_16_VERIFY_DATA) { + read_status = fdc_data(d86f_fdc, dat); + if (read_status == -1) + dev->dma_over++; + } + } + } + + if (dev->turbo_pos >= (128 << dev->last_sector.id.n)) { + /* CRC is valid. */ + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + if (dev->state == STATE_11_SCAN_DATA) { + dev->state = STATE_IDLE; + fdc_sector_finishcompare(d86f_fdc, (dev->satisfying_bytes == ((128 << ((uint32_t) dev->last_sector.id.n)) - 1)) ? 1 : 0); + } else { + dev->state = STATE_IDLE; + fdc_sector_finishread(d86f_fdc); + } + } +} + + +void +d86f_turbo_write(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + uint8_t dat = 0; + + dat = d86f_get_data(drive, 1); + d86f_handler[drive].write_data(drive, side, dev->turbo_pos, dat); + + dev->turbo_pos++; + + if (dev->turbo_pos >= (128 << dev->last_sector.id.n)) { + /* We've written the data. */ + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + d86f_handler[drive].writeback(drive); + fdc_sector_finishread(d86f_fdc); + } +} + + +void +d86f_turbo_format(int drive, int side, int nop) +{ + d86f_t *dev = d86f[drive]; + int dat; + uint16_t sc; + uint16_t dtl; + int i; + + sc = fdc_get_format_sectors(d86f_fdc); + dtl = 128 << fdc_get_format_n(d86f_fdc); + + if (dev->datac <= 3) { + dat = fdc_getdata(d86f_fdc, 0); + if (dat != -1) + dat &= 0xff; + if ((dat == -1) && (dev->datac < 3)) + dat = 0; + dev->format_sector_id.byte_array[dev->datac] = dat & 0xff; + if (dev->datac == 3) { + fdc_stop_id_request(d86f_fdc); + d86f_handler[drive].set_sector(drive, side, dev->format_sector_id.id.c, dev->format_sector_id.id.h, dev->format_sector_id.id.r, dev->format_sector_id.id.n); + } + } else if (dev->datac == 4) { + if (! nop) { + for (i = 0; i < dtl; i++) + d86f_handler[drive].write_data(drive, side, i, dev->fill); + } + + dev->sector_count++; + } + + dev->datac++; + + if (dev->datac == 6) { + dev->datac = 0; + + if (dev->sector_count < sc) { + /* Sector within allotted amount. */ + fdc_request_next_sector_id(d86f_fdc); + } else { + dev->state = STATE_IDLE; + d86f_format_turbo_finish(drive, side, nop); + } + } +} + + +int +d86f_sector_is_present(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + d86f_t *dev = d86f[drive]; + sector_t *s, *t; + + if (dev->last_side_sector[side]) { + s = dev->last_side_sector[side]; + while (s) { + if ((s->c == c) && (s->h == h) && (s->r == r) && (s->n == n)) + return 1; + if (! s->prev) + break; + t = s->prev; + s = t; + } + } + + return 0; +} + + +void +d86f_turbo_poll(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + if ((dev->state != STATE_IDLE) && (dev->state != STATE_SECTOR_NOT_FOUND) && ((dev->state & 0xF8) != 0xE8)) { + if (! d86f_can_read_address(drive)) { + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; + fdc_noidam(d86f_fdc); + dev->state = STATE_IDLE; + return; + } + } + + switch(dev->state) { + case STATE_0D_SPIN_TO_INDEX: + case STATE_0D_NOP_SPIN_TO_INDEX: + dev->sector_count = 0; + dev->datac = 5; + /*FALLTHROUGH*/ + + case STATE_02_SPIN_TO_INDEX: + dev->state++; + return; + + case STATE_02_FIND_ID: + if (! d86f_sector_is_present(drive, side, + fdc_get_read_track_sector(d86f_fdc).id.c, + fdc_get_read_track_sector(d86f_fdc).id.h, + fdc_get_read_track_sector(d86f_fdc).id.r, + fdc_get_read_track_sector(d86f_fdc).id.n)) { + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; + fdc_nosector(d86f_fdc); + dev->state = STATE_IDLE; + return; + } + dev->last_sector.id.c = fdc_get_read_track_sector(d86f_fdc).id.c; + dev->last_sector.id.h = fdc_get_read_track_sector(d86f_fdc).id.h; + dev->last_sector.id.r = fdc_get_read_track_sector(d86f_fdc).id.r; + dev->last_sector.id.n = fdc_get_read_track_sector(d86f_fdc).id.n; + d86f_handler[drive].set_sector(drive, side, dev->last_sector.id.c, dev->last_sector.id.h, dev->last_sector.id.r, dev->last_sector.id.n); + dev->turbo_pos = 0; + dev->state++; + return; + + case STATE_05_FIND_ID: + case STATE_09_FIND_ID: + case STATE_06_FIND_ID: + case STATE_0C_FIND_ID: + case STATE_11_FIND_ID: + case STATE_16_FIND_ID: + if (! d86f_sector_is_present(drive, side, + dev->req_sector.id.c, + dev->req_sector.id.h, + dev->req_sector.id.r, + dev->req_sector.id.n)) { + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; + fdc_nosector(d86f_fdc); + dev->state = STATE_IDLE; + return; + } + dev->last_sector.id.c = dev->req_sector.id.c; + dev->last_sector.id.h = dev->req_sector.id.h; + dev->last_sector.id.r = dev->req_sector.id.r; + dev->last_sector.id.n = dev->req_sector.id.n; + d86f_handler[drive].set_sector(drive, side, dev->last_sector.id.c, dev->last_sector.id.h, dev->last_sector.id.r, dev->last_sector.id.n); + /*FALLTHROUGH*/ + + case STATE_0A_FIND_ID: + dev->turbo_pos = 0; + dev->state++; + return; + + case STATE_0A_READ_ID: + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; + fdc_sectorid(d86f_fdc, dev->last_sector.id.c, dev->last_sector.id.h, dev->last_sector.id.r, dev->last_sector.id.n, 0, 0); + dev->state = STATE_IDLE; + break; + + case STATE_02_READ_ID: + case STATE_05_READ_ID: + case STATE_09_READ_ID: + case STATE_06_READ_ID: + case STATE_0C_READ_ID: + case STATE_11_READ_ID: + case STATE_16_READ_ID: + dev->state++; + break; + + case STATE_02_FIND_DATA: + case STATE_06_FIND_DATA: + case STATE_11_FIND_DATA: + case STATE_16_FIND_DATA: + case STATE_05_FIND_DATA: + case STATE_09_FIND_DATA: + case STATE_0C_FIND_DATA: + dev->state++; + break; + + case STATE_02_READ_DATA: + case STATE_06_READ_DATA: + case STATE_0C_READ_DATA: + case STATE_11_SCAN_DATA: + case STATE_16_VERIFY_DATA: + d86f_turbo_read(drive, side); + break; + + case STATE_05_WRITE_DATA: + case STATE_09_WRITE_DATA: + d86f_turbo_write(drive, side); + break; + + case STATE_0D_FORMAT_TRACK: + d86f_turbo_format(drive, side, 0); + return; + + case STATE_0D_NOP_FORMAT_TRACK: + d86f_turbo_format(drive, side, 1); + return; + + case STATE_IDLE: + case STATE_SECTOR_NOT_FOUND: + default: + break; + } +} + + +void +d86f_poll(int drive) +{ + d86f_t *dev = d86f[drive]; + int mfm, side; + + side = fdd_get_head(drive); + if (! fdd_is_double_sided(drive)) + side = 0; + + mfm = fdc_is_mfm(d86f_fdc); + + if ((dev->state & 0xF8) == 0xE8) { + if (! d86f_can_format(drive)) + dev->state = STATE_SECTOR_NOT_FOUND; + } + + if (fdd_get_turbo(drive) && (dev->version == 0x0063)) { + d86f_turbo_poll(drive, side); + return; + } + + if ((dev->state != STATE_IDLE) && (dev->state != STATE_SECTOR_NOT_FOUND) && ((dev->state & 0xF8) != 0xE8)) { + if (! d86f_can_read_address(drive)) + dev->state = STATE_SECTOR_NOT_FOUND; + } + + if ((dev->state != STATE_02_SPIN_TO_INDEX) && (dev->state != STATE_0D_SPIN_TO_INDEX)) + d86f_get_bit(drive, side ^ 1); + + switch(dev->state) { + case STATE_02_SPIN_TO_INDEX: + case STATE_0D_SPIN_TO_INDEX: + case STATE_0D_NOP_SPIN_TO_INDEX: + d86f_spin_to_index(drive, side); + return; + + case STATE_02_FIND_ID: + case STATE_05_FIND_ID: + case STATE_09_FIND_ID: + case STATE_06_FIND_ID: + case STATE_0A_FIND_ID: + case STATE_0C_FIND_ID: + case STATE_11_FIND_ID: + case STATE_16_FIND_ID: + if (mfm) + d86f_find_address_mark_mfm(drive, side, &(dev->id_find), 0x5554, 0, 0, 0); + else + d86f_find_address_mark_fm(drive, side, &(dev->id_find), 0xF57E, 0, 0, 0); + break; + + case STATE_0A_READ_ID: + case STATE_02_READ_ID: + d86f_read_sector_id(drive, side, 0); + break; + + case STATE_05_READ_ID: + case STATE_09_READ_ID: + case STATE_06_READ_ID: + case STATE_0C_READ_ID: + case STATE_11_READ_ID: + case STATE_16_READ_ID: + d86f_read_sector_id(drive, side, 1); + break; + + case STATE_02_FIND_DATA: + if (mfm) + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, 0x5554, 2); + else + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, 0xF57E, 2); + break; + + case STATE_06_FIND_DATA: + case STATE_11_FIND_DATA: + case STATE_16_FIND_DATA: + if (mfm) + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, 0x5554, fdc_is_sk(d86f_fdc) | 2); + else + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, 0xF57E, fdc_is_sk(d86f_fdc) | 2); + break; + + case STATE_05_FIND_DATA: + case STATE_09_FIND_DATA: + if (mfm) + d86f_write_find_address_mark_mfm(drive, side, &(dev->data_find)); + else + d86f_write_find_address_mark_fm(drive, side, &(dev->data_find)); + break; + + case STATE_0C_FIND_DATA: + if (mfm) + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x554A, 0x5545, 0x5554, fdc_is_sk(d86f_fdc) | 2); + else + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56A, 0xF56F, 0xF57E, fdc_is_sk(d86f_fdc) | 2); + break; + + case STATE_02_READ_DATA: + case STATE_06_READ_DATA: + case STATE_0C_READ_DATA: + case STATE_11_SCAN_DATA: + case STATE_16_VERIFY_DATA: + d86f_read_sector_data(drive, side); + break; + + case STATE_05_WRITE_DATA: + if (mfm) + d86f_write_sector_data(drive, side, mfm, 0x5545); + else + d86f_write_sector_data(drive, side, mfm, 0xF56F); + break; + + case STATE_09_WRITE_DATA: + if (mfm) + d86f_write_sector_data(drive, side, mfm, 0x554A); + else + d86f_write_sector_data(drive, side, mfm, 0xF56A); + break; + + case STATE_0D_FORMAT_TRACK: + if (! (dev->track_pos & 15)) + d86f_format_track_normal(drive, side); + return; + + case STATE_0D_NOP_FORMAT_TRACK: + if (! (dev->track_pos & 15)) + d86f_format_track_nop(drive, side); + return; + + case STATE_IDLE: + case STATE_SECTOR_NOT_FOUND: + default: + d86f_get_bit(drive, side); + break; + } + + d86f_advance_bit(drive, side); + + if (d86f_wrong_densel(drive) && (dev->state != STATE_IDLE)) { + dev->state = STATE_IDLE; + fdc_noidam(d86f_fdc); + return; + } + + if ((dev->index_count == 2) && (dev->state != STATE_IDLE)) { + switch(dev->state) { + case STATE_0A_FIND_ID: + case STATE_SECTOR_NOT_FOUND: + dev->state = STATE_IDLE; + fdc_noidam(d86f_fdc); + break; + + case STATE_02_FIND_DATA: + case STATE_06_FIND_DATA: + case STATE_11_FIND_DATA: + case STATE_16_FIND_DATA: + case STATE_05_FIND_DATA: + case STATE_09_FIND_DATA: + case STATE_0C_FIND_DATA: + + dev->state = STATE_IDLE; + fdc_nodataam(d86f_fdc); + break; + + case STATE_02_SPIN_TO_INDEX: + case STATE_02_READ_DATA: + case STATE_05_WRITE_DATA: + case STATE_06_READ_DATA: + case STATE_09_WRITE_DATA: + case STATE_0C_READ_DATA: + case STATE_0D_SPIN_TO_INDEX: + case STATE_0D_FORMAT_TRACK: + case STATE_11_SCAN_DATA: + case STATE_16_VERIFY_DATA: + /* In these states, we should *NEVER* care about how many index pulses there have been. */ + break; + + default: + dev->state = STATE_IDLE; + if (dev->id_found) { + if (dev->error_condition & 0x18) { + if ((dev->error_condition & 0x18) == 0x08) + fdc_badcylinder(d86f_fdc); + if ((dev->error_condition & 0x10) == 0x10) + fdc_wrongcylinder(d86f_fdc); + else + fdc_nosector(d86f_fdc); + } else + fdc_nosector(d86f_fdc); + } else { + fdc_noidam(d86f_fdc); + } + break; + } + } +} + + +void +d86f_reset_index_hole_pos(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + dev->index_hole_pos[side] = 0; +} + + +uint16_t +d86f_prepare_pretrack(int drive, int side, int iso) +{ + d86f_t *dev = d86f[drive]; + uint16_t i, pos; + int mfm; + int real_gap0_len; + int sync_len; + int real_gap1_len; + uint16_t gap_fill; + uint32_t raw_size; + uint16_t iam_fm = 0xFAF7; + uint16_t iam_mfm = 0x5255; + + mfm = d86f_is_mfm(drive); + real_gap0_len = mfm ? 80 : 40; + sync_len = mfm ? 12 : 6; + real_gap1_len = mfm ? 50 : 26; + gap_fill = mfm ? 0x4E : 0xFF; + raw_size = d86f_handler[drive].get_raw_size(drive, side); + if (raw_size & 15) + raw_size = (raw_size >> 4) + 1; + else + raw_size = (raw_size >> 4); + + dev->index_hole_pos[side] = 0; + + d86f_destroy_linked_lists(drive, side); + + for (i = 0; i < raw_size; i++) + d86f_write_direct_common(drive, side, gap_fill, 0, i); + + pos = 0; + + if (! iso) { + for (i = 0; i < real_gap0_len; i++) { + d86f_write_direct_common(drive, side, gap_fill, 0, pos); + pos = (pos + 1) % raw_size; + } + for (i = 0; i < sync_len; i++) { + d86f_write_direct_common(drive, side, 0, 0, pos); + pos = (pos + 1) % raw_size; + } + if (mfm) { + for (i = 0; i < 3; i++) { + d86f_write_direct_common(drive, side, 0x2452, 1, pos); + pos = (pos + 1) % raw_size; + } + } + + d86f_write_direct_common(drive, side, mfm ? iam_mfm : iam_fm, 1, pos); + pos = (pos + 1) % raw_size; + } + + for (i = 0; i < real_gap1_len; i++) { + d86f_write_direct_common(drive, side, gap_fill, 0, pos); + pos = (pos + 1) % raw_size; + } + + return pos; +} + + +uint16_t +d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t *data_buf, int data_len, int gap2, int gap3, int deleted, int bad_crc) +{ + d86f_t *dev = d86f[drive]; + uint16_t pos; + int i; + sector_t *s; + + int real_gap2_len = gap2; + int real_gap3_len = gap3; + int mfm; + int sync_len; + uint16_t gap_fill; + uint32_t raw_size; + uint16_t idam_fm = 0x7EF5; + uint16_t dataam_fm = 0x6FF5; + uint16_t datadam_fm = 0x6AF5; + uint16_t idam_mfm = 0x5455; + uint16_t dataam_mfm = 0x4555; + uint16_t datadam_mfm = 0x4A55; + + if (fdd_get_turbo(drive) && (dev->version == 0x0063)) { + s = (sector_t *) malloc(sizeof(sector_t)); + memset(s, 0, sizeof(sector_t)); + s->c = id_buf[0]; + s->h = id_buf[1]; + s->r = id_buf[2]; + s->n = id_buf[3]; + if (dev->last_side_sector[side]) + s->prev = dev->last_side_sector[side]; + dev->last_side_sector[side] = s; + } + + mfm = d86f_is_mfm(drive); + + gap_fill = mfm ? 0x4E : 0xFF; + raw_size = d86f_handler[drive].get_raw_size(drive, side); + if (raw_size & 15) + raw_size = (raw_size >> 4) + 1; + else + raw_size = (raw_size >> 4); + + pos = prev_pos; + + sync_len = mfm ? 12 : 6; + + for (i = 0; i < sync_len; i++) { + d86f_write_direct_common(drive, side, 0, 0, pos); + pos = (pos + 1) % raw_size; + } + dev->calc_crc.word = 0xffff; + if (mfm) { + for (i = 0; i < 3; i++) { + d86f_write_direct_common(drive, side, 0x8944, 1, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, 0xA1); + } + } + d86f_write_direct_common(drive, side, mfm ? idam_mfm : idam_fm, 1, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, 0xFE); + for (i = 0; i < 4; i++) { + d86f_write_direct_common(drive, side, id_buf[i], 0, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, id_buf[i]); + } + for (i = 1; i >= 0; i--) { + d86f_write_direct_common(drive, side, dev->calc_crc.bytes[i], 0, pos); + pos = (pos + 1) % raw_size; + } + for (i = 0; i < real_gap2_len; i++) { + d86f_write_direct_common(drive, side, gap_fill, 0, pos); + pos = (pos + 1) % raw_size; + } + for (i = 0; i < sync_len; i++) { + d86f_write_direct_common(drive, side, 0, 0, pos); + pos = (pos + 1) % raw_size; + } + dev->calc_crc.word = 0xffff; + if (mfm) { + for (i = 0; i < 3; i++) { + d86f_write_direct_common(drive, side, 0x8944, 1, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, 0xA1); + } + } + d86f_write_direct_common(drive, side, mfm ? (deleted ? datadam_mfm : dataam_mfm) : (deleted ? datadam_fm : dataam_fm), 1, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, deleted ? 0xF8 : 0xFB); + for (i = 0; i < data_len; i++) { + d86f_write_direct_common(drive, side, data_buf[i], 0, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, data_buf[i]); + } + if (bad_crc) + dev->calc_crc.word ^= 0xffff; + for (i = 1; i >= 0; i--) { + d86f_write_direct_common(drive, side, dev->calc_crc.bytes[i], 0, pos); + pos = (pos + 1) % raw_size; + } + for (i = 0; i < real_gap3_len; i++) { + d86f_write_direct_common(drive, side, gap_fill, 0, pos); + pos = (pos + 1) % raw_size; + } + + return pos; +} + + +/* + * Note on handling of tracks on thick track drives: + * + * - On seek, encoded data is constructed from both (track << 1) and + * ((track << 1) + 1); + * + * - Any bits that differ are treated as thus: + * - Both are regular but contents differ -> Output is fuzzy; + * - One is regular and one is fuzzy -> Output is fuzzy; + * - Both are fuzzy -> Output is fuzzy; + * - Both are physical holes -> Output is a physical hole; + * - One is regular and one is a physical hole -> Output is puzzy, + * the hole half is handled appropriately on writeback; + * - One is fuzzy and one is a physical hole -> Output is puzzy, + * the hole half is handled appropriately on writeback; + * - On write back, apart from the above notes, the final two tracks + * are written; + * - Destination ALWAYS has surface data even if the image does not. + * + * In case of a thin track drive, tracks are handled normally. + */ +void +d86f_construct_encoded_buffer(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + uint32_t i = 0; + + /* *_fuzm are fuzzy bit masks, *_holm are hole masks, dst_neim are masks is mask for bits that are neither fuzzy nor holes in both, + and src1_d and src2_d are filtered source data. */ + uint16_t src1_fuzm, src2_fuzm, dst_fuzm, src1_holm, src2_holm, dst_holm, dst_neim, src1_d, src2_d; + uint32_t len; + uint16_t *dst = dev->track_encoded_data[side]; + uint16_t *dst_s = dev->track_surface_data[side]; + uint16_t *src1 = dev->thin_track_encoded_data[0][side]; + uint16_t *src1_s = dev->thin_track_surface_data[0][side]; + uint16_t *src2 = dev->thin_track_encoded_data[1][side]; + uint16_t *src2_s = dev->thin_track_surface_data[1][side]; + len = d86f_get_array_size(drive, side, 1); + + for (i = 0; i < len; i++) { + /* The two bits differ. */ + if (d86f_has_surface_desc(drive)) { + /* Source image has surface description data, so we have some more handling to do. */ + src1_fuzm = src1[i] & src1_s[i]; + src2_fuzm = src2[i] & src2_s[i]; + dst_fuzm = src1_fuzm | src2_fuzm; /* The bits that remain set are fuzzy in either one or + the other or both. */ + src1_holm = src1[i] | (src1_s[i] ^ 0xffff); + src2_holm = src2[i] | (src2_s[i] ^ 0xffff); + dst_holm = (src1_holm & src2_holm) ^ 0xffff; /* The bits that remain set are holes in both. */ + dst_neim = (dst_fuzm | dst_holm) ^ 0xffff; /* The bits that remain set are those that are neither + fuzzy nor are holes in both. */ + src1_d = src1[i] & dst_neim; + src2_d = src2[i] & dst_neim; + + dst_s[i] = (dst_neim ^ 0xffff); /* The set bits are those that are either fuzzy or are + holes in both. */ + dst[i] = (src1_d | src2_d); /* Initial data is remaining data from Source 1 and + Source 2. */ + dst[i] |= dst_fuzm; /* Add to it the fuzzy bytes (holes have surface bit set + but data bit clear). */ + } else { + /* No surface data, the handling is much simpler - a simple OR. */ + dst[i] = src1[i] | src2[i]; + dst_s[i] = 0; + } + } +} + + +/* Decomposition is easier since we at most have to care about the holes. */ +void +d86f_decompose_encoded_buffer(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + uint32_t i = 0; + uint16_t temp, temp2; + uint32_t len; + uint16_t *dst = dev->track_encoded_data[side]; + uint16_t *src1 = dev->thin_track_encoded_data[0][side]; + uint16_t *src1_s = dev->thin_track_surface_data[0][side]; + uint16_t *src2 = dev->thin_track_encoded_data[1][side]; + uint16_t *src2_s = dev->thin_track_surface_data[1][side]; + dst = d86f_handler[drive].encoded_data(drive, side); + len = d86f_get_array_size(drive, side, 1); + + for (i = 0; i < len; i++) { + if (d86f_has_surface_desc(drive)) { + /* Source image has surface description data, so we have some more handling to do. + We need hole masks for both buffers. Holes have data bit clear and surface bit set. */ + temp = src1[i] & (src1_s[i] ^ 0xffff); + temp2 = src2[i] & (src2_s[i] ^ 0xffff); + src1[i] = dst[i] & temp; + src1_s[i] = temp ^ 0xffff; + src2[i] = dst[i] & temp2; + src2_s[i] = temp2 ^ 0xffff; + } else { + src1[i] = src2[i] = dst[i]; + } + } +} + + +int +d86f_track_header_size(int drive) +{ + int temp = 6; + + if (d86f_has_extra_bit_cells(drive)) + temp += 4; + + return temp; +} + + +void +d86f_read_track(int drive, int track, int thin_track, int side, uint16_t *da, uint16_t *sa) +{ + d86f_t *dev = d86f[drive]; + int logical_track = 0; + int array_size = 0; + + if (d86f_get_sides(drive) == 2) + logical_track = ((track + thin_track) << 1) + side; + else + logical_track = track + thin_track; + + 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 (d86f_has_extra_bit_cells(drive)) { + fread(&(dev->extra_bit_cells[side]), 4, 1, dev->f); + /* If RPM shift is 0% and direction is 1, do not adjust extra bit cells, + as that is the whole track length. */ + if (d86f_get_rpm_mode(drive) || !d86f_get_speed_shift_dir(drive)) { + if (dev->extra_bit_cells[side] < -32768) + dev->extra_bit_cells[side] = -32768; + if (dev->extra_bit_cells[side] > 32768) + dev->extra_bit_cells[side] = 32768; + } + } else + dev->extra_bit_cells[side] = 0; + fread(&(dev->index_hole_pos[side]), 4, 1, dev->f); + } else + fseek(dev->f, dev->track_offset[logical_track] + d86f_track_header_size(drive), SEEK_SET); + array_size = d86f_get_array_size(drive, side, 0); + if (d86f_has_surface_desc(drive)) + fread(sa, 1, array_size, dev->f); + fread(da, 1, array_size, dev->f); + } else { + if (! thin_track) { + switch((dev->disk_flags >> 1) & 3) { + case 0: + default: + dev->side_flags[side] = 0x0A; + break; + + case 1: + dev->side_flags[side] = 0x00; + break; + + case 2: + case 3: + dev->side_flags[side] = 0x03; + break; + } + dev->extra_bit_cells[side] = 0; + } + } +} + + +void +d86f_zero_track(int drive) +{ + d86f_t *dev = d86f[drive]; + int sides, side; + sides = d86f_get_sides(drive); + + for (side = 0; side < sides; side++) { + if (d86f_has_surface_desc(drive)) + memset(dev->track_surface_data[side], 0, 106096); + memset(dev->track_encoded_data[side], 0, 106096); + } +} + + +void +d86f_seek(int drive, int track) +{ + d86f_t *dev = d86f[drive]; + int sides; + int side, thin_track; + sides = d86f_get_sides(drive); + + /* If the drive has thick tracks, shift the track number by 1. */ + if (! fdd_doublestep_40(drive)) { + track <<= 1; + + for (thin_track = 0; thin_track < sides; thin_track++) { + for (side = 0; side < sides; side++) { + if (d86f_has_surface_desc(drive)) + memset(dev->thin_track_surface_data[thin_track][side], 0, 106096); + memset(dev->thin_track_encoded_data[thin_track][side], 0, 106096); + } + } + } + + d86f_zero_track(drive); + + dev->cur_track = track; + + if (! fdd_doublestep_40(drive)) { + for (side = 0; side < sides; side++) { + for (thin_track = 0; thin_track < 2; thin_track++) + d86f_read_track(drive, track, thin_track, side, dev->thin_track_encoded_data[thin_track][side], dev->thin_track_surface_data[thin_track][side]); + + d86f_construct_encoded_buffer(drive, side); + } + } else { + for (side = 0; side < sides; side++) + d86f_read_track(drive, track, 0, side, dev->track_encoded_data[side], dev->track_surface_data[side]); + } + + dev->state = STATE_IDLE; +} + + +void +d86f_write_track(int drive, FILE **f, int side, uint16_t *da0, uint16_t *sa0) +{ + uint32_t array_size = d86f_get_array_size(drive, side, 0); + uint16_t side_flags = d86f_handler[drive].side_flags(drive); + uint32_t extra_bit_cells = d86f_handler[drive].extra_bit_cells(drive, side); + uint32_t index_hole_pos = d86f_handler[drive].index_hole_pos(drive, side); + + fwrite(&side_flags, 1, 2, *f); + + if (d86f_has_extra_bit_cells(drive)) + fwrite(&extra_bit_cells, 1, 4, *f); + + fwrite(&index_hole_pos, 1, 4, *f); + + if (d86f_has_surface_desc(drive)) + fwrite(sa0, 1, array_size, *f); + + fwrite(da0, 1, array_size, *f); +} + + +int +d86f_get_track_table_size(int drive) +{ + int temp = 2048; + + if (d86f_get_sides(drive) == 1) + temp >>= 1; + + return temp; +} + + +void +d86f_set_cur_track(int drive, int track) +{ + d86f_t *dev = d86f[drive]; + + dev->cur_track = track; +} + + +void +d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) +{ + d86f_t *dev = d86f[drive]; + int sides, fdd_side; + int side, thin_track; + int logical_track = 0; + uint32_t *tbl; + tbl = dev->track_offset; + fdd_side = fdd_get_head(drive); + sides = d86f_get_sides(drive); + + if (track_table) + tbl = track_table; + + if (!fdd_doublestep_40(drive)) { + d86f_decompose_encoded_buffer(drive, 0); + if (sides == 2) + d86f_decompose_encoded_buffer(drive, 1); + + for (thin_track = 0; thin_track < 2; thin_track++) { + for (side = 0; side < sides; side++) { + fdd_set_head(drive, side); + + if (sides == 2) + logical_track = ((dev->cur_track + thin_track) << 1) + side; + else + logical_track = dev->cur_track + thin_track; + + if (track_table && !tbl[logical_track]) { + fseek(*f, 0, SEEK_END); + tbl[logical_track] = ftell(*f); + } + + if (tbl[logical_track]) { + fseek(*f, tbl[logical_track], SEEK_SET); + d86f_write_track(drive, f, side, dev->thin_track_encoded_data[thin_track][side], dev->thin_track_surface_data[thin_track][side]); + } + } + } + } else { + for (side = 0; side < sides; side++) { + fdd_set_head(drive, side); + if (sides == 2) + logical_track = (dev->cur_track << 1) + side; + else + logical_track = dev->cur_track; + + if (track_table && !tbl[logical_track]) { + fseek(*f, 0, SEEK_END); + tbl[logical_track] = ftell(*f); + } + + if (tbl[logical_track]) { + fseek(*f, tbl[logical_track], SEEK_SET); + d86f_write_track(drive, f, side, d86f_handler[drive].encoded_data(drive, side), dev->track_surface_data[side]); + } + } + } + + fdd_set_head(drive, fdd_side); +} + + +void +d86f_writeback(int drive) +{ + d86f_t *dev = d86f[drive]; + uint8_t header[32]; + int header_size; +#ifdef D86F_COMPRESS + uint32_t len; + int ret = 0; + FILE *cf; +#endif + header_size = d86f_header_size(drive); + + if (! dev->f) return; + + /* First write the track offsets table. */ + fseek(dev->f, 0, SEEK_SET); + fread(header, 1, header_size, dev->f); + + fseek(dev->f, 8, SEEK_SET); + fwrite(dev->track_offset, 1, d86f_get_track_table_size(drive), dev->f); + + d86f_write_tracks(drive, &dev->f, NULL); + +#ifdef D86F_COMPRESS + if (dev->is_compressed) { + /* The image is compressed. */ + + /* Open the original, compressed file. */ + cf = plat_fopen(dev->original_file_name, L"wb"); + + /* Write the header to the original file. */ + fwrite(header, 1, header_size, cf); + + fseek(dev->f, 0, SEEK_END); + len = ftell(dev->f); + len -= header_size; + + fseek(dev->f, header_size, SEEK_SET); + + /* Compress data from the temporary uncompressed file to the original, compressed file. */ + dev->filebuf = (uint8_t *) malloc(len); + dev->outbuf = (uint8_t *) malloc(len - 1); + fread(dev->filebuf, 1, len, dev->f); + ret = lzf_compress(dev->filebuf, len, dev->outbuf, len - 1); + + if (! ret) + d86f_log("86F: Error compressing file\n"); + + fwrite(dev->outbuf, 1, ret, cf); + free(dev->outbuf); + free(dev->filebuf); + } +#endif +} + + +void +d86f_stop(int drive) +{ + d86f_t *dev = d86f[drive]; + + if (dev) + dev->state = STATE_IDLE; +} + + +int +d86f_common_command(int drive, int sector, int track, int side, int rate, int sector_size) +{ + d86f_t *dev = d86f[drive]; + + d86f_log("d86f_common_command (drive %i): fdc_period=%i img_period=%i rate=%i sector=%i track=%i side=%i\n", drive, fdc_get_bitcell_period(d86f_fdc), d86f_get_bitcell_period(drive), rate, sector, track, side); + + dev->req_sector.id.c = track; + dev->req_sector.id.h = side; + if (sector == SECTOR_FIRST) { + dev->req_sector.id.r = 1; + } else if (sector == SECTOR_NEXT) { + dev->req_sector.id.r++; + } else { + dev->req_sector.id.r = sector; + } + dev->req_sector.id.n = sector_size; + + if (fdd_get_head(drive) && (d86f_get_sides(drive) == 1)) { + fdc_noidam(d86f_fdc); + dev->state = STATE_IDLE; + dev->index_count = 0; + return 0; + } + + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->index_count = dev->error_condition = dev->satisfying_bytes = 0; + dev->id_found = 0; + dev->dma_over = 0; + + return 1; +} + + +void +d86f_readsector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + d86f_t *dev = d86f[drive]; + int ret = 0; + + ret = d86f_common_command(drive, sector, track, side, rate, sector_size); + if (! ret) + return; + + if (sector == SECTOR_FIRST) + dev->state = STATE_02_SPIN_TO_INDEX; + else if (sector == SECTOR_NEXT) + dev->state = STATE_02_FIND_ID; + else + dev->state = fdc_is_deleted(d86f_fdc) ? STATE_0C_FIND_ID : (fdc_is_verify(d86f_fdc) ? STATE_16_FIND_ID : STATE_06_FIND_ID); +} + + +void +d86f_writesector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + d86f_t *dev = d86f[drive]; + int ret = 0; + + if (writeprot[drive]) { + fdc_writeprotect(d86f_fdc); + dev->state = STATE_IDLE; + dev->index_count = 0; + return; + } + + ret = d86f_common_command(drive, sector, track, side, rate, sector_size); + if (! ret) return; + + dev->state = fdc_is_deleted(d86f_fdc) ? STATE_09_FIND_ID : STATE_05_FIND_ID; +} + + +void +d86f_comparesector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + d86f_t *dev = d86f[drive]; + int ret = 0; + + ret = d86f_common_command(drive, sector, track, side, rate, sector_size); + if (! ret) return; + + dev->state = STATE_11_FIND_ID; +} + + +void +d86f_readaddress(int drive, int side, int rate) +{ + d86f_t *dev = d86f[drive]; + + if (fdd_get_head(drive) && (d86f_get_sides(drive) == 1)) { + fdc_noidam(d86f_fdc); + dev->state = STATE_IDLE; + dev->index_count = 0; + return; + } + + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->index_count = dev->error_condition = dev->satisfying_bytes = 0; + dev->id_found = 0; + dev->dma_over = 0; + + dev->state = STATE_0A_FIND_ID; +} + + +void +d86f_add_track(int drive, int track, int side) +{ + d86f_t *dev = d86f[drive]; + uint32_t array_size; + int logical_track; + + array_size = d86f_get_array_size(drive, side, 0); + + if (d86f_get_sides(drive) == 2) { + logical_track = (track << 1) + side; + } else { + if (side) + return; + logical_track = track; + } + + if (! dev->track_offset[logical_track]) { + /* Track is absent from the file, let's add it. */ + dev->track_offset[logical_track] = dev->file_size; + + dev->file_size += (array_size + 6); + if (d86f_has_extra_bit_cells(drive)) + dev->file_size += 4; + if (d86f_has_surface_desc(drive)) + dev->file_size += array_size; + } +} + + +void +d86f_common_format(int drive, int side, int rate, uint8_t fill, int proxy) +{ + d86f_t *dev = d86f[drive]; + uint32_t i = 0; + uint16_t temp, temp2; + uint32_t array_size; + + if (writeprot[drive]) { + fdc_writeprotect(d86f_fdc); + dev->state = STATE_IDLE; + dev->index_count = 0; + return; + } + + if (! d86f_can_format(drive)) { + fdc_cannotformat(d86f_fdc); + dev->state = STATE_IDLE; + dev->index_count = 0; + return; + } + + if (!side || (d86f_get_sides(drive) == 2)) { + if (! proxy) { + d86f_reset_index_hole_pos(drive, side); + + if (dev->cur_track > 256) { + fdc_writeprotect(d86f_fdc); + dev->state = STATE_IDLE; + dev->index_count = 0; + return; + } + + array_size = d86f_get_array_size(drive, side, 0); + + if (d86f_has_surface_desc(drive)) { + /* Preserve the physical holes but get rid of the fuzzy bytes. */ + for (i = 0; i < array_size; i++) { + temp = dev->track_encoded_data[side][i] ^ 0xffff; + temp2 = dev->track_surface_data[side][i]; + temp &= temp2; + dev->track_surface_data[side][i] = temp; + } + } + + /* Zero the data buffer. */ + memset(dev->track_encoded_data[side], 0, array_size); + + d86f_add_track(drive, dev->cur_track, side); + if (! fdd_doublestep_40(drive)) + d86f_add_track(drive, dev->cur_track + 1, side); + } + } + + dev->fill = fill; + + if (! proxy) { + dev->side_flags[side] = 0; + dev->side_flags[side] |= (fdd_getrpm(real_drive(d86f_fdc, drive)) == 360) ? 0x20 : 0; + dev->side_flags[side] |= fdc_get_bit_rate(d86f_fdc); + dev->side_flags[side] |= fdc_is_mfm(d86f_fdc) ? 8 : 0; + + dev->index_hole_pos[side] = 0; + } + + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->index_count = dev->error_condition = dev->satisfying_bytes = dev->sector_count = 0; + dev->dma_over = 0; + + if (!side || (d86f_get_sides(drive) == 2)) + dev->state = STATE_0D_SPIN_TO_INDEX; + else + dev->state = STATE_0D_NOP_SPIN_TO_INDEX; +} + + +void +d86f_proxy_format(int drive, int side, int rate, uint8_t fill) +{ + d86f_common_format(drive, side, rate, fill, 1); +} + + +void +d86f_format(int drive, int side, int rate, uint8_t fill) +{ + d86f_common_format(drive, side, rate, fill, 0); +} + + +void +d86f_common_handlers(int drive) +{ + drives[drive].readsector = d86f_readsector; + drives[drive].writesector = d86f_writesector; + drives[drive].comparesector =d86f_comparesector; + drives[drive].readaddress = d86f_readaddress; + drives[drive].byteperiod = d86f_byteperiod; + drives[drive].poll = d86f_poll; + drives[drive].format = d86f_proxy_format; + drives[drive].stop = d86f_stop; +} + + +int +d86f_export(int drive, wchar_t *fn) +{ + uint32_t tt[512]; + d86f_t *dev = d86f[drive]; + d86f_t *temp86; + FILE *f; + int tracks = 86; + int i; + int inc = 1; + uint32_t magic = 0x46423638; + uint16_t version = 0x020C; + uint16_t disk_flags = d86f_handler[drive].disk_flags(drive); + + memset(tt, 0, 512 * sizeof(uint32_t)); + + f = plat_fopen(fn, L"wb"); + if (!f) + return 0; + + /* Allocate a temporary drive for conversion. */ + temp86 = (d86f_t *)malloc(sizeof(d86f_t)); + memcpy(temp86, dev, sizeof(d86f_t)); + + fwrite(&magic, 4, 1, f); + fwrite(&version, 2, 1, f); + fwrite(&disk_flags, 2, 1, f); + + fwrite(tt, 1, ((d86f_get_sides(drive) == 2) ? 2048 : 1024), f); + + /* In the case of a thick track drive, always increment track + by two, since two tracks are going to get output at once. */ + if (!fdd_doublestep_40(drive)) + inc = 2; + + for (i = 0; i < tracks; i += inc) { + if (inc == 2) + fdd_do_seek(drive, i >> 1); + else + fdd_do_seek(drive, i); + dev->cur_track = i; + d86f_write_tracks(drive, &f, tt); + } + + fclose(f); + + f = plat_fopen(fn, L"rb+"); + + fseek(f, 8, SEEK_SET); + fwrite(tt, 1, ((d86f_get_sides(drive) == 2) ? 2048 : 1024), f); + + fclose(f); + + fdd_do_seek(drive, fdd_current_track(drive)); + + /* Restore the drive from temp. */ + memcpy(dev, temp86, sizeof(d86f_t)); + free(temp86); + + return 1; +} + + +void +d86f_load(int drive, wchar_t *fn) +{ + d86f_t *dev = d86f[drive]; + uint32_t magic = 0; + uint32_t len = 0; + int i = 0, j = 0; +#ifdef D86F_COMPRESS + wchar_t temp_file_name[2048]; + uint16_t temp = 0; + FILE *tf; +#endif + + d86f_unregister(drive); + + writeprot[drive] = 0; + + dev->f = plat_fopen(fn, L"rb+"); + if (! dev->f) { + dev->f = plat_fopen(fn, L"rb"); + if (! dev->f) { + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + writeprot[drive] = 1; + } + + if (ui_writeprot[drive]) { + writeprot[drive] = 1; + } + fwriteprot[drive] = writeprot[drive]; + + fseek(dev->f, 0, SEEK_END); + len = ftell(dev->f); + fseek(dev->f, 0, SEEK_SET); + + fread(&magic, 4, 1, dev->f); + + if (len < 16) { + /* File is WAY too small, abort. */ + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + + if ((magic != 0x46423638) && (magic != 0x66623638)) { + /* File is not of the valid format, abort. */ + d86f_log("86F: Unrecognized magic bytes: %08X\n", magic); + fclose(dev->f); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + + fread(&(dev->version), 2, 1, dev->f); + if (dev->version != D86FVER) { + /* File is not of a recognized format version, abort. */ + if (dev->version == 0x0063) { + d86f_log("86F: File has emulator-internal version 0.99, this version is not valid in a file\n"); + } else if ((dev->version >= 0x0100) && (dev->version < D86FVER)) { + d86f_log("86F: No longer supported development file version: %i.%02i\n", dev->version >> 8, dev->version & 0xff); + } else { + d86f_log("86F: Unrecognized file version: %i.%02i\n", dev->version >> 8, dev->version & 0xff); + } + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } else { + d86f_log("86F: Recognized file version: %i.%02i\n", dev->version >> 8, dev->version & 0xff); + } + + fread(&(dev->disk_flags), 2, 1, dev->f); + + if (d86f_has_surface_desc(drive)) { + for (i = 0; i < 2; i++) + dev->track_surface_data[i] = (uint16_t *) malloc(53048 * sizeof(uint16_t)); + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) + dev->thin_track_surface_data[i][j] = (uint16_t *) malloc(53048 * sizeof(uint16_t)); + } + } + +#ifdef D86F_COMPRESS + dev->is_compressed = (magic == 0x66623638) ? 1 : 0; + if ((len < 51052) && !dev->is_compressed) { +#else + if (len < 51052) { +#endif + /* File too small, abort. */ + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + +#ifdef DO_CRC64 + fseek(dev->f, 8, SEEK_SET); + fread(&read_crc64, 1, 8, dev->f); + + fseek(dev->f, 0, SEEK_SET); + + crc64 = 0xffffffffffffffff; + + dev->filebuf = malloc(len); + fread(dev->filebuf, 1, len, dev->f); + *(uint64_t *) &(dev->filebuf[8]) = 0xffffffffffffffff; + crc64 = (uint64_t) crc64speed(0, dev->filebuf, len); + free(dev->filebuf); + + if (crc64 != read_crc64) { + d86f_log("86F: CRC64 error\n"); + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } +#endif + +#ifdef D86F_COMPRESS + if (dev->is_compressed) { + memcpy(temp_file_name, drive ? nvr_path(L"TEMP$$$1.$$$") : nvr_path(L"TEMP$$$0.$$$"), 256); + memcpy(dev->original_file_name, fn, (wcslen(fn) << 1) + 2); + + fclose(dev->f); + dev->f = NULL; + + dev->f = plat_fopen(temp_file_name, L"wb"); + if (! dev->f) { + d86f_log("86F: Unable to create temporary decompressed file\n"); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + + tf = plat_fopen(fn, L"rb"); + + for (i = 0; i < 8; i++) { + fread(&temp, 1, 2, tf); + fwrite(&temp, 1, 2, dev->f); + } + + dev->filebuf = (uint8_t *) malloc(len); + dev->outbuf = (uint8_t *) malloc(67108864); + fread(dev->filebuf, 1, len, tf); + temp = lzf_decompress(dev->filebuf, len, dev->outbuf, 67108864); + if (temp) { + fwrite(dev->outbuf, 1, temp, dev->f); + } + free(dev->outbuf); + free(dev->filebuf); + + fclose(tf); + fclose(dev->f); + dev->f = NULL; + + if (! temp) { + d86f_log("86F: Error decompressing file\n"); + plat_remove(temp_file_name); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + + dev->f = plat_fopen(temp_file_name, L"rb+"); + } +#endif + + if (dev->disk_flags & 0x100) { + /* Zoned disk. */ + d86f_log("86F: Disk is zoned (Apple or Sony)\n"); + fclose(dev->f); + dev->f = NULL; +#ifdef D86F_COMPRESS + if (dev->is_compressed) + plat_remove(temp_file_name); +#endif + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + + if (dev->disk_flags & 0x600) { + /* Zone type is not 0 but the disk is fixed-RPM. */ + d86f_log("86F: Disk is fixed-RPM but zone type is not 0\n"); + fclose(dev->f); + dev->f = NULL; +#ifdef D86F_COMPRESS + if (dev->is_compressed) + plat_remove(temp_file_name); +#endif + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + + if (!writeprot[drive]) { + writeprot[drive] = (dev->disk_flags & 0x10) ? 1 : 0; + fwriteprot[drive] = writeprot[drive]; + } + + if (writeprot[drive]) { + fclose(dev->f); + dev->f = NULL; + +#ifdef D86F_COMPRESS + if (dev->is_compressed) + dev->f = plat_fopen(temp_file_name, L"rb"); + else +#endif + dev->f = plat_fopen(fn, L"rb"); + } + + /* OK, set the drive data, other code needs it. */ + d86f[drive] = dev; + + fseek(dev->f, 8, SEEK_SET); + + fread(dev->track_offset, 1, d86f_get_track_table_size(drive), dev->f); + + if (! (dev->track_offset[0])) { + /* File has no track 0 side 0, abort. */ + d86f_log("86F: No Track 0 side 0\n"); + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + d86f[drive] = NULL; + return; + } + + if ((d86f_get_sides(drive) == 2) && !(dev->track_offset[1])) { + /* File is 2-sided but has no track 0 side 1, abort. */ + d86f_log("86F: No Track 0 side 1\n"); + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + d86f[drive] = NULL; + return; + } + + /* 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 (dev->disk_flags & 0x80) { + fread(&(dev->extra_bit_cells[0]), 4, 1, dev->f); + if ((dev->disk_flags & 0x1060) != 0x1000) { + if (dev->extra_bit_cells[0] < -32768) dev->extra_bit_cells[0] = -32768; + if (dev->extra_bit_cells[0] > 32768) dev->extra_bit_cells[0] = 32768; + } + } else { + dev->extra_bit_cells[0] = 0; + } + + 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 (dev->disk_flags & 0x80) { + fread(&(dev->extra_bit_cells[1]), 4, 1, dev->f); + if ((dev->disk_flags & 0x1060) != 0x1000) { + if (dev->extra_bit_cells[1] < -32768) dev->extra_bit_cells[1] = -32768; + if (dev->extra_bit_cells[1] > 32768) dev->extra_bit_cells[1] = 32768; + } + } else { + dev->extra_bit_cells[0] = 0; + } + } else { + switch ((dev->disk_flags >> 1) >> 3) { + case 0: + default: + dev->side_flags[1] = 0x0a; + break; + + case 1: + dev->side_flags[1] = 0x00; + break; + + case 2: + case 3: + dev->side_flags[1] = 0x03; + break; + } + + dev->extra_bit_cells[1] = 0; + } + + fseek(dev->f, 0, SEEK_END); + dev->file_size = ftell(dev->f); + + fseek(dev->f, 0, SEEK_SET); + + d86f_register_86f(drive); + + drives[drive].seek = d86f_seek; + d86f_common_handlers(drive); + drives[drive].format = d86f_format; + +#ifdef D86F_COMPRESS + d86f_log("86F: Disk is %scompressed and does%s have surface description data\n", + dev->is_compressed ? "" : "not ", + d86f_has_surface_desc(drive) ? "" : " not"); +#else + d86f_log("86F: Disk does%s have surface description data\n", + d86f_has_surface_desc(drive) ? "" : " not"); +#endif +} + + +void +d86f_init(void) +{ + int i; + + setup_crc(0x1021); + + for (i = 0; i < FDD_NUM; i++) + d86f[i] = NULL; +} + + +void +d86f_set_fdc(void *fdc) +{ + d86f_fdc = (fdc_t *) fdc; +} + + +void +d86f_close(int drive) +{ + int i, j; + + wchar_t temp_file_name[2048]; + d86f_t *dev = d86f[drive]; + + /* Make sure the drive is alive. */ + if (dev == NULL) return; + + memcpy(temp_file_name, drive ? nvr_path(L"TEMP$$$1.$$$") : nvr_path(L"TEMP$$$0.$$$"), 26); + + if (d86f_has_surface_desc(drive)) { + for (i = 0; i < 2; i++) { + if (dev->track_surface_data[i]) { + free(dev->track_surface_data[i]); + dev->track_surface_data[i] = NULL; + } + } + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + if (dev->thin_track_surface_data[i][j]) { + free(dev->thin_track_surface_data[i][j]); + dev->thin_track_surface_data[i][j] = NULL; + } + } + } + } + + if (dev->f) { + fclose(dev->f); + dev->f = NULL; + } +#ifdef D86F_COMPRESS + if (dev->is_compressed) + plat_remove(temp_file_name); +#endif +} + + +/* When an FDD is mounted, set up the D86F data structures. */ +void +d86f_setup(int drive) +{ + d86f_t *dev; + + /* Allocate a drive structure. */ + dev = (d86f_t *)malloc(sizeof(d86f_t)); + memset(dev, 0x00, sizeof(d86f_t)); + dev->state = STATE_IDLE; + + dev->last_side_sector[0] = NULL; + dev->last_side_sector[1] = NULL; + + /* Set the drive as active. */ + d86f[drive] = dev; +} + + +/* If an FDD is unmounted, unlink the D86F data structures. */ +void +d86f_destroy(int drive) +{ + int i, j; + + d86f_t *dev = d86f[drive]; + + if (dev == NULL) return; + + if (d86f_has_surface_desc(drive)) { + for (i = 0; i < 2; i++) { + if (dev->track_surface_data[i]) { + free(dev->track_surface_data[i]); + dev->track_surface_data[i] = NULL; + } + } + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + if (dev->thin_track_surface_data[i][j]) { + free(dev->thin_track_surface_data[i][j]); + dev->thin_track_surface_data[i][j] = NULL; + } + } + } + } + + d86f_destroy_linked_lists(drive, 0); + d86f_destroy_linked_lists(drive, 1); + + free(d86f[drive]); + d86f[drive] = NULL; +} diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index 55ba012cc..f456272a0 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -45,6 +45,7 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../dma.h" #include "../nvr.h" #include "../random.h" @@ -534,6 +535,7 @@ common_get_raw_size(int drive, int side) double size = 100000.0; int mfm; int rm, ssd; + uint32_t extra_bc = 0; mfm = d86f_is_mfm(drive); rpm = ((d86f_track_flags(drive) & 0xE0) == 0x20) ? 360.0 : 300.0; @@ -541,6 +543,13 @@ common_get_raw_size(int drive, int side) rm = d86f_get_rpm_mode(drive); ssd = d86f_get_speed_shift_dir(drive); + /* 0% speed shift and shift direction 1: special case where extra bit cells are the entire track size. */ + if (!rm && ssd) + extra_bc = d86f_handler[drive].extra_bit_cells(drive, side); + + if (extra_bc) + return extra_bc; + switch (rm) { case 1: rpm_diff = 1.01; @@ -590,13 +599,9 @@ common_get_raw_size(int drive, int side) if (! mfm) rate /= 2.0; - if (!rm && ssd) - size = 0.0; - else { - size = (size / 250.0) * rate; - size = (size * 300.0) / rpm; - size *= rpm_diff; - } + size = (size / 250.0) * rate; + size = (size * 300.0) / rpm; + size *= rpm_diff; /* * Round down to a multiple of 16 and add the extra bit cells, @@ -658,7 +663,7 @@ d86f_register_86f(int drive) int -d86f_get_array_size(int drive, int side) +d86f_get_array_size(int drive, int side, int words) { int array_size; int hole, rm; @@ -736,10 +741,14 @@ d86f_get_array_size(int drive, int side) array_size <<= 4; array_size += d86f_handler[drive].extra_bit_cells(drive, side); - array_size >>= 4; - if (d86f_handler[drive].extra_bit_cells(drive, side) & 15) - array_size++; + if (array_size & 15) + array_size = (array_size >> 4) + 1; + else + array_size = (array_size >> 4); + + if (!words) + array_size <<= 1; return array_size; } @@ -795,37 +804,39 @@ d86f_get_encoding(int drive) } -double +uint64_t d86f_byteperiod(int drive) { + double dusec = (double) TIMER_USEC; + double p = 2.0; + switch (d86f_track_flags(drive) & 0x0f) { case 0x02: /* 125 kbps, FM */ - return 4.0; - + p = 4.0; + break; case 0x01: /* 150 kbps, FM */ - return 20.0 / 6.0; - + p = 20.0 / 6.0; + break; case 0x0a: /* 250 kbps, MFM */ case 0x00: /* 250 kbps, FM */ - return 2.0; - - case 0x09: /* 300 kbps, MFM */ - return 10.0 / 6.0; - - case 0x08: /* 500 kbps, MFM */ - return 1.0; - - case 0x0b: /* 1000 kbps, MFM */ - return 0.5; - - case 0x0d: /* 2000 kbps, MFM */ - return 0.25; - default: + p = 2.0; + break; + case 0x09: /* 300 kbps, MFM */ + p = 10.0 / 6.0; + break; + case 0x08: /* 500 kbps, MFM */ + p = 1.0; + break; + case 0x0b: /* 1000 kbps, MFM */ + p = 0.5; + break; + case 0x0d: /* 2000 kbps, MFM */ + p = 0.25; break; } - return 2.0; + return (uint64_t) (p * dusec); } @@ -1592,7 +1603,14 @@ d86f_read_sector_data(int drive, int side) /* We've got a byte. */ d86f_log("86F: We've got a byte.\n"); if (dev->data_find.bytes_obtained < sector_len) { - data = decodefm(drive, dev->last_word[side]); +#ifdef HACK_FOR_DBASE_III + if ((dev->last_sector.id.c == 39) && (dev->last_sector.id.h == 0) && + (dev->last_sector.id.r == 5) && (dev->data_find.bytes_obtained >= 272)) { + pclog("Randomly generating sector 39,0,5 byte %i...\n", dev->data_find.bytes_obtained); + data = (random_generate() & 0xff); + } else +#endif + data = decodefm(drive, dev->last_word[side]); if (dev->state == STATE_11_SCAN_DATA) { /* Scan/compare command. */ recv_data = d86f_get_data(drive, 0); @@ -2618,7 +2636,11 @@ d86f_prepare_pretrack(int drive, int side, int iso) sync_len = mfm ? 12 : 6; real_gap1_len = mfm ? 50 : 26; gap_fill = mfm ? 0x4E : 0xFF; - raw_size = d86f_handler[drive].get_raw_size(drive, side) >> 4; + raw_size = d86f_handler[drive].get_raw_size(drive, side); + if (raw_size & 15) + raw_size = (raw_size >> 4) + 1; + else + raw_size = (raw_size >> 4); dev->index_hole_pos[side] = 0; @@ -2694,7 +2716,11 @@ d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t mfm = d86f_is_mfm(drive); gap_fill = mfm ? 0x4E : 0xFF; - raw_size = d86f_handler[drive].get_raw_size(drive, side) >> 4; + raw_size = d86f_handler[drive].get_raw_size(drive, side); + if (raw_size & 15) + raw_size = (raw_size >> 4) + 1; + else + raw_size = (raw_size >> 4); pos = prev_pos; @@ -2800,7 +2826,7 @@ d86f_construct_encoded_buffer(int drive, int side) uint16_t *src1_s = dev->thin_track_surface_data[0][side]; uint16_t *src2 = dev->thin_track_encoded_data[1][side]; uint16_t *src2_s = dev->thin_track_surface_data[1][side]; - len = d86f_get_array_size(drive, side); + len = d86f_get_array_size(drive, side, 1); for (i = 0; i < len; i++) { /* The two bits differ. */ @@ -2847,7 +2873,7 @@ d86f_decompose_encoded_buffer(int drive, int side) uint16_t *src2 = dev->thin_track_encoded_data[1][side]; uint16_t *src2_s = dev->thin_track_surface_data[1][side]; dst = d86f_handler[drive].encoded_data(drive, side); - len = d86f_get_array_size(drive, side); + len = d86f_get_array_size(drive, side, 1); for (i = 0; i < len; i++) { if (d86f_has_surface_desc(drive)) { @@ -2909,7 +2935,7 @@ d86f_read_track(int drive, int track, int thin_track, int side, uint16_t *da, ui fread(&(dev->index_hole_pos[side]), 4, 1, dev->f); } else fseek(dev->f, dev->track_offset[logical_track] + d86f_track_header_size(drive), SEEK_SET); - array_size = d86f_get_array_size(drive, side) << 1; + array_size = d86f_get_array_size(drive, side, 0); if (d86f_has_surface_desc(drive)) fread(sa, 1, array_size, dev->f); fread(da, 1, array_size, dev->f); @@ -2995,6 +3021,7 @@ d86f_seek(int drive, int track) void d86f_write_track(int drive, FILE **f, int side, uint16_t *da0, uint16_t *sa0) { + uint32_t array_size = d86f_get_array_size(drive, side, 0); uint16_t side_flags = d86f_handler[drive].side_flags(drive); uint32_t extra_bit_cells = d86f_handler[drive].extra_bit_cells(drive, side); uint32_t index_hole_pos = d86f_handler[drive].index_hole_pos(drive, side); @@ -3007,9 +3034,9 @@ d86f_write_track(int drive, FILE **f, int side, uint16_t *da0, uint16_t *sa0) fwrite(&index_hole_pos, 1, 4, *f); if (d86f_has_surface_desc(drive)) - fwrite(sa0, 1, d86f_get_array_size(drive, side) << 1, *f); + fwrite(sa0, 1, array_size, *f); - fwrite(da0, 1, d86f_get_array_size(drive, side) << 1, *f); + fwrite(da0, 1, array_size, *f); } @@ -3049,7 +3076,7 @@ d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) if (track_table) tbl = track_table; - if (! fdd_doublestep_40(drive)) { + if (!fdd_doublestep_40(drive)) { d86f_decompose_encoded_buffer(drive, 0); if (sides == 2) d86f_decompose_encoded_buffer(drive, 1); @@ -3281,8 +3308,7 @@ d86f_add_track(int drive, int track, int side) uint32_t array_size; int logical_track; - array_size = d86f_get_array_size(drive, side); - array_size <<= 1; + array_size = d86f_get_array_size(drive, side, 0); if (d86f_get_sides(drive) == 2) { logical_track = (track << 1) + side; @@ -3338,7 +3364,7 @@ d86f_common_format(int drive, int side, int rate, uint8_t fill, int proxy) return; } - array_size = d86f_get_array_size(drive, side); + array_size = d86f_get_array_size(drive, side, 0); if (d86f_has_surface_desc(drive)) { /* Preserve the physical holes but get rid of the fuzzy bytes. */ @@ -3351,7 +3377,7 @@ d86f_common_format(int drive, int side, int rate, uint8_t fill, int proxy) } /* Zero the data buffer. */ - memset(dev->track_encoded_data[side], 0, array_size << 1); + memset(dev->track_encoded_data[side], 0, array_size); d86f_add_track(drive, dev->cur_track, side); if (! fdd_doublestep_40(drive)) @@ -3727,8 +3753,10 @@ d86f_load(int drive, wchar_t *fn) fread(&(dev->side_flags[0]), 2, 1, dev->f); if (dev->disk_flags & 0x80) { fread(&(dev->extra_bit_cells[0]), 4, 1, dev->f); - if (dev->extra_bit_cells[0] < -32768) dev->extra_bit_cells[0] = -32768; - if (dev->extra_bit_cells[0] > 32768) dev->extra_bit_cells[0] = 32768; + if ((dev->disk_flags & 0x1060) != 0x1000) { + if (dev->extra_bit_cells[0] < -32768) dev->extra_bit_cells[0] = -32768; + if (dev->extra_bit_cells[0] > 32768) dev->extra_bit_cells[0] = 32768; + } } else { dev->extra_bit_cells[0] = 0; } @@ -3738,8 +3766,10 @@ d86f_load(int drive, wchar_t *fn) fread(&(dev->side_flags[1]), 2, 1, dev->f); if (dev->disk_flags & 0x80) { fread(&(dev->extra_bit_cells[1]), 4, 1, dev->f); - if (dev->extra_bit_cells[1] < -32768) dev->extra_bit_cells[1] = -32768; - if (dev->extra_bit_cells[1] > 32768) dev->extra_bit_cells[1] = 32768; + if ((dev->disk_flags & 0x1060) != 0x1000) { + if (dev->extra_bit_cells[1] < -32768) dev->extra_bit_cells[1] = -32768; + if (dev->extra_bit_cells[1] > 32768) dev->extra_bit_cells[1] = 32768; + } } else { dev->extra_bit_cells[0] = 0; } diff --git a/src/floppy/fdd_86f.h b/src/floppy/fdd_86f.h index 394918580..dca663d1d 100644 --- a/src/floppy/fdd_86f.h +++ b/src/floppy/fdd_86f.h @@ -46,7 +46,7 @@ extern void d86f_load(int drive, wchar_t *fn); extern void d86f_close(int drive); extern void d86f_seek(int drive, int track); extern int d86f_hole(int drive); -extern double d86f_byteperiod(int drive); +extern uint64_t d86f_byteperiod(int drive); extern void d86f_stop(int drive); extern void d86f_poll(int drive); extern int d86f_realtrack(int track, int drive); diff --git a/src/floppy/fdd_common.c b/src/floppy/fdd_common.c index 5638b0565..d8a385021 100644 --- a/src/floppy/fdd_common.c +++ b/src/floppy/fdd_common.c @@ -38,6 +38,7 @@ #include #include #include "../86box.h" +#include "../timer.h" #include "fdd.h" #include "fdd_common.h" diff --git a/src/floppy/fdd_fdi.c b/src/floppy/fdd_fdi.c index df3cdbe21..614a415bf 100644 --- a/src/floppy/fdd_fdi.c +++ b/src/floppy/fdd_fdi.c @@ -45,6 +45,7 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../plat.h" #include "fdd.h" #include "fdd_86f.h" diff --git a/src/floppy/fdd_imd.c b/src/floppy/fdd_imd.c index 81fdd5783..0ed9bf1ac 100644 --- a/src/floppy/fdd_imd.c +++ b/src/floppy/fdd_imd.c @@ -42,6 +42,7 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../plat.h" #include "fdd.h" #include "fdd_imd.h" diff --git a/src/floppy/fdd_img.c b/src/floppy/fdd_img.c index 4e9e56f16..66a18a4cc 100644 --- a/src/floppy/fdd_img.c +++ b/src/floppy/fdd_img.c @@ -49,6 +49,7 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../config.h" #include "../plat.h" #include "fdd.h" @@ -620,6 +621,16 @@ img_init(void) } +int +is_divisible(uint16_t total, uint8_t what) +{ + if ((total != 0) && (what != 0)) + return ((total % what) == 0); + else + return 0; +} + + void img_load(int drive, wchar_t *fn) { @@ -968,10 +979,13 @@ jump_if_fdf: img_log("BPB reports %i sides and %i bytes per sector (%i sectors total)\n", bpb_sides, bpb_bps, bpb_total); - guess = (bpb_sides < 1); - guess = guess || (bpb_sides > 2); - guess = guess || !bps_is_valid(bpb_bps); - guess = guess || !first_byte_is_valid(first_byte); + /* Invalid conditions: */ + guess = (bpb_sides < 1); /* Sides < 1; */ + guess = guess || (bpb_sides > 2); /* Sides > 2; */ + guess = guess || !bps_is_valid(bpb_bps); /* Invalid number of bytes per sector; */ + guess = guess || !first_byte_is_valid(first_byte); /* Invalid first bytes; */ + guess = guess || !is_divisible(bpb_total, bpb_sectors); /* Total sectors not divisible by sectors per track; */ + guess = guess || !is_divisible(bpb_total, bpb_sides); /* Total sectors not divisible by sides. */ guess = guess || !fdd_get_check_bpb(drive); guess = guess && !fdi; guess = guess && !cqm; diff --git a/src/floppy/fdd_json.c b/src/floppy/fdd_json.c index e806b068d..c27bd5229 100644 --- a/src/floppy/fdd_json.c +++ b/src/floppy/fdd_json.c @@ -52,6 +52,7 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../plat.h" #include "fdd.h" #include "fdc.h" diff --git a/src/floppy/fdd_mfm.c b/src/floppy/fdd_mfm.c index 45aca2469..25d77fc67 100644 --- a/src/floppy/fdd_mfm.c +++ b/src/floppy/fdd_mfm.c @@ -8,11 +8,11 @@ * * Implementation of the HxC MFM image format. * - * Version: @(#)fdd_mfm.c 1.0.0 2018/11/12 + * Version: @(#)fdd_mfm.c 1.0.1 2019/03/02 * * Authors: Miran Grca, * - * Copyright 2018 Miran Grca. + * Copyright 2018,2019 Miran Grca. */ #include #include @@ -23,6 +23,7 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../plat.h" #include "fdd.h" #include "fdd_86f.h" @@ -69,6 +70,9 @@ typedef struct { mfm_track_t *tracks; mfm_adv_track_t *adv_tracks; + uint16_t disk_flags, pad; + uint16_t side_flags[2]; + int br_rounded, rpm_rounded, total_tracks, cur_track; @@ -101,15 +105,81 @@ mfm_log(const char *fmt, ...) #endif -static uint16_t -disk_flags(int drive) +static int +get_track_index(int drive, int side, int track) { + mfm_t *dev = mfm[drive]; + int i, ret = -1; + + for (i = 0; i < dev->total_tracks; i++) { + if ((dev->tracks[i].track_no == track) && + (dev->tracks[i].side_no == side)) { + ret = i; + break; + } + } + + return ret; +} + + +static int +get_adv_track_index(int drive, int side, int track) +{ + mfm_t *dev = mfm[drive]; + int i, ret = -1; + + for (i = 0; i < dev->total_tracks; i++) { + if ((dev->adv_tracks[i].track_no == track) && + (dev->adv_tracks[i].side_no == side)) { + ret = i; + break; + } + } + + return ret; +} + + +static void +get_adv_track_bitrate(int drive, int side, int track, int *br, int *rpm) +{ + mfm_t *dev = mfm[drive]; + int track_index; + double dbr; + + track_index = get_adv_track_index(drive, side, track); + + if (track_index == -1) { + *br = 250; + *rpm = 300; + } else { + dbr = round(((double) dev->adv_tracks[track_index].bit_rate) / 50.0) * 50.0; + *br = ((int) dbr); + dbr = round(((double) dev->adv_tracks[track_index].rpm) / 60.0) * 60.0; + *rpm = ((int) dbr); + } +} + + +static void +set_disk_flags(int drive) +{ + int br = 250, rpm = 300; mfm_t *dev = mfm[drive]; uint16_t temp_disk_flags = 0x1080; /* We ALWAYS claim to have extra bit cells, even if the actual amount is 0; Bit 12 = 1, bits 6, 5 = 0 - extra bit cells field specifies the entire amount of bit cells per track. */ - switch (dev->br_rounded) { + /* If this is the modified MFM format, get bit rate (and RPM) from track 0 instead. */ + if (dev->hdr.if_type & 0x80) + get_adv_track_bitrate(drive, 0, 0, &br, &rpm); + else { + br = dev->br_rounded; + rpm = dev->rpm_rounded; + } + + switch (br) { case 500: temp_disk_flags |= 2; break; @@ -128,84 +198,35 @@ disk_flags(int drive) if (dev->hdr.sides_no == 2) temp_disk_flags |= 8; - return(temp_disk_flags); -} - - -static int -get_track_index(int drive, int side) -{ - mfm_t *dev = mfm[drive]; - int i, ret = -1; - - for (i = 0; i < dev->total_tracks; i++) { - if ((dev->tracks[i].track_no == dev->cur_track) && - (dev->tracks[i].side_no == side)) { - ret = i; - break; - } - } - - return ret; -} - - -static int -get_adv_track_index(int drive, int side) -{ - mfm_t *dev = mfm[drive]; - int i, ret = -1; - - for (i = 0; i < dev->total_tracks; i++) { - if ((dev->adv_tracks[i].track_no == dev->cur_track) && - (dev->adv_tracks[i].side_no == side)) { - ret = i; - break; - } - } - - return ret; -} - - -static void -get_adv_track_bitrate(int drive, int side, int *br, int *rpm) -{ - mfm_t *dev = mfm[drive]; - int track_index; - double dbr; - - track_index = get_adv_track_index(drive, side); - - if (track_index == -1) { - *br = 250; - *rpm = 300; - } else { - dbr = round(((double) dev->adv_tracks[track_index].bit_rate) / 50.0) * 50.0; - *br = ((int) dbr); - dbr = round(((double) dev->adv_tracks[track_index].rpm) / 60.0) * 60.0; - *rpm = ((int) dbr); - } + dev->disk_flags = temp_disk_flags; } static uint16_t -side_flags(int drive) +disk_flags(int drive) +{ + mfm_t *dev = mfm[drive]; + + return dev->disk_flags; +} + + +static void +set_side_flags(int drive, int side) { mfm_t *dev = mfm[drive]; uint16_t temp_side_flags = 0; - int side, br = 250, rpm = 300; + int br = 250, rpm = 300; - if (dev->hdr.if_type & 0x80) { - side = fdd_get_head(drive); - get_adv_track_bitrate(drive, side, &br, &rpm); - } else { + if (dev->hdr.if_type & 0x80) + get_adv_track_bitrate(drive, side, dev->cur_track, &br, &rpm); + else { br = dev->br_rounded; rpm = dev->rpm_rounded; } /* 300 kbps @ 360 rpm = 250 kbps @ 200 rpm */ - if ((rpm >= 352) && (rpm <= 367) && (br == 300)) { + if ((br == 300) && (rpm == 360)) { br = 250; rpm = 300; } @@ -229,7 +250,7 @@ side_flags(int drive) break; } - if ((rpm >= 352) && (rpm <= 367)) + if (rpm == 360) temp_side_flags |= 0x20; /* @@ -238,7 +259,19 @@ side_flags(int drive) */ temp_side_flags |= 0x08; - return(temp_side_flags); + dev->side_flags[side] = temp_side_flags; +} + + +static uint16_t +side_flags(int drive) +{ + mfm_t *dev = mfm[drive]; + int side; + + side = fdd_get_head(drive); + + return dev->side_flags[side]; } @@ -247,17 +280,32 @@ get_raw_size(int drive, int side) { mfm_t *dev = mfm[drive]; int track_index, is_300_rpm; + int br = 250, rpm = 300; - if (dev->hdr.if_type & 0x80) - track_index = get_adv_track_index(drive, side); - else - track_index = get_track_index(drive, side); + if (dev->hdr.if_type & 0x80) { + track_index = get_adv_track_index(drive, side, dev->cur_track); + get_adv_track_bitrate(drive, 0, 0, &br, &rpm); + } else { + track_index = get_track_index(drive, side, dev->cur_track); + br = dev->br_rounded; + rpm = dev->rpm_rounded; + } - is_300_rpm = (dev->hdr.rpm < 352); + is_300_rpm = (rpm == 300); if (track_index == -1) { mfm_log("MFM: Unable to find track (%i, %i)\n", dev->cur_track, side); - return is_300_rpm ? 100000 : 83333; + switch (br) { + case 250: + default: + return is_300_rpm ? 100000 : 83333; + case 300: + return is_300_rpm ? 120000 : 100000; + case 500: + return is_300_rpm ? 200000 : 166666; + case 1000: + return is_300_rpm ? 400000 : 333333; + } } /* Bit 7 on - my extension of the HxC MFM format to output exact bitcell counts @@ -293,9 +341,9 @@ mfm_read_side(int drive, int side) int track_bytes; if (dev->hdr.if_type & 0x80) - track_index = get_adv_track_index(drive, side); + track_index = get_adv_track_index(drive, side, dev->cur_track); else - track_index = get_track_index(drive, side); + track_index = get_track_index(drive, side, dev->cur_track); track_size = get_raw_size(drive, side); track_bytes = track_size >> 3; @@ -309,7 +357,7 @@ mfm_read_side(int drive, int side) 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_size, dev->f); + fread(dev->track_data[side], 1, track_bytes, dev->f); } mfm_log("drive = %i, side = %i, dev->cur_track = %i, track_index = %i, track_size = %i\n", @@ -340,6 +388,9 @@ mfm_seek(int drive, int track) mfm_read_side(drive, 0); mfm_read_side(drive, 1); + + set_side_flags(drive, 0); + set_side_flags(drive, 1); } @@ -403,16 +454,18 @@ mfm_load(int drive, wchar_t *fn) if (!(dev->hdr.if_type & 0x80)) { dbr = round(((double) dev->hdr.bit_rate) / 50.0) * 50.0; dev->br_rounded = (int) dbr; - mfm_log("Round bit rate: %i kbps\n", dev->br_rounded); + mfm_log("Rounded bit rate: %i kbps\n", dev->br_rounded); dbr = round(((double) dev->hdr.rpm) / 60.0) * 60.0; dev->rpm_rounded = (int) dbr; - mfm_log("Round RPM: %i kbps\n", dev->rpm_rounded); + mfm_log("Rounded RPM: %i kbps\n", dev->rpm_rounded); } /* Set up the drive unit. */ mfm[drive] = dev; + set_disk_flags(drive); + /* Attach this format to the D86F engine. */ d86f_handler[drive].disk_flags = disk_flags; d86f_handler[drive].side_flags = side_flags; diff --git a/src/floppy/fdd_td0.c b/src/floppy/fdd_td0.c index 1a5c64ad9..bc9d2b153 100644 --- a/src/floppy/fdd_td0.c +++ b/src/floppy/fdd_td0.c @@ -54,6 +54,7 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../plat.h" #include "fdd.h" #include "fdd_td0.h" diff --git a/src/game/gameport.c b/src/game/gameport.c index 53b9dac52..eb3eaf893 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -53,7 +53,7 @@ typedef struct { - int64_t count; + pc_timer_t timer; int axis_nr; struct _gameport_ *gameport; } g_axis_t; @@ -157,16 +157,17 @@ joystick_get_pov_name(int js, int id) } -static int -gameport_time(int axis) +static void +gameport_time(gameport_t *gameport, int nr, int axis) { - if (axis == AXIS_NOT_PRESENT) return(0); - - axis += 32768; - axis = (axis * 100) / 65; /*Axis now in ohms*/ - axis = (axis * 11) / 1000; - - return(TIMER_USEC * (axis + 24)); /*max = 11.115 ms*/ + if (axis == AXIS_NOT_PRESENT) + timer_disable(&gameport->axis[nr].timer); + else { + axis += 32768; + axis = (axis * 100) / 65; /*Axis now in ohms*/ + axis = (axis * 11) / 1000; + timer_set_delay_u64(&gameport->axis[nr].timer, TIMER_USEC * (axis + 24)); /*max = 11.115 ms*/ + } } @@ -175,17 +176,16 @@ gameport_write(uint16_t addr, uint8_t val, void *priv) { gameport_t *p = (gameport_t *)priv; - timer_clock(); p->state |= 0x0f; - p->axis[0].count = gameport_time(p->joystick->read_axis(p->joystick_dat, 0)); - p->axis[1].count = gameport_time(p->joystick->read_axis(p->joystick_dat, 1)); - p->axis[2].count = gameport_time(p->joystick->read_axis(p->joystick_dat, 2)); - p->axis[3].count = gameport_time(p->joystick->read_axis(p->joystick_dat, 3)); - + gameport_time(p, 0, p->joystick->read_axis(p->joystick_dat, 0)); + gameport_time(p, 1, p->joystick->read_axis(p->joystick_dat, 1)); + gameport_time(p, 2, p->joystick->read_axis(p->joystick_dat, 2)); + gameport_time(p, 3, p->joystick->read_axis(p->joystick_dat, 3)); + p->joystick->write(p->joystick_dat); - cycles -= ISA_CYCLES(8); + sub_cycles(ISA_CYCLES(8)); } @@ -195,10 +195,9 @@ gameport_read(uint16_t addr, void *priv) gameport_t *p = (gameport_t *)priv; uint8_t ret; - timer_clock(); ret = p->state | p->joystick->read(p->joystick_dat); - cycles -= ISA_CYCLES(8); + sub_cycles(ISA_CYCLES(8)); return(ret); } @@ -211,7 +210,6 @@ timer_over(void *priv) gameport_t *p = axis->gameport; p->state &= ~(1 << axis->axis_nr); - axis->count = 0; if (axis == &p->axis[0]) p->joystick->a0_over(p->joystick_dat); @@ -235,10 +233,10 @@ init_common(void) p->axis[2].axis_nr = 2; p->axis[3].axis_nr = 3; - timer_add(timer_over, &p->axis[0].count, &p->axis[0].count, &p->axis[0]); - timer_add(timer_over, &p->axis[1].count, &p->axis[1].count, &p->axis[1]); - timer_add(timer_over, &p->axis[2].count, &p->axis[2].count, &p->axis[2]); - timer_add(timer_over, &p->axis[3].count, &p->axis[3].count, &p->axis[3]); + timer_add(&p->axis[0].timer, timer_over, &p->axis[0], 0); + timer_add(&p->axis[1].timer, timer_over, &p->axis[1], 0); + timer_add(&p->axis[2].timer, timer_over, &p->axis[2], 0); + timer_add(&p->axis[3].timer, timer_over, &p->axis[3], 0); p->joystick = joystick_list[joystick_type]; p->joystick_dat = p->joystick->init(); diff --git a/src/game/joystick_sw_pad.c b/src/game/joystick_sw_pad.c index feec60593..09030d8ad 100644 --- a/src/game/joystick_sw_pad.c +++ b/src/game/joystick_sw_pad.c @@ -69,47 +69,41 @@ typedef struct { - int64_t poll_time; - int64_t poll_left; - int64_t poll_clock; + pc_timer_t poll_timer; + int poll_left; + int poll_clock; uint64_t poll_data; - int64_t poll_mode; + int poll_mode; - int64_t trigger_time; - int64_t data_mode; + pc_timer_t trigger_timer; + int data_mode; } sw_data; static void sw_timer_over(void *p) { sw_data *sw = (sw_data *)p; - while (sw->poll_time <= 0 && sw->poll_left) - { - sw->poll_clock = !sw->poll_clock; - - if (sw->poll_clock) - { - sw->poll_data >>= (sw->poll_mode ? 3 : 1); - sw->poll_left--; - } + sw->poll_clock = !sw->poll_clock; - if (sw->poll_left == 1 && !sw->poll_clock) - sw->poll_time += TIMER_USEC * 160LL; - else if (sw->poll_left) - sw->poll_time += TIMER_USEC * 5; - else - sw->poll_time = 0; - } - - if (!sw->poll_left) - sw->poll_time = 0; + if (sw->poll_clock) + { + sw->poll_data >>= (sw->poll_mode ? 3 : 1); + sw->poll_left--; + } + + if (sw->poll_left == 1 && !sw->poll_clock) + timer_advance_u64(&sw->poll_timer, TIMER_USEC * 160); + else if (sw->poll_left) + timer_advance_u64(&sw->poll_timer, TIMER_USEC * 5); + else + timer_disable(&sw->poll_timer); } static void sw_trigger_timer_over(void *p) { sw_data *sw = (sw_data *)p; - sw->trigger_time = 0; + timer_disable(&sw->trigger_timer); } static int sw_parity(uint16_t data) @@ -130,9 +124,9 @@ static void *sw_init(void) sw_data *sw = (sw_data *)malloc(sizeof(sw_data)); memset(sw, 0, sizeof(sw_data)); - timer_add(sw_timer_over, &sw->poll_time, &sw->poll_time, sw); - timer_add(sw_trigger_timer_over, &sw->trigger_time, &sw->trigger_time, sw); - + timer_add(&sw->poll_timer, sw_timer_over, sw, 0); + timer_add(&sw->trigger_timer, sw_trigger_timer_over, sw, 0); + return sw; } @@ -151,7 +145,7 @@ static uint8_t sw_read(void *p) if (!JOYSTICK_PRESENT(0)) return 0xff; - if (sw->poll_time) + if (timer_is_enabled(&sw->poll_timer)) { if (sw->poll_clock) temp |= 0x10; @@ -174,7 +168,7 @@ static uint8_t sw_read(void *p) static void sw_write(void *p) { sw_data *sw = (sw_data *)p; - int64_t time_since_last = sw->trigger_time / TIMER_USEC; + int64_t time_since_last = timer_get_remaining_us(&sw->trigger_timer); if (!JOYSTICK_PRESENT(0)) return; @@ -184,7 +178,7 @@ static void sw_write(void *p) if (!sw->poll_left) { sw->poll_clock = 1; - sw->poll_time = TIMER_USEC * 50; + timer_set_delay_u64(&sw->poll_timer, TIMER_USEC * 50); if (time_since_last > 9900 && time_since_last < 9940) { @@ -250,9 +244,7 @@ static void sw_write(void *p) } } - sw->trigger_time = 0; - - timer_update_outstanding(); + timer_disable(&sw->trigger_timer); } static int sw_read_axis(void *p, int axis) @@ -260,14 +252,14 @@ static int sw_read_axis(void *p, int axis) if (!JOYSTICK_PRESENT(0)) return AXIS_NOT_PRESENT; - return 0LL; /*No analogue support on Sidewinder game pad*/ + return 0; /*No analogue support on Sidewinder game pad*/ } static void sw_a0_over(void *p) { sw_data *sw = (sw_data *)p; - sw->trigger_time = TIMER_USEC * 10000; + timer_set_delay_u64(&sw->trigger_timer, TIMER_USEC * 10000); } const joystick_if_t joystick_sw_pad = diff --git a/src/ibm_5161.c b/src/ibm_5161.c new file mode 100644 index 000000000..7cf6fed64 --- /dev/null +++ b/src/ibm_5161.c @@ -0,0 +1,114 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the IBM Expansion Unit (5161). + * + * Version: @(#)ibm_5161.c 1.0.0 2019/06/28 + * + * Authors: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "device.h" +#include "io.h" +#include "apm.h" +#include "dma.h" +#include "mem.h" +#include "pci.h" +#include "timer.h" +#include "pit.h" +#include "port_92.h" +#include "machine/machine.h" +#include "intel_sio.h" + + +typedef struct +{ + uint8_t regs[8]; +} ibm_5161_t; + + +static void +ibm_5161_out(uint16_t port, uint8_t val, void *priv) +{ + ibm_5161_t *dev = (ibm_5161_t *) priv; + + dev->regs[port & 0x0007] = val; +} + + +static uint8_t +ibm_5161_in(uint16_t port, void *priv) +{ + ibm_5161_t *dev = (ibm_5161_t *) priv; + uint8_t ret = 0xff; + + ret = dev->regs[port & 0x0007]; + + switch (port) { + case 0x211: + case 0x215: + ret = (get_last_addr() >> 8) & 0xff; + break; + case 0x212: + case 0x216: + ret = get_last_addr() & 0xff; + break; + case 0x213: + ret = dev->regs[3] & 0x01; + break; + } + + return ret; +} + + +static void +ibm_5161_close(void *p) +{ + ibm_5161_t *dev = (ibm_5161_t *) p; + + free(dev); +} + + +static void * +ibm_5161_init(const device_t *info) +{ + ibm_5161_t *dev = (ibm_5161_t *) malloc(sizeof(ibm_5161_t)); + memset(dev, 0, sizeof(ibm_5161_t)); + + /* Extender Card Registers */ + io_sethandler(0x0210, 0x0004, + ibm_5161_in, NULL, NULL, ibm_5161_out, NULL, NULL, dev); + + /* Receiver Card Registers */ + io_sethandler(0x0214, 0x0003, + ibm_5161_in, NULL, NULL, ibm_5161_out, NULL, NULL, dev); + + return dev; +} + + +const device_t ibm_5161_device = +{ + "IBM Expansion Unit (5161)", + 0, + 0, + ibm_5161_init, + ibm_5161_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/ibm_5161.h b/src/ibm_5161.h new file mode 100644 index 000000000..7ae1913d3 --- /dev/null +++ b/src/ibm_5161.h @@ -0,0 +1,15 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * Emulation of the IBM Expansion Unit (5161). + * + * Version: @(#)ibm_5161.h 1.0.0 2019/06/218 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ + +extern const device_t ibm_5161_device; diff --git a/src/intel.c b/src/intel.c deleted file mode 100644 index 420250cf0..000000000 --- a/src/intel.c +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include -#include -#include -#include -#include -#include "cpu/cpu.h" -#include "device.h" -#include "machine/machine.h" -#include "io.h" -#include "mem.h" -#include "pit.h" -#include "timer.h" -#include "intel.h" - - -typedef struct { - uint16_t timer_latch; - - int64_t timer; -} batman_t; - - -static uint8_t -batman_config_read(uint16_t port, void *priv) -{ - uint8_t ret = 0x00; - - switch (port & 0x000f) { - case 3: - ret = 0xff; - break; - case 5: - ret = 0xdf; - break; - } - - return ret; -} - - -static void -batman_timer_over(void *priv) -{ - batman_t *dev = (batman_t *) priv; - - dev->timer = 0; -} - - -static void -batman_timer_write(uint16_t addr, uint8_t val, void *priv) -{ - batman_t *dev = (batman_t *) priv; - - if (addr & 1) - dev->timer_latch = (dev->timer_latch & 0xff) | (val << 8); - else - dev->timer_latch = (dev->timer_latch & 0xff00) | val; - - dev->timer = dev->timer_latch * TIMER_USEC; -} - - -static uint8_t -batman_timer_read(uint16_t addr, void *priv) -{ - batman_t *dev = (batman_t *) priv; - uint16_t batman_timer_latch; - uint8_t ret; - - cycles -= (int)PITCONST; - - timer_clock(); - - if (dev->timer < 0) - return 0; - - batman_timer_latch = dev->timer / TIMER_USEC; - - if (addr & 1) - ret = batman_timer_latch >> 8; - else - ret = batman_timer_latch & 0xff; - - return ret; -} - - -static void -intel_batman_close(void *priv) -{ - batman_t *dev = (batman_t *) priv; - - free(dev); -} - - -static void * -intel_batman_init(const device_t *info) -{ - batman_t *dev = (batman_t *) malloc(sizeof(batman_t)); - memset(dev, 0, sizeof(batman_t)); - - io_sethandler(0x0073, 0x0001, - batman_config_read, NULL, NULL, NULL, NULL, NULL, dev); - io_sethandler(0x0075, 0x0001, - batman_config_read, NULL, NULL, NULL, NULL, NULL, dev); - - io_sethandler(0x0078, 0x0002, - batman_timer_read, NULL, NULL, batman_timer_write, NULL, NULL, dev); - - timer_add(batman_timer_over, &dev->timer, &dev->timer, dev); - - return dev; -} - - -const device_t intel_batman_device = { - "Intel Batman board chip", - 0, - 0, - intel_batman_init, intel_batman_close, NULL, - NULL, NULL, NULL, - NULL -}; diff --git a/src/intel.h b/src/intel.h deleted file mode 100644 index 307fd49ab..000000000 --- a/src/intel.h +++ /dev/null @@ -1,4 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -extern const device_t intel_batman_device; diff --git a/src/intel_flash.c b/src/intel_flash.c index 6c72ff339..764b97fa9 100644 --- a/src/intel_flash.c +++ b/src/intel_flash.c @@ -6,15 +6,16 @@ * * This file is part of the 86Box distribution. * - * Implementation of the Intel 1 Mbit 8-bit flash devices. + * Implementation of the Intel 1 Mbit and 2 Mbit, 8-bit and + * 16-bit flash devices. * - * Version: @(#)intel_flash.c 1.0.18 2018/10/30 + * Version: @(#)intel_flash.c 1.0.19 2019/06/25 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -25,307 +26,473 @@ #include "device.h" #include "mem.h" #include "machine/machine.h" +#include "timer.h" #include "nvr.h" #include "plat.h" -#define FLASH_IS_BXB 2 -#define FLASH_INVERT 1 +#define FLAG_WORD 4 +#define FLAG_BXB 2 +#define FLAG_INV_A16 1 -#define BLOCK_MAIN 0 -#define BLOCK_DATA1 1 -#define BLOCK_DATA2 2 -#define BLOCK_BOOT 3 enum { - CMD_READ_ARRAY = 0xff, - CMD_IID = 0x90, - CMD_READ_STATUS = 0x70, - CMD_CLEAR_STATUS = 0x50, - CMD_ERASE_SETUP = 0x20, - CMD_ERASE_CONFIRM = 0xd0, - CMD_ERASE_SUSPEND = 0xb0, - CMD_PROGRAM_SETUP = 0x40, - CMD_PROGRAM_SETUP_ALT = 0x10 + BLOCK_MAIN1, + BLOCK_MAIN2, + BLOCK_DATA1, + BLOCK_DATA2, + BLOCK_BOOT, + BLOCKS_NUM }; +enum +{ + CMD_READ_ARRAY = 0xff, + CMD_IID = 0x90, + CMD_READ_STATUS = 0x70, + CMD_CLEAR_STATUS = 0x50, + CMD_ERASE_SETUP = 0x20, + CMD_ERASE_CONFIRM = 0xd0, + CMD_ERASE_SUSPEND = 0xb0, + CMD_PROGRAM_SETUP = 0x40, + CMD_PROGRAM_SETUP_ALT = 0x10 +}; + + typedef struct flash_t { - uint8_t command, status; - uint8_t flash_id; - int invert_high_pin; - uint32_t program_addr; - mem_mapping_t mapping[8], mapping_h[8]; - uint32_t block_start[4], block_end[4], block_len[4]; - uint8_t array[131072]; + uint8_t command, status, + flash_id, flags, + *array; + + uint32_t program_addr, + block_start[BLOCKS_NUM], block_end[BLOCKS_NUM], + block_len[BLOCKS_NUM]; + + mem_mapping_t mapping[4], mapping_h[8]; } flash_t; -static wchar_t flash_path[1024]; -static uint8_t flash_read(uint32_t addr, void *p) +static wchar_t flash_path[1024]; + + +static uint8_t +flash_read(uint32_t addr, void *p) { - flash_t *flash = (flash_t *)p; - if (flash->invert_high_pin) - addr ^= 0x10000; - addr &= 0x1ffff; - switch (flash->command) { - case CMD_READ_ARRAY: - default: - return flash->array[addr]; + flash_t *dev = (flash_t *) p; + uint8_t ret = 0xff; - case CMD_IID: - if (addr & 1) - return flash->flash_id; - return 0x89; + if (dev->flags & FLAG_INV_A16) + addr ^= 0x10000; + addr &= biosmask; - case CMD_READ_STATUS: - return flash->status; - } + switch (dev->command) { + case CMD_READ_ARRAY: + default: + ret = dev->array[addr]; + break; + + case CMD_IID: + if (addr & 1) + ret = dev->flash_id & 0xff; + else + ret = 0x89; + break; + + case CMD_READ_STATUS: + ret = dev->status; + break; + } + + return ret; } -static uint16_t flash_readw(uint32_t addr, void *p) + +static uint16_t +flash_readw(uint32_t addr, void *p) { - flash_t *flash = (flash_t *)p; - uint16_t *q; - addr &= 0x1ffff; - if (flash->invert_high_pin) addr ^= 0x10000; - q = (uint16_t *)&(flash->array[addr]); - return *q; + flash_t *dev = (flash_t *) p; + uint16_t *q; + uint16_t ret = 0xffff; + + if (dev->flags & FLAG_INV_A16) + addr ^= 0x10000; + addr &= biosmask; + + if (dev->flags & FLAG_WORD) + addr &= 0xfffffffe; + + q = (uint16_t *)&(dev->array[addr]); + ret = *q; + + if (dev->flags & FLAG_WORD) switch (dev->command) { + case CMD_READ_ARRAY: + default: + break; + + case CMD_IID: + if (addr & 2) + ret = dev->flash_id; + else + ret = 0x0089; + break; + + case CMD_READ_STATUS: + ret = dev->status; + break; + } + + return ret; } -static uint32_t flash_readl(uint32_t addr, void *p) + +static uint32_t +flash_readl(uint32_t addr, void *p) { - flash_t *flash = (flash_t *)p; - uint32_t *q; - addr &= 0x1ffff; - if (flash->invert_high_pin) addr ^= 0x10000; - q = (uint32_t *)&(flash->array[addr]); - return *q; + flash_t *dev = (flash_t *)p; + uint32_t *q; + + if (dev->flags & FLAG_INV_A16) + addr ^= 0x10000; + addr &= biosmask; + + q = (uint32_t *)&(dev->array[addr]); + + return *q; } -static void flash_write(uint32_t addr, uint8_t val, void *p) + +static void +flash_write(uint32_t addr, uint8_t val, void *p) { - flash_t *flash = (flash_t *)p; - int i; + flash_t *dev = (flash_t *) p; + int i; + uint32_t bb_mask = biosmask & 0xffffe000; + if (biosmask == 0x3ffff) + bb_mask &= 0xffffc000; - if (flash->invert_high_pin) - addr ^= 0x10000; - addr &= 0x1ffff; + if (dev->flags & FLAG_INV_A16) + addr ^= 0x10000; + addr &= biosmask; - switch (flash->command) { - case CMD_ERASE_SETUP: - if (val == CMD_ERASE_CONFIRM) { + switch (dev->command) { + case CMD_ERASE_SETUP: + if (val == CMD_ERASE_CONFIRM) { for (i = 0; i < 3; i++) { - if ((addr >= flash->block_start[i]) && (addr <= flash->block_end[i])) - memset(&(flash->array[flash->block_start[i]]), 0xff, flash->block_len[i]); + if ((addr >= dev->block_start[i]) && (addr <= dev->block_end[i])) + memset(&(dev->array[dev->block_start[i]]), 0xff, dev->block_len[i]); } - flash->status = 0x80; - } - flash->command = CMD_READ_STATUS; - break; - - case CMD_PROGRAM_SETUP: - case CMD_PROGRAM_SETUP_ALT: - if (((addr & 0x1e000) != (flash->block_start[3] & 0x1e000)) && (addr == flash->program_addr)) - flash->array[addr] = val; - flash->command = CMD_READ_STATUS; - flash->status = 0x80; - break; - - default: - flash->command = val; - switch (val) { - case CMD_CLEAR_STATUS: - flash->status = 0; - break; - case CMD_PROGRAM_SETUP: - case CMD_PROGRAM_SETUP_ALT: - flash->program_addr = addr; + dev->status = 0x80; + } + dev->command = CMD_READ_STATUS; + break; + + case CMD_PROGRAM_SETUP: + case CMD_PROGRAM_SETUP_ALT: + if (((addr & bb_mask) != (dev->block_start[4] & bb_mask)) && (addr == dev->program_addr)) + dev->array[addr] = val; + dev->command = CMD_READ_STATUS; + dev->status = 0x80; + break; + + default: + dev->command = val; + switch (val) { + case CMD_CLEAR_STATUS: + dev->status = 0; break; - } - } + case CMD_PROGRAM_SETUP: + case CMD_PROGRAM_SETUP_ALT: + dev->program_addr = addr; + break; + } + } } -static void intel_flash_add_mappings(flash_t *flash) -{ - int i = 0; - for (i = 0; i <= 7; i++) { - mem_mapping_add(&(flash->mapping[i]), 0xe0000 + (i << 14), 0x04000, flash_read, flash_readw, flash_readl, flash_write, mem_write_nullw, mem_write_nulll, flash->array + ((i << 14) & 0x1ffff), MEM_MAPPING_EXTERNAL, (void *)flash); - mem_mapping_add(&(flash->mapping_h[i]), 0xfffe0000 + (i << 14), 0x04000, flash_read, flash_readw, flash_readl, flash_write, mem_write_nullw, mem_write_nulll, flash->array + ((i << 14) & 0x1ffff), 0, (void *)flash); +static void +flash_writew(uint32_t addr, uint16_t val, void *p) +{ + flash_t *dev = (flash_t *) p; + int i; + uint32_t bb_mask = biosmask & 0xffffe000; + if (biosmask == 0x3ffff) + bb_mask &= 0xffffc000; + + if (dev->flags & FLAG_INV_A16) + addr ^= 0x10000; + addr &= biosmask; + + if (dev->flags & FLAG_WORD) switch (dev->command) { + case CMD_ERASE_SETUP: + if (val == CMD_ERASE_CONFIRM) { + for (i = 0; i < 3; i++) { + if ((addr >= dev->block_start[i]) && (addr <= dev->block_end[i])) + memset(&(dev->array[dev->block_start[i]]), 0xff, dev->block_len[i]); + } + + dev->status = 0x80; + } + dev->command = CMD_READ_STATUS; + break; + + case CMD_PROGRAM_SETUP: + case CMD_PROGRAM_SETUP_ALT: + if (((addr & bb_mask) != (dev->block_start[4] & bb_mask)) && (addr == dev->program_addr)) + *(uint16_t *) (&dev->array[addr]) = val; + dev->command = CMD_READ_STATUS; + dev->status = 0x80; + break; + + default: + dev->command = val & 0xff; + switch (val) { + case CMD_CLEAR_STATUS: + dev->status = 0; + break; + case CMD_PROGRAM_SETUP: + case CMD_PROGRAM_SETUP_ALT: + dev->program_addr = addr; + break; + } + } +} + + +static void +flash_writel(uint32_t addr, uint32_t val, void *p) +{ +#if 0 + flash_writew(addr, val & 0xffff, p); + flash_writew(addr + 2, (val >> 16) & 0xffff, p); +#endif +} + + +static void +intel_flash_add_mappings(flash_t *dev) +{ + int max = 2, i = 0; + uint32_t base, fbase; + + if (biosmask == 0x3ffff) + max = 4; + + for (i = 0; i < max; i++) { + if (biosmask == 0x3ffff) + base = 0xc0000 + (i << 16); + else + base = 0xe0000 + (i << 16); + fbase = base & biosmask; + if (dev->flags & FLAG_INV_A16) + fbase ^= 0x10000; + + memcpy(&dev->array[fbase], &rom[base & biosmask], 0x10000); + + if ((max == 2) || (i >= 2)) { + mem_mapping_add(&(dev->mapping[i]), base, 0x10000, + flash_read, flash_readw, flash_readl, + flash_write, flash_writew, flash_writel, + dev->array + fbase, MEM_MAPPING_EXTERNAL, (void *) dev); } + mem_mapping_add(&(dev->mapping_h[i]), (base | 0xfff00000) - 0x40000, 0x10000, + flash_read, flash_readw, flash_readl, + flash_write, flash_writew, flash_writel, + dev->array + fbase, MEM_MAPPING_EXTERNAL, (void *) dev); + mem_mapping_add(&(dev->mapping_h[i + 4]), (base | 0xfff00000), 0x10000, + flash_read, flash_readw, flash_readl, + flash_write, flash_writew, flash_writel, + dev->array + fbase, MEM_MAPPING_EXTERNAL, (void *) dev); + } } -/* This is for boards which invert the high pin - the flash->array pointers need to pointer invertedly in order for INTERNAL writes to go to the right part of the array. */ -static void intel_flash_add_mappings_inverted(flash_t *flash) + +static void * +intel_flash_init(const device_t *info) { - int i = 0; + FILE *f; + int l; + flash_t *dev; + wchar_t *machine_name, *flash_name; + uint8_t type = info->local & 0xff; - for (i = 0; i <= 7; i++) { - mem_mapping_add(&(flash->mapping[i]), 0xe0000 + (i << 14), 0x04000, flash_read, flash_readw, flash_readl, flash_write, mem_write_nullw, mem_write_nulll, flash->array + (((i << 14) ^ 0x10000) & 0x1ffff), MEM_MAPPING_EXTERNAL, (void *)flash); - mem_mapping_add(&(flash->mapping_h[i]), 0xfffe0000 + (i << 14), 0x04000, flash_read, flash_readw, flash_readl, flash_write, mem_write_nullw, mem_write_nulll, flash->array + (((i << 14) ^ 0x10000) & 0x1ffff), 0, (void *)flash); - } -} + dev = malloc(sizeof(flash_t)); + memset(dev, 0, sizeof(flash_t)); -void *intel_flash_init(uint8_t type) -{ - FILE *f; - int i, l; - flash_t *flash; - wchar_t *machine_name; - wchar_t *flash_name; + l = strlen(machine_get_internal_name_ex(machine))+1; + machine_name = (wchar_t *) malloc(l * sizeof(wchar_t)); + mbstowcs(machine_name, machine_get_internal_name_ex(machine), l); + l = wcslen(machine_name)+5; + flash_name = (wchar_t *)malloc(l*sizeof(wchar_t)); + swprintf(flash_name, l, L"%ls.bin", machine_name); - flash = malloc(sizeof(flash_t)); - memset(flash, 0, sizeof(flash_t)); + wcscpy(flash_path, flash_name); - l = strlen(machine_get_internal_name_ex(machine))+1; - machine_name = (wchar_t *) malloc(l * sizeof(wchar_t)); - mbstowcs(machine_name, machine_get_internal_name_ex(machine), l); - l = wcslen(machine_name)+5; - flash_name = (wchar_t *)malloc(l*sizeof(wchar_t)); - swprintf(flash_name, l, L"%ls.bin", machine_name); + dev->flags = info->local & 0xff; - wcscpy(flash_path, flash_name); + mem_mapping_disable(&bios_mapping); + mem_mapping_disable(&bios_high_mapping); - flash->flash_id = (type & FLASH_IS_BXB) ? 0x95 : 0x94; - flash->invert_high_pin = (type & FLASH_INVERT); + dev->array = (uint8_t *) malloc(biosmask + 1); + memset(dev->array, 0xff, biosmask + 1); + + if (biosmask == 0x3ffff) { + if (dev->flags & FLAG_WORD) + dev->flash_id = (dev->flags & FLAG_BXB) ? 0x2275 : 0x2274; + else + dev->flash_id = (dev->flags & FLAG_BXB) ? 0x7D : 0x7C; /* The block lengths are the same both flash types. */ - flash->block_len[BLOCK_MAIN] = 0x1c000; - flash->block_len[BLOCK_DATA1] = 0x01000; - flash->block_len[BLOCK_DATA2] = 0x01000; - flash->block_len[BLOCK_BOOT] = 0x02000; + dev->block_len[BLOCK_MAIN1] = 0x20000; + dev->block_len[BLOCK_MAIN2] = 0x18000; + dev->block_len[BLOCK_DATA1] = 0x02000; + dev->block_len[BLOCK_DATA2] = 0x02000; + dev->block_len[BLOCK_BOOT] = 0x04000; - if (type & FLASH_IS_BXB) { /* 28F001BX-B */ - flash->block_start[BLOCK_MAIN] = 0x04000; /* MAIN BLOCK */ - flash->block_end[BLOCK_MAIN] = 0x1ffff; - flash->block_start[BLOCK_DATA1] = 0x03000; /* DATA AREA 1 BLOCK */ - flash->block_end[BLOCK_DATA1] = 0x03fff; - flash->block_start[BLOCK_DATA2] = 0x04000; /* DATA AREA 2 BLOCK */ - flash->block_end[BLOCK_DATA2] = 0x04fff; - flash->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ - flash->block_end[BLOCK_BOOT] = 0x01fff; - } else { /* 28F001BX-T */ - flash->block_start[BLOCK_MAIN] = 0x00000; /* MAIN BLOCK */ - flash->block_end[BLOCK_MAIN] = 0x1bfff; - flash->block_start[BLOCK_DATA1] = 0x1c000; /* DATA AREA 1 BLOCK */ - flash->block_end[BLOCK_DATA1] = 0x1cfff; - flash->block_start[BLOCK_DATA2] = 0x1d000; /* DATA AREA 2 BLOCK */ - flash->block_end[BLOCK_DATA2] = 0x1dfff; - flash->block_start[BLOCK_BOOT] = 0x1e000; /* BOOT BLOCK */ - flash->block_end[BLOCK_BOOT] = 0x1ffff; + if (dev->flags & FLAG_BXB) { /* 28F002BX-B/28F200BX-B */ + dev->block_start[BLOCK_MAIN1] = 0x20000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x3ffff; + dev->block_start[BLOCK_MAIN2] = 0x08000; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0x1ffff; + dev->block_start[BLOCK_DATA1] = 0x06000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x07fff; + dev->block_start[BLOCK_DATA2] = 0x04000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x05fff; + dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x03fff; + } else { /* 28F002BX-T/28F200BX-T */ + dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1ffff; + dev->block_start[BLOCK_MAIN2] = 0x20000; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0x37fff; + dev->block_start[BLOCK_DATA1] = 0x38000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x39fff; + dev->block_start[BLOCK_DATA2] = 0x3a000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x3bfff; + dev->block_start[BLOCK_BOOT] = 0x3c000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x3ffff; } + } else { + dev->flash_id = (type & FLAG_BXB) ? 0x95 : 0x94; - for (i = 0; i < 8; i++) { - mem_mapping_disable(&bios_mapping[i]); - mem_mapping_disable(&bios_high_mapping[i]); + /* The block lengths are the same both flash types. */ + dev->block_len[BLOCK_MAIN1] = 0x1c000; + dev->block_len[BLOCK_MAIN2] = 0x00000; + dev->block_len[BLOCK_DATA1] = 0x01000; + dev->block_len[BLOCK_DATA2] = 0x01000; + dev->block_len[BLOCK_BOOT] = 0x02000; + + if (dev->flags & FLAG_BXB) { /* 28F001BX-B/28F100BX-B */ + dev->block_start[BLOCK_MAIN1] = 0x04000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1ffff; + dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0xfffff; + dev->block_start[BLOCK_DATA1] = 0x02000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x02fff; + dev->block_start[BLOCK_DATA2] = 0x03000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x03fff; + dev->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x01fff; + } else { /* 28F001BX-T/28F100BX-T */ + dev->block_start[BLOCK_MAIN1] = 0x00000; /* MAIN BLOCK 1 */ + dev->block_end[BLOCK_MAIN1] = 0x1bfff; + dev->block_start[BLOCK_MAIN2] = 0xfffff; /* MAIN BLOCK 2 */ + dev->block_end[BLOCK_MAIN2] = 0xfffff; + dev->block_start[BLOCK_DATA1] = 0x1c000; /* DATA AREA 1 BLOCK */ + dev->block_end[BLOCK_DATA1] = 0x1cfff; + dev->block_start[BLOCK_DATA2] = 0x1d000; /* DATA AREA 2 BLOCK */ + dev->block_end[BLOCK_DATA2] = 0x1dfff; + dev->block_start[BLOCK_BOOT] = 0x1e000; /* BOOT BLOCK */ + dev->block_end[BLOCK_BOOT] = 0x1ffff; } + } - if (flash->invert_high_pin) { - memcpy(flash->array, rom + 65536, 65536); - memcpy(flash->array + 65536, rom, 65536); - } - else - memcpy(flash->array, rom, 131072); + intel_flash_add_mappings(dev); - if (flash->invert_high_pin) - intel_flash_add_mappings_inverted(flash); - else - intel_flash_add_mappings(flash); + dev->command = CMD_READ_ARRAY; + dev->status = 0; - flash->command = CMD_READ_ARRAY; - flash->status = 0; + f = nvr_fopen(flash_path, L"rb"); + if (f) { + fread(&(dev->array[dev->block_start[BLOCK_MAIN1]]), dev->block_len[BLOCK_MAIN1], 1, f); + if (dev->block_len[BLOCK_MAIN2]) + fread(&(dev->array[dev->block_start[BLOCK_MAIN2]]), dev->block_len[BLOCK_MAIN2], 1, f); + fread(&(dev->array[dev->block_start[BLOCK_DATA1]]), dev->block_len[BLOCK_DATA1], 1, f); + fread(&(dev->array[dev->block_start[BLOCK_DATA2]]), dev->block_len[BLOCK_DATA2], 1, f); + fclose(f); + } - f = nvr_fopen(flash_path, L"rb"); - if (f) { - fread(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 1, f); - fread(&(flash->array[flash->block_start[BLOCK_DATA1]]), flash->block_len[BLOCK_DATA1], 1, f); - fread(&(flash->array[flash->block_start[BLOCK_DATA2]]), flash->block_len[BLOCK_DATA2], 1, f); - fclose(f); - } + free(flash_name); + free(machine_name); - free(flash_name); - free(machine_name); - - return flash; + return dev; } -void *intel_flash_bxb_ami_init() + +static void +intel_flash_close(void *p) { - return intel_flash_init(FLASH_IS_BXB | FLASH_INVERT); -} + FILE *f; + flash_t *dev = (flash_t *)p; -/* For AMI BIOS'es - Intel 28F001BXT with high address pin inverted. */ -void *intel_flash_bxt_ami_init() -{ - return intel_flash_init(FLASH_INVERT); -} + f = nvr_fopen(flash_path, L"wb"); + fwrite(&(dev->array[dev->block_start[BLOCK_MAIN1]]), dev->block_len[BLOCK_MAIN1], 1, f); + if (dev->block_len[BLOCK_MAIN2]) + fwrite(&(dev->array[dev->block_start[BLOCK_MAIN2]]), dev->block_len[BLOCK_MAIN2], 1, f); + fwrite(&(dev->array[dev->block_start[BLOCK_DATA1]]), dev->block_len[BLOCK_DATA1], 1, f); + fwrite(&(dev->array[dev->block_start[BLOCK_DATA2]]), dev->block_len[BLOCK_DATA2], 1, f); + fclose(f); -/* For Award BIOS'es - Intel 28F001BXT with high address pin not inverted. */ -void *intel_flash_bxt_init() -{ - return intel_flash_init(0); -} - -/* For Acer BIOS'es - Intel 28F001BXB. */ -void *intel_flash_bxb_init() -{ - return intel_flash_init(FLASH_IS_BXB); -} - -void intel_flash_close(void *p) -{ - FILE *f; - flash_t *flash = (flash_t *)p; - - f = nvr_fopen(flash_path, L"wb"); - fwrite(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 1, f); - fwrite(&(flash->array[flash->block_start[BLOCK_DATA1]]), flash->block_len[BLOCK_DATA1], 1, f); - fwrite(&(flash->array[flash->block_start[BLOCK_DATA2]]), flash->block_len[BLOCK_DATA2], 1, f); - fclose(f); - - free(flash); + free(dev); } +/* For AMI BIOS'es - Intel 28F001BXT with A16 pin inverted. */ const device_t intel_flash_bxt_ami_device = { - "Intel 28F001BXT Flash BIOS", - 0, 0, - intel_flash_bxt_ami_init, - intel_flash_close, - NULL, - NULL, NULL, NULL, NULL + "Intel 28F001BXT/28F002BXT Flash BIOS", + 0, + FLAG_INV_A16, + intel_flash_init, + intel_flash_close, + NULL, + NULL, NULL, NULL, NULL }; -const device_t intel_flash_bxb_ami_device = + +#if defined(DEV_BRANCH) && defined(USE_TC430HX) +const device_t intel_flash_bxtw_ami_device = { - "Intel 28F001BXB Flash BIOS", - 0, 0, - intel_flash_bxb_ami_init, - intel_flash_close, - NULL, - NULL, NULL, NULL, NULL + "Intel 28F100BXT/28F200BXT Flash BIOS", + 0, + FLAG_INV_A16 | FLAG_WORD, + intel_flash_init, + intel_flash_close, + NULL, + NULL, NULL, NULL, NULL }; +#endif + const device_t intel_flash_bxt_device = { - "Intel 28F001BXT Flash BIOS", - 0, 0, - intel_flash_bxt_init, - intel_flash_close, - NULL, - NULL, NULL, NULL, NULL + "Intel 28F001BXT/28F002BXT Flash BIOS", + 0, 0, + intel_flash_init, + intel_flash_close, + NULL, + NULL, NULL, NULL, NULL }; + const device_t intel_flash_bxb_device = { - "Intel 28F001BXB Flash BIOS", - 0, 0, - intel_flash_bxb_init, - intel_flash_close, - NULL, - NULL, NULL, NULL, NULL + "Intel 28F001BXB/28F002BXB Flash BIOS", + 0, FLAG_BXB, + intel_flash_init, + intel_flash_close, + NULL, + NULL, NULL, NULL, NULL }; diff --git a/src/intel_flash.h b/src/intel_flash.h index 241a07c02..3c76ec52a 100644 --- a/src/intel_flash.h +++ b/src/intel_flash.h @@ -8,15 +8,17 @@ * * Implementation of the Intel 1 Mbit 8-bit flash devices. * - * Version: @(#)intel_flash.h 1.0.1 2018/03/14 + * Version: @(#)intel_flash.h 1.0.2 2019/06/25 * * Author: Sarah Walker, * Miran Grca, - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016-2017 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ extern const device_t intel_flash_bxt_ami_device; -extern const device_t intel_flash_bxb_ami_device; +#if defined(DEV_BRANCH) && defined(USE_TC430HX) +extern const device_t intel_flash_bxtw_ami_device; +#endif extern const device_t intel_flash_bxt_device; extern const device_t intel_flash_bxb_device; diff --git a/src/intel_piix.c b/src/intel_piix.c index 8d0556142..d5fdfc36f 100644 --- a/src/intel_piix.c +++ b/src/intel_piix.c @@ -27,46 +27,36 @@ #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 "pci.h" #include "pic.h" +#include "port_92.h" #include "disk/hdc.h" #include "disk/hdc_ide.h" +#include "disk/hdc_ide_sff8038i.h" #include "disk/zip.h" +#include "machine/machine.h" #include "piix.h" -typedef struct -{ - uint8_t command, status, - ptr0; - uint32_t ptr, ptr_cur, - addr; - int count, eot; -} piix_busmaster_t; - typedef struct { int type; - uint8_t regs[256], regs_ide[256]; - piix_busmaster_t bm[2]; + uint8_t cur_readout_reg, + readout_regs[256], + regs[256], regs_ide[256]; + sff8038i_t *bm[2]; } piix_t; -static uint8_t piix_bus_master_read(uint16_t port, void *priv); -static uint16_t piix_bus_master_readw(uint16_t port, void *priv); -static uint32_t piix_bus_master_readl(uint16_t port, void *priv); -static void piix_bus_master_write(uint16_t port, uint8_t val, void *priv); -static void piix_bus_master_writew(uint16_t port, uint16_t val, void *priv); -static void piix_bus_master_writel(uint16_t port, uint32_t val, void *priv); - - #ifdef ENABLE_PIIX_LOG int piix_do_log = ENABLE_PIIX_LOG; @@ -93,25 +83,9 @@ piix_bus_master_handlers(piix_t *dev, uint16_t old_base) uint16_t base; base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); - io_removehandler(old_base, 0x08, - piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, - piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, - &dev->bm[0]); - io_removehandler(old_base + 8, 0x08, - piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, - piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, - &dev->bm[1]); - if ((dev->regs_ide[0x04] & 1) && base) { - io_sethandler(base, 0x08, - piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, - piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, - &dev->bm[0]); - io_sethandler(base + 8, 0x08, - piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, - piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, - &dev->bm[1]); - } + sff_bus_master_handlers(dev->bm[0], old_base, base, (dev->regs_ide[0x04] & 1)); + sff_bus_master_handlers(dev->bm[1], old_base + 8, base + 8, (dev->regs_ide[0x04] & 1)); } @@ -120,11 +94,16 @@ piix_write(int func, int addr, uint8_t val, void *priv) { piix_t *dev = (piix_t *) priv; uint8_t valxor; + uint16_t old_base; + + if ((func == 1) && (dev->type & 0x100)) /* PB640's PIIX has no IDE part. */ + return; - uint16_t old_base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); if (func > 1) return; + old_base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); + if (func == 1) { /*IDE*/ piix_log("PIIX IDE write: %02X %02X\n", addr, val); valxor = val ^ dev->regs_ide[addr]; @@ -204,12 +183,11 @@ piix_write(int func, int addr, uint8_t val, void *priv) case 0x4c: if (valxor) { - if (val & 0x80) { - if (dev->type == 3) - dma_alias_remove(); - else - dma_alias_remove_piix(); - } else + if (dev->type == 3) + dma_alias_remove(); + else + dma_alias_remove_piix(); + if (!(val & 0x80)) dma_alias_set(); } break; @@ -409,330 +387,43 @@ piix_read(int func, int addr, void *priv) static void -piix_bus_master_next_addr(piix_busmaster_t *dev) +board_write(uint16_t port, uint8_t val, void *priv) { - DMAPageRead(dev->ptr_cur, (uint8_t *)&(dev->addr), 4); - DMAPageRead(dev->ptr_cur + 4, (uint8_t *)&(dev->count), 4); - piix_log("PIIX Bus master DWORDs: %08X %08X\n", dev->addr, dev->count); - dev->eot = dev->count >> 31; - dev->count &= 0xfffe; - if (!dev->count) - dev->count = 65536; - dev->addr &= 0xfffffffe; - dev->ptr_cur += 8; -} + piix_t *dev = (piix_t *) priv; - -static void -piix_bus_master_write(uint16_t port, uint8_t val, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; -#ifdef ENABLE_PIIX_LOG - int channel = (port & 8) ? 1 : 0; -#endif - - piix_log("PIIX Bus master BYTE write: %04X %02X\n", port, val); - - switch (port & 7) { - case 0: - piix_log("PIIX Cmd : val = %02X, old = %02X\n", val, dev->command); - if ((val & 1) && !(dev->command & 1)) { /*Start*/ - piix_log("PIIX Bus Master start on channel %i\n", channel); - dev->ptr_cur = dev->ptr; - piix_bus_master_next_addr(dev); - dev->status |= 1; - } - if (!(val & 1) && (dev->command & 1)) { /*Stop*/ - piix_log("PIIX Bus Master stop on channel %i\n", channel); - dev->status &= ~1; - } - - dev->command = val; - break; - case 2: - piix_log("PIIX Status: val = %02X, old = %02X\n", val, dev->status); - dev->status &= 0x07; - dev->status |= (val & 0x60); - if (val & 0x04) - dev->status &= ~0x04; - if (val & 0x02) - dev->status &= ~0x02; - break; - case 4: - dev->ptr = (dev->ptr & 0xffffff00) | (val & 0xfc); - dev->ptr %= (mem_size * 1024); - dev->ptr0 = val; - break; - case 5: - dev->ptr = (dev->ptr & 0xffff00fc) | (val << 8); - dev->ptr %= (mem_size * 1024); - break; - case 6: - dev->ptr = (dev->ptr & 0xff00fffc) | (val << 16); - dev->ptr %= (mem_size * 1024); - break; - case 7: - dev->ptr = (dev->ptr & 0x00fffffc) | (val << 24); - dev->ptr %= (mem_size * 1024); - break; - } -} - - -static void -piix_bus_master_writew(uint16_t port, uint16_t val, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - - piix_log("PIIX Bus master WORD write: %04X %04X\n", port, val); - - switch (port & 7) { - case 0: - case 2: - piix_bus_master_write(port, val & 0xff, priv); - break; - case 4: - dev->ptr = (dev->ptr & 0xffff0000) | (val & 0xfffc); - dev->ptr %= (mem_size * 1024); - dev->ptr0 = val & 0xff; - break; - case 6: - dev->ptr = (dev->ptr & 0x0000fffc) | (val << 16); - dev->ptr %= (mem_size * 1024); - break; - } -} - - -static void -piix_bus_master_writel(uint16_t port, uint32_t val, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - - piix_log("PIIX Bus master DWORD write: %04X %08X\n", port, val); - - switch (port & 7) { - case 0: - case 2: - piix_bus_master_write(port, val & 0xff, priv); - break; - case 4: - dev->ptr = (val & 0xfffffffc); - dev->ptr %= (mem_size * 1024); - dev->ptr0 = val & 0xff; - break; - } + if (port == 0x00e0) + dev->cur_readout_reg = val; + else if (port == 0x00e1) + dev->readout_regs[dev->cur_readout_reg] = val; } static uint8_t -piix_bus_master_read(uint16_t port, void *priv) +board_read(uint16_t port, void *priv) { - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - + piix_t *dev = (piix_t *) priv; uint8_t ret = 0xff; - switch (port & 7) { - case 0: - ret = dev->command; - break; - case 2: - ret = dev->status & 0x67; - break; - case 4: - ret = dev->ptr0; - break; - case 5: - ret = dev->ptr >> 8; - break; - case 6: - ret = dev->ptr >> 16; - break; - case 7: - ret = dev->ptr >> 24; - break; - } - - piix_log("PIIX Bus master BYTE read : %04X %02X\n", port, ret); + if (port == 0x00e0) + ret = dev->cur_readout_reg; + else if (port == 0x00e1) + ret = dev->readout_regs[dev->cur_readout_reg]; return ret; } -static uint16_t -piix_bus_master_readw(uint16_t port, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - - uint16_t ret = 0xffff; - - switch (port & 7) { - case 0: - case 2: - ret = (uint16_t) piix_bus_master_read(port, priv); - break; - case 4: - ret = dev->ptr0 | (dev->ptr & 0xff00); - break; - case 6: - ret = dev->ptr >> 16; - break; - } - - piix_log("PIIX Bus master WORD read : %04X %04X\n", port, ret); - - return ret; -} - - -static uint32_t -piix_bus_master_readl(uint16_t port, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - - uint32_t ret = 0xffffffff; - - switch (port & 7) { - case 0: - case 2: - ret = (uint32_t) piix_bus_master_read(port, priv); - break; - case 4: - ret = dev->ptr0 | (dev->ptr & 0xffffff00); - break; - } - - piix_log("PIIX Bus master DWORD read : %04X %08X\n", port, ret); - - return ret; -} - - -static int -piix_bus_master_dma(int channel, uint8_t *data, int transfer_length, int out, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; -#ifdef ENABLE_PIIX_LOG - char *sop; -#endif - - int force_end = 0, buffer_pos = 0; - -#ifdef ENABLE_PIIX_LOG - sop = out ? "Read" : "Writ"; -#endif - - if (!(dev->status & 1)) - return 2; /*DMA disabled*/ - - piix_log("PIIX Bus master %s: %i bytes\n", out ? "write" : "read", transfer_length); - - while (1) { - if (dev->count <= transfer_length) { - piix_log("%sing %i bytes to %08X\n", sop, dev->count, dev->addr); - if (out) - DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); - else - DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); - transfer_length -= dev->count; - buffer_pos += dev->count; - } else { - piix_log("%sing %i bytes to %08X\n", sop, transfer_length, dev->addr); - if (out) - DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); - else - DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); - /* Increase addr and decrease count so that resumed transfers do not mess up. */ - dev->addr += transfer_length; - dev->count -= transfer_length; - transfer_length = 0; - force_end = 1; - } - - if (force_end) { - piix_log("Total transfer length smaller than sum of all blocks, partial block\n"); - dev->status &= ~2; - return 1; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ - } else { - if (!transfer_length && !dev->eot) { - piix_log("Total transfer length smaller than sum of all blocks, full block\n"); - dev->status &= ~2; - return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */ - } else if (transfer_length && dev->eot) { - piix_log("Total transfer length greater than sum of all blocks\n"); - dev->status |= 2; - return 0; /* There is data left to transfer but we have reached EOT - return with error. */ - } else if (dev->eot) { - piix_log("Regular EOT\n"); - dev->status &= ~3; - return 1; /* We have regularly reached EOT - clear status and break. */ - } else { - /* We have more to transfer and there are blocks left, get next block. */ - piix_bus_master_next_addr(dev); - } - } - } - - return 1; -} - - -void -piix_bus_master_set_irq(int channel, void *priv) -{ - piix_busmaster_t *dev = (piix_busmaster_t *) priv; - dev->status &= ~4; - dev->status |= (channel >> 4); - - channel &= 0x01; - if (dev->status & 0x04) { - if (channel && pci_use_mirq(0)) - pci_set_mirq(0); - else - picint(1 << (14 + channel)); - } else { - if ((channel & 1) && pci_use_mirq(0)) - pci_clear_mirq(0); - else - picintc(1 << (14 + channel)); - } -} - - -static void -piix_bus_master_reset(piix_t *dev) -{ - uint8_t i; - - uint16_t old_base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); - if (old_base) { - io_removehandler(old_base, 0x08, - piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, - piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, - &dev->bm[0]); - io_removehandler(old_base + 8, 0x08, - piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, - piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, - &dev->bm[1]); - } - - for (i = 0; i < 2; i++) { - dev->bm[i].command = 0x00; - dev->bm[i].status = 0x00; - dev->bm[i].ptr = dev->bm[i].ptr_cur = 0x00000000; - dev->bm[i].addr = 0x00000000; - dev->bm[i].ptr0 = 0x00; - dev->bm[i].count = dev->bm[i].eot = 0x00000000; - } -} - - static void piix_reset_hard(void *priv) { piix_t *piix = (piix_t *) priv; - piix_bus_master_reset(piix); + uint16_t old_base = (piix->regs_ide[0x20] & 0xf0) | (piix->regs_ide[0x21] << 8); + + if (!(piix->type & 0x100)) { /* PB640's PIIX has no IDE part. */ + sff_bus_master_reset(piix->bm[0], old_base); + sff_bus_master_reset(piix->bm[1], old_base + 8); + } memset(piix->regs, 0, 256); memset(piix->regs_ide, 0, 256); @@ -806,25 +497,6 @@ piix_reset_hard(void *priv) pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); if (piix->type != 3) pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); - - ide_pri_disable(); - ide_sec_disable(); -} - - -static void -piix_reset(void *p) -{ - int i = 0; - - for (i = 0; i < CDROM_NUM; i++) { - if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && cdrom[i].priv) - scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv); - } - for (i = 0; i < ZIP_NUM; i++) { - if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && zip_drives[i].priv) - zip_reset((scsi_common_t *) zip_drives[i].priv); - } } @@ -843,25 +515,96 @@ static void piix_t *piix = (piix_t *) malloc(sizeof(piix_t)); memset(piix, 0, sizeof(piix_t)); - device_add(&ide_pci_2ch_device); - pci_add_card(7, piix_read, piix_write, piix); piix->type = info->local; + + device_add(&apm_device); + + if (!(piix->type & 0x100)) { /* PB640's PIIX has no IDE part. */ + piix->bm[0] = device_add_inst(&sff8038i_device, 1); + piix->bm[1] = device_add_inst(&sff8038i_device, 2); + } + piix_reset_hard(piix); - ide_set_bus_master(piix_bus_master_dma, piix_bus_master_set_irq, - &piix->bm[0], &piix->bm[1]); - - port_92_reset(); - - port_92_add(); + device_add(&port_92_pci_device); dma_alias_set(); pci_enable_mirq(0); pci_enable_mirq(1); + piix->readout_regs[1] = 0x40; + + /* Port E1 register 01 (TODO: Find how multipliers > 3.0 are defined): + + Bit 6: 1 = can boot, 0 = no; + Bit 7, 1 = multiplier (00 = 2.5, 01 = 2.0, 10 = 3.0, 11 = 1.5); + Bit 5, 4 = bus speed (00 = 50 MHz, 01 = 66 MHz, 10 = 60 MHz, 11 = ????): + Bit 7, 5, 4, 1: 0000 = 125 MHz, 0010 = 166 MHz, 0100 = 150 MHz, 0110 = ??? MHz; + 0001 = 100 MHz, 0011 = 133 MHz, 0101 = 120 MHz, 0111 = ??? MHz; + 1000 = 150 MHz, 1010 = 200 MHz, 1100 = 180 MHz, 1110 = ??? MHz; + 1001 = 75 MHz, 1011 = 100 MHz, 1101 = 90 MHz, 1111 = ??? MHz */ + + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].pci_speed) { + case 20000000: + piix->readout_regs[1] |= 0x30; + break; + case 25000000: + default: + piix->readout_regs[1] |= 0x00; + break; + case 30000000: + piix->readout_regs[1] |= 0x20; + break; + case 33333333: + piix->readout_regs[1] |= 0x10; + break; + } + + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed) { + case 75000000: + piix->readout_regs[1] |= 0x82; /* 50 MHz * 1.5 multiplier */ + break; + case 90000000: + piix->readout_regs[1] |= 0x82; /* 60 MHz * 1.5 multiplier */ + break; + case 100000000: + if ((piix->readout_regs[1] & 0x30) == 0x10) + piix->readout_regs[1] |= 0x82; /* 66 MHz * 1.5 multiplier */ + else + piix->readout_regs[1] |= 0x02; /* 50 MHz * 2.0 multiplier */ + break; + case 12000000: + piix->readout_regs[1] |= 0x02; /* 60 MHz * 2.0 multiplier */ + break; + case 125000000: + piix->readout_regs[1] |= 0x00; /* 50 MHz * 2.5 multiplier */ + break; + case 133333333: + piix->readout_regs[1] |= 0x02; /* 66 MHz * 2.0 multiplier */ + break; + case 150000000: + if ((piix->readout_regs[1] & 0x30) == 0x20) + piix->readout_regs[1] |= 0x00; /* 60 MHz * 2.5 multiplier */ + else + piix->readout_regs[1] |= 0x80; /* 50 MHz * 3.0 multiplier */ + break; + case 166666666: + piix->readout_regs[1] |= 0x00; /* 66 MHz * 2.5 multiplier */ + break; + case 180000000: + piix->readout_regs[1] |= 0x80; /* 60 MHz * 3.0 multiplier */ + break; + case 200000000: + piix->readout_regs[1] |= 0x80; /* 66 MHz * 3.0 multiplier */ + break; + } + + io_sethandler(0x0078, 0x0002, board_read, NULL, NULL, board_write, NULL, NULL, piix); + io_sethandler(0x00e0, 0x0002, board_read, NULL, NULL, board_write, NULL, NULL, piix); + return piix; } @@ -873,7 +616,7 @@ const device_t piix_device = 1, piix_init, piix_close, - piix_reset, + NULL, NULL, NULL, NULL, @@ -887,7 +630,7 @@ const device_t piix_pb640_device = 0x101, piix_init, piix_close, - piix_reset, + NULL, NULL, NULL, NULL, @@ -901,7 +644,7 @@ const device_t piix3_device = 3, piix_init, piix_close, - piix_reset, + NULL, NULL, NULL, NULL, diff --git a/src/intel_piix4.c b/src/intel_piix4.c deleted file mode 100644 index ed4b49335..000000000 --- a/src/intel_piix4.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * Preliminary emulation of the Intel PIIX4 Xcelerator. - * - * PRD format : - * word 0 - base address - * word 1 - bits 1-15 = byte count, bit 31 = end of transfer - * - * Version: @(#)intel_piix4.c 1.0.3 2018/02/14 - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - */ -#include -#include -#include -#include -#include "86box.h" -#include "dma.h" -#include "io.h" -#include "device.h" -#include "keyboard.h" -#include "mem.h" -#include "pci.h" -#include "disk/hdc.h" -#include "disk/hdc_ide.h" -#include "piix.h" - - -static uint8_t card_piix4[256], card_piix4_ide[256]; - - -static void piix4_write(int func, int addr, uint8_t val, void *priv) -{ - uint16_t old_base = (card_piix4_ide[0x20] & 0xf0) | (card_piix4_ide[0x21] << 8); - if (func > 1) - return; - - if (func == 1) /*IDE*/ - { - /* pclog("PIIX IDE write: %02X %02X\n", addr, val); */ - - switch (addr) - { - case 0x04: - card_piix4_ide[0x04] = (val & 5) | 2; - break; - case 0x07: - card_piix4_ide[0x07] = val & 0x3e; - break; - case 0x0d: - card_piix4_ide[0x0d] = val; - break; - - case 0x20: - card_piix4_ide[0x20] = (val & ~0x0f) | 1; - break; - case 0x21: - card_piix4_ide[0x21] = val; - break; - - case 0x40: - card_piix4_ide[0x40] = val; - break; - case 0x41: - if ((val ^ card_piix4_ide[0x41]) & 0x80) - { - ide_pri_disable(); - if (val & 0x80) - ide_pri_enable(); - } - card_piix4_ide[0x41] = val; - break; - case 0x42: - card_piix4_ide[0x42] = val; - break; - case 0x43: - if ((val ^ card_piix4_ide[0x43]) & 0x80) - { - ide_sec_disable(); - if (val & 0x80) - ide_sec_enable(); - } - card_piix4_ide[0x43] = val; - break; - case 0x44: - card_piix4_ide[0x44] = val; - break; - case 0x48: - card_piix4_ide[0x44] = val; - break; - case 0x4A: - card_piix4_ide[0x44] = val; - break; - case 0x4B: - card_piix4_ide[0x44] = val; - break; - } - if (addr == 4 || (addr & ~3) == 0x20) /*Bus master base address*/ - { - uint16_t base = (card_piix4_ide[0x20] & 0xf0) | (card_piix4_ide[0x21] << 8); - io_removehandler(old_base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); - if (card_piix4_ide[0x04] & 1) - { - io_sethandler(base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); - } - } - } - else - { - /* pclog("PIIX writing value %02X to register %02X\n", val, addr); */ - if ((addr >= 0x0f) && (addr < 0x4c)) - return; - - switch (addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: - return; - - case 0x60: - /* pclog("Set IRQ routing: INT A -> %02X\n", val); */ - if (val & 0x80) - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTA, val & 0xf); - break; - case 0x61: - /* pclog("Set IRQ routing: INT B -> %02X\n", val); */ - if (val & 0x80) - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTB, val & 0xf); - break; - case 0x62: - /* pclog("Set IRQ routing: INT C -> %02X\n", val); */ - if (val & 0x80) - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTC, val & 0xf); - break; - case 0x63: - /* pclog("Set IRQ routing: INT D -> %02X\n", val); */ - if (val & 0x80) - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTD, val & 0xf); - break; - } - if (addr == 0x4C) - { - if (!((val ^ card_piix4[addr]) & 0x80)) - { - card_piix4[addr] = val; - return; - } - - card_piix4[addr] = val; - if (val & 0x80) - { - dma_alias_remove(); - } - else - { - dma_alias_set(); - } - } - else if (addr == 0x4E) - { - keyboard_at_set_mouse_scan((val & 0x10) ? 1 : 0); - card_piix4[addr] = val; - } - else - card_piix4[addr] = val; - } -} - -static uint8_t piix4_read(int func, int addr, void *priv) -{ - if (func > 1) - return 0xff; - - if (func == 1) /*IDE*/ - { - if (addr == 4) - { - return (card_piix4_ide[addr] & 5); - } - else if (addr == 5) - { - return 0; - } - else if (addr == 6) - { - return 0x80; - } - else if (addr == 7) - { - return card_piix4_ide[addr] & 0x3E; - } - else if (addr == 0xD) - { - return card_piix4_ide[addr] & 0xF0; - } - else if (addr == 0x20) - { - return (card_piix4_ide[addr] & 0xF0) | 1; - } - else if (addr == 0x22) - { - return 0; - } - else if (addr == 0x23) - { - return 0; - } - else if (addr == 0x41) - { - return card_piix4_ide[addr] & 0xF3; - } - else if (addr == 0x43) - { - return card_piix4_ide[addr] & 0xF3; - } - else if (addr == 0x48) - { - return card_piix4_ide[addr] & 0x0F; - } - else if (addr == 0x4A) - { - return card_piix4_ide[addr] & 0x33; - } - else if (addr == 0x4B) - { - return card_piix4_ide[addr] & 0x33; - } - else - { - return card_piix4_ide[addr]; - } - } - else - { - if ((addr & 0xFC) == 0x60) - { - return card_piix4[addr] & 0x8F; - } - if (addr == 4) - { - return (card_piix4[addr] & 0x08) | 7; - } - else if (addr == 5) - { - return card_piix4[addr] & 0x01; - } - else if (addr == 6) - { - return 0x80; - } - else if (addr == 7) - { - return (card_piix4[addr] & 0x78) | 0x02; - } - else if (addr == 0x4E) - { - return (card_piix4[addr] & 0xEF) | keyboard_at_get_mouse_scan(); - } - else if (addr == 0x4F) - { - return card_piix4[addr] & 0x06; - } - else if (addr == 0x69) - { - return card_piix4[addr] & 0xFE; - } - else if (addr == 0x6A) - { - return card_piix4[addr] & 0x80; - } - else if (addr == 0x6B) - { - return card_piix4[addr] & 0x80; - } - else if (addr == 0x76) - { - return (card_piix4[addr] & 0x87) | 0x08; - } - else if (addr == 0x77) - { - return (card_piix4[addr] & 0x87) | 0x08; - } - else if (addr == 0x80) - { - return card_piix4[addr] & 0x7F; - } - else if (addr == 0x82) - { - return card_piix4[addr] & 0x0F; - } - else if (addr == 0x91) - { - return card_piix4[addr] & 0xFC; - } - else if (addr == 0x92) - { - return card_piix4[addr] & 0xC0; - } - else if (addr == 0x94) - { - return card_piix4[addr] & 0xC0; - } - else if (addr == 0xB0) - { - return card_piix4[addr] & 0x7F; - } - else if (addr == 0xB1) - { - return card_piix4[addr] & 0xDF; - } - else if (addr == 0xB3) - { - return card_piix4[addr] & 0xFD; - } - else if (addr == 0xCB) - { - return card_piix4[addr] & 0x3D; - } - else - return card_piix4[addr]; - } - - return 0; -} - -void piix4_reset(void) -{ - memset(card_piix4, 0, 256); - memset(card_piix4_ide, 0, 256); - - card_piix4[0x00] = 0x86; card_piix4[0x01] = 0x80; /*Intel*/ - card_piix4[0x02] = 0x10; card_piix4[0x03] = 0x71; /*82371AB (PIIX4)*/ - card_piix4[0x04] = 0x07; card_piix4[0x05] = 0x00; - card_piix4[0x06] = 0x80; card_piix4[0x07] = 0x02; - card_piix4[0x08] = 0x00; /*A0 stepping*/ - card_piix4[0x09] = 0x00; card_piix4[0x0a] = 0x01; card_piix4[0x0b] = 0x06; - card_piix4[0x0e] = 0x80; /*Multi-function device*/ - card_piix4[0x4c] = 0x4d; - card_piix4[0x4e] = 0x03; - card_piix4[0x60] = card_piix4[0x61] = card_piix4[0x62] = card_piix4[0x63] = 0x80; - card_piix4[0x64] = 0x10; - card_piix4[0x69] = 0x02; - card_piix4[0x76] = card_piix4[0x77] = 0x04; - card_piix4[0xcb] = 0x21; - - card_piix4_ide[0x00] = 0x86; card_piix4_ide[0x01] = 0x80; /*Intel*/ - card_piix4_ide[0x02] = 0x11; card_piix4_ide[0x03] = 0x71; /*82371AB (PIIX)*/ - card_piix4_ide[0x04] = 0x07; card_piix4_ide[0x05] = 0x00; - card_piix4_ide[0x06] = 0x80; card_piix4_ide[0x07] = 0x02; - card_piix4_ide[0x08] = 0x00; - card_piix4_ide[0x09] = 0x80; card_piix4_ide[0x0a] = 0x01; card_piix4_ide[0x0b] = 0x01; - card_piix4_ide[0x0d] = 0x00; - card_piix4_ide[0x0e] = 0x00; - card_piix4_ide[0x20] = 0x01; card_piix4_ide[0x21] = card_piix4_ide[0x22] = card_piix4_ide[0x23] = 0x00; /*Bus master interface base address*/ - card_piix4_ide[0x40] = card_piix4_ide[0x42] = 0x00; - card_piix4_ide[0x41] = card_piix4_ide[0x43] = 0x80; -} - -void piix4_init(int card) -{ - device_add(&ide_pci_2ch_device); - - pci_add_card(card, piix4_read, piix4_write, NULL); - - piix4_reset(); - - ide_set_bus_master(piix_bus_master_dma_read, piix_bus_master_dma_write, piix_bus_master_set_irq); - - port_92_reset(); - - port_92_add(); - - dma_alias_set(); - - pci_reset_handler.pci_set_reset = piix4_reset; -} diff --git a/src/intel_sio.c b/src/intel_sio.c index 5c098d296..b9e3a07d3 100644 --- a/src/intel_sio.c +++ b/src/intel_sio.c @@ -19,24 +19,106 @@ #include #include #include +#include "86box.h" #include "device.h" #include "io.h" +#include "apm.h" #include "dma.h" #include "mem.h" #include "pci.h" +#include "timer.h" +#include "pit.h" +#include "port_92.h" +#include "machine/machine.h" #include "intel_sio.h" typedef struct { - uint8_t regs[256]; + uint8_t id, + regs[256]; + + uint16_t timer_base, + timer_latch; + + pc_timer_t timer; + + port_92_t * port_92; } sio_t; +static void +sio_timer_write(uint16_t addr, uint8_t val, void *priv) +{ + sio_t *dev = (sio_t *) priv; + + if (!(addr & 0x0002)) { + if (addr & 0x0001) + dev->timer_latch = (dev->timer_latch & 0xff) | (val << 8); + else + dev->timer_latch = (dev->timer_latch & 0xff00) | val; + + timer_set_delay_u64(&dev->timer, ((uint64_t) dev->timer_latch) * TIMER_USEC); + } +} + + +static void +sio_timer_writew(uint16_t addr, uint16_t val, void *priv) +{ + sio_t *dev = (sio_t *) priv; + + if (!(addr & 0x0002)) { + dev->timer_latch = val; + + timer_set_delay_u64(&dev->timer, ((uint64_t) dev->timer_latch) * TIMER_USEC); + } +} + + +static uint8_t +sio_timer_read(uint16_t addr, void *priv) +{ + sio_t *dev = (sio_t *) priv; + uint16_t sio_timer_latch; + uint8_t ret = 0xff; + + if (!(addr & 0x0002)) { + sub_cycles((int)(PITCONST >> 32)); + + sio_timer_latch = timer_get_remaining_us(&dev->timer); + + if (addr & 0x0001) + ret = sio_timer_latch >> 8; + else + ret = sio_timer_latch & 0xff; + } + + return ret; +} + + +static uint16_t +sio_timer_readw(uint16_t addr, void *priv) +{ + sio_t *dev = (sio_t *) priv; + uint16_t ret = 0xffff; + + if (!(addr & 0x0002)) { + sub_cycles((int)(PITCONST >> 32)); + + ret = timer_get_remaining_us(&dev->timer); + } + + return ret; +} + + static void sio_write(int func, int addr, uint8_t val, void *priv) { sio_t *dev = (sio_t *) priv; + uint8_t old; if (func > 0) return; @@ -44,6 +126,13 @@ sio_write(int func, int addr, uint8_t val, void *priv) if (addr >= 0x0f && addr < 0x4c) return; + /* The IB (original) variant of the SIO has no PCI IRQ steering. */ + if ((addr >= 0x60) && (addr <= 0x63) && (dev->id < 0x03)) + return; + + old = dev->regs[addr]; + dev->regs[addr] = val; + switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: @@ -66,23 +155,22 @@ sio_write(int func, int addr, uint8_t val, void *priv) break; case 0x40: - if (!((val ^ dev->regs[addr]) & 0x40)) + if (!((val ^ old) & 0x40)) return; + dma_alias_remove(); if (val & 0x40) - dma_alias_remove(); - else dma_alias_set(); break; case 0x4f: - if (!((val ^ dev->regs[addr]) & 0x40)) + if (!((val ^ old) & 0x40)) return; + port_92_remove(dev->port_92); if (val & 0x40) - port_92_add(); - else - port_92_remove(); + port_92_add(dev->port_92); + break; case 0x60: if (val & 0x80) @@ -108,8 +196,22 @@ sio_write(int func, int addr, uint8_t val, void *priv) else pci_set_irq_routing(PCI_INTD, val & 0xf); break; + + case 0x80: + case 0x81: + if (dev->timer_base & 0x01) { + io_removehandler(dev->timer_base & 0xfffc, 0x0004, + sio_timer_read, sio_timer_readw, NULL, + sio_timer_write, sio_timer_writew, NULL, dev); + } + dev->timer_base = (dev->regs[0x81] << 8) | (dev->regs[0x80] & 0xfd); + if (dev->timer_base & 0x01) { + io_sethandler(dev->timer_base & 0xfffc, 0x0004, + sio_timer_read, sio_timer_readw, NULL, + sio_timer_write, sio_timer_writew, NULL, dev); + } + break; } - dev->regs[addr] = val; } @@ -128,6 +230,46 @@ sio_read(int func, int addr, void *priv) } +static void +sio_config_write(uint16_t addr, uint8_t val, void *priv) +{ +} + + +static uint8_t +sio_config_read(uint16_t port, void *priv) +{ + uint8_t ret = 0x00; + + switch (port & 0x000f) { + case 3: + ret = 0xff; + break; + case 5: + ret = 0xd3; + + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].pci_speed) { + case 20000000: + ret |= 0x0c; + break; + case 25000000: + default: + ret |= 0x00; + break; + case 30000000: + ret |= 0x08; + break; + case 33333333: + ret |= 0x04; + break; + } + break; + } + + return ret; +} + + static void sio_reset(void *priv) { @@ -139,7 +281,7 @@ sio_reset(void *priv) dev->regs[0x02] = 0x84; dev->regs[0x03] = 0x04; /*82378IB (SIO)*/ dev->regs[0x04] = 0x07; dev->regs[0x05] = 0x00; dev->regs[0x06] = 0x00; dev->regs[0x07] = 0x02; - dev->regs[0x08] = 0x03; /*A0 stepping*/ + dev->regs[0x08] = dev->id; dev->regs[0x40] = 0x20; dev->regs[0x41] = 0x00; dev->regs[0x42] = 0x04; dev->regs[0x43] = 0x00; @@ -159,6 +301,14 @@ sio_reset(void *priv) pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + if (dev->timer_base & 0x0001) { + io_removehandler(dev->timer_base & 0xfffc, 0x0004, + sio_timer_read, sio_timer_readw, NULL, + sio_timer_write, sio_timer_writew, NULL, dev); + } + + dev->timer_base = 0x0078; } @@ -172,21 +322,43 @@ sio_close(void *p) static void -*sio_init(const device_t *info) +sio_speed_changed(void *priv) +{ + sio_t *dev = (sio_t *) priv; + int te; + + te = timer_is_enabled(&dev->timer); + + timer_disable(&dev->timer); + if (te) + timer_set_delay_u64(&dev->timer, ((uint64_t) dev->timer_latch) * TIMER_USEC); +} + + +static void * +sio_init(const device_t *info) { sio_t *sio = (sio_t *) malloc(sizeof(sio_t)); memset(sio, 0, sizeof(sio_t)); pci_add_card(2, sio_read, sio_write, sio); - + + device_add(&apm_device); + + sio->id = info->local; sio_reset(sio); - port_92_reset(); - - port_92_add(); + sio->port_92 = device_add(&port_92_pci_device); dma_alias_set(); + io_sethandler(0x0073, 0x0001, + sio_config_read, NULL, NULL, sio_config_write, NULL, NULL, sio); + io_sethandler(0x0075, 0x0001, + sio_config_read, NULL, NULL, sio_config_write, NULL, NULL, sio); + + timer_add(&sio->timer, NULL, NULL, 0); + return sio; } @@ -195,12 +367,27 @@ const device_t sio_device = { "Intel 82378IB (SIO)", DEVICE_PCI, - 0, - sio_init, - sio_close, - NULL, + 0x00, + sio_init, + sio_close, NULL, NULL, + sio_speed_changed, + NULL, + NULL +}; + + +const device_t sio_zb_device = +{ + "Intel 82378ZB (SIO)", + DEVICE_PCI, + 0x03, + sio_init, + sio_close, + NULL, + NULL, + sio_speed_changed, NULL, NULL }; diff --git a/src/intel_sio.h b/src/intel_sio.h index b1976b9b2..3793c6c58 100644 --- a/src/intel_sio.h +++ b/src/intel_sio.h @@ -15,3 +15,4 @@ */ extern const device_t sio_device; +extern const device_t sio_zb_device; diff --git a/src/io.c b/src/io.c index 5747d3975..d236f49b6 100644 --- a/src/io.c +++ b/src/io.c @@ -8,14 +8,14 @@ * * Implement I/O ports and their operations. * - * Version: @(#)io.c 1.0.5 2018/10/17 + * Version: @(#)io.c 1.0.6 2019/03/21 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -27,6 +27,7 @@ #include "86box.h" #include "io.h" #include "cpu/cpu.h" +#include "machine/m_amstrad.h" #define NPORTS 65536 /* PC/AT supports 64K ports */ @@ -208,6 +209,23 @@ io_removehandler(uint16_t base, int size, } +void +io_handler(int set, uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + if (set) + io_sethandler(base, size, inb, inw, inl, outb, outw, outl, priv); + else + io_removehandler(base, size, inb, inw, inl, outb, outw, outl, priv); +} + + #ifdef PC98 void io_sethandler_interleaved(uint16_t base, int size, @@ -288,24 +306,39 @@ io_removehandler_interleaved(uint16_t base, int size, uint8_t inb(uint16_t port) { - uint8_t r = 0xff; + uint8_t ret = 0xff; io_t *p; + int found = 0; p = io[port]; if (p) { while(p) { - if (p->inb) - r &= p->inb(port, p->priv); + if (p->inb) { + ret &= p->inb(port, p->priv); + found++; + } p = p->next; } } + if (port & 0x80) + amstrad_latch = AMSTRAD_NOLATCH; + else if (port & 0x4000) + amstrad_latch = AMSTRAD_SW10; + else + amstrad_latch = AMSTRAD_SW9; + #ifdef ENABLE_IO_LOG if (CS == IO_TRACE) io_log("IOTRACE(%04X): inb(%04x)=%02x\n", IO_TRACE, port, r); #endif - return(r); + if (!found) + sub_cycles(io_delay); + + // pclog("[%04X:%08X] inb(%04X) = %02X\n", CS, cpu_state.pc, port, ret); + + return(ret); } @@ -313,12 +346,15 @@ void outb(uint16_t port, uint8_t val) { io_t *p; + int found = 0; if (io[port]) { p = io[port]; while(p) { - if (p->outb) + if (p->outb) { p->outb(port, val, p->priv); + found++; + } p = p->next; } } @@ -327,6 +363,12 @@ outb(uint16_t port, uint8_t val) if (CS == IO_TRACE) io_log("IOTRACE(%04X): outb(%04x,%02x)\n", IO_TRACE, port, val); #endif + + if (!found) + sub_cycles(io_delay); + + // pclog("[%04X:%08X] outb(%04X) = %02X\n", CS, cpu_state.pc, port, val); + return; } @@ -335,17 +377,26 @@ uint16_t inw(uint16_t port) { io_t *p; + uint16_t ret = 0xffff; + int found = 0; p = io[port]; if (p) { while(p) { - if (p->inw) - return p->inw(port, p->priv); + if (p->inw) { + ret = p->inw(port, p->priv); + found = 1; + } p = p->next; } } - return(inb(port) | (inb(port + 1) << 8)); + if (!found) + ret = (inb(port) | (inb(port + 1) << 8)); + // else + // pclog("[%04X:%08X] inw(%04X) = %04X\n", CS, cpu_state.pc, port, ret); + + return ret; } @@ -359,6 +410,8 @@ outw(uint16_t port, uint16_t val) while(p) { if (p->outw) { p->outw(port, val, p->priv); + + // pclog("[%04X:%08X] outw(%04X) = %04X\n", CS, cpu_state.pc, port, val); return; } p = p->next; @@ -376,17 +429,26 @@ uint32_t inl(uint16_t port) { io_t *p; + uint32_t ret = 0xffffffff; + int found = 0; p = io[port]; if (p) { while(p) { - if (p->inl) - return p->inl(port, p->priv); + if (p->inl) { + ret = p->inl(port, p->priv); + found = 1; + } p = p->next; } } - return(inw(port) | (inw(port + 2) << 16)); + if (!found) + ret = (inw(port) | (inw(port + 2) << 16)); + // else + // pclog("[%04X:%08X] inl(%04X) = %08X\n", CS, cpu_state.pc, port, ret); + + return ret; } @@ -400,6 +462,8 @@ outl(uint16_t port, uint32_t val) while(p) { if (p->outl) { p->outl(port, val, p->priv); + + // pclog("[%04X:%08X] outl(%04X) = %08X\n", CS, cpu_state.pc, port, val); return; } p = p->next; diff --git a/src/io.h b/src/io.h index 43b23c00d..93bb3be03 100644 --- a/src/io.h +++ b/src/io.h @@ -41,6 +41,15 @@ extern void io_removehandler(uint16_t base, int size, void (*outl)(uint16_t addr, uint32_t val, void *priv), void *priv); +extern void io_handler(int set, uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv); + #ifdef PC98 extern void io_sethandler_interleaved(uint16_t base, int size, uint8_t (*inb)(uint16_t addr, void *priv), diff --git a/src/isartc.c b/src/isartc.c index 8332fa91e..22da01027 100644 --- a/src/isartc.c +++ b/src/isartc.c @@ -72,6 +72,7 @@ #include #include "86box.h" #include "cpu/cpu.h" +#include "timer.h" #include "machine/machine.h" #include "io.h" #include "device.h" @@ -387,7 +388,7 @@ mm67_read(uint16_t port, void *priv) uint8_t ret = 0xff; /* This chip is directly mapped on I/O. */ - cycles -= ISA_CYCLES(4); + sub_cycles(ISA_CYCLES(4)); switch(reg) { case MM67_ISTAT: /* IRQ status (RO) */ @@ -423,7 +424,7 @@ mm67_write(uint16_t port, uint8_t val, void *priv) #endif /* This chip is directly mapped on I/O. */ - cycles -= ISA_CYCLES(4); + sub_cycles(ISA_CYCLES(4)); switch(reg) { case MM67_ISTAT: /* intr status (RO) */ diff --git a/src/keyboard.c b/src/keyboard.c index 55fea6571..68f5017df 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -8,15 +8,15 @@ * * General keyboard driver interface. * - * Version: @(#)keyboard.c 1.0.15 2018/03/19 + * Version: @(#)keyboard.c 1.0.16 2019/03/05 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2015-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2015-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -27,7 +27,6 @@ #include "keyboard.h" -int64_t keyboard_delay; int keyboard_scan; void (*keyboard_send)(uint16_t val); @@ -51,7 +50,6 @@ keyboard_init(void) memset(recv_key, 0x00, sizeof(recv_key)); keyboard_scan = 1; - keyboard_delay = 0; scan_table = NULL; memset(keyboard_set3_flags, 0x00, sizeof(keyboard_set3_flags)); @@ -75,6 +73,7 @@ fake_shift_needed(uint16_t scan) case 0x148: case 0x149: case 0x14a: + case 0x14b: case 0x14d: case 0x14f: case 0x150: @@ -97,10 +96,10 @@ key_process(uint16_t scan, int down) if (! keyboard_scan) return; oldkey[scan] = down; - if (down && codes[scan].mk[0] == -1) + if (down && codes[scan].mk[0] == 0) return; - if (!down && codes[scan].brk[0] == -1) + if (!down && codes[scan].brk[0] == 0) return; if (AT && ((keyboard_mode & 3) == 3)) { @@ -113,10 +112,10 @@ key_process(uint16_t scan, int down) /* Send the special code indicating an opening fake shift might be needed. */ if (fake_shift_needed(scan)) keyboard_send(0x100); - while (codes[scan].mk[c] != -1) + while (codes[scan].mk[c] != 0) keyboard_send(codes[scan].mk[c++]); } else { - while (codes[scan].brk[c] != -1) + while (codes[scan].brk[c] != 0) keyboard_send(codes[scan].brk[c++]); /* Send the special code indicating a closing fake shift might be needed. */ if (fake_shift_needed(scan)) @@ -157,13 +156,13 @@ keyboard_input(int down, uint16_t scan) shift |= 0x20; break; case 0x038: /* Left Alt */ - shift |= 0x03; + shift |= 0x04; break; case 0x138: /* Right Alt */ - shift |= 0x30; + shift |= 0x40; break; - } - } else { + } + } else { switch(scan & 0x1ff) { case 0x01c: /* Left Ctrl */ shift &= ~0x01; @@ -178,10 +177,10 @@ keyboard_input(int down, uint16_t scan) shift &= ~0x20; break; case 0x038: /* Left Alt */ - shift &= ~0x03; + shift &= ~0x04; break; case 0x138: /* Right Alt */ - shift &= ~0x30; + shift &= ~0x40; break; case 0x03a: /* Caps Lock */ caps_lock ^= 1; @@ -265,33 +264,33 @@ keyboard_set_states(uint8_t cl, uint8_t nl, uint8_t sl) if (caps_lock != cl) { i = 0; - while (codes[0x03a].mk[i] != -1) + while (codes[0x03a].mk[i] != 0) keyboard_send(codes[0x03a].mk[i++]); if (keyboard_do_break(0x03a)) { i = 0; - while (codes[0x03a].brk[i] != -1) + while (codes[0x03a].brk[i] != 0) keyboard_send(codes[0x03a].brk[i++]); } } if (num_lock != nl) { i = 0; - while (codes[0x045].mk[i] != -1) + while (codes[0x045].mk[i] != 0) keyboard_send(codes[0x045].mk[i++]); if (keyboard_do_break(0x045)) { i = 0; - while (codes[0x045].brk[i] != -1) + while (codes[0x045].brk[i] != 0) keyboard_send(codes[0x045].brk[i++]); } } if (scroll_lock != sl) { i = 0; - while (codes[0x046].mk[i] != -1) + while (codes[0x046].mk[i] != 0) keyboard_send(codes[0x046].mk[i++]); if (keyboard_do_break(0x046)) { i = 0; - while (codes[0x046].brk[i] != -1) + while (codes[0x046].brk[i] != 0) keyboard_send(codes[0x046].brk[i++]); } } diff --git a/src/keyboard.h b/src/keyboard.h index bda91929a..607136757 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -8,7 +8,7 @@ * * Definitions for the keyboard interface. * - * Version: @(#)keyboard.h 1.0.17 2019/02/08 + * Version: @(#)keyboard.h 1.0.18 2019/03/05 * * Authors: Sarah Walker, * Miran Grca, @@ -23,8 +23,8 @@ typedef struct { - int mk[9]; - int brk[9]; + const uint8_t mk[4]; + const uint8_t brk[4]; } scancode; @@ -46,7 +46,6 @@ extern "C" { extern uint8_t keyboard_mode; extern int keyboard_scan; -extern int64_t keyboard_delay; extern void (*keyboard_send)(uint16_t val); extern void kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)); @@ -64,6 +63,7 @@ extern const device_t keyboard_pc_device; extern const device_t keyboard_pc82_device; extern const device_t keyboard_xt_device; extern const device_t keyboard_xt86_device; +extern const device_t keyboard_xt_compaq_device; extern const device_t keyboard_tandy_device; #if defined(DEV_BRANCH) && defined(USE_LASERXT) extern const device_t keyboard_xt_lxt3_device; @@ -72,6 +72,8 @@ extern const device_t keyboard_at_device; extern const device_t keyboard_at_ami_device; extern const device_t keyboard_at_toshiba_device; extern const device_t keyboard_ps2_device; +extern const device_t keyboard_ps2_ps1_device; +extern const device_t keyboard_ps2_ps2_device; extern const device_t keyboard_ps2_xi8088_device; extern const device_t keyboard_ps2_ami_device; extern const device_t keyboard_ps2_mca_device; diff --git a/src/keyboard_at.c b/src/keyboard_at.c index f9163bc5b..dfe28a53b 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.42 2018/10/17 + * Version: @(#)keyboard_at.c 1.0.43 2019/03/05 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -27,14 +27,13 @@ #include #include "86box.h" #include "cpu/cpu.h" +#include "timer.h" #include "io.h" #include "pic.h" #include "pit.h" #include "ppi.h" #include "mem.h" -#include "rom.h" #include "device.h" -#include "timer.h" #include "machine/machine.h" #include "machine/m_xt_xi8088.h" #include "machine/m_at_t3100e.h" @@ -45,17 +44,18 @@ #include "video/video.h" #include "keyboard.h" + #define STAT_PARITY 0x80 #define STAT_RTIMEOUT 0x40 #define STAT_TTIMEOUT 0x20 #define STAT_MFULL 0x20 -#define STAT_LOCK 0x10 +#define STAT_UNLOCKED 0x10 #define STAT_CD 0x08 #define STAT_SYSFLAG 0x04 #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 -#define PS2_REFRESH_TIME (16LL * TIMER_USEC) +#define PS2_REFRESH_TIME (16 * TIMER_USEC) #define CCB_UNUSED 0x80 #define CCB_TRANSLATE 0x40 @@ -69,9 +69,10 @@ #define CCB_MASK 0x68 #define MODE_MASK 0x6c -#define KBC_TYPE_ISA 0x00 -#define KBC_TYPE_PS2_1 0x01 -#define KBC_TYPE_PS2_2 0x02 +#define KBC_TYPE_ISA 0x00 /* AT ISA-based chips */ +#define KBC_TYPE_PS2_NOREF 0x01 /* PS2 type, no refresh */ +#define KBC_TYPE_PS2_1 0x02 /* PS2 on PS/2, type 1 */ +#define KBC_TYPE_PS2_2 0x03 /* PS2 on PS/2, type 2 */ #define KBC_TYPE_MASK 0x03 #define KBC_VEN_GENERIC 0x00 @@ -80,48 +81,36 @@ #define KBC_VEN_QUADTEL 0x0c #define KBC_VEN_TOSHIBA 0x10 #define KBC_VEN_XI8088 0x14 +#define KBC_VEN_IBM_PS1 0x18 +#define KBC_VEN_ACER 0x1c #define KBC_VEN_MASK 0x1c typedef struct { - int initialized; - int want60, - wantirq, - wantirq12; - uint8_t command; - uint8_t status; + uint8_t command, status, out, secr_phase, + mem_addr, input_port, output_port, old_output_port, + key_command, output_locked, ami_stat, initialized, + want60, wantirq, key_wantdata, refresh, first_write; + uint8_t mem[0x100]; - uint8_t out; + int out_new, out_delayed; - uint8_t secr_phase; - uint8_t mem_addr; - - uint8_t input_port, - output_port; - - uint8_t old_output_port; - - uint8_t key_command; - int key_wantdata; - int last_irq; - uint8_t last_scan_code; - - int dtrans; - int first_write; - - int64_t refresh_time; - int refresh; - uint32_t flags; - uint8_t output_locked; - int64_t pulse_cb; - uint8_t ami_stat; + pc_timer_t refresh_time, pulse_cb; uint8_t (*write60_ven)(void *p, uint8_t val); uint8_t (*write64_ven)(void *p, uint8_t val); + + pc_timer_t send_delay_timer; +#ifdef USE_NEW_STUFF + /* Custom machine-dependent keyboard stuff. */ + uint8_t (*read_func)(void *priv); + void (*write_func)(void *priv, uint8_t val); + void *func_priv; +#endif } atkbd_t; @@ -131,7 +120,6 @@ uint8_t keyboard_set3_all_repeat; uint8_t keyboard_set3_all_break; /* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ -/* Q */ uint8_t keyboard_mode = 0x42; int mouse_queue_start = 0, @@ -148,7 +136,7 @@ static uint8_t mouse_queue[16]; static void (*mouse_write)(uint8_t val, void *priv) = NULL; static void *mouse_p = NULL; static uint8_t sc_or = 0; -static atkbd_t *CurrentKbd = NULL; // FIXME: remove!!! --FvK +static atkbd_t *SavedKbd = NULL; // FIXME: remove!!! --FvK /* Non-translated to translated scan codes. */ @@ -187,396 +175,396 @@ static const uint8_t nont_to_t[256] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; -#if 0 +#ifdef USE_SET1 static const scancode scancode_set1[512] = { - { { -1},{ -1} }, { { 0x01,-1},{ 0x81,-1} }, { { 0x02,-1},{ 0x82,-1} }, { { 0x03,-1},{ 0x83,-1} }, /*000*/ - { { 0x04,-1},{ 0x84,-1} }, { { 0x05,-1},{ 0x85,-1} }, { { 0x06,-1},{ 0x86,-1} }, { { 0x07,-1},{ 0x87,-1} }, /*004*/ - { { 0x08,-1},{ 0x88,-1} }, { { 0x09,-1},{ 0x89,-1} }, { { 0x0a,-1},{ 0x8a,-1} }, { { 0x0b,-1},{ 0x8b,-1} }, /*008*/ - { { 0x0c,-1},{ 0x8c,-1} }, { { 0x0d,-1},{ 0x8d,-1} }, { { 0x0e,-1},{ 0x8e,-1} }, { { 0x0f,-1},{ 0x8f,-1} }, /*00c*/ - { { 0x10,-1},{ 0x90,-1} }, { { 0x11,-1},{ 0x91,-1} }, { { 0x12,-1},{ 0x92,-1} }, { { 0x13,-1},{ 0x93,-1} }, /*010*/ - { { 0x14,-1},{ 0x94,-1} }, { { 0x15,-1},{ 0x95,-1} }, { { 0x16,-1},{ 0x96,-1} }, { { 0x17,-1},{ 0x97,-1} }, /*014*/ - { { 0x18,-1},{ 0x98,-1} }, { { 0x19,-1},{ 0x99,-1} }, { { 0x1a,-1},{ 0x9a,-1} }, { { 0x1b,-1},{ 0x9b,-1} }, /*018*/ - { { 0x1c,-1},{ 0x9c,-1} }, { { 0x1d,-1},{ 0x9d,-1} }, { { 0x1e,-1},{ 0x9e,-1} }, { { 0x1f,-1},{ 0x9f,-1} }, /*01c*/ - { { 0x20,-1},{ 0xa0,-1} }, { { 0x21,-1},{ 0xa1,-1} }, { { 0x22,-1},{ 0xa2,-1} }, { { 0x23,-1},{ 0xa3,-1} }, /*020*/ - { { 0x24,-1},{ 0xa4,-1} }, { { 0x25,-1},{ 0xa5,-1} }, { { 0x26,-1},{ 0xa6,-1} }, { { 0x27,-1},{ 0xa7,-1} }, /*024*/ - { { 0x28,-1},{ 0xa8,-1} }, { { 0x29,-1},{ 0xa9,-1} }, { { 0x2a,-1},{ 0xaa,-1} }, { { 0x2b,-1},{ 0xab,-1} }, /*028*/ - { { 0x2c,-1},{ 0xac,-1} }, { { 0x2d,-1},{ 0xad,-1} }, { { 0x2e,-1},{ 0xae,-1} }, { { 0x2f,-1},{ 0xaf,-1} }, /*02c*/ - { { 0x30,-1},{ 0xb0,-1} }, { { 0x31,-1},{ 0xb1,-1} }, { { 0x32,-1},{ 0xb2,-1} }, { { 0x33,-1},{ 0xb3,-1} }, /*030*/ - { { 0x34,-1},{ 0xb4,-1} }, { { 0x35,-1},{ 0xb5,-1} }, { { 0x36,-1},{ 0xb6,-1} }, { { 0x37,-1},{ 0xb7,-1} }, /*034*/ - { { 0x38,-1},{ 0xb8,-1} }, { { 0x39,-1},{ 0xb9,-1} }, { { 0x3a,-1},{ 0xba,-1} }, { { 0x3b,-1},{ 0xbb,-1} }, /*038*/ - { { 0x3c,-1},{ 0xbc,-1} }, { { 0x3d,-1},{ 0xbd,-1} }, { { 0x3e,-1},{ 0xbe,-1} }, { { 0x3f,-1},{ 0xbf,-1} }, /*03c*/ - { { 0x40,-1},{ 0xc0,-1} }, { { 0x41,-1},{ 0xc1,-1} }, { { 0x42,-1},{ 0xc2,-1} }, { { 0x43,-1},{ 0xc3,-1} }, /*040*/ - { { 0x44,-1},{ 0xc4,-1} }, { { 0x45,-1},{ 0xc5,-1} }, { { 0x46,-1},{ 0xc6,-1} }, { { 0x47,-1},{ 0xc7,-1} }, /*044*/ - { { 0x48,-1},{ 0xc8,-1} }, { { 0x49,-1},{ 0xc9,-1} }, { { 0x4a,-1},{ 0xca,-1} }, { { 0x4b,-1},{ 0xcb,-1} }, /*048*/ - { { 0x4c,-1},{ 0xcc,-1} }, { { 0x4d,-1},{ 0xcd,-1} }, { { 0x4e,-1},{ 0xce,-1} }, { { 0x4f,-1},{ 0xcf,-1} }, /*04c*/ - { { 0x50,-1},{ 0xd0,-1} }, { { 0x51,-1},{ 0xd1,-1} }, { { 0x52,-1},{ 0xd2,-1} }, { { 0x53,-1},{ 0xd3,-1} }, /*050*/ - { { 0x54,-1},{ 0xd4,-1} }, { { 0x55,-1},{ 0xd5,-1} }, { { 0x56,-1},{ 0xd6,-1} }, { { 0x57,-1},{ 0xd7,-1} }, /*054*/ - { { 0x58,-1},{ 0xd8,-1} }, { { 0x59,-1},{ 0xd9,-1} }, { { 0x5a,-1},{ 0xda,-1} }, { { 0x5b,-1},{ 0xdb,-1} }, /*058*/ - { { 0x5c,-1},{ 0xdc,-1} }, { { 0x5d,-1},{ 0xdd,-1} }, { { 0x5e,-1},{ 0xde,-1} }, { { 0x5f,-1},{ 0xdf,-1} }, /*05c*/ - { { 0x60,-1},{ 0xe0,-1} }, { { 0x61,-1},{ 0xe1,-1} }, { { 0x62,-1},{ 0xe2,-1} }, { { 0x63,-1},{ 0xe3,-1} }, /*060*/ - { { 0x64,-1},{ 0xe4,-1} }, { { 0x65,-1},{ 0xe5,-1} }, { { 0x66,-1},{ 0xe6,-1} }, { { 0x67,-1},{ 0xe7,-1} }, /*064*/ - { { 0x68,-1},{ 0xe8,-1} }, { { 0x69,-1},{ 0xe9,-1} }, { { 0x6a,-1},{ 0xea,-1} }, { { 0x6b,-1},{ 0xeb,-1} }, /*068*/ - { { 0x6c,-1},{ 0xec,-1} }, { { 0x6d,-1},{ 0xed,-1} }, { { 0x6e,-1},{ 0xee,-1} }, { { 0x6f,-1},{ 0xef,-1} }, /*06c*/ - { { 0x70,-1},{ 0xf0,-1} }, { { 0x71,-1},{ 0xf1,-1} }, { { 0x72,-1},{ 0xf2,-1} }, { { 0x73,-1},{ 0xf3,-1} }, /*070*/ - { { 0x74,-1},{ 0xf4,-1} }, { { 0x75,-1},{ 0xf5,-1} }, { { 0x76,-1},{ 0xf6,-1} }, { { 0x77,-1},{ 0xf7,-1} }, /*074*/ - { { 0x78,-1},{ 0xf8,-1} }, { { 0x79,-1},{ 0xf9,-1} }, { { 0x7a,-1},{ 0xfa,-1} }, { { 0x7b,-1},{ 0xfb,-1} }, /*078*/ - { { 0x7c,-1},{ 0xfc,-1} }, { { 0x7d,-1},{ 0xfd,-1} }, { { 0x7e,-1},{ 0xfe,-1} }, { { 0x7f,-1},{ 0xff,-1} }, /*07c*/ + { { 0},{ 0} }, { { 0x01,0},{ 0x81,0} }, { { 0x02,0},{ 0x82,0} }, { { 0x03,0},{ 0x83,0} }, /*000*/ + { { 0x04,0},{ 0x84,0} }, { { 0x05,0},{ 0x85,0} }, { { 0x06,0},{ 0x86,0} }, { { 0x07,0},{ 0x87,0} }, /*004*/ + { { 0x08,0},{ 0x88,0} }, { { 0x09,0},{ 0x89,0} }, { { 0x0a,0},{ 0x8a,0} }, { { 0x0b,0},{ 0x8b,0} }, /*008*/ + { { 0x0c,0},{ 0x8c,0} }, { { 0x0d,0},{ 0x8d,0} }, { { 0x0e,0},{ 0x8e,0} }, { { 0x0f,0},{ 0x8f,0} }, /*00c*/ + { { 0x10,0},{ 0x90,0} }, { { 0x11,0},{ 0x91,0} }, { { 0x12,0},{ 0x92,0} }, { { 0x13,0},{ 0x93,0} }, /*010*/ + { { 0x14,0},{ 0x94,0} }, { { 0x15,0},{ 0x95,0} }, { { 0x16,0},{ 0x96,0} }, { { 0x17,0},{ 0x97,0} }, /*014*/ + { { 0x18,0},{ 0x98,0} }, { { 0x19,0},{ 0x99,0} }, { { 0x1a,0},{ 0x9a,0} }, { { 0x1b,0},{ 0x9b,0} }, /*018*/ + { { 0x1c,0},{ 0x9c,0} }, { { 0x1d,0},{ 0x9d,0} }, { { 0x1e,0},{ 0x9e,0} }, { { 0x1f,0},{ 0x9f,0} }, /*01c*/ + { { 0x20,0},{ 0xa0,0} }, { { 0x21,0},{ 0xa1,0} }, { { 0x22,0},{ 0xa2,0} }, { { 0x23,0},{ 0xa3,0} }, /*020*/ + { { 0x24,0},{ 0xa4,0} }, { { 0x25,0},{ 0xa5,0} }, { { 0x26,0},{ 0xa6,0} }, { { 0x27,0},{ 0xa7,0} }, /*024*/ + { { 0x28,0},{ 0xa8,0} }, { { 0x29,0},{ 0xa9,0} }, { { 0x2a,0},{ 0xaa,0} }, { { 0x2b,0},{ 0xab,0} }, /*028*/ + { { 0x2c,0},{ 0xac,0} }, { { 0x2d,0},{ 0xad,0} }, { { 0x2e,0},{ 0xae,0} }, { { 0x2f,0},{ 0xaf,0} }, /*02c*/ + { { 0x30,0},{ 0xb0,0} }, { { 0x31,0},{ 0xb1,0} }, { { 0x32,0},{ 0xb2,0} }, { { 0x33,0},{ 0xb3,0} }, /*030*/ + { { 0x34,0},{ 0xb4,0} }, { { 0x35,0},{ 0xb5,0} }, { { 0x36,0},{ 0xb6,0} }, { { 0x37,0},{ 0xb7,0} }, /*034*/ + { { 0x38,0},{ 0xb8,0} }, { { 0x39,0},{ 0xb9,0} }, { { 0x3a,0},{ 0xba,0} }, { { 0x3b,0},{ 0xbb,0} }, /*038*/ + { { 0x3c,0},{ 0xbc,0} }, { { 0x3d,0},{ 0xbd,0} }, { { 0x3e,0},{ 0xbe,0} }, { { 0x3f,0},{ 0xbf,0} }, /*03c*/ + { { 0x40,0},{ 0xc0,0} }, { { 0x41,0},{ 0xc1,0} }, { { 0x42,0},{ 0xc2,0} }, { { 0x43,0},{ 0xc3,0} }, /*040*/ + { { 0x44,0},{ 0xc4,0} }, { { 0x45,0},{ 0xc5,0} }, { { 0x46,0},{ 0xc6,0} }, { { 0x47,0},{ 0xc7,0} }, /*044*/ + { { 0x48,0},{ 0xc8,0} }, { { 0x49,0},{ 0xc9,0} }, { { 0x4a,0},{ 0xca,0} }, { { 0x4b,0},{ 0xcb,0} }, /*048*/ + { { 0x4c,0},{ 0xcc,0} }, { { 0x4d,0},{ 0xcd,0} }, { { 0x4e,0},{ 0xce,0} }, { { 0x4f,0},{ 0xcf,0} }, /*04c*/ + { { 0x50,0},{ 0xd0,0} }, { { 0x51,0},{ 0xd1,0} }, { { 0x52,0},{ 0xd2,0} }, { { 0x53,0},{ 0xd3,0} }, /*050*/ + { { 0x54,0},{ 0xd4,0} }, { { 0x55,0},{ 0xd5,0} }, { { 0x56,0},{ 0xd6,0} }, { { 0x57,0},{ 0xd7,0} }, /*054*/ + { { 0x58,0},{ 0xd8,0} }, { { 0x59,0},{ 0xd9,0} }, { { 0x5a,0},{ 0xda,0} }, { { 0x5b,0},{ 0xdb,0} }, /*058*/ + { { 0x5c,0},{ 0xdc,0} }, { { 0x5d,0},{ 0xdd,0} }, { { 0x5e,0},{ 0xde,0} }, { { 0x5f,0},{ 0xdf,0} }, /*05c*/ + { { 0x60,0},{ 0xe0,0} }, { { 0x61,0},{ 0xe1,0} }, { { 0x62,0},{ 0xe2,0} }, { { 0x63,0},{ 0xe3,0} }, /*060*/ + { { 0x64,0},{ 0xe4,0} }, { { 0x65,0},{ 0xe5,0} }, { { 0x66,0},{ 0xe6,0} }, { { 0x67,0},{ 0xe7,0} }, /*064*/ + { { 0x68,0},{ 0xe8,0} }, { { 0x69,0},{ 0xe9,0} }, { { 0x6a,0},{ 0xea,0} }, { { 0x6b,0},{ 0xeb,0} }, /*068*/ + { { 0x6c,0},{ 0xec,0} }, { { 0x6d,0},{ 0xed,0} }, { { 0x6e,0},{ 0xee,0} }, { { 0x6f,0},{ 0xef,0} }, /*06c*/ + { { 0x70,0},{ 0xf0,0} }, { { 0x71,0},{ 0xf1,0} }, { { 0x72,0},{ 0xf2,0} }, { { 0x73,0},{ 0xf3,0} }, /*070*/ + { { 0x74,0},{ 0xf4,0} }, { { 0x75,0},{ 0xf5,0} }, { { 0x76,0},{ 0xf6,0} }, { { 0x77,0},{ 0xf7,0} }, /*074*/ + { { 0x78,0},{ 0xf8,0} }, { { 0x79,0},{ 0xf9,0} }, { { 0x7a,0},{ 0xfa,0} }, { { 0x7b,0},{ 0xfb,0} }, /*078*/ + { { 0x7c,0},{ 0xfc,0} }, { { 0x7d,0},{ 0xfd,0} }, { { 0x7e,0},{ 0xfe,0} }, { { 0x7f,0},{ 0xff,0} }, /*07c*/ - { { 0x80,-1},{ -1} }, { { 0x81,-1},{ -1} }, { { 0x82,-1},{ -1} }, { { -1},{ -1} }, /*080*/ - { { -1},{ -1} }, { { 0x85,-1},{ -1} }, { { 0x86,-1},{ -1} }, { { 0x87,-1},{ -1} }, /*084*/ - { { 0x88,-1},{ -1} }, { { 0x89,-1},{ -1} }, { { 0x8a,-1},{ -1} }, { { 0x8b,-1},{ -1} }, /*088*/ - { { 0x8c,-1},{ -1} }, { { 0x8d,-1},{ -1} }, { { 0x8e,-1},{ -1} }, { { 0x8f,-1},{ -1} }, /*08c*/ - { { 0x90,-1},{ -1} }, { { 0x91,-1},{ -1} }, { { 0x92,-1},{ -1} }, { { 0x93,-1},{ -1} }, /*090*/ - { { 0x94,-1},{ -1} }, { { 0x95,-1},{ -1} }, { { 0x96,-1},{ -1} }, { { 0x97,-1},{ -1} }, /*094*/ - { { 0x98,-1},{ -1} }, { { 0x99,-1},{ -1} }, { { 0x9a,-1},{ -1} }, { { 0x9b,-1},{ -1} }, /*098*/ - { { 0x9c,-1},{ -1} }, { { 0x9d,-1},{ -1} }, { { 0x9e,-1},{ -1} }, { { 0x9f,-1},{ -1} }, /*09c*/ - { { 0xa0,-1},{ -1} }, { { 0xa1,-1},{ -1} }, { { 0xa2,-1},{ -1} }, { { 0xa3,-1},{ -1} }, /*0a0*/ - { { 0xa4,-1},{ -1} }, { { 0xa5,-1},{ -1} }, { { 0xa6,-1},{ -1} }, { { 0xa7,-1},{ -1} }, /*0a4*/ - { { 0xa8,-1},{ -1} }, { { 0xa9,-1},{ -1} }, { { 0xaa,-1},{ -1} }, { { 0xab,-1},{ -1} }, /*0a8*/ - { { 0xac,-1},{ -1} }, { { 0xad,-1},{ -1} }, { { 0xae,-1},{ -1} }, { { 0xaf,-1},{ -1} }, /*0ac*/ - { { 0xb0,-1},{ -1} }, { { 0xb1,-1},{ -1} }, { { 0xb2,-1},{ -1} }, { { 0xb3,-1},{ -1} }, /*0b0*/ - { { 0xb4,-1},{ -1} }, { { 0xb5,-1},{ -1} }, { { 0xb6,-1},{ -1} }, { { 0xb7,-1},{ -1} }, /*0b4*/ - { { 0xb8,-1},{ -1} }, { { 0xb9,-1},{ -1} }, { { 0xba,-1},{ -1} }, { { 0xbb,-1},{ -1} }, /*0b8*/ - { { 0xbc,-1},{ -1} }, { { 0xbd,-1},{ -1} }, { { 0xbe,-1},{ -1} }, { { 0xbf,-1},{ -1} }, /*0bc*/ - { { 0xc0,-1},{ -1} }, { { 0xc1,-1},{ -1} }, { { 0xc2,-1},{ -1} }, { { 0xc3,-1},{ -1} }, /*0c0*/ - { { 0xc4,-1},{ -1} }, { { 0xc5,-1},{ -1} }, { { 0xc6,-1},{ -1} }, { { 0xc7,-1},{ -1} }, /*0c4*/ - { { 0xc8,-1},{ -1} }, { { 0xc9,-1},{ -1} }, { { 0xca,-1},{ -1} }, { { 0xcb,-1},{ -1} }, /*0c8*/ - { { 0xcc,-1},{ -1} }, { { 0xcd,-1},{ -1} }, { { 0xce,-1},{ -1} }, { { 0xcf,-1},{ -1} }, /*0cc*/ - { { 0xd0,-1},{ -1} }, { { 0xd1,-1},{ -1} }, { { 0xd2,-1},{ -1} }, { { 0xd3,-1},{ -1} }, /*0d0*/ - { { 0xd4,-1},{ -1} }, { { 0xd5,-1},{ -1} }, { { 0xd6,-1},{ -1} }, { { 0xd7,-1},{ -1} }, /*0d4*/ - { { 0xd8,-1},{ -1} }, { { 0xd9,-1},{ -1} }, { { 0xda,-1},{ -1} }, { { 0xdb,-1},{ -1} }, /*0d8*/ - { { 0xdc,-1},{ -1} }, { { 0xdd,-1},{ -1} }, { { 0xde,-1},{ -1} }, { { 0xdf,-1},{ -1} }, /*0dc*/ - { { 0xe0,-1},{ -1} }, { { 0xe1,-1},{ -1} }, { { 0xe2,-1},{ -1} }, { { 0xe3,-1},{ -1} }, /*0e0*/ - { { 0xe4,-1},{ -1} }, { { 0xe5,-1},{ -1} }, { { 0xe6,-1},{ -1} }, { { 0xe7,-1},{ -1} }, /*0e4*/ - { { 0xe8,-1},{ -1} }, { { 0xe9,-1},{ -1} }, { { 0xea,-1},{ -1} }, { { 0xeb,-1},{ -1} }, /*0e8*/ - { { 0xec,-1},{ -1} }, { { 0xed,-1},{ -1} }, { { 0xee,-1},{ -1} }, { { 0xef,-1},{ -1} }, /*0ec*/ - { { -1},{ -1} }, { { 0xf1,-1},{ -1} }, { { 0xf2,-1},{ -1} }, { { 0xf3,-1},{ -1} }, /*0f0*/ - { { 0xf4,-1},{ -1} }, { { 0xf5,-1},{ -1} }, { { 0xf6,-1},{ -1} }, { { 0xf7,-1},{ -1} }, /*0f4*/ - { { 0xf8,-1},{ -1} }, { { 0xf9,-1},{ -1} }, { { 0xfa,-1},{ -1} }, { { 0xfb,-1},{ -1} }, /*0f8*/ - { { 0xfc,-1},{ -1} }, { { 0xfd,-1},{ -1} }, { { 0xfe,-1},{ -1} }, { { 0xff,-1},{ -1} }, /*0fc*/ + { { 0x80,0},{ 0} }, { { 0x81,0},{ 0} }, { { 0x82,0},{ 0} }, { { 0},{ 0} }, /*080*/ + { { 0},{ 0} }, { { 0x85,0},{ 0} }, { { 0x86,0},{ 0} }, { { 0x87,0},{ 0} }, /*084*/ + { { 0x88,0},{ 0} }, { { 0x89,0},{ 0} }, { { 0x8a,0},{ 0} }, { { 0x8b,0},{ 0} }, /*088*/ + { { 0x8c,0},{ 0} }, { { 0x8d,0},{ 0} }, { { 0x8e,0},{ 0} }, { { 0x8f,0},{ 0} }, /*08c*/ + { { 0x90,0},{ 0} }, { { 0x91,0},{ 0} }, { { 0x92,0},{ 0} }, { { 0x93,0},{ 0} }, /*090*/ + { { 0x94,0},{ 0} }, { { 0x95,0},{ 0} }, { { 0x96,0},{ 0} }, { { 0x97,0},{ 0} }, /*094*/ + { { 0x98,0},{ 0} }, { { 0x99,0},{ 0} }, { { 0x9a,0},{ 0} }, { { 0x9b,0},{ 0} }, /*098*/ + { { 0x9c,0},{ 0} }, { { 0x9d,0},{ 0} }, { { 0x9e,0},{ 0} }, { { 0x9f,0},{ 0} }, /*09c*/ + { { 0xa0,0},{ 0} }, { { 0xa1,0},{ 0} }, { { 0xa2,0},{ 0} }, { { 0xa3,0},{ 0} }, /*0a0*/ + { { 0xa4,0},{ 0} }, { { 0xa5,0},{ 0} }, { { 0xa6,0},{ 0} }, { { 0xa7,0},{ 0} }, /*0a4*/ + { { 0xa8,0},{ 0} }, { { 0xa9,0},{ 0} }, { { 0xaa,0},{ 0} }, { { 0xab,0},{ 0} }, /*0a8*/ + { { 0xac,0},{ 0} }, { { 0xad,0},{ 0} }, { { 0xae,0},{ 0} }, { { 0xaf,0},{ 0} }, /*0ac*/ + { { 0xb0,0},{ 0} }, { { 0xb1,0},{ 0} }, { { 0xb2,0},{ 0} }, { { 0xb3,0},{ 0} }, /*0b0*/ + { { 0xb4,0},{ 0} }, { { 0xb5,0},{ 0} }, { { 0xb6,0},{ 0} }, { { 0xb7,0},{ 0} }, /*0b4*/ + { { 0xb8,0},{ 0} }, { { 0xb9,0},{ 0} }, { { 0xba,0},{ 0} }, { { 0xbb,0},{ 0} }, /*0b8*/ + { { 0xbc,0},{ 0} }, { { 0xbd,0},{ 0} }, { { 0xbe,0},{ 0} }, { { 0xbf,0},{ 0} }, /*0bc*/ + { { 0xc0,0},{ 0} }, { { 0xc1,0},{ 0} }, { { 0xc2,0},{ 0} }, { { 0xc3,0},{ 0} }, /*0c0*/ + { { 0xc4,0},{ 0} }, { { 0xc5,0},{ 0} }, { { 0xc6,0},{ 0} }, { { 0xc7,0},{ 0} }, /*0c4*/ + { { 0xc8,0},{ 0} }, { { 0xc9,0},{ 0} }, { { 0xca,0},{ 0} }, { { 0xcb,0},{ 0} }, /*0c8*/ + { { 0xcc,0},{ 0} }, { { 0xcd,0},{ 0} }, { { 0xce,0},{ 0} }, { { 0xcf,0},{ 0} }, /*0cc*/ + { { 0xd0,0},{ 0} }, { { 0xd1,0},{ 0} }, { { 0xd2,0},{ 0} }, { { 0xd3,0},{ 0} }, /*0d0*/ + { { 0xd4,0},{ 0} }, { { 0xd5,0},{ 0} }, { { 0xd6,0},{ 0} }, { { 0xd7,0},{ 0} }, /*0d4*/ + { { 0xd8,0},{ 0} }, { { 0xd9,0},{ 0} }, { { 0xda,0},{ 0} }, { { 0xdb,0},{ 0} }, /*0d8*/ + { { 0xdc,0},{ 0} }, { { 0xdd,0},{ 0} }, { { 0xde,0},{ 0} }, { { 0xdf,0},{ 0} }, /*0dc*/ + { { 0xe0,0},{ 0} }, { { 0xe1,0},{ 0} }, { { 0xe2,0},{ 0} }, { { 0xe3,0},{ 0} }, /*0e0*/ + { { 0xe4,0},{ 0} }, { { 0xe5,0},{ 0} }, { { 0xe6,0},{ 0} }, { { 0xe7,0},{ 0} }, /*0e4*/ + { { 0xe8,0},{ 0} }, { { 0xe9,0},{ 0} }, { { 0xea,0},{ 0} }, { { 0xeb,0},{ 0} }, /*0e8*/ + { { 0xec,0},{ 0} }, { { 0xed,0},{ 0} }, { { 0xee,0},{ 0} }, { { 0xef,0},{ 0} }, /*0ec*/ + { { 0},{ 0} }, { { 0xf1,0},{ 0} }, { { 0xf2,0},{ 0} }, { { 0xf3,0},{ 0} }, /*0f0*/ + { { 0xf4,0},{ 0} }, { { 0xf5,0},{ 0} }, { { 0xf6,0},{ 0} }, { { 0xf7,0},{ 0} }, /*0f4*/ + { { 0xf8,0},{ 0} }, { { 0xf9,0},{ 0} }, { { 0xfa,0},{ 0} }, { { 0xfb,0},{ 0} }, /*0f8*/ + { { 0xfc,0},{ 0} }, { { 0xfd,0},{ 0} }, { { 0xfe,0},{ 0} }, { { 0xff,0},{ 0} }, /*0fc*/ - { {0xe1,0x1d,-1},{0xe1, 0x9d,-1} }, { {0xe0,0x01,-1},{0xe0, 0x81,-1} }, { {0xe0,0x02,-1},{0xe0, 0x82,-1} }, { {0xe0,0x03,-1},{0xe0, 0x83,-1} }, /*100*/ - { {0xe0,0x04,-1},{0xe0, 0x84,-1} }, { {0xe0,0x05,-1},{0xe0, 0x85,-1} }, { {0xe0,0x06,-1},{0xe0, 0x86,-1} }, { {0xe0,0x07,-1},{0xe0, 0x87,-1} }, /*104*/ - { {0xe0,0x08,-1},{0xe0, 0x88,-1} }, { {0xe0,0x09,-1},{0xe0, 0x89,-1} }, { {0xe0,0x0a,-1},{0xe0, 0x8a,-1} }, { {0xe0,0x0b,-1},{0xe0, 0x8b,-1} }, /*108*/ - { {0xe0,0x0c,-1},{0xe0, 0x8c,-1} }, { { -1},{ -1} }, { {0xe0,0x0e,-1},{0xe0, 0x8e,-1} }, { {0xe0,0x0f,-1},{0xe0, 0x8f,-1} }, /*10c*/ - { {0xe0,0x10,-1},{0xe0, 0x90,-1} }, { {0xe0,0x11,-1},{0xe0, 0x91,-1} }, { {0xe0,0x12,-1},{0xe0, 0x92,-1} }, { {0xe0,0x13,-1},{0xe0, 0x93,-1} }, /*110*/ - { {0xe0,0x14,-1},{0xe0, 0x94,-1} }, { {0xe0,0x15,-1},{0xe0, 0x95,-1} }, { {0xe0,0x16,-1},{0xe0, 0x96,-1} }, { {0xe0,0x17,-1},{0xe0, 0x97,-1} }, /*114*/ - { {0xe0,0x18,-1},{0xe0, 0x98,-1} }, { {0xe0,0x19,-1},{0xe0, 0x99,-1} }, { {0xe0,0x1a,-1},{0xe0, 0x9a,-1} }, { {0xe0,0x1b,-1},{0xe0, 0x9b,-1} }, /*118*/ - { {0xe0,0x1c,-1},{0xe0, 0x9c,-1} }, { {0xe0,0x1d,-1},{0xe0, 0x9d,-1} }, { {0xe0,0x1e,-1},{0xe0, 0x9e,-1} }, { {0xe0,0x1f,-1},{0xe0, 0x9f,-1} }, /*11c*/ - { {0xe0,0x20,-1},{0xe0, 0xa0,-1} }, { {0xe0,0x21,-1},{0xe0, 0xa1,-1} }, { {0xe0,0x22,-1},{0xe0, 0xa2,-1} }, { {0xe0,0x23,-1},{0xe0, 0xa3,-1} }, /*120*/ - { {0xe0,0x24,-1},{0xe0, 0xa4,-1} }, { {0xe0,0x25,-1},{0xe0, 0xa5,-1} }, { {0xe0,0x26,-1},{0xe0, 0xa6,-1} }, { { -1},{ -1} }, /*124*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ - { {0xe0,0x2c,-1},{0xe0, 0xac,-1} }, { {0xe0,0x2d,-1},{0xe0, 0xad,-1} }, { {0xe0,0x2e,-1},{0xe0, 0xae,-1} }, { {0xe0,0x2f,-1},{0xe0, 0xaf,-1} }, /*12c*/ - { {0xe0,0x30,-1},{0xe0, 0xb0,-1} }, { {0xe0,0x31,-1},{0xe0, 0xb1,-1} }, { {0xe0,0x32,-1},{0xe0, 0xb2,-1} }, { { -1},{ -1} }, /*130*/ - { {0xe0,0x34,-1},{0xe0, 0xb4,-1} }, { {0xe0,0x35,-1},{0xe0, 0xb5,-1} }, { { -1},{ -1} }, { {0xe0,0x37,-1},{0xe0, 0xb7,-1} }, /*134*/ - { {0xe0,0x38,-1},{0xe0, 0xb8,-1} }, { { -1},{ -1} }, { {0xe0,0x3a,-1},{0xe0, 0xba,-1} }, { {0xe0,0x3b,-1},{0xe0, 0xbb,-1} }, /*138*/ - { {0xe0,0x3c,-1},{0xe0, 0xbc,-1} }, { {0xe0,0x3d,-1},{0xe0, 0xbd,-1} }, { {0xe0,0x3e,-1},{0xe0, 0xbe,-1} }, { {0xe0,0x3f,-1},{0xe0, 0xbf,-1} }, /*13c*/ - { {0xe0,0x40,-1},{0xe0, 0xc0,-1} }, { {0xe0,0x41,-1},{0xe0, 0xc1,-1} }, { {0xe0,0x42,-1},{0xe0, 0xc2,-1} }, { {0xe0,0x43,-1},{0xe0, 0xc3,-1} }, /*140*/ - { {0xe0,0x44,-1},{0xe0, 0xc4,-1} }, { { -1},{ -1} }, { {0xe0,0x46,-1},{0xe0, 0xc6,-1} }, { {0xe0,0x47,-1},{0xe0, 0xc7,-1} }, /*144*/ - { {0xe0,0x48,-1},{0xe0, 0xc8,-1} }, { {0xe0,0x49,-1},{0xe0, 0xc9,-1} }, { { -1},{ -1} }, { {0xe0,0x4b,-1},{0xe0, 0xcb,-1} }, /*148*/ - { {0xe0,0x4c,-1},{0xe0, 0xcc,-1} }, { {0xe0,0x4d,-1},{0xe0, 0xcd,-1} }, { {0xe0,0x4e,-1},{0xe0, 0xce,-1} }, { {0xe0,0x4f,-1},{0xe0, 0xcf,-1} }, /*14c*/ - { {0xe0,0x50,-1},{0xe0, 0xd0,-1} }, { {0xe0,0x51,-1},{0xe0, 0xd1,-1} }, { {0xe0,0x52,-1},{0xe0, 0xd2,-1} }, { {0xe0,0x53,-1},{0xe0, 0xd3,-1} }, /*150*/ - { { -1},{ -1} }, { {0xe0,0x55,-1},{0xe0, 0xd5,-1} }, { { -1},{ -1} }, { {0xe0,0x57,-1},{0xe0, 0xd7,-1} }, /*154*/ - { {0xe0,0x58,-1},{0xe0, 0xd8,-1} }, { {0xe0,0x59,-1},{0xe0, 0xd9,-1} }, { {0xe0,0x5a,-1},{0xe0, 0xaa,-1} }, { {0xe0,0x5b,-1},{0xe0, 0xdb,-1} }, /*158*/ - { {0xe0,0x5c,-1},{0xe0, 0xdc,-1} }, { {0xe0,0x5d,-1},{0xe0, 0xdd,-1} }, { {0xe0,0x5e,-1},{0xe0, 0xee,-1} }, { {0xe0,0x5f,-1},{0xe0, 0xdf,-1} }, /*15c*/ - { { -1},{ -1} }, { {0xe0,0x61,-1},{0xe0, 0xe1,-1} }, { {0xe0,0x62,-1},{0xe0, 0xe2,-1} }, { {0xe0,0x63,-1},{0xe0, 0xe3,-1} }, /*160*/ - { {0xe0,0x64,-1},{0xe0, 0xe4,-1} }, { {0xe0,0x65,-1},{0xe0, 0xe5,-1} }, { {0xe0,0x66,-1},{0xe0, 0xe6,-1} }, { {0xe0,0x67,-1},{0xe0, 0xe7,-1} }, /*164*/ - { {0xe0,0x68,-1},{0xe0, 0xe8,-1} }, { {0xe0,0x69,-1},{0xe0, 0xe9,-1} }, { {0xe0,0x6a,-1},{0xe0, 0xea,-1} }, { {0xe0,0x6b,-1},{0xe0, 0xeb,-1} }, /*168*/ - { {0xe0,0x6c,-1},{0xe0, 0xec,-1} }, { {0xe0,0x6d,-1},{0xe0, 0xed,-1} }, { {0xe0,0x6e,-1},{0xe0, 0xee,-1} }, { { -1},{ -1} }, /*16c*/ - { {0xe0,0x70,-1},{0xe0, 0xf0,-1} }, { {0xe0,0x71,-1},{0xe0, 0xf1,-1} }, { {0xe0,0x72,-1},{0xe0, 0xf2,-1} }, { {0xe0,0x73,-1},{0xe0, 0xf3,-1} }, /*170*/ - { {0xe0,0x74,-1},{0xe0, 0xf4,-1} }, { {0xe0,0x75,-1},{0xe0, 0xf5,-1} }, { { -1},{ -1} }, { {0xe0,0x77,-1},{0xe0, 0xf7,-1} }, /*174*/ - { {0xe0,0x78,-1},{0xe0, 0xf8,-1} }, { {0xe0,0x79,-1},{0xe0, 0xf9,-1} }, { {0xe0,0x7a,-1},{0xe0, 0xfa,-1} }, { {0xe0,0x7b,-1},{0xe0, 0xfb,-1} }, /*178*/ - { {0xe0,0x7c,-1},{0xe0, 0xfc,-1} }, { {0xe0,0x7d,-1},{0xe0, 0xfd,-1} }, { {0xe0,0x7e,-1},{0xe0, 0xfe,-1} }, { {0xe0,0x7f,-1},{0xe0, 0xff,-1} }, /*17c*/ + { {0xe1,0x1d,0},{0xe1, 0x9d,0} }, { {0xe0,0x01,0},{0xe0, 0x81,0} }, { {0xe0,0x02,0},{0xe0, 0x82,0} }, { {0xe0,0x03,0},{0xe0, 0x83,0} }, /*100*/ + { {0xe0,0x04,0},{0xe0, 0x84,0} }, { {0xe0,0x05,0},{0xe0, 0x85,0} }, { {0xe0,0x06,0},{0xe0, 0x86,0} }, { {0xe0,0x07,0},{0xe0, 0x87,0} }, /*104*/ + { {0xe0,0x08,0},{0xe0, 0x88,0} }, { {0xe0,0x09,0},{0xe0, 0x89,0} }, { {0xe0,0x0a,0},{0xe0, 0x8a,0} }, { {0xe0,0x0b,0},{0xe0, 0x8b,0} }, /*108*/ + { {0xe0,0x0c,0},{0xe0, 0x8c,0} }, { { 0},{ 0} }, { {0xe0,0x0e,0},{0xe0, 0x8e,0} }, { {0xe0,0x0f,0},{0xe0, 0x8f,0} }, /*10c*/ + { {0xe0,0x10,0},{0xe0, 0x90,0} }, { {0xe0,0x11,0},{0xe0, 0x91,0} }, { {0xe0,0x12,0},{0xe0, 0x92,0} }, { {0xe0,0x13,0},{0xe0, 0x93,0} }, /*110*/ + { {0xe0,0x14,0},{0xe0, 0x94,0} }, { {0xe0,0x15,0},{0xe0, 0x95,0} }, { {0xe0,0x16,0},{0xe0, 0x96,0} }, { {0xe0,0x17,0},{0xe0, 0x97,0} }, /*114*/ + { {0xe0,0x18,0},{0xe0, 0x98,0} }, { {0xe0,0x19,0},{0xe0, 0x99,0} }, { {0xe0,0x1a,0},{0xe0, 0x9a,0} }, { {0xe0,0x1b,0},{0xe0, 0x9b,0} }, /*118*/ + { {0xe0,0x1c,0},{0xe0, 0x9c,0} }, { {0xe0,0x1d,0},{0xe0, 0x9d,0} }, { {0xe0,0x1e,0},{0xe0, 0x9e,0} }, { {0xe0,0x1f,0},{0xe0, 0x9f,0} }, /*11c*/ + { {0xe0,0x20,0},{0xe0, 0xa0,0} }, { {0xe0,0x21,0},{0xe0, 0xa1,0} }, { {0xe0,0x22,0},{0xe0, 0xa2,0} }, { {0xe0,0x23,0},{0xe0, 0xa3,0} }, /*120*/ + { {0xe0,0x24,0},{0xe0, 0xa4,0} }, { {0xe0,0x25,0},{0xe0, 0xa5,0} }, { {0xe0,0x26,0},{0xe0, 0xa6,0} }, { { 0},{ 0} }, /*124*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ + { {0xe0,0x2c,0},{0xe0, 0xac,0} }, { {0xe0,0x2d,0},{0xe0, 0xad,0} }, { {0xe0,0x2e,0},{0xe0, 0xae,0} }, { {0xe0,0x2f,0},{0xe0, 0xaf,0} }, /*12c*/ + { {0xe0,0x30,0},{0xe0, 0xb0,0} }, { {0xe0,0x31,0},{0xe0, 0xb1,0} }, { {0xe0,0x32,0},{0xe0, 0xb2,0} }, { { 0},{ 0} }, /*130*/ + { {0xe0,0x34,0},{0xe0, 0xb4,0} }, { {0xe0,0x35,0},{0xe0, 0xb5,0} }, { { 0},{ 0} }, { {0xe0,0x37,0},{0xe0, 0xb7,0} }, /*134*/ + { {0xe0,0x38,0},{0xe0, 0xb8,0} }, { { 0},{ 0} }, { {0xe0,0x3a,0},{0xe0, 0xba,0} }, { {0xe0,0x3b,0},{0xe0, 0xbb,0} }, /*138*/ + { {0xe0,0x3c,0},{0xe0, 0xbc,0} }, { {0xe0,0x3d,0},{0xe0, 0xbd,0} }, { {0xe0,0x3e,0},{0xe0, 0xbe,0} }, { {0xe0,0x3f,0},{0xe0, 0xbf,0} }, /*13c*/ + { {0xe0,0x40,0},{0xe0, 0xc0,0} }, { {0xe0,0x41,0},{0xe0, 0xc1,0} }, { {0xe0,0x42,0},{0xe0, 0xc2,0} }, { {0xe0,0x43,0},{0xe0, 0xc3,0} }, /*140*/ + { {0xe0,0x44,0},{0xe0, 0xc4,0} }, { { 0},{ 0} }, { {0xe0,0x46,0},{0xe0, 0xc6,0} }, { {0xe0,0x47,0},{0xe0, 0xc7,0} }, /*144*/ + { {0xe0,0x48,0},{0xe0, 0xc8,0} }, { {0xe0,0x49,0},{0xe0, 0xc9,0} }, { { 0},{ 0} }, { {0xe0,0x4b,0},{0xe0, 0xcb,0} }, /*148*/ + { {0xe0,0x4c,0},{0xe0, 0xcc,0} }, { {0xe0,0x4d,0},{0xe0, 0xcd,0} }, { {0xe0,0x4e,0},{0xe0, 0xce,0} }, { {0xe0,0x4f,0},{0xe0, 0xcf,0} }, /*14c*/ + { {0xe0,0x50,0},{0xe0, 0xd0,0} }, { {0xe0,0x51,0},{0xe0, 0xd1,0} }, { {0xe0,0x52,0},{0xe0, 0xd2,0} }, { {0xe0,0x53,0},{0xe0, 0xd3,0} }, /*150*/ + { { 0},{ 0} }, { {0xe0,0x55,0},{0xe0, 0xd5,0} }, { { 0},{ 0} }, { {0xe0,0x57,0},{0xe0, 0xd7,0} }, /*154*/ + { {0xe0,0x58,0},{0xe0, 0xd8,0} }, { {0xe0,0x59,0},{0xe0, 0xd9,0} }, { {0xe0,0x5a,0},{0xe0, 0xaa,0} }, { {0xe0,0x5b,0},{0xe0, 0xdb,0} }, /*158*/ + { {0xe0,0x5c,0},{0xe0, 0xdc,0} }, { {0xe0,0x5d,0},{0xe0, 0xdd,0} }, { {0xe0,0x5e,0},{0xe0, 0xee,0} }, { {0xe0,0x5f,0},{0xe0, 0xdf,0} }, /*15c*/ + { { 0},{ 0} }, { {0xe0,0x61,0},{0xe0, 0xe1,0} }, { {0xe0,0x62,0},{0xe0, 0xe2,0} }, { {0xe0,0x63,0},{0xe0, 0xe3,0} }, /*160*/ + { {0xe0,0x64,0},{0xe0, 0xe4,0} }, { {0xe0,0x65,0},{0xe0, 0xe5,0} }, { {0xe0,0x66,0},{0xe0, 0xe6,0} }, { {0xe0,0x67,0},{0xe0, 0xe7,0} }, /*164*/ + { {0xe0,0x68,0},{0xe0, 0xe8,0} }, { {0xe0,0x69,0},{0xe0, 0xe9,0} }, { {0xe0,0x6a,0},{0xe0, 0xea,0} }, { {0xe0,0x6b,0},{0xe0, 0xeb,0} }, /*168*/ + { {0xe0,0x6c,0},{0xe0, 0xec,0} }, { {0xe0,0x6d,0},{0xe0, 0xed,0} }, { {0xe0,0x6e,0},{0xe0, 0xee,0} }, { { 0},{ 0} }, /*16c*/ + { {0xe0,0x70,0},{0xe0, 0xf0,0} }, { {0xe0,0x71,0},{0xe0, 0xf1,0} }, { {0xe0,0x72,0},{0xe0, 0xf2,0} }, { {0xe0,0x73,0},{0xe0, 0xf3,0} }, /*170*/ + { {0xe0,0x74,0},{0xe0, 0xf4,0} }, { {0xe0,0x75,0},{0xe0, 0xf5,0} }, { { 0},{ 0} }, { {0xe0,0x77,0},{0xe0, 0xf7,0} }, /*174*/ + { {0xe0,0x78,0},{0xe0, 0xf8,0} }, { {0xe0,0x79,0},{0xe0, 0xf9,0} }, { {0xe0,0x7a,0},{0xe0, 0xfa,0} }, { {0xe0,0x7b,0},{0xe0, 0xfb,0} }, /*178*/ + { {0xe0,0x7c,0},{0xe0, 0xfc,0} }, { {0xe0,0x7d,0},{0xe0, 0xfd,0} }, { {0xe0,0x7e,0},{0xe0, 0xfe,0} }, { {0xe0,0x7f,0},{0xe0, 0xff,0} }, /*17c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ - { { -1},{ -1} }, { {0xe0,0xe1,-1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{ -1} }, { { -1},{ -1} }, /*1ec*/ - { { -1},{ -1} }, { {0xe0,0xf1,-1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{ -1} }, { {0xe0,0xff,-1},{ -1} } /*1fc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ + { { 0},{ 0} }, { {0xe0,0xe1,0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{ 0} }, { { 0},{ 0} }, /*1ec*/ + { { 0},{ 0} }, { {0xe0,0xf1,0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{ 0} }, { {0xe0,0xff,0},{ 0} } /*1fc*/ }; #endif static const scancode scancode_set2[512] = { - { { -1},{ -1} }, { { 0x76,-1},{ 0xF0,0x76,-1} }, { { 0x16,-1},{ 0xF0,0x16,-1} }, { { 0x1E,-1},{ 0xF0,0x1E,-1} }, /*000*/ - { { 0x26,-1},{ 0xF0,0x26,-1} }, { { 0x25,-1},{ 0xF0,0x25,-1} }, { { 0x2E,-1},{ 0xF0,0x2E,-1} }, { { 0x36,-1},{ 0xF0,0x36,-1} }, /*004*/ - { { 0x3D,-1},{ 0xF0,0x3D,-1} }, { { 0x3E,-1},{ 0xF0,0x3E,-1} }, { { 0x46,-1},{ 0xF0,0x46,-1} }, { { 0x45,-1},{ 0xF0,0x45,-1} }, /*008*/ - { { 0x4E,-1},{ 0xF0,0x4E,-1} }, { { 0x55,-1},{ 0xF0,0x55,-1} }, { { 0x66,-1},{ 0xF0,0x66,-1} }, { { 0x0D,-1},{ 0xF0,0x0D,-1} }, /*00c*/ - { { 0x15,-1},{ 0xF0,0x15,-1} }, { { 0x1D,-1},{ 0xF0,0x1D,-1} }, { { 0x24,-1},{ 0xF0,0x24,-1} }, { { 0x2D,-1},{ 0xF0,0x2D,-1} }, /*010*/ - { { 0x2C,-1},{ 0xF0,0x2C,-1} }, { { 0x35,-1},{ 0xF0,0x35,-1} }, { { 0x3C,-1},{ 0xF0,0x3C,-1} }, { { 0x43,-1},{ 0xF0,0x43,-1} }, /*014*/ - { { 0x44,-1},{ 0xF0,0x44,-1} }, { { 0x4D,-1},{ 0xF0,0x4D,-1} }, { { 0x54,-1},{ 0xF0,0x54,-1} }, { { 0x5B,-1},{ 0xF0,0x5B,-1} }, /*018*/ - { { 0x5A,-1},{ 0xF0,0x5A,-1} }, { { 0x14,-1},{ 0xF0,0x14,-1} }, { { 0x1C,-1},{ 0xF0,0x1C,-1} }, { { 0x1B,-1},{ 0xF0,0x1B,-1} }, /*01c*/ - { { 0x23,-1},{ 0xF0,0x23,-1} }, { { 0x2B,-1},{ 0xF0,0x2B,-1} }, { { 0x34,-1},{ 0xF0,0x34,-1} }, { { 0x33,-1},{ 0xF0,0x33,-1} }, /*020*/ - { { 0x3B,-1},{ 0xF0,0x3B,-1} }, { { 0x42,-1},{ 0xF0,0x42,-1} }, { { 0x4B,-1},{ 0xF0,0x4B,-1} }, { { 0x4C,-1},{ 0xF0,0x4C,-1} }, /*024*/ - { { 0x52,-1},{ 0xF0,0x52,-1} }, { { 0x0E,-1},{ 0xF0,0x0E,-1} }, { { 0x12,-1},{ 0xF0,0x12,-1} }, { { 0x5D,-1},{ 0xF0,0x5D,-1} }, /*028*/ - { { 0x1A,-1},{ 0xF0,0x1A,-1} }, { { 0x22,-1},{ 0xF0,0x22,-1} }, { { 0x21,-1},{ 0xF0,0x21,-1} }, { { 0x2A,-1},{ 0xF0,0x2A,-1} }, /*02c*/ - { { 0x32,-1},{ 0xF0,0x32,-1} }, { { 0x31,-1},{ 0xF0,0x31,-1} }, { { 0x3A,-1},{ 0xF0,0x3A,-1} }, { { 0x41,-1},{ 0xF0,0x41,-1} }, /*030*/ - { { 0x49,-1},{ 0xF0,0x49,-1} }, { { 0x4A,-1},{ 0xF0,0x4A,-1} }, { { 0x59,-1},{ 0xF0,0x59,-1} }, { { 0x7C,-1},{ 0xF0,0x7C,-1} }, /*034*/ - { { 0x11,-1},{ 0xF0,0x11,-1} }, { { 0x29,-1},{ 0xF0,0x29,-1} }, { { 0x58,-1},{ 0xF0,0x58,-1} }, { { 0x05,-1},{ 0xF0,0x05,-1} }, /*038*/ - { { 0x06,-1},{ 0xF0,0x06,-1} }, { { 0x04,-1},{ 0xF0,0x04,-1} }, { { 0x0C,-1},{ 0xF0,0x0C,-1} }, { { 0x03,-1},{ 0xF0,0x03,-1} }, /*03c*/ - { { 0x0B,-1},{ 0xF0,0x0B,-1} }, { { 0x83,-1},{ 0xF0,0x83,-1} }, { { 0x0A,-1},{ 0xF0,0x0A,-1} }, { { 0x01,-1},{ 0xF0,0x01,-1} }, /*040*/ - { { 0x09,-1},{ 0xF0,0x09,-1} }, { { 0x77,-1},{ 0xF0,0x77,-1} }, { { 0x7E,-1},{ 0xF0,0x7E,-1} }, { { 0x6C,-1},{ 0xF0,0x6C,-1} }, /*044*/ - { { 0x75,-1},{ 0xF0,0x75,-1} }, { { 0x7D,-1},{ 0xF0,0x7D,-1} }, { { 0x7B,-1},{ 0xF0,0x7B,-1} }, { { 0x6B,-1},{ 0xF0,0x6B,-1} }, /*048*/ - { { 0x73,-1},{ 0xF0,0x73,-1} }, { { 0x74,-1},{ 0xF0,0x74,-1} }, { { 0x79,-1},{ 0xF0,0x79,-1} }, { { 0x69,-1},{ 0xF0,0x69,-1} }, /*04c*/ - { { 0x72,-1},{ 0xF0,0x72,-1} }, { { 0x7A,-1},{ 0xF0,0x7A,-1} }, { { 0x70,-1},{ 0xF0,0x70,-1} }, { { 0x71,-1},{ 0xF0,0x71,-1} }, /*050*/ - { { 0x84,-1},{ 0xF0,0x84,-1} }, { { 0x60,-1},{ 0xF0,0x60,-1} }, { { 0x61,-1},{ 0xF0,0x61,-1} }, { { 0x78,-1},{ 0xF0,0x78,-1} }, /*054*/ - { { 0x07,-1},{ 0xF0,0x07,-1} }, { { 0x0F,-1},{ 0xF0,0x0F,-1} }, { { 0x17,-1},{ 0xF0,0x17,-1} }, { { 0x1F,-1},{ 0xF0,0x1F,-1} }, /*058*/ - { { 0x27,-1},{ 0xF0,0x27,-1} }, { { 0x2F,-1},{ 0xF0,0x2F,-1} }, { { 0x37,-1},{ 0xF0,0x37,-1} }, { { 0x3F,-1},{ 0xF0,0x3F,-1} }, /*05c*/ - { { 0x47,-1},{ 0xF0,0x47,-1} }, { { 0x4F,-1},{ 0xF0,0x4F,-1} }, { { 0x56,-1},{ 0xF0,0x56,-1} }, { { 0x5E,-1},{ 0xF0,0x5E,-1} }, /*060*/ - { { 0x08,-1},{ 0xF0,0x08,-1} }, { { 0x10,-1},{ 0xF0,0x10,-1} }, { { 0x18,-1},{ 0xF0,0x18,-1} }, { { 0x20,-1},{ 0xF0,0x20,-1} }, /*064*/ - { { 0x28,-1},{ 0xF0,0x28,-1} }, { { 0x30,-1},{ 0xF0,0x30,-1} }, { { 0x38,-1},{ 0xF0,0x38,-1} }, { { 0x40,-1},{ 0xF0,0x40,-1} }, /*068*/ - { { 0x48,-1},{ 0xF0,0x48,-1} }, { { 0x50,-1},{ 0xF0,0x50,-1} }, { { 0x57,-1},{ 0xF0,0x57,-1} }, { { 0x6F,-1},{ 0xF0,0x6F,-1} }, /*06c*/ - { { 0x13,-1},{ 0xF0,0x13,-1} }, { { 0x19,-1},{ 0xF0,0x19,-1} }, { { 0x39,-1},{ 0xF0,0x39,-1} }, { { 0x51,-1},{ 0xF0,0x51,-1} }, /*070*/ - { { 0x53,-1},{ 0xF0,0x53,-1} }, { { 0x5C,-1},{ 0xF0,0x5C,-1} }, { { 0x5F,-1},{ 0xF0,0x5F,-1} }, { { 0x62,-1},{ 0xF0,0x62,-1} }, /*074*/ - { { 0x63,-1},{ 0xF0,0x63,-1} }, { { 0x64,-1},{ 0xF0,0x64,-1} }, { { 0x65,-1},{ 0xF0,0x65,-1} }, { { 0x67,-1},{ 0xF0,0x67,-1} }, /*078*/ - { { 0x68,-1},{ 0xF0,0x68,-1} }, { { 0x6A,-1},{ 0xF0,0x6A,-1} }, { { 0x6D,-1},{ 0xF0,0x6D,-1} }, { { 0x6E,-1},{ 0xF0,0x6E,-1} }, /*07c*/ + { { 0},{ 0} }, { { 0x76,0},{ 0xF0,0x76,0} }, { { 0x16,0},{ 0xF0,0x16,0} }, { { 0x1E,0},{ 0xF0,0x1E,0} }, /*000*/ + { { 0x26,0},{ 0xF0,0x26,0} }, { { 0x25,0},{ 0xF0,0x25,0} }, { { 0x2E,0},{ 0xF0,0x2E,0} }, { { 0x36,0},{ 0xF0,0x36,0} }, /*004*/ + { { 0x3D,0},{ 0xF0,0x3D,0} }, { { 0x3E,0},{ 0xF0,0x3E,0} }, { { 0x46,0},{ 0xF0,0x46,0} }, { { 0x45,0},{ 0xF0,0x45,0} }, /*008*/ + { { 0x4E,0},{ 0xF0,0x4E,0} }, { { 0x55,0},{ 0xF0,0x55,0} }, { { 0x66,0},{ 0xF0,0x66,0} }, { { 0x0D,0},{ 0xF0,0x0D,0} }, /*00c*/ + { { 0x15,0},{ 0xF0,0x15,0} }, { { 0x1D,0},{ 0xF0,0x1D,0} }, { { 0x24,0},{ 0xF0,0x24,0} }, { { 0x2D,0},{ 0xF0,0x2D,0} }, /*010*/ + { { 0x2C,0},{ 0xF0,0x2C,0} }, { { 0x35,0},{ 0xF0,0x35,0} }, { { 0x3C,0},{ 0xF0,0x3C,0} }, { { 0x43,0},{ 0xF0,0x43,0} }, /*014*/ + { { 0x44,0},{ 0xF0,0x44,0} }, { { 0x4D,0},{ 0xF0,0x4D,0} }, { { 0x54,0},{ 0xF0,0x54,0} }, { { 0x5B,0},{ 0xF0,0x5B,0} }, /*018*/ + { { 0x5A,0},{ 0xF0,0x5A,0} }, { { 0x14,0},{ 0xF0,0x14,0} }, { { 0x1C,0},{ 0xF0,0x1C,0} }, { { 0x1B,0},{ 0xF0,0x1B,0} }, /*01c*/ + { { 0x23,0},{ 0xF0,0x23,0} }, { { 0x2B,0},{ 0xF0,0x2B,0} }, { { 0x34,0},{ 0xF0,0x34,0} }, { { 0x33,0},{ 0xF0,0x33,0} }, /*020*/ + { { 0x3B,0},{ 0xF0,0x3B,0} }, { { 0x42,0},{ 0xF0,0x42,0} }, { { 0x4B,0},{ 0xF0,0x4B,0} }, { { 0x4C,0},{ 0xF0,0x4C,0} }, /*024*/ + { { 0x52,0},{ 0xF0,0x52,0} }, { { 0x0E,0},{ 0xF0,0x0E,0} }, { { 0x12,0},{ 0xF0,0x12,0} }, { { 0x5D,0},{ 0xF0,0x5D,0} }, /*028*/ + { { 0x1A,0},{ 0xF0,0x1A,0} }, { { 0x22,0},{ 0xF0,0x22,0} }, { { 0x21,0},{ 0xF0,0x21,0} }, { { 0x2A,0},{ 0xF0,0x2A,0} }, /*02c*/ + { { 0x32,0},{ 0xF0,0x32,0} }, { { 0x31,0},{ 0xF0,0x31,0} }, { { 0x3A,0},{ 0xF0,0x3A,0} }, { { 0x41,0},{ 0xF0,0x41,0} }, /*030*/ + { { 0x49,0},{ 0xF0,0x49,0} }, { { 0x4A,0},{ 0xF0,0x4A,0} }, { { 0x59,0},{ 0xF0,0x59,0} }, { { 0x7C,0},{ 0xF0,0x7C,0} }, /*034*/ + { { 0x11,0},{ 0xF0,0x11,0} }, { { 0x29,0},{ 0xF0,0x29,0} }, { { 0x58,0},{ 0xF0,0x58,0} }, { { 0x05,0},{ 0xF0,0x05,0} }, /*038*/ + { { 0x06,0},{ 0xF0,0x06,0} }, { { 0x04,0},{ 0xF0,0x04,0} }, { { 0x0C,0},{ 0xF0,0x0C,0} }, { { 0x03,0},{ 0xF0,0x03,0} }, /*03c*/ + { { 0x0B,0},{ 0xF0,0x0B,0} }, { { 0x83,0},{ 0xF0,0x83,0} }, { { 0x0A,0},{ 0xF0,0x0A,0} }, { { 0x01,0},{ 0xF0,0x01,0} }, /*040*/ + { { 0x09,0},{ 0xF0,0x09,0} }, { { 0x77,0},{ 0xF0,0x77,0} }, { { 0x7E,0},{ 0xF0,0x7E,0} }, { { 0x6C,0},{ 0xF0,0x6C,0} }, /*044*/ + { { 0x75,0},{ 0xF0,0x75,0} }, { { 0x7D,0},{ 0xF0,0x7D,0} }, { { 0x7B,0},{ 0xF0,0x7B,0} }, { { 0x6B,0},{ 0xF0,0x6B,0} }, /*048*/ + { { 0x73,0},{ 0xF0,0x73,0} }, { { 0x74,0},{ 0xF0,0x74,0} }, { { 0x79,0},{ 0xF0,0x79,0} }, { { 0x69,0},{ 0xF0,0x69,0} }, /*04c*/ + { { 0x72,0},{ 0xF0,0x72,0} }, { { 0x7A,0},{ 0xF0,0x7A,0} }, { { 0x70,0},{ 0xF0,0x70,0} }, { { 0x71,0},{ 0xF0,0x71,0} }, /*050*/ + { { 0x84,0},{ 0xF0,0x84,0} }, { { 0x60,0},{ 0xF0,0x60,0} }, { { 0x61,0},{ 0xF0,0x61,0} }, { { 0x78,0},{ 0xF0,0x78,0} }, /*054*/ + { { 0x07,0},{ 0xF0,0x07,0} }, { { 0x0F,0},{ 0xF0,0x0F,0} }, { { 0x17,0},{ 0xF0,0x17,0} }, { { 0x1F,0},{ 0xF0,0x1F,0} }, /*058*/ + { { 0x27,0},{ 0xF0,0x27,0} }, { { 0x2F,0},{ 0xF0,0x2F,0} }, { { 0x37,0},{ 0xF0,0x37,0} }, { { 0x3F,0},{ 0xF0,0x3F,0} }, /*05c*/ + { { 0x47,0},{ 0xF0,0x47,0} }, { { 0x4F,0},{ 0xF0,0x4F,0} }, { { 0x56,0},{ 0xF0,0x56,0} }, { { 0x5E,0},{ 0xF0,0x5E,0} }, /*060*/ + { { 0x08,0},{ 0xF0,0x08,0} }, { { 0x10,0},{ 0xF0,0x10,0} }, { { 0x18,0},{ 0xF0,0x18,0} }, { { 0x20,0},{ 0xF0,0x20,0} }, /*064*/ + { { 0x28,0},{ 0xF0,0x28,0} }, { { 0x30,0},{ 0xF0,0x30,0} }, { { 0x38,0},{ 0xF0,0x38,0} }, { { 0x40,0},{ 0xF0,0x40,0} }, /*068*/ + { { 0x48,0},{ 0xF0,0x48,0} }, { { 0x50,0},{ 0xF0,0x50,0} }, { { 0x57,0},{ 0xF0,0x57,0} }, { { 0x6F,0},{ 0xF0,0x6F,0} }, /*06c*/ + { { 0x13,0},{ 0xF0,0x13,0} }, { { 0x19,0},{ 0xF0,0x19,0} }, { { 0x39,0},{ 0xF0,0x39,0} }, { { 0x51,0},{ 0xF0,0x51,0} }, /*070*/ + { { 0x53,0},{ 0xF0,0x53,0} }, { { 0x5C,0},{ 0xF0,0x5C,0} }, { { 0x5F,0},{ 0xF0,0x5F,0} }, { { 0x62,0},{ 0xF0,0x62,0} }, /*074*/ + { { 0x63,0},{ 0xF0,0x63,0} }, { { 0x64,0},{ 0xF0,0x64,0} }, { { 0x65,0},{ 0xF0,0x65,0} }, { { 0x67,0},{ 0xF0,0x67,0} }, /*078*/ + { { 0x68,0},{ 0xF0,0x68,0} }, { { 0x6A,0},{ 0xF0,0x6A,0} }, { { 0x6D,0},{ 0xF0,0x6D,0} }, { { 0x6E,0},{ 0xF0,0x6E,0} }, /*07c*/ - { { 0x80,-1},{ 0xf0,0x80,-1} }, { { 0x81,-1},{ 0xf0,0x81,-1} }, { { 0x82,-1},{ 0xf0,0x82,-1} }, { { -1},{ -1} }, /*080*/ - { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x54,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { 0x87,-1},{ 0xf0,0x87,-1} }, /*084*/ - { { 0x88,-1},{ 0xf0,0x88,-1} }, { { 0x89,-1},{ 0xf0,0x89,-1} }, { { 0x8a,-1},{ 0xf0,0x8a,-1} }, { { 0x8b,-1},{ 0xf0,0x8b,-1} }, /*088*/ - { { 0x8c,-1},{ 0xf0,0x8c,-1} }, { { 0x8d,-1},{ 0xf0,0x8d,-1} }, { { 0x8e,-1},{ 0xf0,0x8e,-1} }, { { 0x8f,-1},{ 0xf0,0x8f,-1} }, /*08c*/ - { { 0x90,-1},{ 0xf0,0x90,-1} }, { { 0x91,-1},{ 0xf0,0x91,-1} }, { { 0x92,-1},{ 0xf0,0x92,-1} }, { { 0x93,-1},{ 0xf0,0x93,-1} }, /*090*/ - { { 0x94,-1},{ 0xf0,0x94,-1} }, { { 0x95,-1},{ 0xf0,0x95,-1} }, { { 0x96,-1},{ 0xf0,0x96,-1} }, { { 0x97,-1},{ 0xf0,0x97,-1} }, /*094*/ - { { 0x98,-1},{ 0xf0,0x98,-1} }, { { 0x99,-1},{ 0xf0,0x99,-1} }, { { 0x9a,-1},{ 0xf0,0x9a,-1} }, { { 0x9b,-1},{ 0xf0,0x9b,-1} }, /*098*/ - { { 0x9c,-1},{ 0xf0,0x9c,-1} }, { { 0x9d,-1},{ 0xf0,0x9d,-1} }, { { 0x9e,-1},{ 0xf0,0x9e,-1} }, { { 0x9f,-1},{ 0xf0,0x9f,-1} }, /*09c*/ - { { 0xa0,-1},{ 0xf0,0xa0,-1} }, { { 0xa1,-1},{ 0xf0,0xa1,-1} }, { { 0xa2,-1},{ 0xf0,0xa2,-1} }, { { 0xa3,-1},{ 0xf0,0xa3,-1} }, /*0a0*/ - { { 0xa4,-1},{ 0xf0,0xa4,-1} }, { { 0xa5,-1},{ 0xf0,0xa5,-1} }, { { 0xa6,-1},{ 0xf0,0xa6,-1} }, { { 0xa7,-1},{ 0xf0,0xa7,-1} }, /*0a4*/ - { { 0xa8,-1},{ 0xf0,0xa8,-1} }, { { 0xa9,-1},{ 0xf0,0xa9,-1} }, { { 0xaa,-1},{ 0xf0,0xaa,-1} }, { { 0xab,-1},{ 0xf0,0xab,-1} }, /*0a8*/ - { { 0xac,-1},{ 0xf0,0xac,-1} }, { { 0xad,-1},{ 0xf0,0xad,-1} }, { { 0xae,-1},{ 0xf0,0xae,-1} }, { { 0xaf,-1},{ 0xf0,0xaf,-1} }, /*0ac*/ - { { 0xb0,-1},{ 0xf0,0xb0,-1} }, { { 0xb1,-1},{ 0xf0,0xb1,-1} }, { { 0xb2,-1},{ 0xf0,0xb2,-1} }, { { 0xb3,-1},{ 0xf0,0xb3,-1} }, /*0b0*/ - { { 0xb4,-1},{ 0xf0,0xb4,-1} }, { { 0xb5,-1},{ 0xf0,0xb5,-1} }, { { 0xb6,-1},{ 0xf0,0xb6,-1} }, { { 0xb7,-1},{ 0xf0,0xb7,-1} }, /*0b4*/ - { { 0xb8,-1},{ 0xf0,0xb8,-1} }, { { 0xb9,-1},{ 0xf0,0xb9,-1} }, { { 0xba,-1},{ 0xf0,0xba,-1} }, { { 0xbb,-1},{ 0xf0,0xbb,-1} }, /*0b8*/ - { { 0xbc,-1},{ 0xf0,0xbc,-1} }, { { 0xbd,-1},{ 0xf0,0xbd,-1} }, { { 0xbe,-1},{ 0xf0,0xbe,-1} }, { { 0xbf,-1},{ 0xf0,0xbf,-1} }, /*0bc*/ - { { 0xc0,-1},{ 0xf0,0xc0,-1} }, { { 0xc1,-1},{ 0xf0,0xc1,-1} }, { { 0xc2,-1},{ 0xf0,0xc2,-1} }, { { 0xc3,-1},{ 0xf0,0xc3,-1} }, /*0c0*/ - { { 0xc4,-1},{ 0xf0,0xc4,-1} }, { { 0xc5,-1},{ 0xf0,0xc5,-1} }, { { 0xc6,-1},{ 0xf0,0xc6,-1} }, { { 0xc7,-1},{ 0xf0,0xc7,-1} }, /*0c4*/ - { { 0xc8,-1},{ 0xf0,0xc8,-1} }, { { 0xc9,-1},{ 0xf0,0xc9,-1} }, { { 0xca,-1},{ 0xf0,0xca,-1} }, { { 0xcb,-1},{ 0xf0,0xcb,-1} }, /*0c8*/ - { { 0xcc,-1},{ 0xf0,0xcc,-1} }, { { 0xcd,-1},{ 0xf0,0xcd,-1} }, { { 0xce,-1},{ 0xf0,0xce,-1} }, { { 0xcf,-1},{ 0xf0,0xcf,-1} }, /*0cc*/ - { { 0xd0,-1},{ 0xf0,0xd0,-1} }, { { 0xd1,-1},{ 0xf0,0xd0,-1} }, { { 0xd2,-1},{ 0xf0,0xd2,-1} }, { { 0xd3,-1},{ 0xf0,0xd3,-1} }, /*0d0*/ - { { 0xd4,-1},{ 0xf0,0xd4,-1} }, { { 0xd5,-1},{ 0xf0,0xd5,-1} }, { { 0xd6,-1},{ 0xf0,0xd6,-1} }, { { 0xd7,-1},{ 0xf0,0xd7,-1} }, /*0d4*/ - { { 0xd8,-1},{ 0xf0,0xd8,-1} }, { { 0xd9,-1},{ 0xf0,0xd9,-1} }, { { 0xda,-1},{ 0xf0,0xda,-1} }, { { 0xdb,-1},{ 0xf0,0xdb,-1} }, /*0d8*/ - { { 0xdc,-1},{ 0xf0,0xdc,-1} }, { { 0xdd,-1},{ 0xf0,0xdd,-1} }, { { 0xde,-1},{ 0xf0,0xde,-1} }, { { 0xdf,-1},{ 0xf0,0xdf,-1} }, /*0dc*/ - { { 0xe0,-1},{ 0xf0,0xe0,-1} }, { { 0xe1,-1},{ 0xf0,0xe1,-1} }, { { 0xe2,-1},{ 0xf0,0xe2,-1} }, { { 0xe3,-1},{ 0xf0,0xe3,-1} }, /*0e0*/ - { { 0xe4,-1},{ 0xf0,0xe4,-1} }, { { 0xe5,-1},{ 0xf0,0xe5,-1} }, { { 0xe6,-1},{ 0xf0,0xe6,-1} }, { { 0xe7,-1},{ 0xf0,0xe7,-1} }, /*0e4*/ - { { 0xe8,-1},{ 0xf0,0xe8,-1} }, { { 0xe9,-1},{ 0xf0,0xe9,-1} }, { { 0xea,-1},{ 0xf0,0xea,-1} }, { { 0xeb,-1},{ 0xf0,0xeb,-1} }, /*0e8*/ - { { 0xec,-1},{ 0xf0,0xec,-1} }, { { 0xed,-1},{ 0xf0,0xed,-1} }, { { 0xee,-1},{ 0xf0,0xee,-1} }, { { 0xef,-1},{ 0xf0,0xef,-1} }, /*0ec*/ - { { -1},{ -1} }, { { 0xf1,-1},{ 0xf0,0xf1,-1} }, { { 0xf2,-1},{ 0xf0,0xf2,-1} }, { { 0xf3,-1},{ 0xf0,0xf3,-1} }, /*0f0*/ - { { 0xf4,-1},{ 0xf0,0xf4,-1} }, { { 0xf5,-1},{ 0xf0,0xf5,-1} }, { { 0xf6,-1},{ 0xf0,0xf6,-1} }, { { 0xf7,-1},{ 0xf0,0xf7,-1} }, /*0f4*/ - { { 0xf8,-1},{ 0xf0,0xf8,-1} }, { { 0xf9,-1},{ 0xf0,0xf9,-1} }, { { 0xfa,-1},{ 0xf0,0xfa,-1} }, { { 0xfb,-1},{ 0xf0,0xfb,-1} }, /*0f8*/ - { { 0xfc,-1},{ 0xf0,0xfc,-1} }, { { 0xfd,-1},{ 0xf0,0xfd,-1} }, { { 0xfe,-1},{ 0xf0,0xfe,-1} }, { { 0xff,-1},{ 0xf0,0xff,-1} }, /*0fc*/ + { { 0x80,0},{ 0xf0,0x80,0} }, { { 0x81,0},{ 0xf0,0x81,0} }, { { 0x82,0},{ 0xf0,0x82,0} }, { { 0},{ 0} }, /*080*/ + { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x54,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0x87,0},{ 0xf0,0x87,0} }, /*084*/ + { { 0x88,0},{ 0xf0,0x88,0} }, { { 0x89,0},{ 0xf0,0x89,0} }, { { 0x8a,0},{ 0xf0,0x8a,0} }, { { 0x8b,0},{ 0xf0,0x8b,0} }, /*088*/ + { { 0x8c,0},{ 0xf0,0x8c,0} }, { { 0x8d,0},{ 0xf0,0x8d,0} }, { { 0x8e,0},{ 0xf0,0x8e,0} }, { { 0x8f,0},{ 0xf0,0x8f,0} }, /*08c*/ + { { 0x90,0},{ 0xf0,0x90,0} }, { { 0x91,0},{ 0xf0,0x91,0} }, { { 0x92,0},{ 0xf0,0x92,0} }, { { 0x93,0},{ 0xf0,0x93,0} }, /*090*/ + { { 0x94,0},{ 0xf0,0x94,0} }, { { 0x95,0},{ 0xf0,0x95,0} }, { { 0x96,0},{ 0xf0,0x96,0} }, { { 0x97,0},{ 0xf0,0x97,0} }, /*094*/ + { { 0x98,0},{ 0xf0,0x98,0} }, { { 0x99,0},{ 0xf0,0x99,0} }, { { 0x9a,0},{ 0xf0,0x9a,0} }, { { 0x9b,0},{ 0xf0,0x9b,0} }, /*098*/ + { { 0x9c,0},{ 0xf0,0x9c,0} }, { { 0x9d,0},{ 0xf0,0x9d,0} }, { { 0x9e,0},{ 0xf0,0x9e,0} }, { { 0x9f,0},{ 0xf0,0x9f,0} }, /*09c*/ + { { 0xa0,0},{ 0xf0,0xa0,0} }, { { 0xa1,0},{ 0xf0,0xa1,0} }, { { 0xa2,0},{ 0xf0,0xa2,0} }, { { 0xa3,0},{ 0xf0,0xa3,0} }, /*0a0*/ + { { 0xa4,0},{ 0xf0,0xa4,0} }, { { 0xa5,0},{ 0xf0,0xa5,0} }, { { 0xa6,0},{ 0xf0,0xa6,0} }, { { 0xa7,0},{ 0xf0,0xa7,0} }, /*0a4*/ + { { 0xa8,0},{ 0xf0,0xa8,0} }, { { 0xa9,0},{ 0xf0,0xa9,0} }, { { 0xaa,0},{ 0xf0,0xaa,0} }, { { 0xab,0},{ 0xf0,0xab,0} }, /*0a8*/ + { { 0xac,0},{ 0xf0,0xac,0} }, { { 0xad,0},{ 0xf0,0xad,0} }, { { 0xae,0},{ 0xf0,0xae,0} }, { { 0xaf,0},{ 0xf0,0xaf,0} }, /*0ac*/ + { { 0xb0,0},{ 0xf0,0xb0,0} }, { { 0xb1,0},{ 0xf0,0xb1,0} }, { { 0xb2,0},{ 0xf0,0xb2,0} }, { { 0xb3,0},{ 0xf0,0xb3,0} }, /*0b0*/ + { { 0xb4,0},{ 0xf0,0xb4,0} }, { { 0xb5,0},{ 0xf0,0xb5,0} }, { { 0xb6,0},{ 0xf0,0xb6,0} }, { { 0xb7,0},{ 0xf0,0xb7,0} }, /*0b4*/ + { { 0xb8,0},{ 0xf0,0xb8,0} }, { { 0xb9,0},{ 0xf0,0xb9,0} }, { { 0xba,0},{ 0xf0,0xba,0} }, { { 0xbb,0},{ 0xf0,0xbb,0} }, /*0b8*/ + { { 0xbc,0},{ 0xf0,0xbc,0} }, { { 0xbd,0},{ 0xf0,0xbd,0} }, { { 0xbe,0},{ 0xf0,0xbe,0} }, { { 0xbf,0},{ 0xf0,0xbf,0} }, /*0bc*/ + { { 0xc0,0},{ 0xf0,0xc0,0} }, { { 0xc1,0},{ 0xf0,0xc1,0} }, { { 0xc2,0},{ 0xf0,0xc2,0} }, { { 0xc3,0},{ 0xf0,0xc3,0} }, /*0c0*/ + { { 0xc4,0},{ 0xf0,0xc4,0} }, { { 0xc5,0},{ 0xf0,0xc5,0} }, { { 0xc6,0},{ 0xf0,0xc6,0} }, { { 0xc7,0},{ 0xf0,0xc7,0} }, /*0c4*/ + { { 0xc8,0},{ 0xf0,0xc8,0} }, { { 0xc9,0},{ 0xf0,0xc9,0} }, { { 0xca,0},{ 0xf0,0xca,0} }, { { 0xcb,0},{ 0xf0,0xcb,0} }, /*0c8*/ + { { 0xcc,0},{ 0xf0,0xcc,0} }, { { 0xcd,0},{ 0xf0,0xcd,0} }, { { 0xce,0},{ 0xf0,0xce,0} }, { { 0xcf,0},{ 0xf0,0xcf,0} }, /*0cc*/ + { { 0xd0,0},{ 0xf0,0xd0,0} }, { { 0xd1,0},{ 0xf0,0xd0,0} }, { { 0xd2,0},{ 0xf0,0xd2,0} }, { { 0xd3,0},{ 0xf0,0xd3,0} }, /*0d0*/ + { { 0xd4,0},{ 0xf0,0xd4,0} }, { { 0xd5,0},{ 0xf0,0xd5,0} }, { { 0xd6,0},{ 0xf0,0xd6,0} }, { { 0xd7,0},{ 0xf0,0xd7,0} }, /*0d4*/ + { { 0xd8,0},{ 0xf0,0xd8,0} }, { { 0xd9,0},{ 0xf0,0xd9,0} }, { { 0xda,0},{ 0xf0,0xda,0} }, { { 0xdb,0},{ 0xf0,0xdb,0} }, /*0d8*/ + { { 0xdc,0},{ 0xf0,0xdc,0} }, { { 0xdd,0},{ 0xf0,0xdd,0} }, { { 0xde,0},{ 0xf0,0xde,0} }, { { 0xdf,0},{ 0xf0,0xdf,0} }, /*0dc*/ + { { 0xe0,0},{ 0xf0,0xe0,0} }, { { 0xe1,0},{ 0xf0,0xe1,0} }, { { 0xe2,0},{ 0xf0,0xe2,0} }, { { 0xe3,0},{ 0xf0,0xe3,0} }, /*0e0*/ + { { 0xe4,0},{ 0xf0,0xe4,0} }, { { 0xe5,0},{ 0xf0,0xe5,0} }, { { 0xe6,0},{ 0xf0,0xe6,0} }, { { 0xe7,0},{ 0xf0,0xe7,0} }, /*0e4*/ + { { 0xe8,0},{ 0xf0,0xe8,0} }, { { 0xe9,0},{ 0xf0,0xe9,0} }, { { 0xea,0},{ 0xf0,0xea,0} }, { { 0xeb,0},{ 0xf0,0xeb,0} }, /*0e8*/ + { { 0xec,0},{ 0xf0,0xec,0} }, { { 0xed,0},{ 0xf0,0xed,0} }, { { 0xee,0},{ 0xf0,0xee,0} }, { { 0xef,0},{ 0xf0,0xef,0} }, /*0ec*/ + { { 0},{ 0} }, { { 0xf1,0},{ 0xf0,0xf1,0} }, { { 0xf2,0},{ 0xf0,0xf2,0} }, { { 0xf3,0},{ 0xf0,0xf3,0} }, /*0f0*/ + { { 0xf4,0},{ 0xf0,0xf4,0} }, { { 0xf5,0},{ 0xf0,0xf5,0} }, { { 0xf6,0},{ 0xf0,0xf6,0} }, { { 0xf7,0},{ 0xf0,0xf7,0} }, /*0f4*/ + { { 0xf8,0},{ 0xf0,0xf8,0} }, { { 0xf9,0},{ 0xf0,0xf9,0} }, { { 0xfa,0},{ 0xf0,0xfa,0} }, { { 0xfb,0},{ 0xf0,0xfb,0} }, /*0f8*/ + { { 0xfc,0},{ 0xf0,0xfc,0} }, { { 0xfd,0},{ 0xf0,0xfd,0} }, { { 0xfe,0},{ 0xf0,0xfe,0} }, { { 0xff,0},{ 0xf0,0xff,0} }, /*0fc*/ - { {0xe1,0x14,-1},{0xe1,0xf0,0x14,-1} }, { {0xe0,0x76,-1},{0xe0,0xF0,0x76,-1} }, { {0xe0,0x16,-1},{0xe0,0xF0,0x16,-1} }, { {0xe0,0x1E,-1},{0xe0,0xF0,0x1E,-1} }, /*100*/ - { {0xe0,0x26,-1},{0xe0,0xF0,0x26,-1} }, { {0xe0,0x25,-1},{0xe0,0xF0,0x25,-1} }, { {0xe0,0x2E,-1},{0xe0,0xF0,0x2E,-1} }, { {0xe0,0x36,-1},{0xe0,0xF0,0x36,-1} }, /*104*/ - { {0xe0,0x3D,-1},{0xe0,0xF0,0x3D,-1} }, { {0xe0,0x3E,-1},{0xe0,0xF0,0x3E,-1} }, { {0xe0,0x46,-1},{0xe0,0xF0,0x46,-1} }, { {0xe0,0x45,-1},{0xe0,0xF0,0x45,-1} }, /*108*/ - { {0xe0,0x4E,-1},{0xe0,0xF0,0x4E,-1} }, { { -1},{ -1} }, { {0xe0,0x66,-1},{0xe0,0xF0,0x66,-1} }, { {0xe0,0x0D,-1},{0xe0,0xF0,0x0D,-1} }, /*10c*/ - { {0xe0,0x15,-1},{0xe0,0xF0,0x15,-1} }, { {0xe0,0x1D,-1},{0xe0,0xF0,0x1D,-1} }, { {0xe0,0x24,-1},{0xe0,0xF0,0x24,-1} }, { {0xe0,0x2D,-1},{0xe0,0xF0,0x2D,-1} }, /*110*/ - { {0xe0,0x2C,-1},{0xe0,0xF0,0x2C,-1} }, { {0xe0,0x35,-1},{0xe0,0xF0,0x35,-1} }, { {0xe0,0x3C,-1},{0xe0,0xF0,0x3C,-1} }, { {0xe0,0x43,-1},{0xe0,0xF0,0x43,-1} }, /*114*/ - { {0xe0,0x44,-1},{0xe0,0xF0,0x44,-1} }, { {0xe0,0x4D,-1},{0xe0,0xF0,0x4D,-1} }, { {0xe0,0x54,-1},{0xe0,0xF0,0x54,-1} }, { {0xe0,0x5B,-1},{0xe0,0xF0,0x5B,-1} }, /*118*/ - { {0xe0,0x5A,-1},{0xe0,0xF0,0x5A,-1} }, { {0xe0,0x14,-1},{0xe0,0xF0,0x14,-1} }, { {0xe0,0x1C,-1},{0xe0,0xF0,0x1C,-1} }, { {0xe0,0x1B,-1},{0xe0,0xF0,0x1B,-1} }, /*11c*/ - { {0xe0,0x23,-1},{0xe0,0xF0,0x23,-1} }, { {0xe0,0x2B,-1},{0xe0,0xF0,0x2B,-1} }, { {0xe0,0x34,-1},{0xe0,0xF0,0x34,-1} }, { {0xe0,0x33,-1},{0xe0,0xF0,0x33,-1} }, /*120*/ - { {0xe0,0x3B,-1},{0xe0,0xF0,0x3B,-1} }, { {0xe0,0x42,-1},{0xe0,0xF0,0x42,-1} }, { {0xe0,0x4B,-1},{0xe0,0xF0,0x4B,-1} }, { { -1},{ -1} }, /*124*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ - { {0xe0,0x1A,-1},{0xe0,0xF0,0x1A,-1} }, { {0xe0,0x22,-1},{0xe0,0xF0,0x22,-1} }, { {0xe0,0x21,-1},{0xe0,0xF0,0x21,-1} }, { {0xe0,0x2A,-1},{0xe0,0xF0,0x2A,-1} }, /*12c*/ - { {0xe0,0x32,-1},{0xe0,0xF0,0x32,-1} }, { {0xe0,0x31,-1},{0xe0,0xF0,0x31,-1} }, { {0xe0,0x3A,-1},{0xe0,0xF0,0x3A,-1} }, { { -1},{ -1} }, /*130*/ - { {0xe0,0x49,-1},{0xe0,0xF0,0x49,-1} }, { {0xe0,0x4A,-1},{0xe0,0xF0,0x4A,-1} }, { { -1},{ -1} }, { {0xe0,0x7C,-1},{0xe0,0xF0,0x7C,-1} }, /*134*/ - { {0xe0,0x11,-1},{0xe0,0xF0,0x11,-1} }, { { -1},{ -1} }, { {0xe0,0x58,-1},{0xe0,0xF0,0x58,-1} }, { {0xe0,0x05,-1},{0xe0,0xF0,0x05,-1} }, /*138*/ - { {0xe0,0x06,-1},{0xe0,0xF0,0x06,-1} }, { {0xe0,0x04,-1},{0xe0,0xF0,0x04,-1} }, { {0xe0,0x0C,-1},{0xe0,0xF0,0x0C,-1} }, { {0xe0,0x03,-1},{0xe0,0xF0,0x03,-1} }, /*13c*/ - { {0xe0,0x0B,-1},{0xe0,0xF0,0x0B,-1} }, { {0xe0,0x02,-1},{0xe0,0xF0,0x02,-1} }, { {0xe0,0x0A,-1},{0xe0,0xF0,0x0A,-1} }, { {0xe0,0x01,-1},{0xe0,0xF0,0x01,-1} }, /*140*/ - { {0xe0,0x09,-1},{0xe0,0xF0,0x09,-1} }, { { -1},{ -1} }, { {0xe0,0x7E,-1},{0xe0,0xF0,0x7E,-1} }, { {0xe0,0x6C,-1},{0xe0,0xF0,0x6C,-1} }, /*144*/ - { {0xe0,0x75,-1},{0xe0,0xF0,0x75,-1} }, { {0xe0,0x7D,-1},{0xe0,0xF0,0x7D,-1} }, { { -1},{ -1} }, { {0xe0,0x6B,-1},{0xe0,0xF0,0x6B,-1} }, /*148*/ - { {0xe0,0x73,-1},{0xe0,0xF0,0x73,-1} }, { {0xe0,0x74,-1},{0xe0,0xF0,0x74,-1} }, { {0xe0,0x79,-1},{0xe0,0xF0,0x79,-1} }, { {0xe0,0x69,-1},{0xe0,0xF0,0x69,-1} }, /*14c*/ - { {0xe0,0x72,-1},{0xe0,0xF0,0x72,-1} }, { {0xe0,0x7A,-1},{0xe0,0xF0,0x7A,-1} }, { {0xe0,0x70,-1},{0xe0,0xF0,0x70,-1} }, { {0xe0,0x71,-1},{0xe0,0xF0,0x71,-1} }, /*150*/ - { { -1},{ -1} }, { {0xe0,0x60,-1},{0xe0,0xF0,0x60,-1} }, { { -1},{ -1} }, { {0xe0,0x78,-1},{0xe0,0xF0,0x78,-1} }, /*154*/ - { {0xe0,0x07,-1},{0xe0,0xF0,0x07,-1} }, { {0xe0,0x0F,-1},{0xe0,0xF0,0x0F,-1} }, { {0xe0,0x17,-1},{0xe0,0xF0,0x17,-1} }, { {0xe0,0x1F,-1},{0xe0,0xF0,0x1F,-1} }, /*158*/ - { {0xe0,0x27,-1},{0xe0,0xF0,0x27,-1} }, { {0xe0,0x2F,-1},{0xe0,0xF0,0x2F,-1} }, { {0xe0,0x37,-1},{0xe0,0xF0,0x37,-1} }, { {0xe0,0x3F,-1},{0xe0,0xF0,0x3F,-1} }, /*15c*/ - { { -1},{ -1} }, { {0xe0,0x4F,-1},{0xe0,0xF0,0x4F,-1} }, { {0xe0,0x56,-1},{0xe0,0xF0,0x56,-1} }, { {0xe0,0x5E,-1},{0xe0,0xF0,0x5E,-1} }, /*160*/ - { {0xe0,0x08,-1},{0xe0,0xF0,0x08,-1} }, { {0xe0,0x10,-1},{0xe0,0xF0,0x10,-1} }, { {0xe0,0x18,-1},{0xe0,0xF0,0x18,-1} }, { {0xe0,0x20,-1},{0xe0,0xF0,0x20,-1} }, /*164*/ - { {0xe0,0x28,-1},{0xe0,0xF0,0x28,-1} }, { {0xe0,0x30,-1},{0xe0,0xF0,0x30,-1} }, { {0xe0,0x38,-1},{0xe0,0xF0,0x38,-1} }, { {0xe0,0x40,-1},{0xe0,0xF0,0x40,-1} }, /*168*/ - { {0xe0,0x48,-1},{0xe0,0xF0,0x48,-1} }, { {0xe0,0x50,-1},{0xe0,0xF0,0x50,-1} }, { {0xe0,0x57,-1},{0xe0,0xF0,0x57,-1} }, { { -1},{ -1} }, /*16c*/ - { {0xe0,0x13,-1},{0xe0,0xF0,0x13,-1} }, { {0xe0,0x19,-1},{0xe0,0xF0,0x19,-1} }, { {0xe0,0x39,-1},{0xe0,0xF0,0x39,-1} }, { {0xe0,0x51,-1},{0xe0,0xF0,0x51,-1} }, /*170*/ - { {0xe0,0x53,-1},{0xe0,0xF0,0x53,-1} }, { {0xe0,0x5C,-1},{0xe0,0xF0,0x5C,-1} }, { { -1},{ -1} }, { {0xe0,0x62,-1},{0xe0,0xF0,0x62,-1} }, /*174*/ - { {0xe0,0x63,-1},{0xe0,0xF0,0x63,-1} }, { {0xe0,0x64,-1},{0xe0,0xF0,0x64,-1} }, { {0xe0,0x65,-1},{0xe0,0xF0,0x65,-1} }, { {0xe0,0x67,-1},{0xe0,0xF0,0x67,-1} }, /*178*/ - { {0xe0,0x68,-1},{0xe0,0xF0,0x68,-1} }, { {0xe0,0x6A,-1},{0xe0,0xF0,0x6A,-1} }, { {0xe0,0x6D,-1},{0xe0,0xF0,0x6D,-1} }, { {0xe0,0x6E,-1},{0xe0,0xF0,0x6E,-1} }, /*17c*/ + { {0xe1,0x14,0},{0xe1,0xf0,0x14,0} }, { {0xe0,0x76,0},{0xe0,0xF0,0x76,0} }, { {0xe0,0x16,0},{0xe0,0xF0,0x16,0} }, { {0xe0,0x1E,0},{0xe0,0xF0,0x1E,0} }, /*100*/ + { {0xe0,0x26,0},{0xe0,0xF0,0x26,0} }, { {0xe0,0x25,0},{0xe0,0xF0,0x25,0} }, { {0xe0,0x2E,0},{0xe0,0xF0,0x2E,0} }, { {0xe0,0x36,0},{0xe0,0xF0,0x36,0} }, /*104*/ + { {0xe0,0x3D,0},{0xe0,0xF0,0x3D,0} }, { {0xe0,0x3E,0},{0xe0,0xF0,0x3E,0} }, { {0xe0,0x46,0},{0xe0,0xF0,0x46,0} }, { {0xe0,0x45,0},{0xe0,0xF0,0x45,0} }, /*108*/ + { {0xe0,0x4E,0},{0xe0,0xF0,0x4E,0} }, { { 0},{ 0} }, { {0xe0,0x66,0},{0xe0,0xF0,0x66,0} }, { {0xe0,0x0D,0},{0xe0,0xF0,0x0D,0} }, /*10c*/ + { {0xe0,0x15,0},{0xe0,0xF0,0x15,0} }, { {0xe0,0x1D,0},{0xe0,0xF0,0x1D,0} }, { {0xe0,0x24,0},{0xe0,0xF0,0x24,0} }, { {0xe0,0x2D,0},{0xe0,0xF0,0x2D,0} }, /*110*/ + { {0xe0,0x2C,0},{0xe0,0xF0,0x2C,0} }, { {0xe0,0x35,0},{0xe0,0xF0,0x35,0} }, { {0xe0,0x3C,0},{0xe0,0xF0,0x3C,0} }, { {0xe0,0x43,0},{0xe0,0xF0,0x43,0} }, /*114*/ + { {0xe0,0x44,0},{0xe0,0xF0,0x44,0} }, { {0xe0,0x4D,0},{0xe0,0xF0,0x4D,0} }, { {0xe0,0x54,0},{0xe0,0xF0,0x54,0} }, { {0xe0,0x5B,0},{0xe0,0xF0,0x5B,0} }, /*118*/ + { {0xe0,0x5A,0},{0xe0,0xF0,0x5A,0} }, { {0xe0,0x14,0},{0xe0,0xF0,0x14,0} }, { {0xe0,0x1C,0},{0xe0,0xF0,0x1C,0} }, { {0xe0,0x1B,0},{0xe0,0xF0,0x1B,0} }, /*11c*/ + { {0xe0,0x23,0},{0xe0,0xF0,0x23,0} }, { {0xe0,0x2B,0},{0xe0,0xF0,0x2B,0} }, { {0xe0,0x34,0},{0xe0,0xF0,0x34,0} }, { {0xe0,0x33,0},{0xe0,0xF0,0x33,0} }, /*120*/ + { {0xe0,0x3B,0},{0xe0,0xF0,0x3B,0} }, { {0xe0,0x42,0},{0xe0,0xF0,0x42,0} }, { {0xe0,0x4B,0},{0xe0,0xF0,0x4B,0} }, { { 0},{ 0} }, /*124*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ + { {0xe0,0x1A,0},{0xe0,0xF0,0x1A,0} }, { {0xe0,0x22,0},{0xe0,0xF0,0x22,0} }, { {0xe0,0x21,0},{0xe0,0xF0,0x21,0} }, { {0xe0,0x2A,0},{0xe0,0xF0,0x2A,0} }, /*12c*/ + { {0xe0,0x32,0},{0xe0,0xF0,0x32,0} }, { {0xe0,0x31,0},{0xe0,0xF0,0x31,0} }, { {0xe0,0x3A,0},{0xe0,0xF0,0x3A,0} }, { { 0},{ 0} }, /*130*/ + { {0xe0,0x49,0},{0xe0,0xF0,0x49,0} }, { {0xe0,0x4A,0},{0xe0,0xF0,0x4A,0} }, { { 0},{ 0} }, { {0xe0,0x7C,0},{0xe0,0xF0,0x7C,0} }, /*134*/ + { {0xe0,0x11,0},{0xe0,0xF0,0x11,0} }, { { 0},{ 0} }, { {0xe0,0x58,0},{0xe0,0xF0,0x58,0} }, { {0xe0,0x05,0},{0xe0,0xF0,0x05,0} }, /*138*/ + { {0xe0,0x06,0},{0xe0,0xF0,0x06,0} }, { {0xe0,0x04,0},{0xe0,0xF0,0x04,0} }, { {0xe0,0x0C,0},{0xe0,0xF0,0x0C,0} }, { {0xe0,0x03,0},{0xe0,0xF0,0x03,0} }, /*13c*/ + { {0xe0,0x0B,0},{0xe0,0xF0,0x0B,0} }, { {0xe0,0x02,0},{0xe0,0xF0,0x02,0} }, { {0xe0,0x0A,0},{0xe0,0xF0,0x0A,0} }, { {0xe0,0x01,0},{0xe0,0xF0,0x01,0} }, /*140*/ + { {0xe0,0x09,0},{0xe0,0xF0,0x09,0} }, { { 0},{ 0} }, { {0xe0,0x7E,0},{0xe0,0xF0,0x7E,0} }, { {0xe0,0x6C,0},{0xe0,0xF0,0x6C,0} }, /*144*/ + { {0xe0,0x75,0},{0xe0,0xF0,0x75,0} }, { {0xe0,0x7D,0},{0xe0,0xF0,0x7D,0} }, { { 0},{ 0} }, { {0xe0,0x6B,0},{0xe0,0xF0,0x6B,0} }, /*148*/ + { {0xe0,0x73,0},{0xe0,0xF0,0x73,0} }, { {0xe0,0x74,0},{0xe0,0xF0,0x74,0} }, { {0xe0,0x79,0},{0xe0,0xF0,0x79,0} }, { {0xe0,0x69,0},{0xe0,0xF0,0x69,0} }, /*14c*/ + { {0xe0,0x72,0},{0xe0,0xF0,0x72,0} }, { {0xe0,0x7A,0},{0xe0,0xF0,0x7A,0} }, { {0xe0,0x70,0},{0xe0,0xF0,0x70,0} }, { {0xe0,0x71,0},{0xe0,0xF0,0x71,0} }, /*150*/ + { { 0},{ 0} }, { {0xe0,0x60,0},{0xe0,0xF0,0x60,0} }, { { 0},{ 0} }, { {0xe0,0x78,0},{0xe0,0xF0,0x78,0} }, /*154*/ + { {0xe0,0x07,0},{0xe0,0xF0,0x07,0} }, { {0xe0,0x0F,0},{0xe0,0xF0,0x0F,0} }, { {0xe0,0x17,0},{0xe0,0xF0,0x17,0} }, { {0xe0,0x1F,0},{0xe0,0xF0,0x1F,0} }, /*158*/ + { {0xe0,0x27,0},{0xe0,0xF0,0x27,0} }, { {0xe0,0x2F,0},{0xe0,0xF0,0x2F,0} }, { {0xe0,0x37,0},{0xe0,0xF0,0x37,0} }, { {0xe0,0x3F,0},{0xe0,0xF0,0x3F,0} }, /*15c*/ + { { 0},{ 0} }, { {0xe0,0x4F,0},{0xe0,0xF0,0x4F,0} }, { {0xe0,0x56,0},{0xe0,0xF0,0x56,0} }, { {0xe0,0x5E,0},{0xe0,0xF0,0x5E,0} }, /*160*/ + { {0xe0,0x08,0},{0xe0,0xF0,0x08,0} }, { {0xe0,0x10,0},{0xe0,0xF0,0x10,0} }, { {0xe0,0x18,0},{0xe0,0xF0,0x18,0} }, { {0xe0,0x20,0},{0xe0,0xF0,0x20,0} }, /*164*/ + { {0xe0,0x28,0},{0xe0,0xF0,0x28,0} }, { {0xe0,0x30,0},{0xe0,0xF0,0x30,0} }, { {0xe0,0x38,0},{0xe0,0xF0,0x38,0} }, { {0xe0,0x40,0},{0xe0,0xF0,0x40,0} }, /*168*/ + { {0xe0,0x48,0},{0xe0,0xF0,0x48,0} }, { {0xe0,0x50,0},{0xe0,0xF0,0x50,0} }, { {0xe0,0x57,0},{0xe0,0xF0,0x57,0} }, { { 0},{ 0} }, /*16c*/ + { {0xe0,0x13,0},{0xe0,0xF0,0x13,0} }, { {0xe0,0x19,0},{0xe0,0xF0,0x19,0} }, { {0xe0,0x39,0},{0xe0,0xF0,0x39,0} }, { {0xe0,0x51,0},{0xe0,0xF0,0x51,0} }, /*170*/ + { {0xe0,0x53,0},{0xe0,0xF0,0x53,0} }, { {0xe0,0x5C,0},{0xe0,0xF0,0x5C,0} }, { { 0},{ 0} }, { {0xe0,0x62,0},{0xe0,0xF0,0x62,0} }, /*174*/ + { {0xe0,0x63,0},{0xe0,0xF0,0x63,0} }, { {0xe0,0x64,0},{0xe0,0xF0,0x64,0} }, { {0xe0,0x65,0},{0xe0,0xF0,0x65,0} }, { {0xe0,0x67,0},{0xe0,0xF0,0x67,0} }, /*178*/ + { {0xe0,0x68,0},{0xe0,0xF0,0x68,0} }, { {0xe0,0x6A,0},{0xe0,0xF0,0x6A,0} }, { {0xe0,0x6D,0},{0xe0,0xF0,0x6D,0} }, { {0xe0,0x6E,0},{0xe0,0xF0,0x6E,0} }, /*17c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ - { { -1},{ -1} }, { {0xe0,0xe1,-1},{0xe0,0xF0,0xE1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{0xe0,0xF0,0xEE,-1} }, { { -1},{ -1} }, /*1ec*/ - { { -1},{ -1} }, { {0xe0,0xf1,-1},{0xe0,0xF0,0xF1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{0xe0,0xF0,0xFE,-1} }, { {0xe0,0xff,-1},{0xe0,0xF0,0xFF,-1} } /*1fc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ + { { 0},{ 0} }, { {0xe0,0xe1,0},{0xe0,0xF0,0xE1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{0xe0,0xF0,0xEE,0} }, { { 0},{ 0} }, /*1ec*/ + { { 0},{ 0} }, { {0xe0,0xf1,0},{0xe0,0xF0,0xF1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{0xe0,0xF0,0xFE,0} }, { {0xe0,0xff,0},{0xe0,0xF0,0xFF,0} } /*1fc*/ }; static const scancode scancode_set3[512] = { - { { -1},{ -1} }, { { 0x08,-1},{ 0xf0,0x08,-1} }, { { 0x16,-1},{ 0xf0,0x16,-1} }, { { 0x1E,-1},{ 0xf0,0x1E,-1} }, /*000*/ - { { 0x26,-1},{ 0xf0,0x26,-1} }, { { 0x25,-1},{ 0xf0,0x25,-1} }, { { 0x2E,-1},{ 0xf0,0x2E,-1} }, { { 0x36,-1},{ 0xf0,0x36,-1} }, /*004*/ - { { 0x3D,-1},{ 0xf0,0x3D,-1} }, { { 0x3E,-1},{ 0xf0,0x3E,-1} }, { { 0x46,-1},{ 0xf0,0x46,-1} }, { { 0x45,-1},{ 0xf0,0x45,-1} }, /*008*/ - { { 0x4E,-1},{ 0xf0,0x4E,-1} }, { { 0x55,-1},{ 0xf0,0x55,-1} }, { { 0x66,-1},{ 0xf0,0x66,-1} }, { { 0x0D,-1},{ 0xf0,0x0D,-1} }, /*00c*/ - { { 0x15,-1},{ 0xf0,0x15,-1} }, { { 0x1D,-1},{ 0xf0,0x1D,-1} }, { { 0x24,-1},{ 0xf0,0x24,-1} }, { { 0x2D,-1},{ 0xf0,0x2D,-1} }, /*010*/ - { { 0x2C,-1},{ 0xf0,0x2C,-1} }, { { 0x35,-1},{ 0xf0,0x35,-1} }, { { 0x3C,-1},{ 0xf0,0x3C,-1} }, { { 0x43,-1},{ 0xf0,0x43,-1} }, /*014*/ - { { 0x44,-1},{ 0xf0,0x44,-1} }, { { 0x4D,-1},{ 0xf0,0x4D,-1} }, { { 0x54,-1},{ 0xf0,0x54,-1} }, { { 0x5B,-1},{ 0xf0,0x5B,-1} }, /*018*/ - { { 0x5A,-1},{ 0xf0,0x5A,-1} }, { { 0x11,-1},{ 0xf0,0x11,-1} }, { { 0x1C,-1},{ 0xf0,0x1C,-1} }, { { 0x1B,-1},{ 0xf0,0x1B,-1} }, /*01c*/ - { { 0x23,-1},{ 0xf0,0x23,-1} }, { { 0x2B,-1},{ 0xf0,0x2B,-1} }, { { 0x34,-1},{ 0xf0,0x34,-1} }, { { 0x33,-1},{ 0xf0,0x33,-1} }, /*020*/ - { { 0x3B,-1},{ 0xf0,0x3B,-1} }, { { 0x42,-1},{ 0xf0,0x42,-1} }, { { 0x4B,-1},{ 0xf0,0x4B,-1} }, { { 0x4C,-1},{ 0xf0,0x4C,-1} }, /*024*/ - { { 0x52,-1},{ 0xf0,0x52,-1} }, { { 0x0E,-1},{ 0xf0,0x0E,-1} }, { { 0x12,-1},{ 0xf0,0x12,-1} }, { { 0x5C,-1},{ 0xf0,0x5C,-1} }, /*028*/ - { { 0x1A,-1},{ 0xf0,0x1A,-1} }, { { 0x22,-1},{ 0xf0,0x22,-1} }, { { 0x21,-1},{ 0xf0,0x21,-1} }, { { 0x2A,-1},{ 0xf0,0x2A,-1} }, /*02c*/ - { { 0x32,-1},{ 0xf0,0x32,-1} }, { { 0x31,-1},{ 0xf0,0x31,-1} }, { { 0x3A,-1},{ 0xf0,0x3A,-1} }, { { 0x41,-1},{ 0xf0,0x41,-1} }, /*030*/ - { { 0x49,-1},{ 0xf0,0x49,-1} }, { { 0x4A,-1},{ 0xf0,0x4A,-1} }, { { 0x59,-1},{ 0xf0,0x59,-1} }, { { 0x7E,-1},{ 0xf0,0x7E,-1} }, /*034*/ - { { 0x19,-1},{ 0xf0,0x19,-1} }, { { 0x29,-1},{ 0xf0,0x29,-1} }, { { 0x14,-1},{ 0xf0,0x14,-1} }, { { 0x07,-1},{ 0xf0,0x07,-1} }, /*038*/ - { { 0x0F,-1},{ 0xf0,0x0F,-1} }, { { 0x17,-1},{ 0xf0,0x17,-1} }, { { 0x1F,-1},{ 0xf0,0x1F,-1} }, { { 0x27,-1},{ 0xf0,0x27,-1} }, /*03c*/ - { { 0x2F,-1},{ 0xf0,0x2F,-1} }, { { 0x37,-1},{ 0xf0,0x37,-1} }, { { 0x3F,-1},{ 0xf0,0x3F,-1} }, { { 0x47,-1},{ 0xf0,0x47,-1} }, /*040*/ - { { 0x4F,-1},{ 0xf0,0x4F,-1} }, { { 0x76,-1},{ 0xf0,0x76,-1} }, { { 0x5F,-1},{ 0xf0,0x5F,-1} }, { { 0x6C,-1},{ 0xf0,0x6C,-1} }, /*044*/ - { { 0x75,-1},{ 0xf0,0x75,-1} }, { { 0x7D,-1},{ 0xf0,0x7D,-1} }, { { 0x84,-1},{ 0xf0,0x84,-1} }, { { 0x6B,-1},{ 0xf0,0x6B,-1} }, /*048*/ - { { 0x73,-1},{ 0xf0,0x73,-1} }, { { 0x74,-1},{ 0xf0,0x74,-1} }, { { 0x7C,-1},{ 0xf0,0x7C,-1} }, { { 0x69,-1},{ 0xf0,0x69,-1} }, /*04c*/ - { { 0x72,-1},{ 0xf0,0x72,-1} }, { { 0x7A,-1},{ 0xf0,0x7A,-1} }, { { 0x70,-1},{ 0xf0,0x70,-1} }, { { 0x71,-1},{ 0xf0,0x71,-1} }, /*050*/ - { { 0x57,-1},{ 0xf0,0x57,-1} }, { { 0x60,-1},{ 0xf0,0x60,-1} }, { { -1},{ -1} }, { { 0x56,-1},{ 0xf0,0x56,-1} }, /*054*/ - { { 0x5E,-1},{ 0xf0,0x5E,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*058*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*05c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*060*/ - { { -1},{ -1} }, { { 0x10,-1},{ 0xf0,0x10,-1} }, { { 0x18,-1},{ 0xf0,0x18,-1} }, { { 0x20,-1},{ 0xf0,0x20,-1} }, /*064*/ - { { 0x28,-1},{ 0xf0,0x28,-1} }, { { 0x30,-1},{ 0xf0,0x30,-1} }, { { 0x38,-1},{ 0xf0,0x38,-1} }, { { 0x40,-1},{ 0xf0,0x40,-1} }, /*068*/ - { { 0x48,-1},{ 0xf0,0x48,-1} }, { { 0x50,-1},{ 0xf0,0x50,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*06c*/ - { { 0x87,-1},{ 0xf0,0x87,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { 0x51,-1},{ 0xf0,0x51,-1} }, /*070*/ - { { 0x53,-1},{ 0xf0,0x53,-1} }, { { 0x5C,-1},{ 0xf0,0x5C,-1} }, { { -1},{ -1} }, { { 0x62,-1},{ 0xf0,0x62,-1} }, /*074*/ - { { 0x63,-1},{ 0xf0,0x63,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x85,-1} }, /*078*/ - { { 0x68,-1},{ 0xf0,0x68,-1} }, { { 0x13,-1},{ 0xf0,0x13,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*07c*/ + { { 0},{ 0} }, { { 0x08,0},{ 0xf0,0x08,0} }, { { 0x16,0},{ 0xf0,0x16,0} }, { { 0x1E,0},{ 0xf0,0x1E,0} }, /*000*/ + { { 0x26,0},{ 0xf0,0x26,0} }, { { 0x25,0},{ 0xf0,0x25,0} }, { { 0x2E,0},{ 0xf0,0x2E,0} }, { { 0x36,0},{ 0xf0,0x36,0} }, /*004*/ + { { 0x3D,0},{ 0xf0,0x3D,0} }, { { 0x3E,0},{ 0xf0,0x3E,0} }, { { 0x46,0},{ 0xf0,0x46,0} }, { { 0x45,0},{ 0xf0,0x45,0} }, /*008*/ + { { 0x4E,0},{ 0xf0,0x4E,0} }, { { 0x55,0},{ 0xf0,0x55,0} }, { { 0x66,0},{ 0xf0,0x66,0} }, { { 0x0D,0},{ 0xf0,0x0D,0} }, /*00c*/ + { { 0x15,0},{ 0xf0,0x15,0} }, { { 0x1D,0},{ 0xf0,0x1D,0} }, { { 0x24,0},{ 0xf0,0x24,0} }, { { 0x2D,0},{ 0xf0,0x2D,0} }, /*010*/ + { { 0x2C,0},{ 0xf0,0x2C,0} }, { { 0x35,0},{ 0xf0,0x35,0} }, { { 0x3C,0},{ 0xf0,0x3C,0} }, { { 0x43,0},{ 0xf0,0x43,0} }, /*014*/ + { { 0x44,0},{ 0xf0,0x44,0} }, { { 0x4D,0},{ 0xf0,0x4D,0} }, { { 0x54,0},{ 0xf0,0x54,0} }, { { 0x5B,0},{ 0xf0,0x5B,0} }, /*018*/ + { { 0x5A,0},{ 0xf0,0x5A,0} }, { { 0x11,0},{ 0xf0,0x11,0} }, { { 0x1C,0},{ 0xf0,0x1C,0} }, { { 0x1B,0},{ 0xf0,0x1B,0} }, /*01c*/ + { { 0x23,0},{ 0xf0,0x23,0} }, { { 0x2B,0},{ 0xf0,0x2B,0} }, { { 0x34,0},{ 0xf0,0x34,0} }, { { 0x33,0},{ 0xf0,0x33,0} }, /*020*/ + { { 0x3B,0},{ 0xf0,0x3B,0} }, { { 0x42,0},{ 0xf0,0x42,0} }, { { 0x4B,0},{ 0xf0,0x4B,0} }, { { 0x4C,0},{ 0xf0,0x4C,0} }, /*024*/ + { { 0x52,0},{ 0xf0,0x52,0} }, { { 0x0E,0},{ 0xf0,0x0E,0} }, { { 0x12,0},{ 0xf0,0x12,0} }, { { 0x5C,0},{ 0xf0,0x5C,0} }, /*028*/ + { { 0x1A,0},{ 0xf0,0x1A,0} }, { { 0x22,0},{ 0xf0,0x22,0} }, { { 0x21,0},{ 0xf0,0x21,0} }, { { 0x2A,0},{ 0xf0,0x2A,0} }, /*02c*/ + { { 0x32,0},{ 0xf0,0x32,0} }, { { 0x31,0},{ 0xf0,0x31,0} }, { { 0x3A,0},{ 0xf0,0x3A,0} }, { { 0x41,0},{ 0xf0,0x41,0} }, /*030*/ + { { 0x49,0},{ 0xf0,0x49,0} }, { { 0x4A,0},{ 0xf0,0x4A,0} }, { { 0x59,0},{ 0xf0,0x59,0} }, { { 0x7E,0},{ 0xf0,0x7E,0} }, /*034*/ + { { 0x19,0},{ 0xf0,0x19,0} }, { { 0x29,0},{ 0xf0,0x29,0} }, { { 0x14,0},{ 0xf0,0x14,0} }, { { 0x07,0},{ 0xf0,0x07,0} }, /*038*/ + { { 0x0F,0},{ 0xf0,0x0F,0} }, { { 0x17,0},{ 0xf0,0x17,0} }, { { 0x1F,0},{ 0xf0,0x1F,0} }, { { 0x27,0},{ 0xf0,0x27,0} }, /*03c*/ + { { 0x2F,0},{ 0xf0,0x2F,0} }, { { 0x37,0},{ 0xf0,0x37,0} }, { { 0x3F,0},{ 0xf0,0x3F,0} }, { { 0x47,0},{ 0xf0,0x47,0} }, /*040*/ + { { 0x4F,0},{ 0xf0,0x4F,0} }, { { 0x76,0},{ 0xf0,0x76,0} }, { { 0x5F,0},{ 0xf0,0x5F,0} }, { { 0x6C,0},{ 0xf0,0x6C,0} }, /*044*/ + { { 0x75,0},{ 0xf0,0x75,0} }, { { 0x7D,0},{ 0xf0,0x7D,0} }, { { 0x84,0},{ 0xf0,0x84,0} }, { { 0x6B,0},{ 0xf0,0x6B,0} }, /*048*/ + { { 0x73,0},{ 0xf0,0x73,0} }, { { 0x74,0},{ 0xf0,0x74,0} }, { { 0x7C,0},{ 0xf0,0x7C,0} }, { { 0x69,0},{ 0xf0,0x69,0} }, /*04c*/ + { { 0x72,0},{ 0xf0,0x72,0} }, { { 0x7A,0},{ 0xf0,0x7A,0} }, { { 0x70,0},{ 0xf0,0x70,0} }, { { 0x71,0},{ 0xf0,0x71,0} }, /*050*/ + { { 0x57,0},{ 0xf0,0x57,0} }, { { 0x60,0},{ 0xf0,0x60,0} }, { { 0},{ 0} }, { { 0x56,0},{ 0xf0,0x56,0} }, /*054*/ + { { 0x5E,0},{ 0xf0,0x5E,0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*058*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*05c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*060*/ + { { 0},{ 0} }, { { 0x10,0},{ 0xf0,0x10,0} }, { { 0x18,0},{ 0xf0,0x18,0} }, { { 0x20,0},{ 0xf0,0x20,0} }, /*064*/ + { { 0x28,0},{ 0xf0,0x28,0} }, { { 0x30,0},{ 0xf0,0x30,0} }, { { 0x38,0},{ 0xf0,0x38,0} }, { { 0x40,0},{ 0xf0,0x40,0} }, /*068*/ + { { 0x48,0},{ 0xf0,0x48,0} }, { { 0x50,0},{ 0xf0,0x50,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*06c*/ + { { 0x87,0},{ 0xf0,0x87,0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0x51,0},{ 0xf0,0x51,0} }, /*070*/ + { { 0x53,0},{ 0xf0,0x53,0} }, { { 0x5C,0},{ 0xf0,0x5C,0} }, { { 0},{ 0} }, { { 0x62,0},{ 0xf0,0x62,0} }, /*074*/ + { { 0x63,0},{ 0xf0,0x63,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x85,0} }, /*078*/ + { { 0x68,0},{ 0xf0,0x68,0} }, { { 0x13,0},{ 0xf0,0x13,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*07c*/ - { { 0x80,-1},{ 0xf0,0x80,-1} }, { { 0x81,-1},{ 0xf0,0x81,-1} }, { { 0x82,-1},{ 0xf0,0x82,-1} }, { { -1},{ -1} }, /*080*/ - { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x54,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { 0x87,-1},{ 0xf0,0x87,-1} }, /*084*/ - { { 0x88,-1},{ 0xf0,0x88,-1} }, { { 0x89,-1},{ 0xf0,0x89,-1} }, { { 0x8a,-1},{ 0xf0,0x8a,-1} }, { { 0x8b,-1},{ 0xf0,0x8b,-1} }, /*088*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { 0x8e,-1},{ 0xf0,0x8e,-1} }, { { 0x8f,-1},{ 0xf0,0x8f,-1} }, /*08c*/ - { { 0x90,-1},{ 0xf0,0x90,-1} }, { { 0x91,-1},{ 0xf0,0x91,-1} }, { { 0x92,-1},{ 0xf0,0x92,-1} }, { { 0x93,-1},{ 0xf0,0x93,-1} }, /*090*/ - { { 0x94,-1},{ 0xf0,0x94,-1} }, { { 0x95,-1},{ 0xf0,0x95,-1} }, { { 0x96,-1},{ 0xf0,0x96,-1} }, { { 0x97,-1},{ 0xf0,0x97,-1} }, /*094*/ - { { 0x98,-1},{ 0xf0,0x98,-1} }, { { 0x99,-1},{ 0xf0,0x99,-1} }, { { 0x9a,-1},{ 0xf0,0x9a,-1} }, { { 0x9b,-1},{ 0xf0,0x9b,-1} }, /*098*/ - { { 0x9c,-1},{ 0xf0,0x9c,-1} }, { { 0x9d,-1},{ 0xf0,0x9d,-1} }, { { 0x9e,-1},{ 0xf0,0x9e,-1} }, { { 0x9f,-1},{ 0xf0,0x9f,-1} }, /*09c*/ - { { 0xa0,-1},{ 0xf0,0xa0,-1} }, { { 0xa1,-1},{ 0xf0,0xa1,-1} }, { { 0xa2,-1},{ 0xf0,0xa2,-1} }, { { 0xa3,-1},{ 0xf0,0xa3,-1} }, /*0a0*/ - { { 0xa4,-1},{ 0xf0,0xa4,-1} }, { { 0xa5,-1},{ 0xf0,0xa5,-1} }, { { 0xa6,-1},{ 0xf0,0xa6,-1} }, { { 0xa7,-1},{ 0xf0,0xa7,-1} }, /*0a4*/ - { { 0xa8,-1},{ 0xf0,0xa8,-1} }, { { 0xa9,-1},{ 0xf0,0xa9,-1} }, { { 0xaa,-1},{ 0xf0,0xaa,-1} }, { { 0xab,-1},{ 0xf0,0xab,-1} }, /*0a8*/ - { { 0xac,-1},{ 0xf0,0xac,-1} }, { { 0xad,-1},{ 0xf0,0xad,-1} }, { { 0xae,-1},{ 0xf0,0xae,-1} }, { { 0xaf,-1},{ 0xf0,0xaf,-1} }, /*0ac*/ - { { 0xb0,-1},{ 0xf0,0xb0,-1} }, { { 0xb1,-1},{ 0xf0,0xb1,-1} }, { { 0xb2,-1},{ 0xf0,0xb2,-1} }, { { 0xb3,-1},{ 0xf0,0xb3,-1} }, /*0b0*/ - { { 0xb4,-1},{ 0xf0,0xb4,-1} }, { { 0xb5,-1},{ 0xf0,0xb5,-1} }, { { 0xb6,-1},{ 0xf0,0xb6,-1} }, { { 0xb7,-1},{ 0xf0,0xb7,-1} }, /*0b4*/ - { { 0xb8,-1},{ 0xf0,0xb8,-1} }, { { 0xb9,-1},{ 0xf0,0xb9,-1} }, { { 0xba,-1},{ 0xf0,0xba,-1} }, { { 0xbb,-1},{ 0xf0,0xbb,-1} }, /*0b8*/ - { { 0xbc,-1},{ 0xf0,0xbc,-1} }, { { 0xbd,-1},{ 0xf0,0xbd,-1} }, { { 0xbe,-1},{ 0xf0,0xbe,-1} }, { { 0xbf,-1},{ 0xf0,0xbf,-1} }, /*0bc*/ - { { 0xc0,-1},{ 0xf0,0xc0,-1} }, { { 0xc1,-1},{ 0xf0,0xc1,-1} }, { { 0xc2,-1},{ 0xf0,0xc2,-1} }, { { 0xc3,-1},{ 0xf0,0xc3,-1} }, /*0c0*/ - { { 0xc4,-1},{ 0xf0,0xc4,-1} }, { { 0xc5,-1},{ 0xf0,0xc5,-1} }, { { 0xc6,-1},{ 0xf0,0xc6,-1} }, { { 0xc7,-1},{ 0xf0,0xc7,-1} }, /*0c4*/ - { { 0xc8,-1},{ 0xf0,0xc8,-1} }, { { 0xc9,-1},{ 0xf0,0xc9,-1} }, { { 0xca,-1},{ 0xf0,0xca,-1} }, { { 0xcb,-1},{ 0xf0,0xcb,-1} }, /*0c8*/ - { { 0xcc,-1},{ 0xf0,0xcc,-1} }, { { 0xcd,-1},{ 0xf0,0xcd,-1} }, { { 0xce,-1},{ 0xf0,0xce,-1} }, { { 0xcf,-1},{ 0xf0,0xcf,-1} }, /*0cc*/ - { { 0xd0,-1},{ 0xf0,0xd0,-1} }, { { 0xd1,-1},{ 0xf0,0xd0,-1} }, { { 0xd2,-1},{ 0xf0,0xd2,-1} }, { { 0xd3,-1},{ 0xf0,0xd3,-1} }, /*0d0*/ - { { 0xd4,-1},{ 0xf0,0xd4,-1} }, { { 0xd5,-1},{ 0xf0,0xd5,-1} }, { { 0xd6,-1},{ 0xf0,0xd6,-1} }, { { 0xd7,-1},{ 0xf0,0xd7,-1} }, /*0d4*/ - { { 0xd8,-1},{ 0xf0,0xd8,-1} }, { { 0xd9,-1},{ 0xf0,0xd9,-1} }, { { 0xda,-1},{ 0xf0,0xda,-1} }, { { 0xdb,-1},{ 0xf0,0xdb,-1} }, /*0d8*/ - { { 0xdc,-1},{ 0xf0,0xdc,-1} }, { { 0xdd,-1},{ 0xf0,0xdd,-1} }, { { 0xde,-1},{ 0xf0,0xde,-1} }, { { 0xdf,-1},{ 0xf0,0xdf,-1} }, /*0dc*/ - { { 0xe0,-1},{ 0xf0,0xe0,-1} }, { { 0xe1,-1},{ 0xf0,0xe1,-1} }, { { 0xe2,-1},{ 0xf0,0xe2,-1} }, { { 0xe3,-1},{ 0xf0,0xe3,-1} }, /*0e0*/ - { { 0xe4,-1},{ 0xf0,0xe4,-1} }, { { 0xe5,-1},{ 0xf0,0xe5,-1} }, { { 0xe6,-1},{ 0xf0,0xe6,-1} }, { { 0xe7,-1},{ 0xf0,0xe7,-1} }, /*0e4*/ - { { 0xe8,-1},{ 0xf0,0xe8,-1} }, { { 0xe9,-1},{ 0xf0,0xe9,-1} }, { { 0xea,-1},{ 0xf0,0xea,-1} }, { { 0xeb,-1},{ 0xf0,0xeb,-1} }, /*0e8*/ - { { 0xec,-1},{ 0xf0,0xec,-1} }, { { 0xed,-1},{ 0xf0,0xed,-1} }, { { 0xee,-1},{ 0xf0,0xee,-1} }, { { 0xef,-1},{ 0xf0,0xef,-1} }, /*0ec*/ - { { -1},{ -1} }, { { 0xf1,-1},{ 0xf0,0xf1,-1} }, { { 0xf2,-1},{ 0xf0,0xf2,-1} }, { { 0xf3,-1},{ 0xf0,0xf3,-1} }, /*0f0*/ - { { 0xf4,-1},{ 0xf0,0xf4,-1} }, { { 0xf5,-1},{ 0xf0,0xf5,-1} }, { { 0xf6,-1},{ 0xf0,0xf6,-1} }, { { 0xf7,-1},{ 0xf0,0xf7,-1} }, /*0f4*/ - { { 0xf8,-1},{ 0xf0,0xf8,-1} }, { { 0xf9,-1},{ 0xf0,0xf9,-1} }, { { 0xfa,-1},{ 0xf0,0xfa,-1} }, { { 0xfb,-1},{ 0xf0,0xfb,-1} }, /*0f8*/ - { { 0xfc,-1},{ 0xf0,0xfc,-1} }, { { 0xfd,-1},{ 0xf0,0xfd,-1} }, { { 0xfe,-1},{ 0xf0,0xfe,-1} }, { { 0xff,-1},{ 0xf0,0xff,-1} }, /*0fc*/ + { { 0x80,0},{ 0xf0,0x80,0} }, { { 0x81,0},{ 0xf0,0x81,0} }, { { 0x82,0},{ 0xf0,0x82,0} }, { { 0},{ 0} }, /*080*/ + { { 0},{ 0} }, { { 0x85,0},{ 0xf0,0x54,0} }, { { 0x86,0},{ 0xf0,0x86,0} }, { { 0x87,0},{ 0xf0,0x87,0} }, /*084*/ + { { 0x88,0},{ 0xf0,0x88,0} }, { { 0x89,0},{ 0xf0,0x89,0} }, { { 0x8a,0},{ 0xf0,0x8a,0} }, { { 0x8b,0},{ 0xf0,0x8b,0} }, /*088*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0x8e,0},{ 0xf0,0x8e,0} }, { { 0x8f,0},{ 0xf0,0x8f,0} }, /*08c*/ + { { 0x90,0},{ 0xf0,0x90,0} }, { { 0x91,0},{ 0xf0,0x91,0} }, { { 0x92,0},{ 0xf0,0x92,0} }, { { 0x93,0},{ 0xf0,0x93,0} }, /*090*/ + { { 0x94,0},{ 0xf0,0x94,0} }, { { 0x95,0},{ 0xf0,0x95,0} }, { { 0x96,0},{ 0xf0,0x96,0} }, { { 0x97,0},{ 0xf0,0x97,0} }, /*094*/ + { { 0x98,0},{ 0xf0,0x98,0} }, { { 0x99,0},{ 0xf0,0x99,0} }, { { 0x9a,0},{ 0xf0,0x9a,0} }, { { 0x9b,0},{ 0xf0,0x9b,0} }, /*098*/ + { { 0x9c,0},{ 0xf0,0x9c,0} }, { { 0x9d,0},{ 0xf0,0x9d,0} }, { { 0x9e,0},{ 0xf0,0x9e,0} }, { { 0x9f,0},{ 0xf0,0x9f,0} }, /*09c*/ + { { 0xa0,0},{ 0xf0,0xa0,0} }, { { 0xa1,0},{ 0xf0,0xa1,0} }, { { 0xa2,0},{ 0xf0,0xa2,0} }, { { 0xa3,0},{ 0xf0,0xa3,0} }, /*0a0*/ + { { 0xa4,0},{ 0xf0,0xa4,0} }, { { 0xa5,0},{ 0xf0,0xa5,0} }, { { 0xa6,0},{ 0xf0,0xa6,0} }, { { 0xa7,0},{ 0xf0,0xa7,0} }, /*0a4*/ + { { 0xa8,0},{ 0xf0,0xa8,0} }, { { 0xa9,0},{ 0xf0,0xa9,0} }, { { 0xaa,0},{ 0xf0,0xaa,0} }, { { 0xab,0},{ 0xf0,0xab,0} }, /*0a8*/ + { { 0xac,0},{ 0xf0,0xac,0} }, { { 0xad,0},{ 0xf0,0xad,0} }, { { 0xae,0},{ 0xf0,0xae,0} }, { { 0xaf,0},{ 0xf0,0xaf,0} }, /*0ac*/ + { { 0xb0,0},{ 0xf0,0xb0,0} }, { { 0xb1,0},{ 0xf0,0xb1,0} }, { { 0xb2,0},{ 0xf0,0xb2,0} }, { { 0xb3,0},{ 0xf0,0xb3,0} }, /*0b0*/ + { { 0xb4,0},{ 0xf0,0xb4,0} }, { { 0xb5,0},{ 0xf0,0xb5,0} }, { { 0xb6,0},{ 0xf0,0xb6,0} }, { { 0xb7,0},{ 0xf0,0xb7,0} }, /*0b4*/ + { { 0xb8,0},{ 0xf0,0xb8,0} }, { { 0xb9,0},{ 0xf0,0xb9,0} }, { { 0xba,0},{ 0xf0,0xba,0} }, { { 0xbb,0},{ 0xf0,0xbb,0} }, /*0b8*/ + { { 0xbc,0},{ 0xf0,0xbc,0} }, { { 0xbd,0},{ 0xf0,0xbd,0} }, { { 0xbe,0},{ 0xf0,0xbe,0} }, { { 0xbf,0},{ 0xf0,0xbf,0} }, /*0bc*/ + { { 0xc0,0},{ 0xf0,0xc0,0} }, { { 0xc1,0},{ 0xf0,0xc1,0} }, { { 0xc2,0},{ 0xf0,0xc2,0} }, { { 0xc3,0},{ 0xf0,0xc3,0} }, /*0c0*/ + { { 0xc4,0},{ 0xf0,0xc4,0} }, { { 0xc5,0},{ 0xf0,0xc5,0} }, { { 0xc6,0},{ 0xf0,0xc6,0} }, { { 0xc7,0},{ 0xf0,0xc7,0} }, /*0c4*/ + { { 0xc8,0},{ 0xf0,0xc8,0} }, { { 0xc9,0},{ 0xf0,0xc9,0} }, { { 0xca,0},{ 0xf0,0xca,0} }, { { 0xcb,0},{ 0xf0,0xcb,0} }, /*0c8*/ + { { 0xcc,0},{ 0xf0,0xcc,0} }, { { 0xcd,0},{ 0xf0,0xcd,0} }, { { 0xce,0},{ 0xf0,0xce,0} }, { { 0xcf,0},{ 0xf0,0xcf,0} }, /*0cc*/ + { { 0xd0,0},{ 0xf0,0xd0,0} }, { { 0xd1,0},{ 0xf0,0xd0,0} }, { { 0xd2,0},{ 0xf0,0xd2,0} }, { { 0xd3,0},{ 0xf0,0xd3,0} }, /*0d0*/ + { { 0xd4,0},{ 0xf0,0xd4,0} }, { { 0xd5,0},{ 0xf0,0xd5,0} }, { { 0xd6,0},{ 0xf0,0xd6,0} }, { { 0xd7,0},{ 0xf0,0xd7,0} }, /*0d4*/ + { { 0xd8,0},{ 0xf0,0xd8,0} }, { { 0xd9,0},{ 0xf0,0xd9,0} }, { { 0xda,0},{ 0xf0,0xda,0} }, { { 0xdb,0},{ 0xf0,0xdb,0} }, /*0d8*/ + { { 0xdc,0},{ 0xf0,0xdc,0} }, { { 0xdd,0},{ 0xf0,0xdd,0} }, { { 0xde,0},{ 0xf0,0xde,0} }, { { 0xdf,0},{ 0xf0,0xdf,0} }, /*0dc*/ + { { 0xe0,0},{ 0xf0,0xe0,0} }, { { 0xe1,0},{ 0xf0,0xe1,0} }, { { 0xe2,0},{ 0xf0,0xe2,0} }, { { 0xe3,0},{ 0xf0,0xe3,0} }, /*0e0*/ + { { 0xe4,0},{ 0xf0,0xe4,0} }, { { 0xe5,0},{ 0xf0,0xe5,0} }, { { 0xe6,0},{ 0xf0,0xe6,0} }, { { 0xe7,0},{ 0xf0,0xe7,0} }, /*0e4*/ + { { 0xe8,0},{ 0xf0,0xe8,0} }, { { 0xe9,0},{ 0xf0,0xe9,0} }, { { 0xea,0},{ 0xf0,0xea,0} }, { { 0xeb,0},{ 0xf0,0xeb,0} }, /*0e8*/ + { { 0xec,0},{ 0xf0,0xec,0} }, { { 0xed,0},{ 0xf0,0xed,0} }, { { 0xee,0},{ 0xf0,0xee,0} }, { { 0xef,0},{ 0xf0,0xef,0} }, /*0ec*/ + { { 0},{ 0} }, { { 0xf1,0},{ 0xf0,0xf1,0} }, { { 0xf2,0},{ 0xf0,0xf2,0} }, { { 0xf3,0},{ 0xf0,0xf3,0} }, /*0f0*/ + { { 0xf4,0},{ 0xf0,0xf4,0} }, { { 0xf5,0},{ 0xf0,0xf5,0} }, { { 0xf6,0},{ 0xf0,0xf6,0} }, { { 0xf7,0},{ 0xf0,0xf7,0} }, /*0f4*/ + { { 0xf8,0},{ 0xf0,0xf8,0} }, { { 0xf9,0},{ 0xf0,0xf9,0} }, { { 0xfa,0},{ 0xf0,0xfa,0} }, { { 0xfb,0},{ 0xf0,0xfb,0} }, /*0f8*/ + { { 0xfc,0},{ 0xf0,0xfc,0} }, { { 0xfd,0},{ 0xf0,0xfd,0} }, { { 0xfe,0},{ 0xf0,0xfe,0} }, { { 0xff,0},{ 0xf0,0xff,0} }, /*0fc*/ - { { 0x62,-1},{ 0xF0,0x62,-1} }, { {0xe0,0x76,-1},{0xe0,0xF0,0x76,-1} }, { {0xe0,0x16,-1},{0xe0,0xF0,0x16,-1} }, { {0xe0,0x1E,-1},{0xe0,0xF0,0x1E,-1} }, /*100*/ - { {0xe0,0x26,-1},{0xe0,0xF0,0x26,-1} }, { {0xe0,0x25,-1},{0xe0,0xF0,0x25,-1} }, { {0xe0,0x2E,-1},{0xe0,0xF0,0x2E,-1} }, { {0xe0,0x36,-1},{0xe0,0xF0,0x36,-1} }, /*104*/ - { {0xe0,0x3D,-1},{0xe0,0xF0,0x3D,-1} }, { {0xe0,0x3E,-1},{0xe0,0xF0,0x3E,-1} }, { {0xe0,0x46,-1},{0xe0,0xF0,0x46,-1} }, { {0xe0,0x45,-1},{0xe0,0xF0,0x45,-1} }, /*108*/ - { {0xe0,0x4E,-1},{0xe0,0xF0,0x4E,-1} }, { { -1},{ -1} }, { {0xe0,0x66,-1},{0xe0,0xF0,0x66,-1} }, { {0xe0,0x0D,-1},{0xe0,0xF0,0x0D,-1} }, /*10c*/ - { {0xe0,0x15,-1},{0xe0,0xF0,0x15,-1} }, { {0xe0,0x1D,-1},{0xe0,0xF0,0x1D,-1} }, { {0xe0,0x24,-1},{0xe0,0xF0,0x24,-1} }, { {0xe0,0x2D,-1},{0xe0,0xF0,0x2D,-1} }, /*110*/ - { {0xe0,0x2C,-1},{0xe0,0xF0,0x2C,-1} }, { {0xe0,0x35,-1},{0xe0,0xF0,0x35,-1} }, { {0xe0,0x3C,-1},{0xe0,0xF0,0x3C,-1} }, { {0xe0,0x43,-1},{0xe0,0xF0,0x43,-1} }, /*114*/ - { {0xe0,0x44,-1},{0xe0,0xF0,0x44,-1} }, { {0xe0,0x4D,-1},{0xe0,0xF0,0x4D,-1} }, { {0xe0,0x54,-1},{0xe0,0xF0,0x54,-1} }, { {0xe0,0x5B,-1},{0xe0,0xF0,0x5B,-1} }, /*118*/ - { { 0x79,-1},{ 0xf0,0x79,-1} }, { { 0x58,-1},{ 0xf0,0x58,-1} }, { {0xe0,0x1C,-1},{0xe0,0xF0,0x1C,-1} }, { {0xe0,0x1B,-1},{0xe0,0xF0,0x1B,-1} }, /*11c*/ - { {0xe0,0x23,-1},{0xe0,0xF0,0x23,-1} }, { {0xe0,0x2B,-1},{0xe0,0xF0,0x2B,-1} }, { {0xe0,0x34,-1},{0xe0,0xF0,0x34,-1} }, { {0xe0,0x33,-1},{0xe0,0xF0,0x33,-1} }, /*120*/ - { {0xe0,0x3B,-1},{0xe0,0xF0,0x3B,-1} }, { {0xe0,0x42,-1},{0xe0,0xF0,0x42,-1} }, { {0xe0,0x4B,-1},{0xe0,0xF0,0x4B,-1} }, { { -1},{ -1} }, /*124*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ - { {0xe0,0x1A,-1},{0xe0,0xF0,0x1A,-1} }, { {0xe0,0x22,-1},{0xe0,0xF0,0x22,-1} }, { {0xe0,0x21,-1},{0xe0,0xF0,0x21,-1} }, { {0xe0,0x2A,-1},{0xe0,0xF0,0x2A,-1} }, /*12c*/ - { {0xe0,0x32,-1},{0xe0,0xF0,0x32,-1} }, { {0xe0,0x31,-1},{0xe0,0xF0,0x31,-1} }, { {0xe0,0x3A,-1},{0xe0,0xF0,0x3A,-1} }, { { -1},{ -1} }, /*130*/ - { {0xe0,0x49,-1},{0xe0,0xF0,0x49,-1} }, { { 0x77,-1},{ 0xf0,0x77,-1} }, { { -1},{ -1} }, { { 0x57,-1},{ 0xf0,0x57,-1} }, /*134*/ - { { 0x39,-1},{ 0xf0,0x39,-1} }, { { -1},{ -1} }, { {0xe0,0x58,-1},{0xe0,0xF0,0x58,-1} }, { {0xe0,0x05,-1},{0xe0,0xF0,0x05,-1} }, /*138*/ - { {0xe0,0x06,-1},{0xe0,0xF0,0x06,-1} }, { {0xe0,0x04,-1},{0xe0,0xF0,0x04,-1} }, { {0xe0,0x0C,-1},{0xe0,0xF0,0x0C,-1} }, { {0xe0,0x03,-1},{0xe0,0xF0,0x03,-1} }, /*13c*/ - { {0xe0,0x0B,-1},{0xe0,0xF0,0x0B,-1} }, { {0xe0,0x02,-1},{0xe0,0xF0,0x02,-1} }, { {0xe0,0x0A,-1},{0xe0,0xF0,0x0A,-1} }, { {0xe0,0x01,-1},{0xe0,0xF0,0x01,-1} }, /*140*/ - { {0xe0,0x09,-1},{0xe0,0xF0,0x09,-1} }, { { -1},{ -1} }, { {0xe0,0x7E,-1},{0xe0,0xF0,0x7E,-1} }, { { 0x6E,-1},{ 0xf0,0x6E,-1} }, /*144*/ - { { 0x63,-1},{ 0xf0,0x63,-1} }, { { 0x6F,-1},{ 0xf0,0x6F,-1} }, { { -1},{ -1} }, { { 0x61,-1},{ 0xf0,0x61,-1} }, /*148*/ - { {0xe0,0x73,-1},{0xe0,0xF0,0x73,-1} }, { { 0x6A,-1},{ 0xf0,0x6A,-1} }, { {0xe0,0x79,-1},{0xe0,0xF0,0x79,-1} }, { { 0x65,-1},{ 0xf0,0x65,-1} }, /*14c*/ - { { 0x60,-1},{ 0xf0,0x60,-1} }, { { 0x6D,-1},{ 0xf0,0x6D,-1} }, { { 0x67,-1},{ 0xf0,0x67,-1} }, { { 0x64,-1},{ 0xf0,0x64,-1} }, /*150*/ - { { 0xd4,-1},{ 0xf0,0xD4,-1} }, { {0xe0,0x60,-1},{0xe0,0xF0,0x60,-1} }, { { -1},{ -1} }, { {0xe0,0x78,-1},{0xe0,0xF0,0x78,-1} }, /*154*/ - { {0xe0,0x07,-1},{0xe0,0xF0,0x07,-1} }, { {0xe0,0x0F,-1},{0xe0,0xF0,0x0F,-1} }, { {0xe0,0x17,-1},{0xe0,0xF0,0x17,-1} }, { { 0x8B,-1},{ 0xf0,0x8B,-1} }, /*158*/ - { { 0x8C,-1},{ 0xf0,0x8C,-1} }, { { 0x8D,-1},{ 0xf0,0x8D,-1} }, { { -1},{ -1} }, { { 0x7F,-1},{ 0xf0,0x7F,-1} }, /*15c*/ - { { -1},{ -1} }, { {0xe0,0x4F,-1},{0xe0,0xF0,0x4F,-1} }, { {0xe0,0x56,-1},{0xe0,0xF0,0x56,-1} }, { { -1},{ -1} }, /*160*/ - { {0xe0,0x08,-1},{0xe0,0xF0,0x08,-1} }, { {0xe0,0x10,-1},{0xe0,0xF0,0x10,-1} }, { {0xe0,0x18,-1},{0xe0,0xF0,0x18,-1} }, { {0xe0,0x20,-1},{0xe0,0xF0,0x20,-1} }, /*164*/ - { {0xe0,0x28,-1},{0xe0,0xF0,0x28,-1} }, { {0xe0,0x30,-1},{0xe0,0xF0,0x30,-1} }, { {0xe0,0x38,-1},{0xe0,0xF0,0x38,-1} }, { {0xe0,0x40,-1},{0xe0,0xF0,0x40,-1} }, /*168*/ - { {0xe0,0x48,-1},{0xe0,0xF0,0x48,-1} }, { {0xe0,0x50,-1},{0xe0,0xF0,0x50,-1} }, { {0xe0,0x57,-1},{0xe0,0xF0,0x57,-1} }, { { -1},{ -1} }, /*16c*/ - { {0xe0,0x13,-1},{0xe0,0xF0,0x13,-1} }, { {0xe0,0x19,-1},{0xe0,0xF0,0x19,-1} }, { {0xe0,0x39,-1},{0xe0,0xF0,0x39,-1} }, { {0xe0,0x51,-1},{0xe0,0xF0,0x51,-1} }, /*170*/ - { {0xe0,0x53,-1},{0xe0,0xF0,0x53,-1} }, { {0xe0,0x5C,-1},{0xe0,0xF0,0x5C,-1} }, { { -1},{ -1} }, { {0xe0,0x62,-1},{0xe0,0xF0,0x62,-1} }, /*174*/ - { {0xe0,0x63,-1},{0xe0,0xF0,0x63,-1} }, { {0xe0,0x64,-1},{0xe0,0xF0,0x64,-1} }, { {0xe0,0x65,-1},{0xe0,0xF0,0x65,-1} }, { {0xe0,0x67,-1},{0xe0,0xF0,0x67,-1} }, /*178*/ - { {0xe0,0x68,-1},{0xe0,0xF0,0x68,-1} }, { {0xe0,0x6A,-1},{0xe0,0xF0,0x6A,-1} }, { {0xe0,0x6D,-1},{0xe0,0xF0,0x6D,-1} }, { {0xe0,0x6E,-1},{0xe0,0xF0,0x6E,-1} }, /*17c*/ + { { 0x62,0},{ 0xF0,0x62,0} }, { {0xe0,0x76,0},{0xe0,0xF0,0x76,0} }, { {0xe0,0x16,0},{0xe0,0xF0,0x16,0} }, { {0xe0,0x1E,0},{0xe0,0xF0,0x1E,0} }, /*100*/ + { {0xe0,0x26,0},{0xe0,0xF0,0x26,0} }, { {0xe0,0x25,0},{0xe0,0xF0,0x25,0} }, { {0xe0,0x2E,0},{0xe0,0xF0,0x2E,0} }, { {0xe0,0x36,0},{0xe0,0xF0,0x36,0} }, /*104*/ + { {0xe0,0x3D,0},{0xe0,0xF0,0x3D,0} }, { {0xe0,0x3E,0},{0xe0,0xF0,0x3E,0} }, { {0xe0,0x46,0},{0xe0,0xF0,0x46,0} }, { {0xe0,0x45,0},{0xe0,0xF0,0x45,0} }, /*108*/ + { {0xe0,0x4E,0},{0xe0,0xF0,0x4E,0} }, { { 0},{ 0} }, { {0xe0,0x66,0},{0xe0,0xF0,0x66,0} }, { {0xe0,0x0D,0},{0xe0,0xF0,0x0D,0} }, /*10c*/ + { {0xe0,0x15,0},{0xe0,0xF0,0x15,0} }, { {0xe0,0x1D,0},{0xe0,0xF0,0x1D,0} }, { {0xe0,0x24,0},{0xe0,0xF0,0x24,0} }, { {0xe0,0x2D,0},{0xe0,0xF0,0x2D,0} }, /*110*/ + { {0xe0,0x2C,0},{0xe0,0xF0,0x2C,0} }, { {0xe0,0x35,0},{0xe0,0xF0,0x35,0} }, { {0xe0,0x3C,0},{0xe0,0xF0,0x3C,0} }, { {0xe0,0x43,0},{0xe0,0xF0,0x43,0} }, /*114*/ + { {0xe0,0x44,0},{0xe0,0xF0,0x44,0} }, { {0xe0,0x4D,0},{0xe0,0xF0,0x4D,0} }, { {0xe0,0x54,0},{0xe0,0xF0,0x54,0} }, { {0xe0,0x5B,0},{0xe0,0xF0,0x5B,0} }, /*118*/ + { { 0x79,0},{ 0xf0,0x79,0} }, { { 0x58,0},{ 0xf0,0x58,0} }, { {0xe0,0x1C,0},{0xe0,0xF0,0x1C,0} }, { {0xe0,0x1B,0},{0xe0,0xF0,0x1B,0} }, /*11c*/ + { {0xe0,0x23,0},{0xe0,0xF0,0x23,0} }, { {0xe0,0x2B,0},{0xe0,0xF0,0x2B,0} }, { {0xe0,0x34,0},{0xe0,0xF0,0x34,0} }, { {0xe0,0x33,0},{0xe0,0xF0,0x33,0} }, /*120*/ + { {0xe0,0x3B,0},{0xe0,0xF0,0x3B,0} }, { {0xe0,0x42,0},{0xe0,0xF0,0x42,0} }, { {0xe0,0x4B,0},{0xe0,0xF0,0x4B,0} }, { { 0},{ 0} }, /*124*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*128*/ + { {0xe0,0x1A,0},{0xe0,0xF0,0x1A,0} }, { {0xe0,0x22,0},{0xe0,0xF0,0x22,0} }, { {0xe0,0x21,0},{0xe0,0xF0,0x21,0} }, { {0xe0,0x2A,0},{0xe0,0xF0,0x2A,0} }, /*12c*/ + { {0xe0,0x32,0},{0xe0,0xF0,0x32,0} }, { {0xe0,0x31,0},{0xe0,0xF0,0x31,0} }, { {0xe0,0x3A,0},{0xe0,0xF0,0x3A,0} }, { { 0},{ 0} }, /*130*/ + { {0xe0,0x49,0},{0xe0,0xF0,0x49,0} }, { { 0x77,0},{ 0xf0,0x77,0} }, { { 0},{ 0} }, { { 0x57,0},{ 0xf0,0x57,0} }, /*134*/ + { { 0x39,0},{ 0xf0,0x39,0} }, { { 0},{ 0} }, { {0xe0,0x58,0},{0xe0,0xF0,0x58,0} }, { {0xe0,0x05,0},{0xe0,0xF0,0x05,0} }, /*138*/ + { {0xe0,0x06,0},{0xe0,0xF0,0x06,0} }, { {0xe0,0x04,0},{0xe0,0xF0,0x04,0} }, { {0xe0,0x0C,0},{0xe0,0xF0,0x0C,0} }, { {0xe0,0x03,0},{0xe0,0xF0,0x03,0} }, /*13c*/ + { {0xe0,0x0B,0},{0xe0,0xF0,0x0B,0} }, { {0xe0,0x02,0},{0xe0,0xF0,0x02,0} }, { {0xe0,0x0A,0},{0xe0,0xF0,0x0A,0} }, { {0xe0,0x01,0},{0xe0,0xF0,0x01,0} }, /*140*/ + { {0xe0,0x09,0},{0xe0,0xF0,0x09,0} }, { { 0},{ 0} }, { {0xe0,0x7E,0},{0xe0,0xF0,0x7E,0} }, { { 0x6E,0},{ 0xf0,0x6E,0} }, /*144*/ + { { 0x63,0},{ 0xf0,0x63,0} }, { { 0x6F,0},{ 0xf0,0x6F,0} }, { { 0},{ 0} }, { { 0x61,0},{ 0xf0,0x61,0} }, /*148*/ + { {0xe0,0x73,0},{0xe0,0xF0,0x73,0} }, { { 0x6A,0},{ 0xf0,0x6A,0} }, { {0xe0,0x79,0},{0xe0,0xF0,0x79,0} }, { { 0x65,0},{ 0xf0,0x65,0} }, /*14c*/ + { { 0x60,0},{ 0xf0,0x60,0} }, { { 0x6D,0},{ 0xf0,0x6D,0} }, { { 0x67,0},{ 0xf0,0x67,0} }, { { 0x64,0},{ 0xf0,0x64,0} }, /*150*/ + { { 0xd4,0},{ 0xf0,0xD4,0} }, { {0xe0,0x60,0},{0xe0,0xF0,0x60,0} }, { { 0},{ 0} }, { {0xe0,0x78,0},{0xe0,0xF0,0x78,0} }, /*154*/ + { {0xe0,0x07,0},{0xe0,0xF0,0x07,0} }, { {0xe0,0x0F,0},{0xe0,0xF0,0x0F,0} }, { {0xe0,0x17,0},{0xe0,0xF0,0x17,0} }, { { 0x8B,0},{ 0xf0,0x8B,0} }, /*158*/ + { { 0x8C,0},{ 0xf0,0x8C,0} }, { { 0x8D,0},{ 0xf0,0x8D,0} }, { { 0},{ 0} }, { { 0x7F,0},{ 0xf0,0x7F,0} }, /*15c*/ + { { 0},{ 0} }, { {0xe0,0x4F,0},{0xe0,0xF0,0x4F,0} }, { {0xe0,0x56,0},{0xe0,0xF0,0x56,0} }, { { 0},{ 0} }, /*160*/ + { {0xe0,0x08,0},{0xe0,0xF0,0x08,0} }, { {0xe0,0x10,0},{0xe0,0xF0,0x10,0} }, { {0xe0,0x18,0},{0xe0,0xF0,0x18,0} }, { {0xe0,0x20,0},{0xe0,0xF0,0x20,0} }, /*164*/ + { {0xe0,0x28,0},{0xe0,0xF0,0x28,0} }, { {0xe0,0x30,0},{0xe0,0xF0,0x30,0} }, { {0xe0,0x38,0},{0xe0,0xF0,0x38,0} }, { {0xe0,0x40,0},{0xe0,0xF0,0x40,0} }, /*168*/ + { {0xe0,0x48,0},{0xe0,0xF0,0x48,0} }, { {0xe0,0x50,0},{0xe0,0xF0,0x50,0} }, { {0xe0,0x57,0},{0xe0,0xF0,0x57,0} }, { { 0},{ 0} }, /*16c*/ + { {0xe0,0x13,0},{0xe0,0xF0,0x13,0} }, { {0xe0,0x19,0},{0xe0,0xF0,0x19,0} }, { {0xe0,0x39,0},{0xe0,0xF0,0x39,0} }, { {0xe0,0x51,0},{0xe0,0xF0,0x51,0} }, /*170*/ + { {0xe0,0x53,0},{0xe0,0xF0,0x53,0} }, { {0xe0,0x5C,0},{0xe0,0xF0,0x5C,0} }, { { 0},{ 0} }, { {0xe0,0x62,0},{0xe0,0xF0,0x62,0} }, /*174*/ + { {0xe0,0x63,0},{0xe0,0xF0,0x63,0} }, { {0xe0,0x64,0},{0xe0,0xF0,0x64,0} }, { {0xe0,0x65,0},{0xe0,0xF0,0x65,0} }, { {0xe0,0x67,0},{0xe0,0xF0,0x67,0} }, /*178*/ + { {0xe0,0x68,0},{0xe0,0xF0,0x68,0} }, { {0xe0,0x6A,0},{0xe0,0xF0,0x6A,0} }, { {0xe0,0x6D,0},{0xe0,0xF0,0x6D,0} }, { {0xe0,0x6E,0},{0xe0,0xF0,0x6E,0} }, /*17c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ - { { -1},{ -1} }, { {0xe0,0xe1,-1},{0xe0,0xF0,0xE1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{0xe0,0xF0,0xEE,-1} }, { { -1},{ -1} }, /*1ec*/ - { { -1},{ -1} }, { {0xe0,0xf1,-1},{0xe0,0xF0,0xF1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ - { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ - { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{0xe0,0xF0,0xFE,-1} }, { {0xe0,0xff,-1},{0xe0,0xF0,0xFF,-1} } /*1fc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*180*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*184*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*188*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*18c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*190*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*194*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*198*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*19c*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1a8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1ac*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1c8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1cc*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1d8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1dc*/ + { { 0},{ 0} }, { {0xe0,0xe1,0},{0xe0,0xF0,0xE1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1e8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xee,0},{0xe0,0xF0,0xEE,0} }, { { 0},{ 0} }, /*1ec*/ + { { 0},{ 0} }, { {0xe0,0xf1,0},{0xe0,0xF0,0xF1,0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f0*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f4*/ + { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, { { 0},{ 0} }, /*1f8*/ + { { 0},{ 0} }, { { 0},{ 0} }, { {0xe0,0xfe,0},{0xe0,0xF0,0xFE,0} }, { {0xe0,0xff,0},{0xe0,0xF0,0xFF,0} } /*1fc*/ }; @@ -599,120 +587,118 @@ kbd_log(const char *fmt, ...) #define kbd_log(fmt, ...) #endif + static void -kbd_setmap(atkbd_t *kbd) +set_scancode_map(atkbd_t *dev) { switch (keyboard_mode & 3) { -#if 0 +#ifdef USE_SET1 case 1: default: keyboard_set_table(scancode_set1); break; - - case 2: - keyboard_set_table(scancode_set2); - break; #else - case 2: default: +#endif + case 2: keyboard_set_table(scancode_set2); break; -#endif + case 3: keyboard_set_table(scancode_set3); break; } if (keyboard_mode & 0x20) +#ifdef USE_SET1 + keyboard_set_table(scancode_set1); +#else keyboard_set_table(scancode_set2); +#endif } static void kbd_poll(void *priv) { - atkbd_t *kbd = (atkbd_t *)priv; + atkbd_t *dev = (atkbd_t *)priv; - keyboard_delay += (1000LL * TIMER_USEC); + timer_advance_u64(&dev->send_delay_timer, (1000 * TIMER_USEC)); - if ((kbd->out_new != -1) && !kbd->last_irq) { - kbd->wantirq = 0; - if (kbd->out_new & 0x100) { -#ifdef ENABLE_KEYBOARD_LOG + if ((dev->out_new != -1) && !dev->last_irq) { + dev->wantirq = 0; + if (dev->out_new & 0x100) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: want mouse data\n"); #endif - if (kbd->mem[0] & 0x02) + if (dev->mem[0] & 0x02) picint(0x1000); - kbd->out = kbd->out_new & 0xff; - kbd->out_new = -1; - kbd->status |= STAT_OFULL; - kbd->status &= ~STAT_IFULL; - kbd->status |= STAT_MFULL; - kbd->last_irq = 0x1000; + dev->out = dev->out_new & 0xff; + dev->out_new = -1; + dev->status |= STAT_OFULL; + dev->status &= ~STAT_IFULL; + dev->status |= STAT_MFULL; + dev->last_irq = 0x1000; } else { -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: want keyboard data\n"); #endif - if (kbd->mem[0] & 0x01) + if (dev->mem[0] & 0x01) picint(2); - kbd->out = kbd->out_new & 0xff; - kbd->out_new = -1; - kbd->status |= STAT_OFULL; - kbd->status &= ~STAT_IFULL; - kbd->status &= ~STAT_MFULL; - kbd->last_irq = 2; + dev->out = dev->out_new & 0xff; + dev->out_new = -1; + dev->status |= STAT_OFULL; + dev->status &= ~STAT_IFULL; + dev->status &= ~STAT_MFULL; + dev->last_irq = 2; } } - if (kbd->out_new == -1 && !(kbd->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { - kbd->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; + if (dev->out_new == -1 && !(dev->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { + dev->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; - } else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1 && kbd->out_delayed != -1) { - kbd->out_new = kbd->out_delayed; - kbd->out_delayed = -1; - } else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1 && !(kbd->mem[0] & 0x10) && kbd->out_delayed != -1) { - kbd->out_new = kbd->out_delayed; - kbd->out_delayed = -1; - } else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1/* && !(kbd->mem[0] & 0x20)*/ && + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && dev->out_delayed != -1) { + dev->out_new = dev->out_delayed; + dev->out_delayed = -1; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1 && !(dev->mem[0] & 0x10) && dev->out_delayed != -1) { + dev->out_new = dev->out_delayed; + dev->out_delayed = -1; + } else if (!(dev->status & STAT_OFULL) && dev->out_new == -1/* && !(dev->mem[0] & 0x20)*/ && (mouse_queue_start != mouse_queue_end)) { - kbd->out_new = mouse_queue[mouse_queue_start] | 0x100; + dev->out_new = mouse_queue[mouse_queue_start] | 0x100; mouse_queue_start = (mouse_queue_start + 1) & 0xf; - } else if (!(kbd->status&STAT_OFULL) && kbd->out_new == -1 && - !(kbd->mem[0]&0x10) && (key_queue_start != key_queue_end)) { - kbd->out_new = key_queue[key_queue_start]; + } else if (!(dev->status&STAT_OFULL) && dev->out_new == -1 && + !(dev->mem[0]&0x10) && (key_queue_start != key_queue_end)) { + dev->out_new = key_queue[key_queue_start]; key_queue_start = (key_queue_start + 1) & 0xf; } } static void -kbd_adddata(uint8_t val) +add_data(atkbd_t *dev, uint8_t val) { key_ctrl_queue[key_ctrl_queue_end] = val; key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; - if (!(CurrentKbd->out_new & 0x300)) { - CurrentKbd->out_delayed = CurrentKbd->out_new; - CurrentKbd->out_new = -1; + if (! (dev->out_new & 0x300)) { + dev->out_delayed = dev->out_new; + dev->out_new = -1; } } static void -kbd_adddata_vals(uint8_t *val, uint8_t len) +add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) { - int xt_mode = (keyboard_mode & 0x20) && ((CurrentKbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1); + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); int translate = (keyboard_mode & 0x40); int i; uint8_t or = 0; uint8_t send; -#if 0 - translate = translate || (keyboard_mode & 0x40) && !xt_mode; -#else translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((CurrentKbd->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); -#endif + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); for (i = 0; i < len; i++) { if (translate) { @@ -725,16 +711,17 @@ kbd_adddata_vals(uint8_t *val, uint8_t len) or = 0; } else send = val[i]; -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("%02X", send); #endif - kbd_adddata(send); -#ifdef ENABLE_KEYBOARD_LOG + key_queue[key_queue_end] = send; + key_queue_end = (key_queue_end + 1) & 0xf; +#ifdef ENABLE_KEYBOARD_AT_LOG if (i < (len - 1)) kbd_log(" "); #endif } -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG if (translate) { kbd_log(" original: ("); for (i = 0; i < len; i++) { @@ -749,26 +736,23 @@ kbd_adddata_vals(uint8_t *val, uint8_t len) static void -kbd_adddata_keyboard(uint16_t val) +add_data_kbd(uint16_t val) { - int xt_mode = (keyboard_mode & 0x20) && ((CurrentKbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1); + atkbd_t *dev = SavedKbd; + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); int translate = (keyboard_mode & 0x40); uint8_t fake_shift[4]; uint8_t num_lock = 0, shift_states = 0; -#if 0 - translate = translate || (keyboard_mode & 0x40) && !xt_mode; -#else translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((CurrentKbd->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); -#endif + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); keyboard_get_states(NULL, &num_lock, NULL); shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; /* Allow for scan code translation. */ if (translate && (val == 0xf0)) { -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: translate is on, F0 prefix detected\n"); #endif sc_or = 0x80; @@ -777,7 +761,7 @@ kbd_adddata_keyboard(uint16_t val) /* Skip break code if translated make code has bit 7 set. */ if (translate && (sc_or == 0x80) && (val & 0x80)) { -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); #endif sc_or = 0; @@ -785,37 +769,37 @@ kbd_adddata_keyboard(uint16_t val) } /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ - if (CurrentKbd && ((CurrentKbd->flags & KBC_VEN_MASK) == KBC_VEN_TOSHIBA) && (keyboard_recv(0xb8) || keyboard_recv(0x9d))) { - switch (val) { - case 0x4f: t3100e_notify_set(0x01); break; /* End */ - case 0x50: t3100e_notify_set(0x02); break; /* Down */ - case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ - case 0x52: t3100e_notify_set(0x04); break; /* Ins */ - case 0x53: t3100e_notify_set(0x05); break; /* Del */ - case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ - case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ - case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ - case 0x47: t3100e_notify_set(0x09); break; /* Home */ - case 0x48: t3100e_notify_set(0x0A); break; /* Up */ - case 0x49: t3100e_notify_set(0x0B); break; /* PgUp */ - case 0x4A: t3100e_notify_set(0x0C); break; /* Keypad -*/ - case 0x4B: t3100e_notify_set(0x0D); break; /* Left */ - case 0x4C: t3100e_notify_set(0x0E); break; /* KP 5 */ - case 0x4D: t3100e_notify_set(0x0F); break; /* Right */ - } + if ((dev != NULL) && + ((dev->flags & KBC_VEN_MASK) == KBC_VEN_TOSHIBA) && + (keyboard_recv(0xb8) || keyboard_recv(0x9d))) switch (val) { + case 0x4f: t3100e_notify_set(0x01); break; /* End */ + case 0x50: t3100e_notify_set(0x02); break; /* Down */ + case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ + case 0x52: t3100e_notify_set(0x04); break; /* Ins */ + case 0x53: t3100e_notify_set(0x05); break; /* Del */ + case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ + case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ + case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ + case 0x47: t3100e_notify_set(0x09); break; /* Home */ + case 0x48: t3100e_notify_set(0x0a); break; /* Up */ + case 0x49: t3100e_notify_set(0x0b); break; /* PgUp */ + case 0x4A: t3100e_notify_set(0x0c); break; /* Keypad -*/ + case 0x4B: t3100e_notify_set(0x0d); break; /* Left */ + case 0x4C: t3100e_notify_set(0x0e); break; /* KP 5 */ + case 0x4D: t3100e_notify_set(0x0f); break; /* Right */ } -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); #endif switch(val) { case FAKE_LSHIFT_ON: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("fake left shift on, scan code: "); #endif if (num_lock) { if (shift_states) { -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (one or both shifts on)\n"); #endif break; @@ -824,14 +808,16 @@ kbd_adddata_keyboard(uint16_t val) switch(keyboard_mode & 0x02) { case 1: fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + case 2: fake_shift[0] = 0xe0; fake_shift[1] = 0x12; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + default: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); #endif break; @@ -843,14 +829,16 @@ kbd_adddata_keyboard(uint16_t val) switch(keyboard_mode & 0x02) { case 1: fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + case 2: fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; - kbd_adddata_vals(fake_shift, 3); + add_data_vals(dev, fake_shift, 3); break; + default: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); #endif break; @@ -861,32 +849,35 @@ kbd_adddata_keyboard(uint16_t val) switch(keyboard_mode & 0x02) { case 1: fake_shift[0] = 0xe0; fake_shift[1] = 0xb6; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + case 2: fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x59; - kbd_adddata_vals(fake_shift, 3); + add_data_vals(dev, fake_shift, 3); break; + default: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); #endif break; } } -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG if (!shift_states) kbd_log("N/A (both shifts off)\n"); #endif } break; + case FAKE_LSHIFT_OFF: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("fake left shift on, scan code: "); #endif if (num_lock) { if (shift_states) { -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (one or both shifts on)\n"); #endif break; @@ -895,14 +886,16 @@ kbd_adddata_keyboard(uint16_t val) switch(keyboard_mode & 0x02) { case 1: fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + case 2: fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; - kbd_adddata_vals(fake_shift, 3); + add_data_vals(dev, fake_shift, 3); break; + default: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); #endif break; @@ -914,14 +907,16 @@ kbd_adddata_keyboard(uint16_t val) switch(keyboard_mode & 0x02) { case 1: fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + case 2: fake_shift[0] = 0xe0; fake_shift[1] = 0x12; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + default: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); #endif break; @@ -932,27 +927,30 @@ kbd_adddata_keyboard(uint16_t val) switch(keyboard_mode & 0x02) { case 1: fake_shift[0] = 0xe0; fake_shift[1] = 0x36; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + case 2: fake_shift[0] = 0xe0; fake_shift[1] = 0x59; - kbd_adddata_vals(fake_shift, 2); + add_data_vals(dev, fake_shift, 2); break; + default: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("N/A (scan code set %i)\n", keyboard_mode & 0x02); #endif break; } } -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG if (!shift_states) kbd_log("N/A (both shifts off)\n"); #endif } break; + default: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("scan code: "); if (translate) { kbd_log("%02X (original: ", (nont_to_t[val] | sc_or)); @@ -968,60 +966,62 @@ kbd_adddata_keyboard(uint16_t val) break; } - if (sc_or == 0x80) sc_or = 0; + if (sc_or == 0x80) + sc_or = 0; } static void -kbd_output_write(atkbd_t *kbd, uint8_t val) +write_output(atkbd_t *dev, uint8_t val) { -#ifdef ENABLE_KEYBOARD_LOG - kbd_log("ATkbd: write output port: %02X (old: %02X)\n", val, kbd->output_port); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write output port: %02X (old: %02X)\n", val, dev->output_port); #endif - if ((kbd->output_port ^ val) & 0x20) { /*IRQ 12*/ + + if ((dev->output_port ^ val) & 0x20) { /*IRQ 12*/ if (val & 0x20) picint(1 << 12); else picintc(1 << 12); } - if ((kbd->output_port ^ val) & 0x10) { /*IRQ 1*/ + if ((dev->output_port ^ val) & 0x10) { /*IRQ 1*/ if (val & 0x10) picint(1 << 1); else picintc(1 << 1); } - if ((kbd->output_port ^ val) & 0x02) { /*A20 enable change*/ + if ((dev->output_port ^ val) & 0x02) { /*A20 enable change*/ mem_a20_key = val & 0x02; mem_a20_recalc(); flushmmucache(); } - if ((kbd->output_port ^ val) & 0x01) { /*Reset*/ + if ((dev->output_port ^ val) & 0x01) { /*Reset*/ if (! (val & 0x01)) { /* Pin 0 selected. */ softresetx86(); /*Pulse reset!*/ cpu_set_edx(); } } - kbd->output_port = val; + dev->output_port = val; } static void -kbd_cmd_write(atkbd_t *kbd, uint8_t val) +write_cmd(atkbd_t *dev, uint8_t val) { -#ifdef ENABLE_KEYBOARD_LOG - kbd_log("ATkbd: write command byte: %02X (old: %02X)\n", val, kbd->mem[0]); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write command byte: %02X (old: %02X)\n", val, dev->mem[0]); #endif - if ((val & 1) && (kbd->status & STAT_OFULL)) - kbd->wantirq = 1; - if (!(val & 1) && kbd->wantirq) - kbd->wantirq = 0; + if ((val & 1) && (dev->status & STAT_OFULL)) + dev->wantirq = 1; + if (!(val & 1) && dev->wantirq) + dev->wantirq = 0; /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ - if ((kbd->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { + if ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { val &= ~CCB_TRANSLATE; - kbd->mem[0] &= ~CCB_TRANSLATE; + dev->mem[0] &= ~CCB_TRANSLATE; } /* Scan code translate ON/OFF. */ @@ -1029,183 +1029,194 @@ kbd_cmd_write(atkbd_t *kbd, uint8_t val) keyboard_mode |= (val & MODE_MASK); keyboard_scan = !(val & 0x10); -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: keyboard is now %s\n", keyboard_scan ? "enabled" : "disabled"); kbd_log("ATkbd: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); #endif /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. */ - if (((kbd->flags & KBC_VEN_MASK) == KBC_VEN_AMI) || - ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) { + if (((dev->flags & KBC_VEN_MASK) == KBC_VEN_AMI) || + ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { keyboard_mode &= ~CCB_PCMODE; mouse_scan = !(val & 0x20); -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: mouse is now %s\n", mouse_scan ? "enabled" : "disabled"); kbd_log("ATkbd: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); #endif } - kbd_log("Command byte now: %02X (%02X)\n", kbd->mem[0], val); + kbd_log("Command byte now: %02X (%02X)\n", dev->mem[0], val); } static void -kbd_output_pulse(atkbd_t *kbd, uint8_t mask) +pulse_output(atkbd_t *dev, uint8_t mask) { - if (mask != 0xF) { - kbd->old_output_port = kbd->output_port & ~(0xF0 | mask); - kbd_output_write(kbd, kbd->output_port & (0xF0 | mask)); - kbd->pulse_cb = 6LL * TIMER_USEC; + if (mask != 0x0f) { + dev->old_output_port = dev->output_port & ~(0xf0 | mask); + write_output(dev, dev->output_port & (0xf0 | mask)); + timer_set_delay_u64(&dev->pulse_cb, 6ULL * TIMER_USEC); } } static void -kbd_pulse_poll(void *p) +pulse_poll(void *priv) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; - kbd_output_write(kbd, kbd->output_port | kbd->old_output_port); - kbd->pulse_cb = 0LL; + write_output(dev, dev->output_port | dev->old_output_port); } static void -kbd_keyboard_set(atkbd_t *kbd, uint8_t enable) +set_enable_kbd(atkbd_t *dev, uint8_t enable) { - kbd->mem[0] &= 0xef; - kbd->mem[0] |= (enable ? 0x00 : 0x10); - - if (enable) - kbd->status |= STAT_LOCK; - else - kbd->status &= ~STAT_LOCK; + dev->mem[0] &= 0xef; + dev->mem[0] |= (enable ? 0x00 : 0x10); keyboard_scan = enable; } static void -kbd_mouse_set(atkbd_t *kbd, uint8_t enable) +set_enable_mouse(atkbd_t *dev, uint8_t enable) { - kbd->mem[0] &= 0xdf; - kbd->mem[0] |= (enable ? 0x00 : 0x20); + dev->mem[0] &= 0xdf; + dev->mem[0] |= (enable ? 0x00 : 0x20); + mouse_scan = enable; } static uint8_t -kbd_write64_generic(void *p, uint8_t val) +write64_generic(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *)p; + atkbd_t *dev = (atkbd_t *)priv; + uint8_t current_drive; switch (val) { - case 0xa4: /*Check if password installed*/ - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + case 0xa4: /* check if password installed */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: check if password installed\n"); #endif - kbd_adddata(0xf1); + add_data(dev, 0xf1); return 0; } -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG else kbd_log("ATkbd: bad command A4\n"); #endif break; - case 0xa7: /*Disable mouse port*/ - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + case 0xa7: /* disable mouse port */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: disable mouse port\n"); #endif - kbd_mouse_set(kbd, 0); + set_enable_mouse(dev, 0); return 0; } -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG else kbd_log("ATkbd: bad command A7\n"); #endif break; case 0xa8: /*Enable mouse port*/ - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: enable mouse port\n"); #endif - kbd_mouse_set(kbd, 1); + set_enable_mouse(dev, 1); return 0; } -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG else kbd_log("ATkbd: bad command A8\n"); #endif break; case 0xa9: /*Test mouse port*/ -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: test mouse port\n"); #endif - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { if (mouse_write) - kbd_adddata(0x00); /*no error*/ + add_data(dev, 0x00); /* no error */ else - kbd_adddata(0xff); /*no mouse*/ + add_data(dev, 0xff); /* no mouse */ return 0; } -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG else kbd_log("ATkbd: bad command A9\n"); #endif break; - case 0xaf: /*Read keyboard version*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xaf: /* read keyboard version */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: read keyboard version\n"); #endif - kbd_adddata(0x00); + add_data(dev, 0x00); return 0; - case 0xc0: /*Read input port*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xc0: /* read input port */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: read input port\n"); #endif - - kbd_adddata(kbd->input_port | 4 | fdc_ps1_525()); - kbd->input_port = ((kbd->input_port + 1) & 3) | (kbd->input_port & 0xfc) | fdc_ps1_525(); + if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_IBM_PS1) { + current_drive = fdc_get_current_drive(); + add_data(dev, dev->input_port | 4 | (fdd_is_525(current_drive) ? 0x40 : 0x00)); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc) | + (fdd_is_525(current_drive) ? 0x40 : 0x00); + } else { + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + add_data(dev, (dev->input_port | 4) & 0xef); + else + add_data(dev, dev->input_port | 4); + dev->input_port = ((dev->input_port + 1) & 3) | + (dev->input_port & 0xfc); + } return 0; - case 0xd3: /*Write mouse output buffer*/ - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + case 0xd3: /* write mouse output buffer */ + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: write mouse output buffer\n"); #endif - kbd->want60 = 1; + dev->want60 = 1; return 0; } break; - case 0xd4: /*Write to mouse*/ - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + case 0xd4: /* write to mouse */ +#if 0 + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { +#endif +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: write to mouse\n"); #endif - kbd->want60 = 1; + dev->want60 = 1; return 0; +#if 0 } break; +#endif case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: -#ifdef ENABLE_KEYBOARD_LOG - // kbd_log("ATkbd: pulse %01X\n", val & 0x0f); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: pulse %01X\n", val & 0x0f); #endif - kbd_output_pulse(kbd, val & 0x0f); + pulse_output(dev, val & 0x0f); return 0; } @@ -1214,11 +1225,45 @@ kbd_write64_generic(void *p, uint8_t val) static uint8_t -kbd_write60_ami(void *p, uint8_t val) +write60_acer(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; +#if 0 + atkbd_t *dev = (atkbd_t *)priv; - switch(kbd->command) { + switch(dev->command) { + case 0xc0: /* sent by Acer V30 BIOS */ + return 0; + } +#endif + + return 1; +} + + +static uint8_t +write64_acer(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *)priv; + + kbd_log("ACER: write64(%02x, %02x)\n", dev->command, val); + +#if 0 + switch (val) { + case 0xc0: /* sent by Acer V30 BIOS */ + return 0; + } +#endif + + return write64_generic(dev, val); +} + + +static uint8_t +write60_ami(void *priv, uint8_t val) +{ + atkbd_t *dev = (atkbd_t *)priv; + + switch(dev->command) { /* 0x40 - 0x5F are aliases for 0x60-0x7F */ case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: @@ -1228,30 +1273,28 @@ kbd_write60_ami(void *p, uint8_t val) case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: -#ifdef ENABLE_KEYBOARD_LOG - kbd_log("ATkbd: AMI - alias write to %08X\n", kbd->command); -#endif - kbd->mem[kbd->command & 0x1f] = val; - if (kbd->command == 0x60) - kbd_cmd_write(kbd, val); + kbd_log("ATkbd: AMI - alias write to %08X\n", dev->command); + dev->mem[dev->command & 0x1f] = val; + if (dev->command == 0x60) + write_cmd(dev, val); return 0; - case 0xaf: /*AMI - set extended controller RAM*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xaf: /* set extended controller RAM */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - set extended controller RAM\n"); #endif - if (kbd->secr_phase == 1) { - kbd->mem_addr = val; - kbd->want60 = 1; - kbd->secr_phase = 2; - } else if (kbd->secr_phase == 2) { - kbd->mem[kbd->mem_addr] = val; - kbd->secr_phase = 0; + if (dev->secr_phase == 1) { + dev->mem_addr = val; + dev->want60 = 1; + dev->secr_phase = 2; + } else if (dev->secr_phase == 2) { + dev->mem[dev->mem_addr] = val; + dev->secr_phase = 0; } return 0; - case 0xcb: /*AMI - set keyboard mode*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xcb: /* set keyboard mode */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - set keyboard mode\n"); #endif return 0; @@ -1262,9 +1305,9 @@ kbd_write60_ami(void *p, uint8_t val) static uint8_t -kbd_write64_ami(void *p, uint8_t val) +write64_ami(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; switch (val) { case 0x00: case 0x01: case 0x02: case 0x03: @@ -1275,10 +1318,8 @@ kbd_write64_ami(void *p, uint8_t val) case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: -#ifdef ENABLE_KEYBOARD_LOG kbd_log("ATkbd: AMI - alias read from %08X\n", val); -#endif - kbd_adddata(kbd->mem[val]); + add_data(dev, dev->mem[val]); return 0; case 0x40: case 0x41: case 0x42: case 0x43: @@ -1289,204 +1330,206 @@ kbd_write64_ami(void *p, uint8_t val) case 0x54: case 0x55: case 0x56: case 0x57: case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f: -#ifdef ENABLE_KEYBOARD_LOG - kbd_log("ATkbd: AMI - alias write to %08X\n", kbd->command); -#endif - kbd->want60 = 1; + kbd_log("ATkbd: AMI - alias write to %08X\n", dev->command); + dev->want60 = 1; return 0; - case 0xa1: /*AMI - get controller version*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xa1: /* get controller version */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - get controller version\n"); #endif return 0; - case 0xa2: /*AMI - reset keyboard controller lines P22 and P23 low*/ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + case 0xa2: /* clear keyboard controller lines P22/P23 */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - clear KBC lines P22 and P23\n"); #endif - kbd_output_write(kbd, kbd->output_port & 0xf3); - kbd_adddata(0x00); + write_output(dev, dev->output_port & 0xf3); + add_data(dev, 0x00); return 0; } break; - case 0xa3: /*AMI - set keyboard controller lines P22 and P23 high*/ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + case 0xa3: /* set keyboard controller lines P22/P23 */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - set KBC lines P22 and P23\n"); #endif - kbd_output_write(kbd, kbd->output_port | 0x0c); - kbd_adddata(0x00); + write_output(dev, dev->output_port | 0x0c); + add_data(dev, 0x00); return 0; } break; - case 0xa4: /* AMI - write clock = low */ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + case 0xa4: /* write clock = low */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - write clock = low\n"); #endif - kbd->ami_stat &= 0xfe; + dev->ami_stat &= 0xfe; return 0; } break; - case 0xa5: /* AMI - write clock = high */ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + case 0xa5: /* write clock = high */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - write clock = high\n"); #endif - kbd->ami_stat |= 0x01; + dev->ami_stat |= 0x01; return 0; } break; - case 0xa6: /* AMI - read clock */ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + case 0xa6: /* read clock */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - read clock\n"); #endif - kbd_adddata(!!(kbd->ami_stat & 1)); + add_data(dev, !!(dev->ami_stat & 1)); return 0; } break; - case 0xa7: /* AMI - write cache bad */ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + case 0xa7: /* write cache bad */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - write cache bad\n"); #endif - kbd->ami_stat &= 0xfd; + dev->ami_stat &= 0xfd; return 0; } break; - case 0xa8: /* AMI - write cache good */ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + case 0xa8: /* write cache good */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - write cache good\n"); #endif - kbd->ami_stat |= 0x02; + dev->ami_stat |= 0x02; return 0; } break; - case 0xa9: /* AMI - read cache */ - if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { -#ifdef ENABLE_KEYBOARD_LOG + case 0xa9: /* read cache */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - read cache\n"); #endif - kbd_adddata(!!(kbd->ami_stat & 2)); + add_data(dev, !!(dev->ami_stat & 2)); return 0; } break; - case 0xaf: /*Set extended controller RAM*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xaf: /* set extended controller RAM */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set extended controller RAM\n"); #endif - kbd->want60 = 1; - kbd->secr_phase = 1; + dev->want60 = 1; + dev->secr_phase = 1; return 0; case 0xb0: case 0xb1: case 0xb2: case 0xb3: - /*Set keyboard controller line P10-P13 (input port bits 0-3) low*/ + /* set KBC lines P10-P13 (input port bits 0-3) low */ if (!PCI || (val > 0xb1)) - kbd->input_port &= ~(1 << (val & 0x03)); - kbd_adddata(0x00); + dev->input_port &= ~(1 << (val & 0x03)); + add_data(dev, 0x00); return 0; case 0xb4: case 0xb5: - /*Set keyboard controller line P22-P23 (output port bits 2-3) low*/ - if (!PCI) - kbd_output_write(kbd, kbd->output_port & ~(4 << (val & 0x01))); - kbd_adddata(0x00); + /* set KBC lines P22-P23 (output port bits 2-3) low */ + if (! PCI) + write_output(dev, dev->output_port & ~(4 << (val & 0x01))); + add_data(dev, 0x00); return 0; case 0xb8: case 0xb9: case 0xba: case 0xbb: - /*Set keyboard controller line P10-P13 (input port bits 0-3) high*/ + /* set KBC lines P10-P13 (input port bits 0-3) high */ if (!PCI || (val > 0xb9)) { - kbd->input_port |= (1 << (val & 0x03)); - kbd_adddata(0x00); + dev->input_port |= (1 << (val & 0x03)); + add_data(dev, 0x00); } return 0; case 0xbc: case 0xbd: - /*Set keyboard controller line P22-P23 (output port bits 2-3) high*/ - if (!PCI) - kbd_output_write(kbd, kbd->output_port | (4 << (val & 0x01))); - kbd_adddata(0x00); + /* set KBC lines P22-P23 (output port bits 2-3) high */ + if (! PCI) + write_output(dev, dev->output_port | (4 << (val & 0x01))); + add_data(dev, 0x00); return 0; - case 0xc8: /*AMI - unblock keyboard controller lines P22 and P23 - (allow command D1 to change bits 2 and 3 of the output - port)*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xc8: + /* + * unblock KBC lines P22/P23 + * (allow command D1 to change bits 2/3 of the output port) + */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - unblock KBC lines P22 and P23\n"); #endif - kbd->output_locked = 1; + dev->output_locked = 1; return 0; - case 0xc9: /*AMI - block keyboard controller lines P22 and P23 - (prevent command D1 from changing bits 2 and 3 of the - output port)*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xc9: + /* + * block KBC lines P22/P23 + * (disallow command D1 from changing bits 2/3 of the port) + */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - block KBC lines P22 and P23\n"); #endif - kbd->output_locked = 1; + dev->output_locked = 1; return 0; - case 0xca: /*AMI - read keyboard mode*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xca: /* read keyboard mode */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - read keyboard mode\n"); #endif - kbd_adddata(0x00); /*ISA mode*/ + add_data(dev, 0x00); /*ISA mode*/ return 0; - case 0xcb: /*AMI - set keyboard mode*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xcb: /* set keyboard mode */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: AMI - set keyboard mode\n"); #endif - kbd->want60 = 1; + dev->want60 = 1; return 0; - case 0xef: /*??? - sent by AMI486*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xef: /* ??? - sent by AMI486 */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: ??? - sent by AMI486\n"); #endif return 0; } - return kbd_write64_generic(kbd, val); + return write64_generic(dev, val); } static uint8_t -kbd_write64_ibm_mca(void *p, uint8_t val) +write64_ibm_mca(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; switch (val) { case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: copy bits 0 to 3 of input port to status bits 4 to 7\n"); #endif - kbd->status &= 0xf; - kbd->status |= ((((kbd->input_port & 0xfc) | 0x84 | fdc_ps1_525()) & 0xf) << 4); + dev->status &= 0x0f; + dev->status |= ((((dev->input_port & 0xfc) | 0x84) & 0x0f) << 4); return 0; case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: copy bits 4 to 7 of input port to status bits 4 to 7\n"); #endif - kbd->status &= 0xf; - kbd->status |= (((kbd->input_port & 0xfc) | 0x84 | fdc_ps1_525()) & 0xf0); + dev->status &= 0x0f; + dev->status |= (((dev->input_port & 0xfc) | 0x84) & 0xf0); return 0; case 0xaf: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: bad KBC command AF\n"); #endif return 1; @@ -1495,25 +1538,23 @@ kbd_write64_ibm_mca(void *p, uint8_t val) case 0xf4: case 0xf5: case 0xf6: case 0xf7: case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff: -#ifdef ENABLE_KEYBOARD_LOG kbd_log("ATkbd: pulse: %01X\n", (val & 0x03) | 0x0c); -#endif - kbd_output_pulse(kbd, (val & 0x03) | 0x0c); + pulse_output(dev, (val & 0x03) | 0x0c); return 0; } - return kbd_write64_generic(kbd, val); + return write64_generic(dev, val); } static uint8_t -kbd_write60_quadtel(void *p, uint8_t val) +write60_quadtel(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; - switch(kbd->command) { + switch(dev->command) { case 0xcf: /*??? - sent by MegaPC BIOS*/ -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: ??? - sent by MegaPC BIOS\n"); #endif return 0; @@ -1524,35 +1565,35 @@ kbd_write60_quadtel(void *p, uint8_t val) static uint8_t -kbd_write64_quadtel(void *p, uint8_t val) +write64_quadtel(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; switch (val) { case 0xaf: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: bad KBC command AF\n"); #endif return 1; case 0xcf: /*??? - sent by MegaPC BIOS*/ -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: ??? - sent by MegaPC BIOS\n"); #endif - kbd->want60 = 1; + dev->want60 = 1; return 0; } - return kbd_write64_generic(kbd, val); + return write64_generic(dev, val); } static uint8_t -kbd_write60_toshiba(void *p, uint8_t val) +write60_toshiba(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; - switch(kbd->command) { + switch(dev->command) { case 0xb6: /* T3100e - set color/mono switch */ t3100e_mono_set(val); return 0; @@ -1563,13 +1604,13 @@ kbd_write60_toshiba(void *p, uint8_t val) static uint8_t -kbd_write64_toshiba(void *p, uint8_t val) +write64_toshiba(void *priv, uint8_t val) { - atkbd_t *kbd = (atkbd_t *) p; + atkbd_t *dev = (atkbd_t *)priv; switch (val) { case 0xaf: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: bad KBC command AF\n"); #endif return 1; @@ -1591,15 +1632,15 @@ kbd_write64_toshiba(void *p, uint8_t val) return 0; case 0xb4: /* T3100e: Get configuration / status */ - kbd_adddata(t3100e_config_get()); + add_data(dev, t3100e_config_get()); return 0; case 0xb5: /* T3100e: Get colour / mono byte */ - kbd_adddata(t3100e_mono_get()); + add_data(dev, t3100e_mono_get()); return 0; case 0xb6: /* T3100e: Set colour / mono byte */ - kbd->want60 = 1; + dev->want60 = 1; return 0; case 0xb7: /* T3100e: Emulate PS/2 keyboard - not implemented */ @@ -1612,8 +1653,8 @@ kbd_write64_toshiba(void *p, uint8_t val) using 'Fn'. */ if (keyboard_recv(0xb8) || /* Right Alt */ keyboard_recv(0x9d)) /* Right Ctrl */ - kbd_adddata(0x04); - else kbd_adddata(0x00); + add_data(dev, 0x04); + else add_data(dev, 0x00); return 0; case 0xbc: /* T3100e: Reset Fn+Key notification */ @@ -1621,42 +1662,44 @@ kbd_write64_toshiba(void *p, uint8_t val) return 0; case 0xc0: /*Read input port*/ -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: read input port\n"); #endif /* The T3100e returns all bits set except bit 6 which * is set by t3100e_mono_set() */ - kbd->input_port = (t3100e_mono_get() & 1) ? 0xff : 0xbf; - kbd_adddata(kbd->input_port); + dev->input_port = (t3100e_mono_get() & 1) ? 0xff : 0xbf; + add_data(dev, dev->input_port); return 0; } - return kbd_write64_generic(kbd, val); + return write64_generic(dev, val); } static void kbd_write(uint16_t port, uint8_t val, void *priv) { - atkbd_t *kbd = (atkbd_t *)priv; + atkbd_t *dev = (atkbd_t *)priv; int i = 0; int bad = 1; uint8_t mask; - if (((kbd->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) && (port == 0x63)) + if (((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) && (port == 0x63)) port = 0x61; -#ifdef _DEBUG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: write(%04X, %02X)\n", port, val); #endif + switch (port) { case 0x60: - if (kbd->want60) { - /*Write to controller*/ - kbd->want60 = 0; - switch (kbd->command) { + if (dev->want60) { + /* Write data to controller. */ + dev->want60 = 0; + + switch (dev->command) { case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: @@ -1665,277 +1708,299 @@ kbd_write(uint16_t port, uint8_t val, void *priv) case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: - kbd->mem[kbd->command & 0x1f] = val; - if (kbd->command == 0x60) - kbd_cmd_write(kbd, val); + dev->mem[dev->command & 0x1f] = val; + if (dev->command == 0x60) + write_cmd(dev, val); break; - case 0xd1: /*Write output port*/ -#ifdef ENABLE_KEYBOARD_LOG - // kbd_log("ATkbd: write output port\n"); + case 0xd1: /* write output port */ +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: write output port\n"); #endif - if (kbd->output_locked) { + if (dev->output_locked) { /*If keyboard controller lines P22-P23 are blocked, we force them to remain unchanged.*/ val &= ~0x0c; - val |= (kbd->output_port & 0x0c); + val |= (dev->output_port & 0x0c); } - kbd_output_write(kbd, val); + write_output(dev, val); break; - case 0xd2: /*Write to keyboard output buffer*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xd2: /* write to keyboard output buffer */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: write to keyboard output buffer\n"); #endif - kbd_adddata_keyboard(val); + add_data_kbd(val); break; - case 0xd3: /*Write to mouse output buffer*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xd3: /* write to mouse output buffer */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: write to mouse output buffer\n"); #endif - if (mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) keyboard_at_adddata_mouse(val); break; - case 0xd4: /*Write to mouse*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xd4: /* write to mouse */ kbd_log("ATkbd: write to mouse (%02X)\n", val); -#endif - kbd_mouse_set(kbd, 1); - if (mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + + if (val == 0xbb) + break; + + set_enable_mouse(dev, 1); + if (mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) mouse_write(val, mouse_p); - else if (!mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) { -#ifdef ENABLE_KEYBOARD_LOG - kbd_log("ATkbd: adding 0xFF to queue\n"); -#endif + else if (!mouse_write && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && + ((dev->flags & KBC_VEN_MASK) == KBC_VEN_AMI)) keyboard_at_adddata_mouse(0xff); - } break; default: - /* Run the vendor-specific command handler, if present, - otherwise (or if the former returns 1), assume bad command. */ - if (kbd->write60_ven) - bad = kbd->write60_ven(kbd, val); + /* + * Run the vendor-specific handler + * if we have one. Otherwise, or if + * it returns an error, log a bad + * controller command. + */ + if (dev->write60_ven) + bad = dev->write60_ven(dev, val); -#ifdef ENABLE_KEYBOARD_LOG - if (bad) - kbd_log("ATkbd: bad keyboard controller 0060 write %02X command %02X\n", val, kbd->command); -#else - (void)bad; -#endif + if (bad) { + kbd_log("ATkbd: bad controller command %02x data %02x\n", dev->command, val); + add_data_kbd(0xfe); + } } } else { - /*Write to keyboard*/ - kbd->mem[0] &= ~0x10; - if (kbd->key_wantdata) { - kbd->key_wantdata = 0; - switch (kbd->key_command) { - case 0xed: /*Set/reset LEDs*/ - if (val & 0xf8) - goto do_command; /* Command ED does command if command is recognized. */ - kbd_adddata_keyboard(0xfa); + /* Write data to keyboard. */ + dev->mem[0] &= ~0x10; + + if (dev->key_wantdata) { + dev->key_wantdata = 0; + + /* + * Several system BIOSes and OS device drivers + * mess up with this, and repeat the command + * code many times. Fun! + */ + if (val == dev->key_command) { +#if 1 + /* Respond NAK and ignore it. */ + add_data_kbd(0xfe); + dev->key_command = 0x00; + break; +#else + goto do_command; +#endif + } + + switch (dev->key_command) { + case 0xed: /* set/reset LEDs */ + add_data_kbd(0xfa); + kbd_log("ATkbd: set LEDs [%02x]\n", val); break; - case 0xf0: /*Get/set scancode set*/ - kbd_adddata_keyboard(0xfa); + case 0xf0: /* get/set scancode set */ + add_data_kbd(0xfa); if (val == 0) { kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); - kbd_adddata_keyboard(keyboard_mode & 3); + add_data_kbd(keyboard_mode & 3); } else { if ((val <= 3) && (val != 1)) { - keyboard_mode &= 0xFC; + keyboard_mode &= 0xfc; keyboard_mode |= (val & 3); kbd_log("Scan code set now: %02X\n", val); } - kbd_setmap(kbd); + set_scancode_map(dev); } break; - case 0xf3: /*Set typematic rate/delay*/ - kbd_adddata_keyboard(0xfa); + case 0xf3: /* set typematic rate/delay */ + add_data_kbd(0xfa); break; default: -#ifdef ENABLE_KEYBOARD_LOG - kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, kbd->key_command); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, dev->key_command); #endif + add_data_kbd(0xfe); break; } /* Keyboard command is now done. */ - kbd->key_command = 0x00; + dev->key_command = 0x00; } else { +#if 0 do_command: +#endif /* No keyboard command in progress. */ - kbd->key_command = 0x00; + dev->key_command = 0x00; - kbd_keyboard_set(kbd, 1); + set_enable_kbd(dev, 1); switch (val) { case 0x00: -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: command 00\n"); #endif - kbd_adddata_keyboard(0xfa); + add_data_kbd(0xfa); break; case 0x05: /*??? - sent by NT 4.0*/ -#ifdef ENABLE_KEYBOARD_LOG - kbd_log("ATkbd: NT4.0 command FE\n"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("ATkbd: command 05 (NT 4.0)\n"); #endif - kbd_adddata_keyboard(0xfe); + add_data_kbd(0xfe); break; - case 0x71: /*These two commands are sent by Pentium-era AMI BIOS'es.*/ + /* Sent by Pentium-era AMI BIOS'es.*/ + case 0x71: case 0x82: -#ifdef ENABLE_KEYBOARD_LOG kbd_log("ATkbd: Pentium-era AMI BIOS command %02X\n", val); -#endif break; - case 0xed: /*Set/reset LEDs*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xed: /* set/reset LEDs */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set/reset leds\n"); #endif - kbd_adddata_keyboard(0xfa); + add_data_kbd(0xfa); - kbd->key_wantdata = 1; - kbd->key_command = val; + dev->key_wantdata = 1; break; - case 0xee: /*Diagnostic echo*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xee: /* diagnostic echo */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: ECHO\n"); #endif - kbd_adddata_keyboard(0xee); + add_data_kbd(0xee); break; - case 0xef: /*NOP (No OPeration). Reserved for future use.*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xef: /* NOP (reserved for future use) */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: NOP\n"); #endif break; - case 0xf0: /*Get/set scan code set*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xf0: /* get/set scan code set */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: scan code set\n"); #endif - kbd_adddata_keyboard(0xfa); - kbd->key_wantdata = 1; - kbd->key_command = val; + add_data_kbd(0xfa); + dev->key_wantdata = 1; break; - case 0xf2: /*Read ID*/ - /* Fixed as translation will be done in kbd_adddata_keyboard(). */ -#ifdef ENABLE_KEYBOARD_LOG + case 0xf2: /* read ID */ + /* Fixed as translation will be done in add_data_kbd(). */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: read keyboard id\n"); #endif - kbd_adddata_keyboard(0xfa); - kbd_adddata_keyboard(0xab); - kbd_adddata_keyboard(0x83); + add_data_kbd(0xfa); + add_data_kbd(0xab); + add_data_kbd(0x83); break; - case 0xf3: /*Set typematic rate/delay*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xf3: /* set typematic rate/delay */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set typematic rate/delay\n"); #endif - kbd_adddata_keyboard(0xfa); - kbd->key_wantdata = 1; - kbd->key_command = val; + add_data_kbd(0xfa); + dev->key_wantdata = 1; break; - case 0xf4: /*Enable keyboard*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xf4: /* enable keyboard */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: enable keyboard via keyboard\n"); #endif - kbd_adddata_keyboard(0xfa); + add_data_kbd(0xfa); keyboard_scan = 1; break; - case 0xf5: /*Disable keyboard*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xf5: /* disable keyboard */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: disable keyboard via keyboard\n"); #endif - kbd_adddata_keyboard(0xfa); keyboard_scan = 0; - /* Disabling the keyboard also resets it to the default values, so continue below. */ - // break; - case 0xf6: /*Set defaults*/ -#ifdef ENABLE_KEYBOARD_LOG + /* + * Disabling the keyboard also + * resets it to the default + * values. + */ + /*FALLTHROUGH*/ + + case 0xf6: /* set defaults */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set defaults\n"); #endif - kbd_adddata_keyboard(0xfa); + add_data_kbd(0xfa); keyboard_set3_all_break = 0; keyboard_set3_all_repeat = 0; memset(keyboard_set3_flags, 0, 512); - /* Q */ - keyboard_mode = (keyboard_mode & 0xFC) | 0x02; - kbd_setmap(kbd); + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); break; - case 0xf7: /*Set all keys to repeat*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xf7: /* set all keys to repeat */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set all keys to repeat\n"); #endif - kbd_adddata_keyboard(0xfa); + add_data_kbd(0xfa); keyboard_set3_all_break = 1; break; - case 0xf8: /*Set all keys to give make/break codes*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xf8: /* set all keys to give make/break codes */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set all keys to give make/break codes\n"); #endif - kbd_adddata_keyboard(0xfa); + add_data_kbd(0xfa); keyboard_set3_all_break = 1; break; - case 0xf9: /*Set all keys to give make codes only*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xf9: /* set all keys to give make codes only */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set all keys to give make codes only\n"); #endif - kbd_adddata_keyboard(0xfa); + add_data_kbd(0xfa); keyboard_set3_all_break = 0; break; - case 0xfa: /*Set all keys to repeat and give make/break codes*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xfa: /* set all keys to repeat and give make/break codes */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); #endif - kbd_adddata_keyboard(0xfa); + add_data_kbd(0xfa); keyboard_set3_all_repeat = 1; keyboard_set3_all_break = 1; break; - case 0xfe: /*Resend last scan code*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xfe: /* resend last scan code */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: reset last scan code\n"); #endif - kbd_adddata_keyboard(kbd->last_scan_code); + add_data_kbd(key_queue[key_queue_end]); break; - case 0xff: /*Reset*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xff: /* reset */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: kbd reset\n"); #endif key_queue_start = key_queue_end = 0; /*Clear key queue*/ - kbd_adddata_keyboard(0xfa); - kbd_adddata_keyboard(0xaa); + add_data_kbd(0xfa); + add_data_kbd(0xaa); + /* Set scan code set to 2. */ - /* Q */ - keyboard_mode = (keyboard_mode & 0xFC) | 0x02; - kbd_setmap(kbd); + keyboard_mode = (keyboard_mode & 0xfc) | 0x02; + set_scancode_map(dev); break; default: -#ifdef ENABLE_KEYBOARD_LOG kbd_log("ATkbd: bad keyboard command %02X\n", val); -#endif - kbd_adddata_keyboard(0xfe); + add_data_kbd(0xfe); } + + /* If command needs data, remember command. */ + if (dev->key_wantdata == 1) + dev->key_command = val; } } break; @@ -1943,9 +2008,6 @@ do_command: case 0x61: ppi.pb = val; - timer_process(); - timer_update_outstanding(); - speaker_update(); speaker_gated = val & 1; speaker_enable = val & 2; @@ -1953,37 +2015,20 @@ do_command: was_speaker_enable = 1; pit_set_gate(&pit, 2, val & 1); - if ((kbd->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) { - if (val & 0x04) - xi8088_turbo_set(1); - else - xi8088_turbo_set(0); - } + if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) +#ifdef USE_NEW_STUFF + dev->write_func(dev->func_priv, !!(val & 0x04)); +#else + xi8088_turbo_set(!!(val & 0x04)); +#endif break; case 0x64: - /* - * Try to recover from bad commands. - * - * If we get a command here, but seem to be still in - * keyboard-command data mode, abort that... - */ - if (kbd->key_wantdata || kbd->key_command) { - kbd_log("ATkbd: *** BUG ALERT *** aborting previous keyboard command 0x%02X (data %d)\n", kbd->key_command, kbd->key_wantdata); + /* Controller command. */ + dev->want60 = 0; - /* If they were waiting for data.. */ - kbd_adddata(0xfa); - - /* Abort the previous command. */ - kbd->key_command = 0x00; - kbd->key_wantdata = 0; - } - - kbd->want60 = 0; - kbd->command = val; - - /*New controller command*/ switch (val) { + /* Read data from KBC memory. */ case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: case 0x2a: case 0x2b: @@ -1992,9 +2037,10 @@ do_command: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f: - kbd_adddata(kbd->mem[val & 0x1f]); + add_data(dev, dev->mem[val & 0x1f]); break; + /* Write data to KBC memory. */ case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: @@ -2003,119 +2049,135 @@ do_command: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: - kbd->want60 = 1; + dev->want60 = 1; break; - case 0xaa: /*Self-test*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xaa: /* self-test */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: self-test\n"); #endif - if ((kbd->flags & KBC_VEN_MASK) == KBC_VEN_TOSHIBA) - kbd->status |= STAT_IFULL; - if (! kbd->initialized) { - kbd->initialized = 1; + if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_TOSHIBA) + dev->status |= STAT_IFULL; + if (! dev->initialized) { + dev->initialized = 1; key_ctrl_queue_start = key_ctrl_queue_end = 0; - kbd->status &= ~STAT_OFULL; + dev->status &= ~STAT_OFULL; } - kbd->status |= STAT_SYSFLAG; - kbd->mem[0] |= 0x04; - kbd_keyboard_set(kbd, 1); - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) - kbd_mouse_set(kbd, 1); - kbd_output_write(kbd, 0xcf); - kbd_adddata(0x55); + dev->status |= STAT_SYSFLAG; + dev->mem[0] |= 0x04; + keyboard_mode |= 0x04; + set_enable_kbd(dev, 1); + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) + set_enable_mouse(dev, 1); + write_output(dev, 0xcf); + add_data(dev, 0x55); break; - case 0xab: /*Interface test*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xab: /* interface test */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: interface test\n"); #endif - kbd_adddata(0x00); /*no error*/ + add_data(dev, 0x00); /*no error*/ break; - case 0xac: /*Diagnostic dump*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xac: /* diagnostic dump */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: diagnostic dump\n"); #endif for (i = 0; i < 16; i++) - kbd_adddata(kbd->mem[i]); - kbd_adddata((kbd->input_port & 0xf0) | 0x80); - kbd_adddata(kbd->output_port); - kbd_adddata(kbd->status); + add_data(dev, dev->mem[i]); + add_data(dev, (dev->input_port & 0xf0) | 0x80); + add_data(dev, dev->output_port); + add_data(dev, dev->status); break; - case 0xad: /*Disable keyboard*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xad: /* disable keyboard */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: disable keyboard\n"); #endif - kbd_keyboard_set(kbd, 0); + set_enable_kbd(dev, 0); break; - case 0xae: /*Enable keyboard*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xae: /* enable keyboard */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: enable keyboard\n"); #endif - kbd_keyboard_set(kbd, 1); + set_enable_kbd(dev, 1); break; - case 0xd0: /*Read output port*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xd0: /* read output port */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: read output port\n"); #endif mask = 0xff; - if (! keyboard_scan) + if (!keyboard_scan) mask &= 0xbf; - if (!mouse_scan && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + if (!mouse_scan && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) mask &= 0xf7; - kbd_adddata(kbd->output_port & mask); + add_data(dev, dev->output_port & mask); break; - case 0xd1: /*Write output port*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xd1: /* write output port */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: write output port\n"); #endif - kbd->want60 = 1; + dev->want60 = 1; break; - case 0xd2: /*Write keyboard output buffer*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xd2: /* write keyboard output buffer */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: write keyboard output buffer\n"); #endif - kbd->want60 = 1; + dev->want60 = 1; break; - case 0xdd: /* Disable A20 Address Line */ -#ifdef ENABLE_KEYBOARD_LOG +#if 0 + case 0xd4: /* dunno, but OS/2 2.00LA sends it */ + dev->want60 = 1; + break; +#endif + + case 0xdd: /* disable A20 address line */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: disable A20\n"); #endif - kbd_output_write(kbd, kbd->output_port & 0xfd); + write_output(dev, dev->output_port & 0xfd); break; - case 0xdf: /* Enable A20 Address Line */ -#ifdef ENABLE_KEYBOARD_LOG + case 0xdf: /* enable A20 address line */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: enable A20\n"); #endif - kbd_output_write(kbd, kbd->output_port | 0x02); + write_output(dev, dev->output_port | 0x02); break; - case 0xe0: /*Read test inputs*/ -#ifdef ENABLE_KEYBOARD_LOG + case 0xe0: /* read test inputs */ +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: read test inputs\n"); #endif - kbd_adddata(0x00); + add_data(dev, 0x00); break; default: - /* Run the vendor-specific command handler, if present, - otherwise (or if the former returns 1), assume bad command. */ - if (kbd->write64_ven) - bad = kbd->write64_ven(kbd, val); + /* + * Unrecognized controller command. + * + * If we have a vendor-specific handler, run + * that. Otherwise, or if that handler fails, + * log a bad command. + */ + if (dev->write64_ven) + bad = dev->write64_ven(dev, val); -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG if (bad) kbd_log("ATkbd: bad controller command %02X\n", val); #endif } + + /* If the command needs data, remember the command. */ + if (dev->want60) + dev->command = val; break; } } @@ -2124,33 +2186,38 @@ do_command: static uint8_t kbd_read(uint16_t port, void *priv) { - atkbd_t *kbd = (atkbd_t *)priv; + atkbd_t *dev = (atkbd_t *)priv; uint8_t ret = 0xff; - if (((kbd->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) && (port == 0x63)) + if (((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) && (port == 0x63)) port = 0x61; switch (port) { case 0x60: - ret = kbd->out; - kbd->status &= ~(STAT_OFULL); - if (kbd->last_irq) - picintc(kbd->last_irq); - kbd->last_irq = 0; + ret = dev->out; + dev->status &= ~(STAT_OFULL); + if (dev->last_irq) { + picintc(dev->last_irq); + dev->last_irq = 0; + } break; case 0x61: ret = ppi.pb & ~0xe0; if (ppispeakon) ret |= 0x20; - if ((kbd->flags & KBC_TYPE_MASK) != KBC_TYPE_ISA) { - if (kbd->refresh) + if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { + if (dev->refresh) ret |= 0x10; else ret &= ~0x10; } - if ((kbd->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) { - if (xi8088_turbo_get()) + if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) { +#ifdef USE_NEW_STUFF + if (dev->read_func(dev->func_priv)) +#else + if (xi8088_turbo_get()) +#endif ret |= 0x04; else ret &= ~0x04; @@ -2158,18 +2225,24 @@ kbd_read(uint16_t port, void *priv) break; case 0x64: - ret = (kbd->status & 0xFB) | (keyboard_mode & CCB_SYSTEM); -#if 0 - ret |= STAT_LOCK; -#endif + // ret = (dev->status & 0xFB) | (keyboard_mode & CCB_SYSTEM); + // ret |= STAT_UNLOCKED; + ret = (dev->status & 0xFB); + if (dev->mem[0] & STAT_SYSFLAG) + ret |= STAT_SYSFLAG; /* The transmit timeout (TTIMEOUT) flag should *NOT* be cleared, otherwise the IBM PS/2 Model 80's BIOS gives error 8601 (mouse error). */ - kbd->status &= ~(STAT_RTIMEOUT/* | STAT_TTIMEOUT*/); + dev->status &= ~(STAT_RTIMEOUT/* | STAT_TTIMEOUT*/); + break; + + default: + kbd_log("ATkbd: read(%04x) invalid!\n", port); break; } -#ifdef _DEBUG - kbd_log("ATkbd: read(%04X) = %02X\n", port, ret); +#ifdef ENABLE_KEYBOARD_AT_LOG + if (port != 0x61) + kbd_log("ATkbd: read(%04X) = %02X\n", port, ret); #endif return(ret); @@ -2179,128 +2252,62 @@ kbd_read(uint16_t port, void *priv) static void kbd_refresh(void *priv) { - atkbd_t *kbd = (atkbd_t *)priv; + atkbd_t *dev = (atkbd_t *)priv; - kbd->refresh = !kbd->refresh; - kbd->refresh_time += PS2_REFRESH_TIME; + dev->refresh = !dev->refresh; + timer_advance_u64(&dev->refresh_time, PS2_REFRESH_TIME); } static void kbd_reset(void *priv) { - atkbd_t *kbd = (atkbd_t *)priv; + atkbd_t *dev = (atkbd_t *)priv; - kbd->initialized = 0; - kbd->dtrans = 0; - kbd->first_write = 1; - kbd->status = STAT_LOCK | STAT_CD; - kbd->mem[0] = 0x01; - kbd->wantirq = 0; - kbd_output_write(kbd, 0xcf); - kbd->input_port = (video_is_mda()) ? 0xf0 : 0xb0; - kbd->out_new = -1; - kbd->last_irq = 0; - kbd->secr_phase = 0; - kbd->key_wantdata = 0; + dev->initialized = 0; + dev->first_write = 1; + dev->status = STAT_UNLOCKED | STAT_CD; + dev->mem[0] = 0x01; + if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) + dev->mem[0] |= CCB_TRANSLATE; + dev->wantirq = 0; + write_output(dev, 0xcf); + dev->out_new = -1; + dev->last_irq = 0; + dev->secr_phase = 0; + dev->key_wantdata = 0; - /* Q */ - keyboard_mode = 0x02 | kbd->dtrans; + /* Set up the correct Video Type bits. */ + if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_XI8088) + dev->input_port = video_is_mda() ? 0xb0 : 0xf0; + else + dev->input_port = video_is_mda() ? 0xf0 : 0xb0; + kbd_log("ATkbd: input port = %02x\n", dev->input_port); - kbd_keyboard_set(kbd, 1); - kbd_mouse_set(kbd, 0); + keyboard_mode = 0x02 | (dev->mem[0] & CCB_TRANSLATE); + + /* Enable keyboard, disable mouse. */ + set_enable_kbd(dev, 1); + set_enable_mouse(dev, 0); sc_or = 0; - keyboard_update_states(0, 0, 0); memset(keyboard_set3_flags, 0, 512); - kbd_setmap(kbd); -} - - -static void * -kbd_init(const device_t *info) -{ - atkbd_t *kbd; - - kbd = (atkbd_t *)malloc(sizeof(atkbd_t)); - memset(kbd, 0x00, sizeof(atkbd_t)); - - kbd->flags = info->local; - - kbd_reset(kbd); - - io_sethandler(0x0060, 5, - kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); - keyboard_send = kbd_adddata_keyboard; - - timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, kbd); - - if ((kbd->flags & KBC_TYPE_MASK) != KBC_TYPE_ISA) { -#if 0 - if ((kbd->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { - /* - * These machines force translation off, so the - * the keyboard must start in scan code set 1. - */ - keyboard_mode &= ~0x03; - keyboard_mode |= 0x01; - } -#endif - - timer_add(kbd_refresh, - &kbd->refresh_time, TIMER_ALWAYS_ENABLED, kbd); - } - - timer_add(kbd_pulse_poll, - &kbd->pulse_cb, &kbd->pulse_cb, kbd); - - kbd->write60_ven = NULL; - kbd->write64_ven = NULL; - - switch(kbd->flags & KBC_VEN_MASK) { - case KBC_VEN_GENERIC: - kbd->write64_ven = &kbd_write64_generic; - break; - - case KBC_VEN_AMI: - kbd->write60_ven = &kbd_write60_ami; - kbd->write64_ven = &kbd_write64_ami; - break; - - case KBC_VEN_IBM_MCA: - kbd->write64_ven = &kbd_write64_ibm_mca; - break; - - case KBC_VEN_QUADTEL: - kbd->write60_ven = &kbd_write60_quadtel; - kbd->write64_ven = &kbd_write64_quadtel; - break; - - case KBC_VEN_TOSHIBA: - kbd->write60_ven = &kbd_write60_toshiba; - kbd->write64_ven = &kbd_write64_toshiba; - break; - } - - /* We need this, sadly. */ - CurrentKbd = kbd; - - return(kbd); + set_scancode_map(dev); } static void kbd_close(void *priv) { - atkbd_t *kbd = (atkbd_t *)priv; + atkbd_t *dev = (atkbd_t *)priv; - kbd_reset(kbd); + kbd_reset(dev); /* Stop timers. */ - keyboard_delay = 0; - kbd->refresh_time = 0; + timer_disable(&dev->send_delay_timer); + timer_disable(&dev->refresh_time); keyboard_scan = 0; keyboard_send = NULL; @@ -2308,8 +2315,74 @@ kbd_close(void *priv) /* Disable the scancode maps. */ keyboard_set_table(NULL); - CurrentKbd = NULL; - free(kbd); + SavedKbd = NULL; + free(dev); +} + + +static void * +kbd_init(const device_t *info) +{ + atkbd_t *dev; + + dev = (atkbd_t *)malloc(sizeof(atkbd_t)); + memset(dev, 0x00, sizeof(atkbd_t)); + + dev->flags = info->local; + + video_reset(gfxcard); + kbd_reset(dev); + + io_sethandler(0x0060, 5, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, dev); + keyboard_send = add_data_kbd; + + timer_add(&dev->send_delay_timer, kbd_poll, dev, 1); + + if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) + timer_add(&dev->refresh_time, kbd_refresh, dev, 1); + + timer_add(&dev->pulse_cb, pulse_poll, dev, 0); + + dev->write60_ven = NULL; + dev->write64_ven = NULL; + + switch(dev->flags & KBC_VEN_MASK) { + case KBC_VEN_GENERIC: + case KBC_VEN_IBM_PS1: + case KBC_VEN_XI8088: + dev->write64_ven = write64_generic; + break; + + case KBC_VEN_AMI: + dev->write60_ven = write60_ami; + dev->write64_ven = write64_ami; + break; + + case KBC_VEN_IBM_MCA: + dev->write64_ven = write64_ibm_mca; + break; + + case KBC_VEN_QUADTEL: + dev->write60_ven = write60_quadtel; + dev->write64_ven = write64_quadtel; + break; + + case KBC_VEN_TOSHIBA: + dev->write60_ven = write60_toshiba; + dev->write64_ven = write64_toshiba; + break; + + case KBC_VEN_ACER: + dev->write60_ven = write60_acer; + dev->write64_ven = write64_acer; + break; + } + + /* We need this, sadly. */ + SavedKbd = dev; + + return(dev); } @@ -2344,6 +2417,16 @@ const device_t keyboard_at_toshiba_device = { }; const device_t keyboard_ps2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ps2_device = { "PS/2 Keyboard", 0, KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, @@ -2353,6 +2436,16 @@ const device_t keyboard_ps2_device = { NULL, NULL, NULL, NULL }; +const device_t keyboard_ps2_ps1_device = { + "PS/2 Keyboard (IBM PS/1)", + 0, + KBC_TYPE_PS2_NOREF | KBC_VEN_IBM_PS1, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL, NULL +}; + const device_t keyboard_ps2_xi8088_device = { "PS/2 Keyboard (Xi8088)", 0, @@ -2366,7 +2459,7 @@ const device_t keyboard_ps2_xi8088_device = { const device_t keyboard_ps2_ami_device = { "PS/2 Keyboard (AMI)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, @@ -2396,18 +2489,17 @@ const device_t keyboard_ps2_mca_2_device = { const device_t keyboard_ps2_quadtel_device = { "PS/2 Keyboard (Quadtel/MegaPC)", 0, - KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, + KBC_TYPE_PS2_NOREF | KBC_VEN_QUADTEL, kbd_init, kbd_close, kbd_reset, NULL, NULL, NULL, NULL }; - const device_t keyboard_ps2_pci_device = { "PS/2 Keyboard", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, kbd_init, kbd_close, kbd_reset, @@ -2417,21 +2509,26 @@ const device_t keyboard_ps2_pci_device = { const device_t keyboard_ps2_ami_pci_device = { "PS/2 Keyboard (AMI)", DEVICE_PCI, - KBC_TYPE_PS2_1 | KBC_VEN_AMI, + KBC_TYPE_PS2_NOREF | KBC_VEN_AMI, kbd_init, kbd_close, kbd_reset, NULL, NULL, NULL }; -void -keyboard_at_reset(void) -{ - atkbd_t *kbd = CurrentKbd; - - if (kbd != NULL) - kbd_reset(kbd); -} +const device_t keyboard_ps2_acer_device = { + "PS/2 Keyboard (Acer 90M002A)", + DEVICE_PCI, +#ifdef KBC_VEN_ACER + KBC_TYPE_PS2_NOREF | KBC_VEN_ACER, +#else + KBC_TYPE_PS2_NOREF | KBC_VEN_GENERIC, +#endif + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; void @@ -2458,17 +2555,31 @@ keyboard_at_adddata_mouse(uint8_t val) } +#ifdef USE_NEW_STUFF +/* Set custom machine-dependent keyboard stuff. */ +void +keyboard_at_set_funcs(void *arg, uint8_t (*readfunc)(void *), void (*writefunc)(void *, uint8_t), void *priv) +{ + atkbd_t *dev = (atkbd_t *)arg; + + dev->read_func = readfunc; + dev->write_func = writefunc; + dev->func_priv = priv; +} +#endif + + void keyboard_at_set_mouse_scan(uint8_t val) { - atkbd_t *kbd = CurrentKbd; + atkbd_t *dev = SavedKbd; uint8_t temp_mouse_scan = val ? 1 : 0; if (temp_mouse_scan == mouse_scan) return; - kbd_mouse_set(kbd, val ? 1 : 0); + set_enable_mouse(dev, val ? 1 : 0); -#ifdef ENABLE_KEYBOARD_LOG +#ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("ATkbd: mouse scan %sabled via PCI\n", mouse_scan ? "en" : "dis"); #endif } diff --git a/src/keyboard_xt.c b/src/keyboard_xt.c index 3e4637ac4..3bd7c6c8e 100644 --- a/src/keyboard_xt.c +++ b/src/keyboard_xt.c @@ -8,15 +8,15 @@ * * Implementation of the XT-style keyboard. * - * Version: @(#)keyboard_xt.c 1.0.15 2019/01/24 + * Version: @(#)keyboard_xt.c 1.0.17 2019/03/05 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van kempen. */ #include #include @@ -24,16 +24,17 @@ #include #include #include "86box.h" +#include "device.h" +#include "timer.h" #include "floppy/fdd.h" #include "machine/machine.h" +#include "machine/m_xt_t1000.h" #include "io.h" #include "pic.h" #include "pit.h" #include "ppi.h" #include "mem.h" #include "rom.h" -#include "timer.h" -#include "device.h" #include "sound/sound.h" #include "sound/snd_speaker.h" #include "video/video.h" @@ -58,273 +59,296 @@ typedef struct { uint8_t pa, pb, pd; uint8_t key_waiting; uint8_t type; + + pc_timer_t send_delay_timer; } xtkbd_t; /*XT keyboard has no escape scancodes, and no scancodes beyond 53*/ const scancode scancode_xt[512] = { - { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, - { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, - { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, - { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, - { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, - { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, - { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, - { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, - { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, - { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, - { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, - { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, - { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, - { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, - { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, - { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, - { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, - { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, - { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, - { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, - { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, - { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} }, - { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, - { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, - { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, - { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, - { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, - { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, - { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, - { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, - { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, - { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, - { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, - { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, - { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, - { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, - { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, - { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, - { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, - { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, - { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, - { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*054*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*058*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*05c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*060*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*064*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*068*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*06c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*070*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*074*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*078*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*07c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*080*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*084*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*088*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*08c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*090*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*094*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*098*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*09c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0a0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0a4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0a8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0ac*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0b0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0b4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0b8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0bc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0c0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0c4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0c8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0cc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0d0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0d4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0d8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0dc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0e0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0e4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0e8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0ec*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0f0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0f4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0f8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0fc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*100*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*104*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*108*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*10c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*110*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*114*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*118*/ - { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*11c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*120*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*124*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*128*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*12c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*130*/ - { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, - { {-1}, {-1} }, { {0x37, -1}, {0xb7, -1} }, /*134*/ - { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*138*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*13c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*140*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*144*/ - { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, - { {-1}, {-1} }, { {0x4b, -1}, {0xcb, -1} }, /*148*/ - { {-1}, {-1} }, { {0x4d, -1}, {0xcd, -1} }, - { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*14c*/ - { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, - { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*150*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*154*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*158*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*15c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*160*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*164*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*168*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*16c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*170*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*174*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*148*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*17c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*180*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*184*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*18c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*190*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*194*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*198*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*19c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1a0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1a4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1a8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1ac*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1b0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1b4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1b8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1bc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1c0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1c4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1c8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1cc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1d0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1d4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1d8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1dc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1e0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1e4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1e8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1ec*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1f0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1f4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1f8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} } /*1fc*/ + { {0}, {0} }, { {0x01, 0}, {0x81, 0} }, + { {0x02, 0}, {0x82, 0} }, { {0x03, 0}, {0x83, 0} }, + { {0x04, 0}, {0x84, 0} }, { {0x05, 0}, {0x85, 0} }, + { {0x06, 0}, {0x86, 0} }, { {0x07, 0}, {0x87, 0} }, + { {0x08, 0}, {0x88, 0} }, { {0x09, 0}, {0x89, 0} }, + { {0x0a, 0}, {0x8a, 0} }, { {0x0b, 0}, {0x8b, 0} }, + { {0x0c, 0}, {0x8c, 0} }, { {0x0d, 0}, {0x8d, 0} }, + { {0x0e, 0}, {0x8e, 0} }, { {0x0f, 0}, {0x8f, 0} }, + { {0x10, 0}, {0x90, 0} }, { {0x11, 0}, {0x91, 0} }, + { {0x12, 0}, {0x92, 0} }, { {0x13, 0}, {0x93, 0} }, + { {0x14, 0}, {0x94, 0} }, { {0x15, 0}, {0x95, 0} }, + { {0x16, 0}, {0x96, 0} }, { {0x17, 0}, {0x97, 0} }, + { {0x18, 0}, {0x98, 0} }, { {0x19, 0}, {0x99, 0} }, + { {0x1a, 0}, {0x9a, 0} }, { {0x1b, 0}, {0x9b, 0} }, + { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, + { {0x1e, 0}, {0x9e, 0} }, { {0x1f, 0}, {0x9f, 0} }, + { {0x20, 0}, {0xa0, 0} }, { {0x21, 0}, {0xa1, 0} }, + { {0x22, 0}, {0xa2, 0} }, { {0x23, 0}, {0xa3, 0} }, + { {0x24, 0}, {0xa4, 0} }, { {0x25, 0}, {0xa5, 0} }, + { {0x26, 0}, {0xa6, 0} }, { {0x27, 0}, {0xa7, 0} }, + { {0x28, 0}, {0xa8, 0} }, { {0x29, 0}, {0xa9, 0} }, + { {0x2a, 0}, {0xaa, 0} }, { {0x2b, 0}, {0xab, 0} }, + { {0x2c, 0}, {0xac, 0} }, { {0x2d, 0}, {0xad, 0} }, + { {0x2e, 0}, {0xae, 0} }, { {0x2f, 0}, {0xaf, 0} }, + { {0x30, 0}, {0xb0, 0} }, { {0x31, 0}, {0xb1, 0} }, + { {0x32, 0}, {0xb2, 0} }, { {0x33, 0}, {0xb3, 0} }, + { {0x34, 0}, {0xb4, 0} }, { {0x35, 0}, {0xb5, 0} }, + { {0x36, 0}, {0xb6, 0} }, { {0x37, 0}, {0xb7, 0} }, + { {0x38, 0}, {0xb8, 0} }, { {0x39, 0}, {0xb9, 0} }, + { {0x3a, 0}, {0xba, 0} }, { {0x3b, 0}, {0xbb, 0} }, + { {0x3c, 0}, {0xbc, 0} }, { {0x3d, 0}, {0xbd, 0} }, + { {0x3e, 0}, {0xbe, 0} }, { {0x3f, 0}, {0xbf, 0} }, + { {0x40, 0}, {0xc0, 0} }, { {0x41, 0}, {0xc1, 0} }, + { {0x42, 0}, {0xc2, 0} }, { {0x43, 0}, {0xc3, 0} }, + { {0x44, 0}, {0xc4, 0} }, { {0x45, 0}, {0xc5, 0} }, + { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, + { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, + { {0x4a, 0}, {0xca, 0} }, { {0x4b, 0}, {0xcb, 0} }, + { {0x4c, 0}, {0xcc, 0} }, { {0x4d, 0}, {0xcd, 0} }, + { {0x4e, 0}, {0xce, 0} }, { {0x4f, 0}, {0xcf, 0} }, + { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, + { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} }, + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*054*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*058*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*05c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*060*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*064*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*068*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*06c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*070*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*074*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*078*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*07c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*080*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*084*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*088*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*08c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*090*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*094*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*098*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*09c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0a0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0a4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0a8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0ac*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0b0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0b4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0b8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0bc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0c0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0c4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0c8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0cc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0d0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0d4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0d8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0dc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0e0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0e4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0e8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0ec*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0f0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0f4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0f8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0fc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*100*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*104*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*108*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*10c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*110*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*114*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*118*/ + { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, + { {0}, {0} }, { {0}, {0} }, /*11c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*120*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*124*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*128*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*12c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*130*/ + { {0}, {0} }, { {0x35, 0}, {0xb5, 0} }, + { {0}, {0} }, { {0x37, 0}, {0xb7, 0} }, /*134*/ + { {0x38, 0}, {0xb8, 0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*138*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*13c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*140*/ + { {0}, {0} }, { {0}, {0} }, + { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, /*144*/ + { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, + { {0}, {0} }, { {0x4b, 0}, {0xcb, 0} }, /*148*/ + { {0}, {0} }, { {0x4d, 0}, {0xcd, 0} }, + { {0}, {0} }, { {0x4f, 0}, {0xcf, 0} }, /*14c*/ + { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, + { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} }, /*150*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*154*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*158*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*15c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*160*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*164*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*168*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*16c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*170*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*174*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*148*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*17c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*180*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*184*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*88*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*18c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*190*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*194*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*198*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*19c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1a0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1a4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1a8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1ac*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1b0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1b4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1b8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1bc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1c0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1c4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1c8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1cc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1d0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1d4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1d8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1dc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1e0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1e4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1e8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1ec*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1f0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1f4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1f8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} } /*1fc*/ }; static uint8_t key_queue[16]; -static int key_queue_start, - key_queue_end; +static int key_queue_start = 0, + key_queue_end = 0; +static int is_t1x00 = 0; + + +#ifdef ENABLE_KEYBOARD_XT_LOG +int keyboard_xt_do_log = ENABLE_KEYBOARD_XT_LOG; + + +static void +kbd_log(const char *fmt, ...) +{ + va_list ap; + + if (keyboard_xt_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define kbd_log(fmt, ...) +#endif static void @@ -332,9 +356,9 @@ kbd_poll(void *priv) { xtkbd_t *kbd = (xtkbd_t *)priv; - keyboard_delay += (1000LL * TIMER_USEC); + timer_advance_u64(&kbd->send_delay_timer, 1000 * TIMER_USEC); - if (!(kbd->pb & 0x40) && (romset != ROM_TANDY)) + if (!(kbd->pb & 0x40) && (kbd->type != 5)) return; if (kbd->want_irq) { @@ -342,14 +366,15 @@ kbd_poll(void *priv) kbd->pa = kbd->key_waiting; kbd->blocked = 1; picint(2); +#ifdef ENABLE_KEYBOARD_XT_LOG + kbd_log("keyboard_xt : take IRQ\n"); +#endif } if (key_queue_start != key_queue_end && !kbd->blocked) { kbd->key_waiting = key_queue[key_queue_start]; -#if ENABLE_KEYBOARD_LOG - pclog("XTkbd: reading %02X from the key queue at %i\n", - kbd->pa, key_queue_start); -#endif + kbd_log("XTkbd: reading %02X from the key queue at %i\n", + kbd->key_waiting, key_queue_start); key_queue_start = (key_queue_start + 1) & 0x0f; kbd->want_irq = 1; } @@ -359,11 +384,33 @@ kbd_poll(void *priv) static void kbd_adddata(uint16_t val) { + /* Test for T1000 'Fn' key (Right Alt / Right Ctrl) */ + if (is_t1x00) { + if (keyboard_recv(0xb8) || keyboard_recv(0x9d)) { /* 'Fn' pressed */ + t1000_syskey(0x00, 0x04, 0x00); /* Set 'Fn' indicator */ + switch (val) { + case 0x45: /* Num Lock => toggle numpad */ + t1000_syskey(0x00, 0x00, 0x10); break; + case 0x47: /* Home => internal display */ + t1000_syskey(0x40, 0x00, 0x00); break; + case 0x49: /* PgDn => turbo on */ + t1000_syskey(0x80, 0x00, 0x00); break; + case 0x4D: /* Right => toggle LCD font */ + t1000_syskey(0x00, 0x00, 0x20); break; + case 0x4F: /* End => external display */ + t1000_syskey(0x00, 0x40, 0x00); break; + case 0x51: /* PgDn => turbo off */ + t1000_syskey(0x00, 0x80, 0x00); break; + case 0x54: /* SysRQ => toggle window */ + t1000_syskey(0x00, 0x00, 0x08); break; + } + } else + t1000_syskey(0x04, 0x00, 0x00); /* Reset 'Fn' indicator */ + } + key_queue[key_queue_end] = val; -#if ENABLE_KEYBOARD_LOG - pclog("XTkbd: %02X added to key queue at %i\n", - val, key_queue_end); -#endif + kbd_log("XTkbd: %02X added to key queue at %i\n", + val, key_queue_end); key_queue_end = (key_queue_end + 1) & 0x0f; } @@ -424,7 +471,7 @@ kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) static void kbd_adddata_ex(uint16_t val) { - kbd_adddata_process(val, kbd_adddata); + kbd_adddata_process(val, kbd_adddata); } @@ -444,12 +491,13 @@ kbd_write(uint16_t port, uint8_t val, void *priv) kbd->pb = val; ppi.pb = val; - timer_process(); - timer_update_outstanding(); - speaker_update(); - speaker_gated = val & 1; - speaker_enable = val & 2; + if ((kbd->type <= 1) && !(kbd->pb & 0x08)) + speaker_gated = speaker_enable = 1; + else { + speaker_gated = val & 1; + speaker_enable = val & 2; + } if (speaker_enable) was_speaker_enable = 1; pit_set_gate(&pit, 2, val & 1); @@ -459,7 +507,18 @@ kbd_write(uint16_t port, uint8_t val, void *priv) kbd->blocked = 0; picintc(2); } + +#ifdef ENABLE_KEYBOARD_XT_LOG + if (kbd->type <= 1) + kbd_log("Casette motor is %s\n", !(val & 0x08) ? "ON" : "OFF"); +#endif break; +#ifdef ENABLE_KEYBOARD_XT_LOG + case 0x62: + if (kbd->type <= 1) + kbd_log("Casette IN is %i\n", !!(val & 0x10)); + break; +#endif } } @@ -485,7 +544,7 @@ kbd_read(uint16_t port, void *priv) break; case 0x62: - if (!kbd->type) + if (kbd->type == 0) ret = 0x00; else if (kbd->type == 1) { if (kbd->pb & 0x04) @@ -499,7 +558,7 @@ kbd_read(uint16_t port, void *priv) /* LaserXT = Always 512k RAM; LaserXT/3 = Bit 0: set = 512k, clear = 256k. */ #if defined(DEV_BRANCH) && defined(USE_LASERXT) - if (kbd->type == 5) + if (kbd->type == 6) ret = (mem_size == 512) ? 0x0d : 0x0c; else #endif @@ -508,12 +567,17 @@ kbd_read(uint16_t port, void *priv) } ret |= (ppispeakon ? 0x20 : 0); - if (kbd->type == 4) + /* This is needed to avoid error 131 (cassette error). + This is serial read: bit 5 = clock, bit 4 = data, cassette header is 256 x 0xff. */ + if (kbd->type <= 1) + ret |= (ppispeakon ? 0x10 : 0); + + if (kbd->type == 5) ret |= (tandy1k_eeprom_read() ? 0x10 : 0); break; case 0x63: - if ((kbd->type == 2) || (kbd->type == 3)) + if ((kbd->type == 2) || (kbd->type == 3) || (kbd->type == 4) || (kbd->type == 6)) ret = kbd->pd; break; } @@ -555,6 +619,10 @@ kbd_init(const device_t *info) kbd_reset(kbd); kbd->type = info->local; + key_queue_start = key_queue_end = 0; + + video_reset(gfxcard); + if (kbd->type <= 3) { for (i = 0; i < FDD_NUM; i++) { if (fdd_get_flags(i)) @@ -570,10 +638,12 @@ kbd_init(const device_t *info) /* Switches 5, 6 - video. */ if (video_is_mda()) kbd->pd |= 0x30; - else + else if (video_is_cga()) kbd->pd |= 0x20; /* 0x10 would be 40x25 */ + else + kbd->pd |= 0x00; /* Switches 3, 4 - memory size. */ - if (kbd->type == 3) { + if ((kbd->type == 3) || (kbd->type == 4) || (kbd->type == 6)) { switch (mem_size) { case 256: kbd->pd |= 0x00; @@ -589,7 +659,7 @@ kbd_init(const device_t *info) kbd->pd |= 0x0c; break; } - } else if (kbd->type == 2) { + } else if (kbd->type >= 1) { switch (mem_size) { case 64: kbd->pd |= 0x00; @@ -622,15 +692,21 @@ kbd_init(const device_t *info) break; } } - /* Switch 2 - return bit clear (switch ON) because no 8087 right now. */ + + /* Switch 2 - 8087 FPU. */ + if (hasfpu) + kbd->pd |= 0x02; + /* Switch 1 - always off. */ - kbd->pd |= 0x01; + kbd->pd |= 0x01; } - timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, kbd); + timer_add(&kbd->send_delay_timer, kbd_poll, kbd, 1); keyboard_set_table(scancode_xt); + is_t1x00 = (kbd->type == 6); + return(kbd); } @@ -641,7 +717,7 @@ kbd_close(void *priv) xtkbd_t *kbd = (xtkbd_t *)priv; /* Stop the timer. */ - keyboard_delay = 0; + timer_disable(&kbd->send_delay_timer); /* Disable scanning. */ keyboard_scan = 0; @@ -695,10 +771,30 @@ const device_t keyboard_xt86_device = { NULL, NULL, NULL }; +const device_t keyboard_xt_compaq_device = { + "Compaq Portable Keyboard", + 0, + 4, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + const device_t keyboard_tandy_device = { "Tandy 1000 Keyboard", 0, - 4, + 5, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_xt_t1x00_device = { + "Toshiba T1x00 Keyboard", + 0, + 6, kbd_init, kbd_close, kbd_reset, @@ -709,7 +805,7 @@ const device_t keyboard_tandy_device = { const device_t keyboard_xt_lxt3_device = { "VTech Laser XT3 Keyboard", 0, - /*5*/ 3, + 7, kbd_init, kbd_close, kbd_reset, diff --git a/src/lpt.c b/src/lpt.c index d37211844..1c8a0fc66 100644 --- a/src/lpt.c +++ b/src/lpt.c @@ -8,12 +8,13 @@ #include "86box.h" #include "io.h" #include "lpt.h" +#include "pic.h" #include "sound/snd_lpt_dac.h" #include "sound/snd_lpt_dss.h" #include "printer/prt_devs.h" -char lpt_device_names[3][16]; +lpt_port_t lpt_ports[3]; static const struct @@ -32,205 +33,201 @@ static const struct {"", "", NULL} }; -char *lpt_device_get_name(int id) + +char * +lpt_device_get_name(int id) { - if (strlen((char *) lpt_devices[id].name) == 0) - return NULL; - return (char *) lpt_devices[id].name; -} -char *lpt_device_get_internal_name(int id) -{ - if (strlen((char *) lpt_devices[id].internal_name) == 0) - return NULL; - return (char *) lpt_devices[id].internal_name; + if (strlen((char *) lpt_devices[id].name) == 0) + return NULL; + + return (char *) lpt_devices[id].name; } -static lpt_device_t *lpt_device_ts[3]; -static void *lpt_device_ps[3]; -void lpt_devices_init() +char * +lpt_device_get_internal_name(int id) { - int i = 0; - int c; - - for (i = 0; i < 3; i++) { - c = 0; - - while (strcmp((char *) lpt_devices[c].internal_name, lpt_device_names[i]) && strlen((char *) lpt_devices[c].internal_name) != 0) - c++; - - if (strlen((char *) lpt_devices[c].internal_name) == 0) - lpt_device_ts[i] = NULL; - else - { - lpt_device_ts[i] = (lpt_device_t *) lpt_devices[c].device; - if (lpt_device_ts[i]) - lpt_device_ps[i] = lpt_device_ts[i]->init(lpt_device_ts[i]); - } - } + if (strlen((char *) lpt_devices[id].internal_name) == 0) + return NULL; + return (char *) lpt_devices[id].internal_name; } -void lpt_devices_close() -{ - int i = 0; - for (i = 0; i < 3; i++) { - if (lpt_device_ts[i]) - lpt_device_ts[i]->close(lpt_device_ps[i]); - lpt_device_ts[i] = NULL; - } +int +lpt_device_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen((char *) lpt_devices[c].internal_name) != 0) { + if (strcmp(lpt_devices[c].internal_name, s) == 0) + return c; + c++; + } + + return 0; } -static uint8_t lpt_dats[3], lpt_ctrls[3] = { 0x04, 0x04, 0x04 }; -void lpt_write(int i, uint16_t port, uint8_t val, void *priv) +void +lpt_devices_init(void) { - switch (port & 3) - { - case 0: - if (lpt_device_ts[i] && lpt_device_ts[i]->write_data) - lpt_device_ts[i]->write_data(val, lpt_device_ps[i]); - lpt_dats[i] = val; - break; - - case 1: + int i = 0; + + for (i = 0; i < 3; i++) { + lpt_ports[i].dt = (lpt_device_t *) lpt_devices[lpt_ports[i].device].device; + + if (lpt_ports[i].dt) + lpt_ports[i].priv = lpt_ports[i].dt->init(&lpt_ports[i]); + } +} + + +void +lpt_devices_close(void) +{ + int i = 0; + lpt_port_t *dev; + + for (i = 0; i < 3; i++) { + dev = &lpt_ports[i]; + + if (dev->dt) + dev->dt->close(dev->priv); + + dev->dt = NULL; + } +} + + +void +lpt_write(uint16_t port, uint8_t val, void *priv) +{ + lpt_port_t *dev = (lpt_port_t *) priv; + + switch (port & 3) { + case 0: + if (dev->dt && dev->dt->write_data) + dev->dt->write_data(val, dev->priv); + dev->dat = val; break; - - case 2: - if (lpt_device_ts[i] && lpt_device_ts[i]->write_ctrl) - lpt_device_ts[i]->write_ctrl(val, lpt_device_ps[i]); - lpt_ctrls[i] = val; - break; - } -} -uint8_t lpt_read(int i, uint16_t port, void *priv) -{ - uint8_t retval = 0xff; - - switch (port & 3) - { - case 0: - if (lpt_device_ts[i] && lpt_device_ts[i]->read_data) { - retval = lpt_device_ts[i]->read_data(lpt_device_ps[i]); - break; - } - retval = lpt_dats[i]; + + case 1: break; - - case 1: - if (lpt_device_ts[i] && lpt_device_ts[i]->read_status) { - retval = lpt_device_ts[i]->read_status(lpt_device_ps[i]); - break; - } - retval = 0xdf; - break; - - case 2: - if (lpt_device_ts[i] && lpt_device_ts[i]->read_ctrl) { - retval = lpt_device_ts[i]->read_ctrl(lpt_device_ps[i]); - break; - } - retval = 0xe0 | lpt_ctrls[i]; + + case 2: + if (dev->dt && dev->dt->write_ctrl) + dev->dt->write_ctrl(val, dev->priv); + dev->ctrl = val; break; - } - return retval; -} - -void lpt1_write(uint16_t port, uint8_t val, void *priv) -{ - lpt_write(0, port, val, priv); -} - -uint8_t lpt1_read(uint16_t port, void *priv) -{ - return lpt_read(0, port, priv); + } } -void lpt2_write(uint16_t port, uint8_t val, void *priv) +uint8_t +lpt_read(uint16_t port, void *priv) { - lpt_write(1, port, val, priv); + uint8_t ret = 0xff; + lpt_port_t *dev = (lpt_port_t *) priv; + + switch (port & 3) { + case 0: + if (dev->dt && dev->dt->read_data) + ret = dev->dt->read_data(dev->priv); + else + ret = dev->dat; + break; + + case 1: + if (dev->dt && dev->dt->read_status) + ret = dev->dt->read_status(dev->priv); + else + ret = 0xdf; + break; + + case 2: + if (dev->dt && dev->dt->read_ctrl) + ret = dev->dt->read_ctrl(dev->priv); + else + ret = 0xe0 | dev->ctrl; + break; + } + + return ret; } -uint8_t lpt2_read(uint16_t port, void *priv) + +void +lpt_irq(void *priv, int raise) { - return lpt_read(1, port, priv); + lpt_port_t *dev = (lpt_port_t *) priv; + + uint8_t ctrl = lpt_read(2, priv); + + if ((ctrl & 0x10) && (dev->irq != 0xff)) { + if (raise) + picint(1 << dev->irq); + else + picintc(1 << dev->irq); + } } -void lpt3_write(uint16_t port, uint8_t val, void *priv) -{ - lpt_write(2, port, val, priv); -} -uint8_t lpt3_read(uint16_t port, void *priv) +void +lpt_init(void) { - return lpt_read(2, port, priv); -} + int i; + uint16_t default_ports[3] = { 0x378, 0x278, 0x3bc }; + uint8_t default_irqs[3] = { 7, 5, 7 }; -uint16_t lpt_addr[3] = { 0x378, 0x278, 0x3bc }; + for (i = 0; i < 3; i++) { + lpt_ports[i].addr = 0xffff; + lpt_ports[i].irq = 0xff; -void lpt_init(void) -{ - if (lpt_enabled) - { - io_sethandler(0x0378, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); - io_sethandler(0x0278, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); - lpt_addr[0] = 0x378; - lpt_addr[1] = 0x278; + if (lpt_ports[i].enabled) { + lpt_port_init(i, default_ports[i]); + lpt_port_irq(i, default_irqs[i]); } + } } -void lpt1_init(uint16_t port) + +void +lpt_port_init(int i, uint16_t port) { - if (lpt_enabled) - { - io_sethandler(port, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); - lpt_addr[0] = port; - } -} -void lpt1_remove(void) -{ - if (lpt_enabled) - { - io_removehandler(lpt_addr[0], 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); - } -} -void lpt2_init(uint16_t port) -{ - if (lpt_enabled) - { - io_sethandler(port, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); - lpt_addr[1] = port; - } -} -void lpt2_remove(void) -{ - if (lpt_enabled) - { - io_removehandler(lpt_addr[1], 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); - } + if (lpt_ports[i].enabled) { + if (lpt_ports[i].addr != 0xffff) + io_removehandler(lpt_ports[i].addr, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]); + if (port != 0xffff) + io_sethandler(port, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]); + lpt_ports[i].addr = port; + } else + lpt_ports[i].addr = 0xffff; } -void lpt2_remove_ams(void) + +void +lpt_port_irq(int i, uint8_t irq) { - if (lpt_enabled) - { - io_removehandler(0x0379, 0x0002, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); - } + if (lpt_ports[i].enabled) + lpt_ports[i].irq = irq; + else + lpt_ports[i].irq = 0xff; } -void lpt3_init(uint16_t port) + +void +lpt_port_remove(int i) { - if (lpt_enabled) - { - io_sethandler(port, 0x0003, lpt3_read, NULL, NULL, lpt3_write, NULL, NULL, NULL); - lpt_addr[2] = port; - } + if (lpt_ports[i].enabled && (lpt_ports[i].addr != 0xffff)) { + io_removehandler(lpt_ports[i].addr, 0x0003, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[i]); + lpt_ports[i].addr = 0xffff; + } } -void lpt3_remove(void) + + +void +lpt1_remove_ams(void) { - if (lpt_enabled) - { - io_removehandler(lpt_addr[2], 0x0003, lpt3_read, NULL, NULL, lpt3_write, NULL, NULL, NULL); - } + if (lpt_ports[0].enabled) + io_removehandler(lpt_ports[0].addr + 1, 0x0002, lpt_read, NULL, NULL, lpt_write, NULL, NULL, &lpt_ports[0]); } diff --git a/src/lpt.h b/src/lpt.h index f5edae8ba..87cb46f24 100644 --- a/src/lpt.h +++ b/src/lpt.h @@ -1,28 +1,55 @@ -extern void lpt_init(); -extern void lpt1_init(uint16_t port); -extern void lpt1_remove(); -extern void lpt2_init(uint16_t port); -extern void lpt2_remove(); -extern void lpt2_remove_ams(); -extern void lpt3_init(uint16_t port); -extern void lpt3_remove(); - -void lpt_devices_init(); -void lpt_devices_close(); - -char *lpt_device_get_name(int id); -char *lpt_device_get_internal_name(int id); - -extern char lpt_device_names[3][16]; - typedef struct { - const char *name; - void *(*init)(); - void (*close)(void *p); - void (*write_data)(uint8_t val, void *p); - void (*write_ctrl)(uint8_t val, void *p); - uint8_t (*read_data)(void *p); - uint8_t (*read_status)(void *p); - uint8_t (*read_ctrl)(void *p); + const char *name; + + void * (*init)(void *lpt); + void (*close)(void *p); + void (*write_data)(uint8_t val, void *p); + void (*write_ctrl)(uint8_t val, void *p); + uint8_t (*read_data)(void *p); + uint8_t (*read_status)(void *p); + uint8_t (*read_ctrl)(void *p); } lpt_device_t; + + +extern void lpt_init(void); +extern void lpt_port_init(int i, uint16_t port); +extern void lpt_port_irq(int i, uint8_t irq); +extern void lpt_port_remove(int i); +extern void lpt1_remove_ams(void); + +#define lpt1_init(a) lpt_port_init(0, a); +#define lpt1_irq(a) lpt_port_irq(0, a); +#define lpt1_remove() lpt_port_remove(0); +#define lpt2_init(a) lpt_port_init(1, a); +#define lpt2_irq(a) lpt_port_irq(1, a); +#define lpt2_remove() lpt_port_remove(1); +#define lpt3_init(a) lpt_port_init(2, a); +#define lpt3_irq(a) lpt_port_irq(2, a); +#define lpt3_remove() lpt_port_remove(2); + + +void lpt_devices_init(void); +void lpt_devices_close(void); + + +typedef struct { + uint8_t enabled, irq, + dat, ctrl; + uint16_t addr, pad0; + int device; + lpt_device_t * dt; + void * priv; +} lpt_port_t; + +extern lpt_port_t lpt_ports[3]; + +extern void lpt_write(uint16_t port, uint8_t val, void *priv); +extern uint8_t lpt_read(uint16_t port, void *priv); + +extern void lpt_irq(void *priv, int raise); + +extern char * lpt_device_get_name(int id); +extern char * lpt_device_get_internal_name(int id); + +extern int lpt_device_get_from_internal_name(char *s); diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 887e39015..910ad8781 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -32,15 +32,17 @@ * in alpha mode, but in highres ("ECD350") mode, it displays * some semi-random junk. Video-memory pointer maybe? * - * Version: @(#)m_amstrad.c 1.0.16 2018/10/22 + * Version: @(#)m_amstrad.c 1.0.20 2019/03/09 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, + * John Elliott, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2019 John Elliott. */ #include #include @@ -51,6 +53,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../cpu/cpu.h" +#include "../timer.h" #include "../io.h" #include "../nmi.h" #include "../pic.h" @@ -58,7 +61,6 @@ #include "../ppi.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "../nvr.h" #include "../keyboard.h" @@ -72,8 +74,10 @@ #include "../video/video.h" #include "../video/vid_cga.h" #include "../video/vid_ega.h" +#include "../video/vid_mda.h" #include "../video/vid_paradise.h" #include "machine.h" +#include "m_amstrad.h" #define STAT_PARITY 0x80 @@ -89,7 +93,17 @@ typedef struct { rom_t bios_rom; /* 1640 */ cga_t cga; /* 1640/200 */ + mda_t mda; /* 1512/200/PPC512/640*/ ega_t ega; /* 1640 */ + uint8_t emulation; /* Which display are we emulating? */ + uint8_t dipswitches; /* DIP switches 1-3 */ + uint8_t crtc_index; /* CRTC index readback + * Bit 7: CGA control port written + * Bit 6: Operation control port written + * Bit 5: CRTC register written + * Bits 0-4: Last CRTC register selected */ + uint8_t operation_ctrl; + uint8_t reg_3df, type; uint8_t crtc[32]; int crtcreg; int cga_enabled; /* 1640 */ @@ -99,6 +113,7 @@ typedef struct { uint8_t plane_write, /* 1512/200 */ plane_read, /* 1512/200 */ border; /* 1512/200 */ + int fontbase; /* 1512/200 */ int linepos, displine; int sc, vc; @@ -106,17 +121,18 @@ typedef struct { int con, coff, cursoron, cgablink; - int64_t vsynctime; + int vsynctime; int vadj; uint16_t ma, maback; int dispon; int blink; - int64_t dispontime, /* 1512/1640 */ + uint64_t dispontime, /* 1512/1640 */ dispofftime; /* 1512/1640 */ - int64_t vidtime; /* 1512/1640 */ + pc_timer_t timer; /* 1512/1640 */ int firstline, lastline; uint8_t *vram; + void *ams; } amsvid_t; typedef struct { @@ -124,12 +140,15 @@ typedef struct { uint8_t dead; uint8_t stat1, stat2; + uint8_t type, + language; /* Keyboard stuff. */ int8_t wantirq; uint8_t key_waiting; uint8_t pa; uint8_t pb; + pc_timer_t send_delay_timer; /* Mouse stuff. */ uint8_t mousex, @@ -138,9 +157,13 @@ typedef struct { /* Video stuff. */ amsvid_t *vid; + fdc_t *fdc; } amstrad_t; +int amstrad_latch; + + static uint8_t key_queue[16]; static int key_queue_start = 0, key_queue_end = 0; @@ -156,6 +179,17 @@ static video_timings_t timing_pc1640 = {VIDEO_ISA, 8,16,32, 8,16,32}; static video_timings_t timing_pc200 = {VIDEO_ISA, 8,16,32, 8,16,32}; +enum +{ + AMS_PC1512, + AMS_PC1640, + AMS_PC200, + AMS_PPC512, + AMS_PC2086, + AMS_PC3086 +}; + + #ifdef ENABLE_AMSTRAD_LOG int amstrad_do_log = ENABLE_AMSTRAD_LOG; @@ -182,13 +216,13 @@ recalc_timings_1512(amsvid_t *vid) { double _dispontime, _dispofftime, disptime; - disptime = 128; /*Fixed on PC1512*/ + disptime = /*128*/ 114; /*Fixed on PC1512*/ _dispontime = 80; _dispofftime = disptime - _dispontime; _dispontime *= CGACONST; _dispofftime *= CGACONST; - vid->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - vid->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + vid->dispontime = (uint64_t)_dispontime; + vid->dispofftime = (uint64_t)_dispofftime; } @@ -250,12 +284,15 @@ vid_in_1512(uint16_t addr, void *priv) switch (addr) { case 0x03d4: ret = vid->crtcreg; + break; case 0x03d5: ret = vid->crtc[vid->crtcreg]; + break; case 0x03da: ret = vid->stat; + break; } return(ret); @@ -268,7 +305,7 @@ vid_write_1512(uint32_t addr, uint8_t val, void *priv) amsvid_t *vid = (amsvid_t *)priv; egawrites++; - cycles -= 12; + sub_cycles(12); addr &= 0x3fff; if ((vid->cgamode & 0x12) == 0x12) { @@ -287,7 +324,7 @@ vid_read_1512(uint32_t addr, void *priv) amsvid_t *vid = (amsvid_t *)priv; egareads++; - cycles -= 12; + sub_cycles(12); addr &= 0x3fff; if ((vid->cgamode & 0x12) == 0x12) @@ -311,7 +348,7 @@ vid_poll_1512(void *priv) int oldsc; if (! vid->linepos) { - vid->vidtime += vid->dispofftime; + timer_advance_u64(&vid->timer, vid->dispofftime); vid->stat |= 1; vid->linepos = 1; oldsc = vid->sc; @@ -323,17 +360,17 @@ vid_poll_1512(void *priv) vid->lastline = vid->displine; for (c = 0; c < 8; c++) { if ((vid->cgamode & 0x12) == 0x12) { - buffer->line[vid->displine][c] = (vid->border & 15) + 16; + ((uint32_t *)buffer32->line[vid->displine])[c] = (vid->border & 15) + 16; if (vid->cgamode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = 0; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 3) + 8] = 0; else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = 0; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 4) + 8] = 0; } else { - buffer->line[vid->displine][c] = (vid->cgacol & 15) + 16; + ((uint32_t *)buffer32->line[vid->displine])[c] = (vid->cgacol & 15) + 16; if (vid->cgamode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = (vid->cgacol & 15) + 16; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 3) + 8] = (vid->cgacol & 15) + 16; else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = (vid->cgacol & 15) + 16; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 4) + 8] = (vid->cgacol & 15) + 16; } } if (vid->cgamode & 1) { @@ -352,10 +389,10 @@ vid_poll_1512(void *priv) } if (drawcursor) { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + c + 8] = cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + c + 8] = cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } vid->ma++; } @@ -376,12 +413,12 @@ vid_poll_1512(void *priv) vid->ma++; if (drawcursor) { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } } } else if (! (vid->cgamode & 16)) { @@ -404,8 +441,8 @@ vid_poll_1512(void *priv) dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; vid->ma++; for (c = 0; c < 8; c++) { - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; dat <<= 2; } } @@ -419,7 +456,7 @@ vid_poll_1512(void *priv) vid->ma++; for (c = 0; c < 16; c++) { - buffer->line[vid->displine][(x << 4) + c + 8] = (((dat >> 15) | ((dat2 >> 15) << 1) | ((dat3 >> 15) << 2) | ((dat4 >> 15) << 3)) & (vid->cgacol & 15)) + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + c + 8] = (((dat >> 15) | ((dat2 >> 15) << 1) | ((dat3 >> 15) << 2) | ((dat4 >> 15) << 3)) & (vid->cgacol & 15)) + 16; dat <<= 1; dat2 <<= 1; dat3 <<= 1; @@ -430,9 +467,9 @@ vid_poll_1512(void *priv) } else { cols[0] = ((vid->cgamode & 0x12) == 0x12) ? 0 : (vid->cgacol & 15) + 16; if (vid->cgamode & 1) - hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); + hline(buffer32, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); else - hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); } vid->sc = oldsc; @@ -442,7 +479,7 @@ vid_poll_1512(void *priv) if (vid->displine >= 360) vid->displine = 0; } else { - vid->vidtime += vid->dispontime; + timer_advance_u64(&vid->timer, vid->dispontime); if ((vid->lastline - vid->firstline) == 199) vid->dispon = 0; /*Amstrad PC1512 always displays 200 lines, regardless of CRTC settings*/ if (vid->dispon) @@ -553,7 +590,7 @@ vid_init_1512(amstrad_t *ams) vid->cgacol = 7; vid->cgamode = 0x12; - timer_add(vid_poll_1512, &vid->vidtime, TIMER_ALWAYS_ENABLED, vid); + timer_add(&vid->timer, vid_poll_1512, vid, 1); mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, vid_read_1512, NULL, NULL, vid_write_1512, NULL, NULL, NULL, 0, vid); @@ -562,6 +599,11 @@ vid_init_1512(amstrad_t *ams) overscan_x = overscan_y = 16; + vid->fontbase = (device_get_config_int("codepage") & 3) * 256; + + cga_palette = (device_get_config_int("display_type") << 1); + cgapal_rebuild(); + ams->vid = vid; } @@ -586,16 +628,95 @@ vid_speed_change_1512(void *priv) } +device_config_t vid_1512_config[] = +{ + { + "display_type", "Display type", CONFIG_SELECTION, "", 0, + { + { + "PC-CM (Colour)", 0 + }, + { + "PC-MM (Monochrome)", 3 + }, + { + "" + } + } + }, + { + "codepage", "Hardware font", CONFIG_SELECTION, "", 3, + { + { + "US English", 3 + }, + { + "Danish", 1 + }, + { + "Greek", 0 + }, + { + "" + } + } + }, + { + "language", "BIOS language", CONFIG_SELECTION, "", 7, + { + { + "English", 7 + }, + { + "German", 6 + }, + { + "French", 5 + }, + { + "Spanish", 4 + }, + { + "Danish", 3 + }, + { + "Swedish", 2 + }, + { + "Italian", 1 + }, + { + "Diagnostic mode", 0 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + static const device_t vid_1512_device = { "Amstrad PC1512 (video)", 0, 0, NULL, vid_close_1512, NULL, NULL, vid_speed_change_1512, - NULL + NULL, + vid_1512_config }; +const device_t * +pc1512_get_device(void) +{ + return(&vid_1512_device); +} + + static void recalc_timings_1640(amsvid_t *vid) { @@ -625,9 +746,13 @@ vid_out_1640(uint16_t addr, uint8_t val, void *priv) case 0x03db: vid->cga_enabled = val & 0x40; if (vid->cga_enabled) { + timer_disable(&vid->ega.timer); + timer_set_delay_u64(&vid->cga.timer, 0); mem_mapping_enable(&vid->cga.mapping); mem_mapping_disable(&vid->ega.mapping); } else { + timer_disable(&vid->cga.timer); + timer_set_delay_u64(&vid->ega.timer, 0); mem_mapping_disable(&vid->cga.mapping); switch (vid->ega.gdcreg[6] & 0xc) { case 0x0: /*128k at A0000*/ @@ -666,9 +791,6 @@ vid_in_1640(uint16_t addr, void *priv) { amsvid_t *vid = (amsvid_t *)priv; - switch (addr) { - } - if (vid->cga_enabled) return(cga_in(addr, &vid->cga)); else @@ -676,27 +798,6 @@ vid_in_1640(uint16_t addr, void *priv) } -static void -vid_poll_1640(void *priv) -{ - amsvid_t *vid = (amsvid_t *)priv; - - if (vid->cga_enabled) { - overscan_x = overscan_y = 16; - - vid->cga.vidtime = vid->vidtime; - cga_poll(&vid->cga); - vid->vidtime = vid->cga.vidtime; - } else { - overscan_x = 16; overscan_y = 28; - - vid->ega.vidtime = vid->vidtime; - ega_poll(&vid->ega); - vid->vidtime = vid->ega.vidtime; - } -} - - static void vid_init_1640(amstrad_t *ams) { @@ -715,6 +816,7 @@ vid_init_1640(amstrad_t *ams) vid->cga.vram = vid->ega.vram; vid->cga_enabled = 1; cga_init(&vid->cga); + timer_disable(&vid->ega.timer); mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, &vid->cga); @@ -723,8 +825,6 @@ vid_init_1640(amstrad_t *ams) io_sethandler(0x03a0, 64, vid_in_1640, NULL, NULL, vid_out_1640, NULL, NULL, vid); - timer_add(vid_poll_1640, &vid->vidtime, TIMER_ALWAYS_ENABLED, vid); - overscan_x = overscan_y = 16; ams->vid = vid; @@ -751,31 +851,275 @@ vid_speed_changed_1640(void *priv) } +device_config_t vid_1640_config[] = +{ + { + "language", "BIOS language", CONFIG_SELECTION, "", 7, + { + { + "English", 7 + }, + { + "German", 6 + }, + { + "French", 5 + }, + { + "Spanish", 4 + }, + { + "Danish", 3 + }, + { + "Swedish", 2 + }, + { + "Italian", 1 + }, + { + "Diagnostic mode", 0 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + static const device_t vid_1640_device = { "Amstrad PC1640 (video)", 0, 0, NULL, vid_close_1640, NULL, NULL, vid_speed_changed_1640, - NULL + NULL, + vid_1640_config }; +const device_t * +pc1640_get_device(void) +{ + return(&vid_1640_device); +} + +/* Display type */ +#define PC200_CGA 0 /* CGA monitor */ +#define PC200_MDA 1 /* MDA monitor */ +#define PC200_TV 2 /* Television */ +#define PC200_LCDC 3 /* PPC512 LCD as CGA*/ +#define PC200_LCDM 4 /* PPC512 LCD as MDA*/ + +extern int nmi_mask; + +static uint32_t blue, green; + +static uint32_t lcdcols[256][2][2]; + + +static void +ams_inform(amsvid_t *vid) +{ + switch (vid->emulation) { + case PC200_CGA: + case PC200_TV: + case PC200_LCDC: + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_pc200); + break; + case PC200_MDA: + case PC200_LCDM: + video_inform(VIDEO_FLAG_TYPE_MDA, &timing_pc200); + break; + } +} + + +static void +vid_speed_changed_200(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + cga_recalctimings(&vid->cga); + mda_recalctimings(&vid->mda); +} + + +/* LCD colour mappings + * + * 0 => solid green + * 1 => blue on green + * 2 => green on blue + * 3 => solid blue + */ +static unsigned char mapping1[256] = +{ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +/*00*/ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/*10*/ 2, 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, +/*20*/ 2, 2, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, +/*30*/ 2, 2, 2, 0, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1, 1, +/*40*/ 2, 2, 1, 1, 0, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, +/*50*/ 2, 2, 1, 1, 2, 0, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, +/*60*/ 2, 2, 2, 2, 2, 2, 0, 1, 2, 2, 2, 2, 2, 2, 1, 1, +/*70*/ 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, +/*80*/ 2, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, +/*90*/ 2, 2, 1, 1, 1, 1, 1, 1, 2, 0, 1, 1, 1, 1, 1, 1, +/*A0*/ 2, 2, 2, 1, 2, 2, 1, 1, 2, 2, 0, 1, 2, 2, 1, 1, +/*B0*/ 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 0, 2, 2, 1, 1, +/*C0*/ 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 0, 1, 1, 1, +/*D0*/ 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 0, 1, 1, +/*E0*/ 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 0, 1, +/*F0*/ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, +}; + +static unsigned char mapping2[256] = +{ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +/*00*/ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/*10*/ 1, 3, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, +/*20*/ 1, 1, 3, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, +/*30*/ 1, 1, 1, 3, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, +/*40*/ 1, 1, 2, 2, 3, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, +/*50*/ 1, 1, 2, 2, 1, 3, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, +/*60*/ 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 2, 2, +/*70*/ 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 2, +/*80*/ 2, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, +/*90*/ 1, 1, 2, 2, 2, 2, 2, 2, 1, 3, 2, 2, 2, 2, 2, 2, +/*A0*/ 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 3, 2, 1, 1, 2, 2, +/*B0*/ 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 3, 1, 1, 2, 2, +/*C0*/ 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 3, 2, 2, 2, +/*D0*/ 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 3, 2, 2, +/*E0*/ 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 2, +/*F0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, +}; + + +static void set_lcd_cols(uint8_t mode_reg) +{ + unsigned char *mapping = (mode_reg & 0x80) ? mapping2 : mapping1; + int c; + + for (c = 0; c < 256; c++) { + switch (mapping[c]) { + case 0: + lcdcols[c][0][0] = lcdcols[c][1][0] = green; + lcdcols[c][0][1] = lcdcols[c][1][1] = green; + break; + + case 1: + lcdcols[c][0][0] = lcdcols[c][1][0] = + lcdcols[c][1][1] = green; + lcdcols[c][0][1] = blue; + break; + + case 2: + lcdcols[c][0][0] = lcdcols[c][1][0] = + lcdcols[c][1][1] = blue; + lcdcols[c][0][1] = green; + break; + + case 3: + lcdcols[c][0][0] = lcdcols[c][1][0] = blue; + lcdcols[c][0][1] = lcdcols[c][1][1] = blue; + break; + } + } +} + + +static uint8_t +vid_in_200(uint16_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + cga_t *cga = &vid->cga; + mda_t *mda = &vid->mda; + uint8_t ret; + + switch (addr) { + case 0x03b8: + return(mda->ctrl); + + case 0x03d8: + return(cga->cgamode); + + case 0x03dd: + ret = vid->crtc_index; /* Read NMI reason */ + vid->crtc_index &= 0x1f; /* Reset NMI reason */ + nmi = 0; /* And reset NMI flag */ + return(ret); + + case 0x03de: + return((vid->operation_ctrl & 0xc7) | vid->dipswitches); /*External CGA*/ + + case 0x03df: + return(vid->reg_3df); + } + + if (addr >= 0x3D0 && addr <= 0x3DF) + return cga_in(addr, cga); + + if (addr >= 0x3B0 && addr <= 0x3BB) + return mda_in(addr, mda); + + return 0xFF; +} + static void vid_out_200(uint16_t addr, uint8_t val, void *priv) { amsvid_t *vid = (amsvid_t *)priv; cga_t *cga = &vid->cga; + mda_t *mda = &vid->mda; uint8_t old; switch (addr) { - case 0x03d5: - if (!(vid->plane_read & 0x40) && cga->crtcreg <= 11) { - if (vid->plane_read & 0x80) +/* MDA writes ============================================================== */ + case 0x3b1: + case 0x3b3: + case 0x3b5: + case 0x3b7: + /* Writes banned to CRTC registers 0-11? */ + if (!(vid->operation_ctrl & 0x40) && mda->crtcreg <= 11) { + vid->crtc_index = 0x20 | (mda->crtcreg & 0x1f); + if (vid->operation_ctrl & 0x80) nmi = 1; + vid->reg_3df = val; + return; + } + old = mda->crtc[mda->crtcreg]; + mda->crtc[mda->crtcreg] = val & crtc_mask[mda->crtcreg]; + if (old != val) { + if (mda->crtcreg < 0xe || mda->crtcreg > 0x10) { + fullchange = changeframecount; + mda_recalctimings(mda); + } + } + return; + case 0x3b8: + old = mda->ctrl; + mda->ctrl = val; + if ((mda->ctrl ^ old) & 3) + mda_recalctimings(mda); + vid->crtc_index &= 0x1F; + vid->crtc_index |= 0x80; + if (vid->operation_ctrl & 0x80) + nmi = 1; + return; - vid->plane_write = 0x20 | (cga->crtcreg & 0x1f); - vid->border = val; +/* CGA writes ============================================================== */ + case 0x03d1: + case 0x03d3: + case 0x03d5: + case 0x03d7: + if (!(vid->operation_ctrl & 0x40) && cga->crtcreg <= 11) { + vid->crtc_index = 0x20 | (cga->crtcreg & 0x1f); + if (vid->operation_ctrl & 0x80) + nmi = 1; + vid->reg_3df = val; return; } old = cga->crtc[cga->crtcreg]; @@ -792,49 +1136,437 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) old = cga->cgamode; cga->cgamode = val; if ((cga->cgamode ^ old) & 3) - cga_recalctimings(cga); - vid->plane_write |= 0x80; - if (vid->plane_read & 0x80) + cga_recalctimings(cga); + vid->crtc_index &= 0x1f; + vid->crtc_index |= 0x80; + if (vid->operation_ctrl & 0x80) nmi = 1; + else + set_lcd_cols(val); return; +/* PC200 control port writes ============================================== */ case 0x03de: - vid->plane_read = val; - vid->plane_write = 0x1f; - if (val & 0x80) - vid->plane_write |= 0x40; + vid->crtc_index = 0x1f; + /* NMI only seems to be triggered if the value being written has the high + * bit set (enable NMI). So it only protects writes to this port if you + * let it? */ + if (val & 0x80) { + vid->operation_ctrl = val; + vid->crtc_index |= 0x40; + nmi = 1; + return; + } + timer_disable(&vid->cga.timer); + timer_disable(&vid->mda.timer); + timer_disable(&vid->timer); + vid->operation_ctrl = val; + /* Bits 0 and 1 control emulation and output mode */ + amstrad_log("emulation and mode = %02X\n", val & 0x03); + if (val & 1) /* Monitor */ + vid->emulation = (val & 2) ? PC200_MDA : PC200_CGA; + else if (vid->type == AMS_PPC512) + vid->emulation = (val & 2) ? PC200_LCDM : PC200_LCDC; + else + vid->emulation = PC200_TV; + if (vid->emulation == PC200_CGA || vid->emulation == PC200_TV) + timer_advance_u64(&vid->cga.timer, 1); + else if (vid->emulation == PC200_MDA) + timer_advance_u64(&vid->mda.timer, 1); + else + timer_advance_u64(&vid->timer, 1); + + /* Bit 2 disables the IDA. We don't support dynamic enabling + * and disabling of the IDA (instead, PCEM disconnects the + * IDA from the bus altogether) so don't implement this */ + + /* Enable the appropriate memory ranges depending whether + * the IDA is configured as MDA or CGA */ + if (vid->emulation == PC200_MDA || + vid->emulation == PC200_LCDM) { + mem_mapping_disable(&vid->cga.mapping); + mem_mapping_enable(&vid->mda.mapping); + } + else { + mem_mapping_disable(&vid->mda.mapping); + mem_mapping_enable(&vid->cga.mapping); + } return; } - cga_out(addr, val, cga); + if (addr >= 0x3D0 && addr <= 0x3DF) + cga_out(addr, val, cga); + + if (addr >= 0x3B0 && addr <= 0x3BB) + mda_out(addr, val, mda); } -static uint8_t -vid_in_200(uint16_t addr, void *priv) +static void +lcd_draw_char_80(amsvid_t *vid, uint32_t *buffer, uint8_t chr, + uint8_t attr, int drawcursor, int blink, int sc, + int mode160, uint8_t control) { - amsvid_t *vid = (amsvid_t *)priv; - cga_t *cga = &vid->cga; - uint8_t ret; + int c; + uint8_t bits = fontdat[chr + vid->cga.fontbase][sc]; + uint8_t bright = 0; + uint16_t mask; - switch (addr) { - case 0x03d8: - return(cga->cgamode); - - case 0x03dd: - ret = vid->plane_write; - vid->plane_write &= 0x1f; - nmi = 0; - return(ret); - - case 0x03de: - return((vid->plane_read & 0xc7) | 0x10); /*External CGA*/ - - case 0x03df: - return(vid->border); + if (attr & 8) { /* bright */ + /* The brightness algorithm appears to be: replace any bit sequence 011 + * with 001 (assuming an extra 0 to the left of the byte). + */ + bright = bits; + for (c = 0, mask = 0x100; c < 7; c++, mask >>= 1) { + if (((bits & mask) == 0) && ((bits & (mask >> 1)) != 0) && + ((bits & (mask >> 2)) != 0)) + bright &= ~(mask >> 1); + } + bits = bright; } - return(cga_in(addr, cga)); + if (drawcursor) bits ^= 0xFF; + + for (c = 0, mask = 0x80; c < 8; c++, mask >>= 1) { + if (mode160) buffer[c] = (attr & mask) ? blue : green; + else if (control & 0x20) /* blinking */ + buffer[c] = lcdcols[attr & 0x7F][blink][(bits & mask) ? 1 : 0]; + else buffer[c] = lcdcols[attr][blink][(bits & mask) ? 1 : 0]; + } +} + + +static void +lcd_draw_char_40(amsvid_t *vid, uint32_t *buffer, uint8_t chr, + uint8_t attr, int drawcursor, int blink, int sc, + uint8_t control) +{ + int c; + uint8_t bits = fontdat[chr + vid->cga.fontbase][sc]; + uint8_t mask = 0x80; + + if (attr & 8) /* bright */ + bits = bits & (bits >> 1); + if (drawcursor) bits ^= 0xFF; + + for (c = 0; c < 8; c++, mask >>= 1) { + if (control & 0x20) { + buffer[c*2] = buffer[c*2+1] = + lcdcols[attr & 0x7F][blink][(bits & mask) ? 1 : 0]; + } else { + buffer[c*2] = buffer[c*2+1] = + lcdcols[attr][blink][(bits & mask) ? 1 : 0]; + } + } +} + + +static void +lcdm_poll(amsvid_t *vid) +{ + mda_t *mda = &vid->mda; + uint16_t ca = (mda->crtc[15] | (mda->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x; + int oldvc; + uint8_t chr, attr; + int oldsc; + int blink; + + if (!mda->linepos) { + timer_advance_u64(&vid->timer, mda->dispofftime); + mda->stat |= 1; + mda->linepos = 1; + oldsc = mda->sc; + if ((mda->crtc[8] & 3) == 3) + mda->sc = (mda->sc << 1) & 7; + if (mda->dispon) { + if (mda->displine < mda->firstline) + mda->firstline = mda->displine; + mda->lastline = mda->displine; + for (x = 0; x < mda->crtc[1]; x++) { + chr = mda->vram[(mda->ma << 1) & 0xfff]; + attr = mda->vram[((mda->ma << 1) + 1) & 0xfff]; + drawcursor = ((mda->ma == ca) && mda->con && mda->cursoron); + blink = ((mda->blink & 16) && (mda->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + + lcd_draw_char_80(vid, &((uint32_t *)(buffer32->line[mda->displine]))[x * 8], chr, attr, drawcursor, blink, mda->sc, 0, mda->ctrl); + mda->ma++; + } + } + mda->sc = oldsc; + if (mda->vc == mda->crtc[7] && !mda->sc) + mda->stat |= 8; + mda->displine++; + if (mda->displine >= 500) + mda->displine=0; + } else { + timer_advance_u64(&vid->timer, mda->dispontime); + if (mda->dispon) mda->stat&=~1; + mda->linepos=0; + if (mda->vsynctime) { + mda->vsynctime--; + if (!mda->vsynctime) + mda->stat&=~8; + } + if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) { + mda->con = 0; + mda->coff = 1; + } + if (mda->vadj) { + mda->sc++; + mda->sc &= 31; + mda->ma = mda->maback; + mda->vadj--; + if (!mda->vadj) { + mda->dispon = 1; + mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; + mda->sc = 0; + } + } else if (mda->sc == mda->crtc[9] || ((mda->crtc[8] & 3) == 3 && mda->sc == (mda->crtc[9] >> 1))) { + mda->maback = mda->ma; + mda->sc = 0; + oldvc = mda->vc; + mda->vc++; + mda->vc &= 127; + if (mda->vc == mda->crtc[6]) + mda->dispon=0; + if (oldvc == mda->crtc[4]) { + mda->vc = 0; + mda->vadj = mda->crtc[5]; + if (!mda->vadj) mda->dispon = 1; + if (!mda->vadj) mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; + if ((mda->crtc[10] & 0x60) == 0x20) mda->cursoron = 0; + else mda->cursoron = mda->blink & 16; + } + if (mda->vc == mda->crtc[7]) { + mda->dispon = 0; + mda->displine = 0; + mda->vsynctime = 16; + if (mda->crtc[7]) { + x = mda->crtc[1] * 8; + mda->lastline++; + if ((x != xsize) || ((mda->lastline - mda->firstline) != ysize) || video_force_resize_get()) { + xsize = x; + ysize = mda->lastline - mda->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(0, mda->firstline, 0, ysize, xsize, ysize); + frames++; + video_res_x = mda->crtc[1]; + video_res_y = mda->crtc[6]; + video_bpp = 0; + } + mda->firstline = 1000; + mda->lastline = 0; + mda->blink++; + } + } else { + mda->sc++; + mda->sc &= 31; + mda->ma = mda->maback; + } + if ((mda->sc == (mda->crtc[10] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[10] & 31) >> 1)))) + mda->con = 1; + } +} + + +static void +lcdc_poll(amsvid_t *vid) +{ + cga_t *cga = &vid->cga; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int oldsc; + uint16_t ca; + int blink; + + ca = (cga->crtc[15] | (cga->crtc[14] << 8)) & 0x3fff; + + if (!cga->linepos) { + timer_advance_u64(&vid->timer, cga->dispofftime); + cga->cgastat |= 1; + cga->linepos = 1; + oldsc = cga->sc; + if ((cga->crtc[8] & 3) == 3) + cga->sc = ((cga->sc << 1) + cga->oddeven) & 7; + if (cga->cgadispon) { + if (cga->displine < cga->firstline) { + cga->firstline = cga->displine; + video_wait_for_buffer(); + } + cga->lastline = cga->displine; + + if (cga->cgamode & 1) { + for (x = 0; x < cga->crtc[1]; x++) { + chr = cga->charbuffer[x << 1]; + attr = cga->charbuffer[(x << 1) + 1]; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + blink = ((cga->cgablink & 16) && (cga->cgamode & 0x20) && (attr & 0x80) && !drawcursor); + lcd_draw_char_80(vid, &((uint32_t *)(buffer32->line[cga->displine]))[x * 8], chr, attr, drawcursor, blink, cga->sc, cga->cgamode & 0x40, cga->cgamode); + cga->ma++; + } + } else if (!(cga->cgamode & 2)) { + for (x = 0; x < cga->crtc[1]; x++) { + chr = cga->vram[((cga->ma << 1) & 0x3fff)]; + attr = cga->vram[(((cga->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + blink = ((cga->cgablink & 16) && (cga->cgamode & 0x20) && (attr & 0x80) && !drawcursor); + lcd_draw_char_40(vid, &((uint32_t *)(buffer32->line[cga->displine]))[x * 16], chr, attr, drawcursor, blink, cga->sc, cga->cgamode); + cga->ma++; + } + } else { /* Graphics mode */ + for (x = 0; x < cga->crtc[1]; x++) { + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + cga->ma++; + for (c = 0; c < 16; c++) { + ((uint32_t *)buffer32->line[cga->displine])[(x << 4) + c] = (dat & 0x8000) ? blue : green; + dat <<= 1; + } + } + } + } else { + if (cga->cgamode & 1) hline(buffer32, 0, cga->displine, (cga->crtc[1] << 3), green); + else hline(buffer32, 0, cga->displine, (cga->crtc[1] << 4), green); + } + + if (cga->cgamode & 1) x = (cga->crtc[1] << 3); + else x = (cga->crtc[1] << 4); + + cga->sc = oldsc; + if (cga->vc == cga->crtc[7] && !cga->sc) + cga->cgastat |= 8; + cga->displine++; + if (cga->displine >= 360) + cga->displine = 0; + } else { + timer_advance_u64(&vid->timer, cga->dispontime); + cga->linepos = 0; + if (cga->vsynctime) { + cga->vsynctime--; + if (!cga->vsynctime) + cga->cgastat &= ~8; + } + if (cga->sc == (cga->crtc[11] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[11] & 31) >> 1))) { + cga->con = 0; + cga->coff = 1; + } + if ((cga->crtc[8] & 3) == 3 && cga->sc == (cga->crtc[9] >> 1)) + cga->maback = cga->ma; + if (cga->vadj) { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + cga->vadj--; + if (!cga->vadj) { + cga->cgadispon = 1; + cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + cga->sc = 0; + } + } else if (cga->sc == cga->crtc[9]) { + cga->maback = cga->ma; + cga->sc = 0; + oldvc = cga->vc; + cga->vc++; + cga->vc &= 127; + + if (cga->vc == cga->crtc[6]) + cga->cgadispon = 0; + + if (oldvc == cga->crtc[4]) { + cga->vc = 0; + cga->vadj = cga->crtc[5]; + if (!cga->vadj) cga->cgadispon = 1; + if (!cga->vadj) cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + if ((cga->crtc[10] & 0x60) == 0x20) cga->cursoron = 0; + else cga->cursoron = cga->cgablink & 8; + } + + if (cga->vc == cga->crtc[7]) { + cga->cgadispon = 0; + cga->displine = 0; + cga->vsynctime = 16; + if (cga->crtc[7]) { + if (cga->cgamode & 1) x = (cga->crtc[1] << 3); + else x = (cga->crtc[1] << 4); + cga->lastline++; + if ((cga->cgamode & 8) && x && (cga->lastline - cga->firstline) && + ((x != xsize) || (((cga->lastline - cga->firstline) << 1) != ysize) || + video_force_resize_get())) { + xsize = x; + ysize = (cga->lastline - cga->firstline) << 1; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 400; + set_screen_size(xsize, ysize + 16); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + video_blit_memtoscreen(0, cga->firstline, 0, (cga->lastline - cga->firstline), + xsize, (cga->lastline - cga->firstline)); + frames++; + + video_res_x = xsize - 16; + video_res_y = ysize; + if (cga->cgamode & 1) { + video_res_x /= 8; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } else if (!(cga->cgamode & 2)) { + video_res_x /= 16; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } else if (!(cga->cgamode & 16)) { + video_res_x /= 2; + video_bpp = 2; + } else + video_bpp = 1; + } + cga->firstline = 1000; + cga->lastline = 0; + cga->cgablink++; + cga->oddeven ^= 1; + } + } else { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + } + if (cga->cgadispon) + cga->cgastat &= ~1; + if ((cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1)))) + cga->con = 1; + if (cga->cgadispon && (cga->cgamode & 1)) { + for (x = 0; x < (cga->crtc[1] << 1); x++) + cga->charbuffer[x] = cga->vram[(((cga->ma << 1) + x) & 0x3fff)]; + } + } +} + + +static void +vid_poll_200(void *p) +{ + amsvid_t *vid = (amsvid_t *)p; + + switch (vid->emulation) { + case PC200_LCDM: + lcdm_poll(vid); + return; + case PC200_LCDC: + lcdc_poll(vid); + return; + } } @@ -843,26 +1575,81 @@ vid_init_200(amstrad_t *ams) { amsvid_t *vid; cga_t *cga; + mda_t *mda; /* Allocate a video controller block. */ vid = (amsvid_t *)malloc(sizeof(amsvid_t)); memset(vid, 0x00, sizeof(amsvid_t)); - video_inform(VIDEO_FLAG_TYPE_CGA, &timing_pc200); + vid->emulation = device_get_config_int("video_emulation"); + cga_palette = (device_get_config_int("display_type") << 1); + ams_inform(vid); + + /* Default to CGA */ + vid->dipswitches = 0x10; + vid->type = ams->type; + + if (ams->type == AMS_PC200) switch (vid->emulation) { + /* DIP switches for PC200. Switches 2,3 give video emulation. + * Switch 1 is 'swap floppy drives' (not implemented) */ + case PC200_CGA: vid->dipswitches = 0x10; break; + case PC200_MDA: vid->dipswitches = 0x30; break; + case PC200_TV: vid->dipswitches = 0x00; break; + /* The other combination is 'IDA disabled' (0x20) - see + * m_amstrad.c */ + } else switch (vid->emulation) { + /* DIP switches for PPC512. Switch 1 is CRT/LCD. Switch 2 + * is MDA / CGA. Switch 3 disables IDA, not implemented. */ + /* 1 = on, 0 = off + SW1: off = crt, on = lcd; + SW2: off = mda, on = cga; + SW3: off = disable built-in card, on = enable */ + case PC200_CGA: vid->dipswitches = 0x08; break; + case PC200_MDA: vid->dipswitches = 0x18; break; + case PC200_LCDC: vid->dipswitches = 0x00; break; + case PC200_LCDM: vid->dipswitches = 0x10; break; + } cga = &vid->cga; - cga->vram = malloc(0x4000); + mda = &vid->mda; + cga->vram = mda->vram = malloc(0x4000); cga_init(cga); + mda_init(mda); + /* Attribute 8 is white on black (on a real MDA it's black on black) */ + mda_setcol(0x08, 0, 1, 15); + mda_setcol(0x88, 0, 1, 15); + /* Attribute 64 is black on black (on a real MDA it's white on black) */ + mda_setcol(0x40, 0, 1, 0); + mda_setcol(0xC0, 0, 1, 0); + + cga->fontbase = (device_get_config_int("codepage") & 3) * 256; + + timer_add(&vid->timer, vid_poll_200, vid, 1); + mem_mapping_add(&vid->mda.mapping, 0xb0000, 0x08000, + mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, 0, mda); mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, - cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); - io_sethandler(0x03d0, 16, - vid_in_200, NULL, NULL, vid_out_200, NULL, NULL, vid); - - timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); + cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); + io_sethandler(0x03d0, 16, vid_in_200, NULL, NULL, vid_out_200, NULL, NULL, vid); + io_sethandler(0x03b0, 0x000c, vid_in_200, NULL, NULL, vid_out_200, NULL, NULL, vid); overscan_x = overscan_y = 16; + green = makecol(0x1C, 0x71, 0x31); + blue = makecol(0x0f, 0x21, 0x3f); + cgapal_rebuild(); + set_lcd_cols(0); + + timer_disable(&vid->cga.timer); + timer_disable(&vid->mda.timer); + timer_disable(&vid->timer); + if (vid->emulation == PC200_CGA || vid->emulation == PC200_TV) + timer_enable(&vid->cga.timer); + else if (vid->emulation == PC200_MDA) + timer_enable(&vid->mda.timer); + else + timer_enable(&vid->timer); + ams->vid = vid; } @@ -873,18 +1660,114 @@ vid_close_200(void *priv) amsvid_t *vid = (amsvid_t *)priv; free(vid->cga.vram); + free(vid->mda.vram); free(vid); } -static void -vid_speed_changed_200(void *priv) +device_config_t vid_200_config[] = { - amsvid_t *vid = (amsvid_t *)priv; - - cga_recalctimings(&vid->cga); -} + /* TODO: Should have options here for: + * + * > Display port (TTL or RF) + */ + { + "video_emulation", "Display type", CONFIG_SELECTION, "", PC200_CGA, + { + { + "CGA monitor", PC200_CGA + }, + { + "MDA monitor", PC200_MDA + }, + { + "Television", PC200_TV + }, + { + "" + } + } + }, + { + "display_type", "Monitor type", CONFIG_SELECTION, "", 0, + { + { + "RGB", 0 + }, + { + "RGB (no brown)", 4 + }, + { + "Green Monochrome", 1 + }, + { + "Amber Monochrome", 2 + }, + { + "White Monochrome", 3 + }, + { + "" + } + } + }, + { + "codepage", "Hardware font", CONFIG_SELECTION, "", 3, + { + { + "US English", 3 + }, + { + "Portugese", 2 + }, + { + "Norwegian", 1 + }, + { + "Greek", 0 + }, + { + "" + } + } + }, + { + "language", "BIOS language", CONFIG_SELECTION, "", 7, + { + { + "English", 7 + }, + { + "German", 6 + }, + { + "French", 5 + }, + { + "Spanish", 4 + }, + { + "Danish", 3 + }, + { + "Swedish", 2 + }, + { + "Italian", 1 + }, + { + "Diagnostic mode", 0 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; static const device_t vid_200_device = { @@ -893,10 +1776,220 @@ static const device_t vid_200_device = { NULL, vid_close_200, NULL, NULL, vid_speed_changed_200, - NULL + NULL, + vid_200_config }; +const device_t * +pc200_get_device(void) +{ + return(&vid_200_device); +} + + +device_config_t vid_ppc512_config[] = +{ + /* TODO: Should have options here for: + * + * > Display port (TTL or RF) + */ + { + "video_emulation", "Display type", CONFIG_SELECTION, "", PC200_LCDC, + { + { + "CGA monitor", PC200_CGA + }, + { + "MDA monitor", PC200_MDA + }, + { + "LCD (CGA mode)", PC200_LCDC + }, + { + "LCD (MDA mode)", PC200_LCDM + }, + { + "" + } + }, + }, + { + "display_type", "Monitor type", CONFIG_SELECTION, "", 0, + { + { + "RGB", 0 + }, + { + "RGB (no brown)", 4 + }, + { + "Green Monochrome", 1 + }, + { + "Amber Monochrome", 2 + }, + { + "White Monochrome", 3 + }, + { + "" + } + }, + }, + { + "codepage", "Hardware font", CONFIG_SELECTION, "", 3, + { + { + "US English", 3 + }, + { + "Portugese", 2 + }, + { + "Norwegian",1 + }, + { + "Greek", 0 + }, + { + "" + } + }, + }, + { + "language", "BIOS language", CONFIG_SELECTION, "", 7, + { + { + "English", 7 + }, + { + "German", 6 + }, + { + "French", 5 + }, + { + "Spanish", 4 + }, + { + "Danish", 3 + }, + { + "Swedish", 2 + }, + { + "Italian", 1 + }, + { + "Diagnostic mode", 0 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_t vid_ppc512_device = { + "Amstrad PPC512 (video)", + 0, 0, + NULL, vid_close_200, NULL, + NULL, + vid_speed_changed_200, + NULL, + vid_ppc512_config +}; + + +const device_t * +ppc512_get_device(void) +{ + return(&vid_ppc512_device); +} + + +device_config_t vid_pc2086_config[] = +{ + { + "language", "BIOS language", CONFIG_SELECTION, "", 7, + { + { + "English", 7 + }, + { + "Diagnostic mode", 0 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_t vid_pc2086_device = { + "Amstrad PC2086", + 0, 0, + NULL, NULL, NULL, + NULL, + NULL, + NULL, + vid_pc2086_config +}; + + +const device_t * +pc2086_get_device(void) +{ + return(&vid_pc2086_device); +} + + +device_config_t vid_pc3086_config[] = +{ + { + "language", "BIOS language", CONFIG_SELECTION, "", 7, + { + { + "English", 7 + }, + { + "Diagnostic mode", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_t vid_pc3086_device = { + "Amstrad PC3086", + 0, 0, + NULL, NULL, NULL, + NULL, + NULL, + NULL, + vid_pc3086_config +}; + + +const device_t * +pc3086_get_device(void) +{ + return(&vid_pc3086_device); +} + + static void ms_write(uint16_t addr, uint8_t val, void *priv) { @@ -992,9 +2085,6 @@ kbd_write(uint16_t port, uint8_t val, void *priv) ams->pb = val; ppi.pb = val; - timer_process(); - timer_update_outstanding(); - speaker_update(); speaker_gated = val & 0x01; speaker_enable = val & 0x02; @@ -1060,12 +2150,12 @@ kbd_read(uint16_t port, void *priv) * 2. The ROS then sets the initial VDU state based * on the DDM value. */ - ret = (0x0d | ams->stat1) & 0x7f; + ret = (ams->stat1 | 0x0d) & 0x7f; } else { ret = ams->pa; - if (key_queue_start == key_queue_end) { + if (key_queue_start == key_queue_end) ams->wantirq = 0; - } else { + else { ams->key_waiting = key_queue[key_queue_start]; key_queue_start = (key_queue_start + 1) & 0xf; ams->wantirq = 1; @@ -1105,7 +2195,7 @@ kbd_read(uint16_t port, void *priv) */ if (ams->pb & 0x04) ret = ams->stat2 & 0x0f; - else + else ret = ams->stat2 >> 4; ret |= (ppispeakon ? 0x20 : 0); if (nmi) @@ -1124,8 +2214,8 @@ static void kbd_poll(void *priv) { amstrad_t *ams = (amstrad_t *)priv; - - keyboard_delay += (1000 * TIMER_USEC); + + timer_advance_u64(&ams->send_delay_timer, 1000 * TIMER_USEC); if (ams->wantirq) { ams->wantirq = 0; @@ -1150,6 +2240,12 @@ ams_write(uint16_t port, uint8_t val, void *priv) amstrad_t *ams = (amstrad_t *)priv; switch (port) { + case 0x0378: + case 0x0379: + case 0x037a: + lpt_write(port, val, &lpt_ports[0]); + break; + case 0xdead: ams->dead = val; break; @@ -1164,34 +2260,71 @@ ams_read(uint16_t port, void *priv) uint8_t ret = 0xff; switch (port) { + case 0x0378: + ret = lpt_read(port, &lpt_ports[0]); + break; + case 0x0379: /* printer control, also set LK1-3. - * 0 English Language. - * 1 German Language. - * 2 French Language. - * 3 Spanish Language. - * 4 Danish Language. - * 5 Swedish Language. - * 6 Italian Language. - * 7 Diagnostic Mode. + * per John Elliott's site, this is xor'ed with 0x07 + * 7 English Language. + * 6 German Language. + * 5 French Language. + * 4 Spanish Language. + * 3 Danish Language. + * 2 Swedish Language. + * 1 Italian Language. + * 0 Diagnostic Mode. */ - ret = 0x02; /* ENGLISH. no Diags mode */ + ret = (lpt_read(port, &lpt_ports[0]) & 0xf8) | ams->language; break; case 0x037a: /* printer status */ - switch(romset) { - case ROM_PC1512: - ret = 0x20; + ret = lpt_read(port, &lpt_ports[0]) & 0x1f; + + switch(ams->type) { + case AMS_PC1512: + ret |= 0x20; break; - case ROM_PC200: - ret = 0x80; + case AMS_PC200: + case AMS_PPC512: + if (video_is_cga()) + ret |= 0x80; + else if (video_is_mda()) + ret |= 0xc0; + + if (fdc_read(0x037f, ams->fdc) & 0x80) + ret |= 0x20; + break; + + case AMS_PC1640: + if (video_is_cga()) + ret |= 0x80; + else if (video_is_mda()) + ret |= 0xc0; + + switch (amstrad_latch) { + case AMSTRAD_NOLATCH: + ret &= ~0x20; + break; + case AMSTRAD_SW9: + ret &= ~0x20; + break; + case AMSTRAD_SW10: + ret |= 0x20; + break; + } break; default: - ret = 0x00; + break; } break; + case 0x03de: + ret = 0x20; + break; + case 0xdead: ret = ams->dead; break; @@ -1201,8 +2334,8 @@ ams_read(uint16_t port, void *priv) } -void -machine_amstrad_init(const machine_t *model) +static void +machine_amstrad_init(const machine_t *model, int type) { amstrad_t *ams; @@ -1215,10 +2348,11 @@ machine_amstrad_init(const machine_t *model) nmi_init(); - lpt2_remove_ams(); + lpt1_remove_ams(); + lpt2_remove(); - io_sethandler(0x0379, 2, - ams_read, NULL, NULL, NULL, NULL, NULL, ams); + io_sethandler(0x0378, 3, + ams_read, NULL, NULL, ams_write, NULL, NULL, ams); io_sethandler(0xdead, 1, ams_read, NULL, NULL, ams_write, NULL, NULL, ams); @@ -1229,70 +2363,82 @@ machine_amstrad_init(const machine_t *model) io_sethandler(0x007a, 1, ms_read, NULL, NULL, ms_write, NULL, NULL, ams); -// device_add(&fdc_at_actlow_device); + ams->type = type; - switch(romset) { - case ROM_PC1512: - device_add(&fdc_xt_device); + switch(type) { + case AMS_PC1512: + case AMS_PC1640: + case AMS_PC200: + case AMS_PPC512: + ams->fdc = device_add(&fdc_xt_device); break; - case ROM_PC1640: - device_add(&fdc_xt_device); - break; - - case ROM_PC200: - device_add(&fdc_xt_device); - break; - - case ROM_PC2086: - device_add(&fdc_at_actlow_device); - break; - - case ROM_PC3086: - device_add(&fdc_at_actlow_device); - break; - - case ROM_MEGAPC: - device_add(&fdc_at_actlow_device); + case AMS_PC2086: + case AMS_PC3086: + ams->fdc = device_add(&fdc_at_actlow_device); break; } - if (gfxcard == VID_INTERNAL) switch(romset) { - case ROM_PC1512: - loadfont(L"roms/machines/pc1512/40078", 2); + ams->language = 7; + + if (gfxcard == VID_INTERNAL) switch(type) { + case AMS_PC1512: + loadfont(L"roms/machines/pc1512/40078", 8); + device_context(&vid_1512_device); + ams->language = device_get_config_int("language"); vid_init_1512(ams); + device_context_restore(); device_add_ex(&vid_1512_device, ams->vid); break; - - case ROM_PC1640: + + case AMS_PPC512: + loadfont(L"roms/machines/ppc512/40109", 1); + device_context(&vid_ppc512_device); + ams->language = device_get_config_int("language"); + vid_init_200(ams); + device_context_restore(); + device_add_ex(&vid_ppc512_device, ams->vid); + break; + + case AMS_PC1640: + device_context(&vid_1640_device); + ams->language = device_get_config_int("language"); vid_init_1640(ams); + device_context_restore(); device_add_ex(&vid_1640_device, ams->vid); break; - case ROM_PC200: - loadfont(L"roms/machines/pc200/40109.bin", 1); + case AMS_PC200: + loadfont(L"roms/machines/pc200/40109", 1); + device_context(&vid_200_device); + ams->language = device_get_config_int("language"); vid_init_200(ams); + device_context_restore(); device_add_ex(&vid_200_device, ams->vid); break; - case ROM_PC2086: + case AMS_PC2086: + device_context(&vid_pc2086_device); + ams->language = device_get_config_int("language"); + device_context_restore(); device_add(¶dise_pvga1a_pc2086_device); break; - case ROM_PC3086: + case AMS_PC3086: + device_context(&vid_pc3086_device); + ams->language = device_get_config_int("language"); + device_context_restore(); device_add(¶dise_pvga1a_pc3086_device); break; - - case ROM_MEGAPC: - device_add(¶dise_wd90c11_megapc_device); - break; - } + } else if ((type == AMS_PC200) || (type == AMS_PPC512)) + io_sethandler(0x03de, 1, + ams_read, NULL, NULL, ams_write, NULL, NULL, ams); /* Initialize the (custom) keyboard/mouse interface. */ ams->wantirq = 0; - io_sethandler(0x0060, 7, + io_sethandler(0x0060, 6, kbd_read, NULL, NULL, kbd_write, NULL, NULL, ams); - timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, ams); + timer_add(&ams->send_delay_timer, kbd_poll, ams, 1); keyboard_set_table(scancode_xt); keyboard_send = kbd_adddata_ex; keyboard_scan = 1; @@ -1304,3 +2450,116 @@ machine_amstrad_init(const machine_t *model) if (joystick_type != 7) device_add(&gameport_device); } + + +int +machine_pc1512_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/pc1512/40044", + L"roms/machines/pc1512/40043", + 0x000fc000, 16384, 0); + ret &= rom_present(L"roms/machines/pc1512/40078"); + + if (bios_only || !ret) + return ret; + + machine_amstrad_init(model, AMS_PC1512); + + return ret; +} + + +int +machine_pc1640_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/pc1640/40044.v3", + L"roms/machines/pc1640/40043.v3", + 0x000fc000, 16384, 0); + ret &= rom_present(L"roms/machines/pc1640/40100"); + + if (bios_only || !ret) + return ret; + + machine_amstrad_init(model, AMS_PC1640); + + return ret; +} + + +int +machine_pc200_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/pc200/pc20v2.1", + L"roms/machines/pc200/pc20v2.0", + 0x000fc000, 16384, 0); + ret &= rom_present(L"roms/machines/pc200/40109"); + + if (bios_only || !ret) + return ret; + + machine_amstrad_init(model, AMS_PC200); + + return ret; +} + + +int +machine_ppc512_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/ppc512/40107.v2", + L"roms/machines/ppc512/40108.v2", + 0x000fc000, 16384, 0); + ret &= rom_present(L"roms/machines/ppc512/40109"); + + if (bios_only || !ret) + return ret; + + machine_amstrad_init(model, AMS_PPC512); + + return ret; +} + + +int +machine_pc2086_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleavedr(L"roms/machines/pc2086/40179.ic129", + L"roms/machines/pc2086/40180.ic132", + 0x000fc000, 65536, 0); + ret &= rom_present(L"roms/machines/pc2086/40186.ic171"); + + if (bios_only || !ret) + return ret; + + machine_amstrad_init(model, AMS_PC2086); + + return ret; +} + + +int +machine_pc3086_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linearr(L"roms/machines/pc3086/fc00.bin", + 0x000fc000, 65536, 0); + ret &= rom_present(L"roms/machines/pc3086/c000.bin"); + + if (bios_only || !ret) + return ret; + + machine_amstrad_init(model, AMS_PC3086); + + return ret; +} diff --git a/src/machine/m_amstrad.h b/src/machine/m_amstrad.h new file mode 100644 index 000000000..d85c3375b --- /dev/null +++ b/src/machine/m_amstrad.h @@ -0,0 +1,26 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header of the emulation of the Amstrad series of PC's: + * PC1512, PC1640 and PC200, including their keyboard, mouse and + * video devices, as well as the PC2086 and PC3086 systems. + * + * Version: @(#)m_amstrad.h 1.0.0 2019/03/21 + * + * Authors: Sarah Walker, + * + * Copyright 2008-2019 Sarah Walker. + */ +extern int amstrad_latch; + +enum +{ + AMSTRAD_NOLATCH, + AMSTRAD_SW9, + AMSTRAD_SW10 +}; diff --git a/src/machine/m_at.c b/src/machine/m_at.c index b35d40e6f..8c775ef0f 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -41,6 +41,7 @@ #include #include #include "../86box.h" +#include "../timer.h" #include "../pic.h" #include "../pit.h" #include "../dma.h" @@ -52,12 +53,13 @@ #include "../game/gameport.h" #include "../keyboard.h" #include "../lpt.h" +#include "../rom.h" #include "../disk/hdc.h" #include "machine.h" void -machine_at_common_init(const machine_t *model) +machine_at_common_init_ex(const machine_t *model, int is_ibm) { machine_common_init(model); @@ -65,16 +67,23 @@ machine_at_common_init(const machine_t *model) pic2_init(); dma16_init(); - if (lpt_enabled) - lpt2_remove(); - - device_add(&at_nvr_device); + if (is_ibm) + device_add(&ibmat_nvr_device); + else + device_add(&at_nvr_device); if (joystick_type != 7) device_add(&gameport_device); } +void +machine_at_common_init(const machine_t *model) +{ + machine_at_common_init_ex(model, 0); +} + + void machine_at_init(const machine_t *model) { @@ -84,22 +93,10 @@ machine_at_init(const machine_t *model) } -void -machine_at_ibm_init(const machine_t *model) +static void +machine_at_ibm_common_init(const machine_t *model) { - machine_common_init(model); - - pit_set_out_func(&pit, 1, pit_refresh_timer_at); - pic2_init(); - dma16_init(); - - if (lpt_enabled) - lpt2_remove(); - - device_add(&ibmat_nvr_device); - - if (joystick_type != 7) - device_add(&gameport_device); + machine_at_common_init_ex(model, 1); device_add(&keyboard_at_device); @@ -108,6 +105,7 @@ machine_at_ibm_init(const machine_t *model) device_add(&fdc_at_device); } + void machine_at_ps2_init(const machine_t *model) { @@ -122,7 +120,16 @@ machine_at_common_ide_init(const machine_t *model) { machine_at_common_init(model); - device_add(&ide_isa_2ch_opt_device); + device_add(&ide_isa_device); +} + + +void +machine_at_ibm_common_ide_init(const machine_t *model) +{ + machine_at_common_init_ex(model, 1); + + device_add(&ide_isa_device); } @@ -131,7 +138,7 @@ machine_at_ide_init(const machine_t *model) { machine_at_init(model); - device_add(&ide_isa_2ch_opt_device); + device_add(&ide_isa_device); } @@ -140,5 +147,60 @@ machine_at_ps2_ide_init(const machine_t *model) { machine_at_ps2_init(model); - device_add(&ide_isa_2ch_opt_device); + device_add(&ide_isa_device); } + + +int +machine_at_ibm_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmat/62x0820.u27", + L"roms/machines/ibmat/62x0821.u47", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ibm_common_init(model); + + return ret; +} + + +int +machine_at_ibmxt286_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmxt286/bios_5162_21apr86_u34_78x7460_27256.bin", + L"roms/machines/ibmxt286/bios_5162_21apr86_u35_78x7461_27256.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ibm_common_init(model); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_OPEN_AT) +int +machine_at_open_at_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/open_at/bios.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ibm_common_init(model); + + return ret; +} +#endif diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c new file mode 100644 index 000000000..06b542800 --- /dev/null +++ b/src/machine/m_at_286_386sx.c @@ -0,0 +1,318 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of 286 and 386SX machines. + * + * Version: @(#)m_at_286_386sx.c 1.0.0 2019/05/16 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../timer.h" +#include "../io.h" +#include "../device.h" +#include "../chipset/chipset.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../rom.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../disk/hdc.h" +#include "../video/video.h" +#include "../video/vid_et4000.h" +#include "../video/vid_oak_oti.h" +#include "../video/vid_paradise.h" +#include "machine.h" + + +static void +machine_at_headland_common_init(int ht386) +{ + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); + + if (ht386) + device_add(&headland_386_device); + else + device_add(&headland_device); +} + + +#if defined(DEV_BRANCH) && defined(USE_AMI386SX) +int +machine_at_headland_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ami386/ami386.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + machine_at_headland_common_init(1); + + return ret; +} +#endif + + +int +machine_at_tg286m_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/tg286m/ami.bin", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + machine_at_headland_common_init(0); + + return ret; +} + + +const device_t * +at_ama932j_get_device(void) +{ + return &oti067_ama932j_device; +} + + +int +machine_at_ama932j_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ama932j/ami.bin", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + machine_at_headland_common_init(1); + + if (gfxcard == VID_INTERNAL) + device_add(&oti067_ama932j_device); + + return ret; +} + + +int +machine_at_neat_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/dtk386/3cto001.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_init(model); + + device_add(&neat_device); + device_add(&fdc_at_device); + + return ret; +} + + +int +machine_at_neat_ami_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ami286/amic206.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + device_add(&neat_device); + device_add(&fdc_at_device); + + device_add(&keyboard_at_ami_device); + + return ret; +} + + +static void +machine_at_scat_init(const machine_t *model, int is_v4) +{ + machine_at_init(model); + device_add(&fdc_at_device); + + if (is_v4) + device_add(&scat_4_device); + else + device_add(&scat_device); +} + + +static void +machine_at_scatsx_init(const machine_t *model) +{ + machine_at_common_init(model); + + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); + + device_add(&scat_sx_device); +} + + +int +machine_at_award286_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/award286/award.bin", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scat_init(model, 0); + + return ret; +} + + +int +machine_at_gw286ct_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/gw286ct/2ctc001.bin", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scat_init(model, 1); + + return ret; +} + + +int +machine_at_super286tr_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/super286tr/hyundai_award286.bin", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scat_init(model, 0); + + return ret; +} + + +int +machine_at_spc4200p_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/spc4200p/u8.01", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scat_init(model, 0); + + return ret; +} + + +int +machine_at_spc4216p_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/spc4216p/7101.u8", + L"roms/machines/spc4216p/ac64.u10", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scat_init(model, 1); + + return ret; +} + + +int +machine_at_kmxc02_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/kmxc02/3ctm005.bin", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_scatsx_init(model); + + return ret; +} + + +int +machine_at_wd76c10_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/megapc/41651-bios lo.u18", + L"roms/machines/megapc/211253-bios hi.u19", + 0x000f0000, 65536, 0x08000); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + device_add(&keyboard_ps2_quadtel_device); + + device_add(&wd76c10_device); + + if (gfxcard == VID_INTERNAL) + device_add(¶dise_wd90c11_megapc_device); + + return ret; +} diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c new file mode 100644 index 000000000..a9b913b5a --- /dev/null +++ b/src/machine/m_at_386dx_486.c @@ -0,0 +1,341 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of 386DX and 486 machines. + * + * Version: @(#)m_at_386dx_486.c 1.0.0 2019/05/16 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../timer.h" +#include "../io.h" +#include "../device.h" +#include "../chipset/chipset.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../pci.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../rom.h" +#include "../sio.h" +#include "../disk/hdc.h" +#include "../video/video.h" +#include "../video/vid_ht216.h" +#include "../intel_flash.h" +#include "../intel_sio.h" +#include "machine.h" + + +int +machine_at_pb410a_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/pb410a/pb410a.080337.4abf.u25.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ibm_common_ide_init(model); + + device_add(&keyboard_ps2_device); + + device_add(&acc3221_device); + device_add(&acc2168_device); + + if (gfxcard == VID_INTERNAL) + device_add(&ht216_32_pb410a_device); + + return ret; +} + + +static void +machine_at_ali1429_common_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + + device_add(&ali1429_device); + + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); +} + + +int +machine_at_ali1429_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ami486/ami486.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ali1429_common_init(model); + + return ret; +} + + +int +machine_at_winbios1429_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/win486/ali1429g.amw", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ali1429_common_init(model); + + return ret; +} + + +int +machine_at_opti495_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/award495/opt495s.awa", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + device_add(&opti495_device); + + device_add(&keyboard_at_device); + device_add(&fdc_at_device); + + return ret; +} + + +static void +machine_at_opti495_ami_common_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + + device_add(&opti495_device); + + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); +} + + +int +machine_at_opti495_ami_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ami495/opt495sx.ami", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_opti495_ami_common_init(model); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_MR495) +int +machine_at_opti495_mr_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/mr495/opt495sx.mr", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_opti495_ami_common_init(model); + + return ret; +} +#endif + + +static void +machine_at_sis_85c471_common_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + device_add(&fdc_at_device); + + device_add(&sis_85c471_device); +} + + +int +machine_at_ami471_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ami471/SIS471BE.AMI", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis_85c471_common_init(model); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +int +machine_at_dtk486_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/dtk486/4siw005.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis_85c471_common_init(model); + device_add(&keyboard_at_device); + + return ret; +} + + +int +machine_at_px471_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/px471/SIS471A1.PHO", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis_85c471_common_init(model); + device_add(&keyboard_at_device); + + return ret; +} + + +int +machine_at_win471_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/win471/4sim001.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis_85c471_common_init(model); + device_add(&keyboard_at_ami_device); + + return ret; +} + + +static void +machine_at_sis_85c496_common_init(const machine_t *model) +{ + machine_at_common_init(model); + + device_add(&ide_pci_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x05, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&keyboard_ps2_pci_device); + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + device_add(&sis_85c496_device); +} + + +int +machine_at_r418_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/r418/r418i.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_sis_85c496_common_init(model); + + device_add(&fdc37c665_device); + + return ret; +} + + +int +machine_at_alfredo_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/alfredo/1010AQ0_.BIO", + L"roms/machines/alfredo/1010AQ0_.BI1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sio_device); + device_add(&fdc37c663_device); + device_add(&intel_flash_bxt_ami_device); + + device_add(&i420tx_device); + + return ret; +} diff --git a/src/machine/m_at_4x0.c b/src/machine/m_at_4x0.c deleted file mode 100644 index 7ee7b21ab..000000000 --- a/src/machine/m_at_4x0.c +++ /dev/null @@ -1,938 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of the Intel PCISet chips from 430LX to 440FX. - * - * Version: @(#)m_at_430lx_nx.c 1.0.4 2018/11/05 - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2016-2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#include "../86box.h" -#include "../mem.h" -#include "../memregs.h" -#include "../io.h" -#include "../rom.h" -#include "../pci.h" -#include "../device.h" -#include "../disk/hdc.h" -#include "../disk/hdc_ide.h" -#include "../keyboard.h" -#include "../intel.h" -#include "../intel_flash.h" -#include "../intel_sio.h" -#include "../piix.h" -#include "../sio.h" -#include "../video/video.h" -#include "../video/vid_cl54xx.h" -#include "../video/vid_s3.h" -#include "machine.h" - - -enum -{ - INTEL_430LX, - INTEL_430NX, - INTEL_430FX, - INTEL_430FX_PB640, - INTEL_430HX, - INTEL_430VX -#if defined(DEV_BRANCH) && defined(USE_I686) - ,INTEL_440FX -#endif -}; - -typedef struct -{ - uint8_t regs[256]; - int type; -} i4x0_t; - - -typedef struct -{ - int index; -} acerm3a_t; - - -static void -i4x0_map(uint32_t addr, uint32_t size, int state) -{ - switch (state & 3) { - case 0: - mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 1: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } - flushmmucache_nopc(); -} - - -static void -i4x0_write(int func, int addr, uint8_t val, void *priv) -{ - i4x0_t *dev = (i4x0_t *) priv; - - if (func) - return; - - if ((addr >= 0x10) && (addr < 0x4f)) - return; - - switch (addr) { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0e: - return; - - case 0x04: /*Command register*/ - if (dev->type >= INTEL_430FX) { - if (dev->type == INTEL_430FX_PB640) - val &= 0x06; - else - val &= 0x02; - } else - val &= 0x42; - val |= 0x04; - break; - case 0x05: - if (dev->type >= INTEL_430FX) - val = 0; - else - val &= 0x01; - break; - - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - if (dev->type >= INTEL_430HX) { - val &= 0x80; - val |= 0x02; - } else { - val = 0x02; - if (dev->type == INTEL_430FX_PB640) - val |= 0x20; - } - break; - - case 0x59: /*PAM0*/ - if ((dev->regs[0x59] ^ val) & 0xf0) { - i4x0_map(0xf0000, 0x10000, val >> 4); - shadowbios = (val & 0x10); - } - break; - case 0x5a: /*PAM1*/ - if ((dev->regs[0x5a] ^ val) & 0x0f) - i4x0_map(0xc0000, 0x04000, val & 0xf); - if ((dev->regs[0x5a] ^ val) & 0xf0) - i4x0_map(0xc4000, 0x04000, val >> 4); - break; - case 0x5b: /*PAM2*/ - if ((dev->regs[0x5b] ^ val) & 0x0f) - i4x0_map(0xc8000, 0x04000, val & 0xf); - if ((dev->regs[0x5b] ^ val) & 0xf0) - i4x0_map(0xcc000, 0x04000, val >> 4); - break; - case 0x5c: /*PAM3*/ - if ((dev->regs[0x5c] ^ val) & 0x0f) - i4x0_map(0xd0000, 0x04000, val & 0xf); - if ((dev->regs[0x5c] ^ val) & 0xf0) - i4x0_map(0xd4000, 0x04000, val >> 4); - break; - case 0x5d: /*PAM4*/ - if ((dev->regs[0x5d] ^ val) & 0x0f) - i4x0_map(0xd8000, 0x04000, val & 0xf); - if ((dev->regs[0x5d] ^ val) & 0xf0) - i4x0_map(0xdc000, 0x04000, val >> 4); - break; - case 0x5e: /*PAM5*/ - if ((dev->regs[0x5e] ^ val) & 0x0f) - i4x0_map(0xe0000, 0x04000, val & 0xf); - if ((dev->regs[0x5e] ^ val) & 0xf0) - i4x0_map(0xe4000, 0x04000, val >> 4); - break; - case 0x5f: /*PAM6*/ - if ((dev->regs[0x5f] ^ val) & 0x0f) - i4x0_map(0xe8000, 0x04000, val & 0xf); - if ((dev->regs[0x5f] ^ val) & 0xf0) - i4x0_map(0xec000, 0x04000, val >> 4); - break; - case 0x72: /*SMRAM*/ - if ((dev->type >= INTEL_430FX) && ((dev->regs[0x72] ^ val) & 0x48)) - i4x0_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); - break; - } - - dev->regs[addr] = val; -} - - -static uint8_t -i4x0_read(int func, int addr, void *priv) -{ - i4x0_t *dev = (i4x0_t *) priv; - - if (func) - return 0xff; - - return dev->regs[addr]; -} - - -static void -i4x0_reset(void *priv) -{ - i4x0_t *i4x0 = (i4x0_t *)priv; - - i4x0_write(0, 0x59, 0x00, priv); - if (i4x0->type >= INTEL_430FX) - i4x0_write(0, 0x72, 0x02, priv); -} - - -static void -i4x0_close(void *p) -{ - i4x0_t *i4x0 = (i4x0_t *)p; - - free(i4x0); -} - - -static void -*i4x0_init(const device_t *info) -{ - i4x0_t *i4x0 = (i4x0_t *) malloc(sizeof(i4x0_t)); - memset(i4x0, 0, sizeof(i4x0_t)); - - i4x0->type = info->local; - - i4x0->regs[0x00] = 0x86; i4x0->regs[0x01] = 0x80; /*Intel*/ - switch(i4x0->type) { - case INTEL_430LX: - i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/ - i4x0->regs[0x08] = 0x03; /*A3 stepping*/ - i4x0->regs[0x50] = 0x80; - i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/ - break; - case INTEL_430NX: - i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/ - i4x0->regs[0x08] = 0x10; /*A0 stepping*/ - i4x0->regs[0x50] = 0xA0; - i4x0->regs[0x52] = 0x44; /*256kb PLB cache*/ - i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02; - break; - case INTEL_430FX: - case INTEL_430FX_PB640: - i4x0->regs[0x02] = 0x2d; i4x0->regs[0x03] = 0x12; /*SB82437FX-66*/ - if (i4x0->type == INTEL_430FX_PB640) - i4x0->regs[0x08] = 0x02; /*???? stepping*/ - else - i4x0->regs[0x08] = 0x00; /*A0 stepping*/ - i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/ - break; - case INTEL_430HX: - i4x0->regs[0x02] = 0x50; i4x0->regs[0x03] = 0x12; /*82439HX*/ - i4x0->regs[0x08] = 0x00; /*A0 stepping*/ - i4x0->regs[0x51] = 0x20; - i4x0->regs[0x52] = 0xB5; /*512kb cache*/ - i4x0->regs[0x56] = 0x52; /*DRAM control*/ - i4x0->regs[0x59] = 0x40; - i4x0->regs[0x5A] = i4x0->regs[0x5B] = i4x0->regs[0x5C] = i4x0->regs[0x5D] = 0x44; - i4x0->regs[0x5E] = i4x0->regs[0x5F] = 0x44; - i4x0->regs[0x65] = i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02; - i4x0->regs[0x68] = 0x11; - break; - case INTEL_430VX: - i4x0->regs[0x02] = 0x30; i4x0->regs[0x03] = 0x70; /*82437VX*/ - i4x0->regs[0x08] = 0x00; /*A0 stepping*/ - i4x0->regs[0x52] = 0x42; /*256kb PLB cache*/ - i4x0->regs[0x53] = 0x14; - i4x0->regs[0x56] = 0x52; /*DRAM control*/ - i4x0->regs[0x67] = 0x11; - i4x0->regs[0x69] = 0x03; - i4x0->regs[0x70] = 0x20; - i4x0->regs[0x74] = 0x0e; - i4x0->regs[0x78] = 0x23; - break; -#if defined(DEV_BRANCH) && defined(USE_I686) - case INTEL_440FX: - i4x0->regs[0x02] = 0x37; i4x0->regs[0x03] = 0x12; /*82441FX*/ - i4x0->regs[0x08] = 0x02; /*A0 stepping*/ - i4x0->regs[0x2c] = 0xf4; - i4x0->regs[0x2d] = 0x1a; - i4x0->regs[0x2f] = 0x11; - i4x0->regs[0x51] = 0x01; - i4x0->regs[0x53] = 0x80; - i4x0->regs[0x58] = 0x10; - i4x0->regs[0x5a] = i4x0->regs[0x5b] = i4x0->regs[0x5c] = i4x0->regs[0x5d] = 0x11; - i4x0->regs[0x5e] = 0x11; - i4x0->regs[0x5f] = 0x31; - break; -#endif - } - i4x0->regs[0x04] = 0x06; i4x0->regs[0x05] = 0x00; -#if defined(DEV_BRANCH) && defined(USE_I686) - if (i4x0->type == INTEL_440FX) - i4x0->regs[0x06] = 0x80; -#endif - if (i4x0->type == INTEL_430FX) - i4x0->regs[0x07] = 0x82; -#if defined(DEV_BRANCH) && defined(USE_I686) - else if (i4x0->type != INTEL_440FX) -#else - else -#endif - i4x0->regs[0x07] = 0x02; - i4x0->regs[0x0b] = 0x06; - if (i4x0->type >= INTEL_430FX) - i4x0->regs[0x57] = 0x01; - else - i4x0->regs[0x57] = 0x31; - i4x0->regs[0x60] = i4x0->regs[0x61] = i4x0->regs[0x62] = i4x0->regs[0x63] = 0x02; - i4x0->regs[0x64] = 0x02; - if (i4x0->type >= INTEL_430FX) - i4x0->regs[0x72] = 0x02; - - pci_add_card(0, i4x0_read, i4x0_write, i4x0); - - return i4x0; -} - - -const device_t i430lx_device = -{ - "Intel 82434LX", - DEVICE_PCI, - INTEL_430LX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; - - -const device_t i430nx_device = -{ - "Intel 82434NX", - DEVICE_PCI, - INTEL_430NX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; - - -const device_t i430fx_device = -{ - "Intel SB82437FX-66", - DEVICE_PCI, - INTEL_430FX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; - - -const device_t i430fx_pb640_device = -{ - "Intel SB82437FX-66 (PB640)", - DEVICE_PCI, - INTEL_430FX_PB640, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; - - -const device_t i430hx_device = -{ - "Intel 82439HX", - DEVICE_PCI, - INTEL_430HX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; - - -const device_t i430vx_device = -{ - "Intel 82437VX", - DEVICE_PCI, - INTEL_430VX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; - - -#if defined(DEV_BRANCH) && defined(USE_I686) -const device_t i440fx_device = -{ - "Intel 82441FX", - DEVICE_PCI, - INTEL_440FX, - i4x0_init, - i4x0_close, - i4x0_reset, - NULL, - NULL, - NULL, - NULL -}; -#endif - - -static void -acerm3a_out(uint16_t port, uint8_t val, void *p) -{ - acerm3a_t *dev = (acerm3a_t *) p; - - if (port == 0xea) - dev->index = val; -} - - -static uint8_t -acerm3a_in(uint16_t port, void *p) -{ - acerm3a_t *dev = (acerm3a_t *) p; - - if (port == 0xeb) { - switch (dev->index) { - case 2: - return 0xfd; - } - } - return 0xff; -} - - -static void -acerm3a_close(void *p) -{ - acerm3a_t *dev = (acerm3a_t *)p; - - free(dev); -} - - -static void -*acerm3a_init(const device_t *info) -{ - acerm3a_t *acerm3a = (acerm3a_t *) malloc(sizeof(acerm3a_t)); - memset(acerm3a, 0, sizeof(acerm3a_t)); - - io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, acerm3a); - - return acerm3a; -} - - -const device_t acerm3a_device = -{ - "Acer M3A Register", - 0, - 0, - acerm3a_init, - acerm3a_close, - NULL, - NULL, - NULL, - NULL, - NULL -}; - - -static void -machine_at_premiere_common_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - device_add(&ide_pci_2ch_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_2); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); - pci_register_slot(0x02, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&sio_device); - device_add(&fdc37c665_device); - device_add(&intel_batman_device); - device_add(&intel_flash_bxt_ami_device); -} - - -void -machine_at_batman_init(const machine_t *model) -{ - machine_at_premiere_common_init(model); - - device_add(&i430lx_device); -} - - -void -machine_at_plato_init(const machine_t *model) -{ - machine_at_premiere_common_init(model); - - device_add(&i430nx_device); -} - - -void -machine_at_p54tp4xe_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&fdc37c665_device); - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_endeavor_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_ami_device); - - if (gfxcard == VID_INTERNAL) - device_add(&s3_phoenix_trio64_onboard_pci_device); -} - - -const device_t * -at_endeavor_get_device(void) -{ - return &s3_phoenix_trio64_onboard_pci_device; -} - - -void -machine_at_zappa_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_ami_device); -} - - -void -machine_at_mb500n_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&fdc37c665_device); - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_president_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&w83877f_president_device); - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_thor_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 2, 1); - pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 3, 2, 1); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_device); - device_add(&piix_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_ami_device); -} - - -void -machine_at_pb640_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 2, 1, 4); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430fx_pb640_device); - device_add(&piix_pb640_device); - ide_enable_pio_override(); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_ami_device); - - if (gfxcard == VID_INTERNAL) - device_add(&gd5440_onboard_pci_device); -} - - -const device_t * -at_pb640_get_device(void) -{ - return &gd5440_onboard_pci_device; -} - - -void -machine_at_acerm3a_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - powermate_memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x1F, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x10, PCI_CARD_ONBOARD, 4, 0, 0, 0); - device_add(&i430hx_device); - device_add(&piix3_device); - device_add(&fdc37c932fr_device); - device_add(&acerm3a_device); - - device_add(&intel_flash_bxb_device); -} - - -void -machine_at_acerv35n_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - powermate_memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i430hx_device); - device_add(&piix3_device); - device_add(&fdc37c932fr_device); - device_add(&acerm3a_device); - - device_add(&intel_flash_bxb_device); -} - - -void -machine_at_ap53_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - powermate_memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x06, PCI_CARD_ONBOARD, 1, 2, 3, 4); - device_add(&i430hx_device); - device_add(&piix3_device); - device_add(&fdc37c669_device); - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_p55t2p4_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430hx_device); - device_add(&piix3_device); - device_add(&w83877f_device); - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_p55t2s_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - powermate_memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430hx_device); - device_add(&piix3_device); - device_add(&pc87306_device); - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_p55tvp4_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - device_add(&w83877f_device); - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_i430vx_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - device_add(&um8669f_device); - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_p55va_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - device_add(&fdc37c932fr_device); - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_j656vxd_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i430vx_device); - device_add(&piix3_device); - device_add(&fdc37c669_device); - device_add(&intel_flash_bxt_device); -} - - -#if defined(DEV_BRANCH) && defined(USE_I686) -void -machine_at_i440fx_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - device_add(&i440fx_device); - device_add(&piix3_device); - device_add(&fdc37c665_device); - device_add(&intel_flash_bxt_device); -} - - -void -machine_at_s1668_init(const machine_t *model) -{ - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_pci_device); - - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); - device_add(&i440fx_device); - device_add(&piix3_device); - device_add(&fdc37c665_device); - device_add(&intel_flash_bxt_device); -} -#endif diff --git a/src/machine/m_at_ali1429.c b/src/machine/m_at_ali1429.c deleted file mode 100644 index 624691e4a..000000000 --- a/src/machine/m_at_ali1429.c +++ /dev/null @@ -1,111 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include -#include -#include -#include -#include "../86box.h" -#include "../cpu/cpu.h" -#include "../io.h" -#include "../mem.h" -#include "../device.h" -#include "../keyboard.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "../disk/hdc.h" -#include "../disk/hdc_ide.h" -#include "machine.h" - - -static int ali1429_index; -static uint8_t ali1429_regs[256]; - - -static void ali1429_recalc(void) -{ - int c; - - for (c = 0; c < 8; c++) - { - uint32_t base = 0xc0000 + (c << 15); - if (ali1429_regs[0x13] & (1 << c)) - { - switch (ali1429_regs[0x14] & 3) - { - case 0: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 1: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } - } - else - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } - - flushmmucache(); -} - -void ali1429_write(uint16_t port, uint8_t val, void *priv) -{ - if (!(port & 1)) - ali1429_index = val; - else - { - ali1429_regs[ali1429_index] = val; - switch (ali1429_index) - { - case 0x13: - ali1429_recalc(); - break; - case 0x14: - shadowbios = val & 1; - shadowbios_write = val & 2; - ali1429_recalc(); - break; - } - } -} - -uint8_t ali1429_read(uint16_t port, void *priv) -{ - if (!(port & 1)) - return ali1429_index; - if ((ali1429_index >= 0xc0 || ali1429_index == 0x20) && cpu_iscyrix) - return 0xff; /*Don't conflict with Cyrix config registers*/ - return ali1429_regs[ali1429_index]; -} - - -static void ali1429_reset(void) -{ - memset(ali1429_regs, 0xff, 256); -} - - -static void ali1429_init(void) -{ - io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, NULL); -} - - -void -machine_at_ali1429_init(const machine_t *model) -{ - ali1429_reset(); - - machine_at_common_ide_init(model); - - device_add(&keyboard_at_ami_device); - device_add(&fdc_at_device); - - ali1429_init(); -} diff --git a/src/machine/m_at_commodore.c b/src/machine/m_at_commodore.c index 294e6a12e..348c43e36 100644 --- a/src/machine/m_at_commodore.c +++ b/src/machine/m_at_commodore.c @@ -42,9 +42,11 @@ #include #include "../86box.h" #include "../device.h" +#include "../timer.h" #include "../io.h" #include "../mem.h" #include "../lpt.h" +#include "../rom.h" #include "../serial.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" @@ -90,10 +92,19 @@ cbm_io_init() } -void +int machine_at_cmdpc_init(const machine_t *model) { - machine_at_ide_init(model); + int ret; + + ret = bios_load_interleaved(L"roms/machines/cmdpc30/commodore pc 30 iii even.bin", + L"roms/machines/cmdpc30/commodore pc 30 iii odd.bin", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + + machine_at_init(model); mem_remap_top(384); @@ -101,4 +112,6 @@ machine_at_cmdpc_init(const machine_t *model) cmd_uart = device_add(&i8250_device); cbm_io_init(); + + return ret; } diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index 5b848873c..801de3412 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -23,6 +23,7 @@ #include #include "../86box.h" #include "../cpu/cpu.h" +#include "../timer.h" #include "../mem.h" #include "../rom.h" #include "../device.h" @@ -33,6 +34,16 @@ #include "machine.h" +enum +{ + COMPAQ_PORTABLEII = 0 +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + , COMPAQ_PORTABLEIII, + COMPAQ_PORTABLEIII386 +#endif +}; + + /* Compaq Deskpro 386 remaps RAM from 0xA0000-0xFFFFF to 0xFA0000-0xFFFFFF */ static mem_mapping_t ram_mapping; @@ -97,8 +108,8 @@ write_raml(uint32_t addr, uint32_t val, void *priv) } -void -machine_at_compaq_init(const machine_t *model) +static void +machine_at_compaq_init(const machine_t *model, int type) { machine_at_init(model); @@ -111,30 +122,74 @@ machine_at_compaq_init(const machine_t *model) write_ram, write_ramw, write_raml, 0xa0000+ram, MEM_MAPPING_INTERNAL, NULL); - switch(model->id) { -#ifdef PORTABLE3 - case ROM_DESKPRO_386: - if (hdc_current == 1) - device_add(&ide_isa_device); - break; -#endif - - case ROM_PORTABLE: + switch(type) { + case COMPAQ_PORTABLEII: break; - case ROM_PORTABLEII: +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + case COMPAQ_PORTABLEIII: break; -#ifdef PORTABLE3 - case ROM_PORTABLEIII: - machine_olim24_video_init(); - break; - - case ROM_PORTABLEIII386: - machine_olim24_video_init(); + case COMPAQ_PORTABLEIII386: if (hdc_current == 1) device_add(&ide_isa_device); break; #endif } } + + +int +machine_at_portableii_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/portableii/109740-001.rom", + L"roms/machines/portableii/109739-001.rom", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + + machine_at_compaq_init(model, COMPAQ_PORTABLEII); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) +int +machine_at_portableiii_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/portableiii/109738-002.bin", + L"roms/machines/portableiii/109737-002.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_compaq_init(model, COMPAQ_PORTABLEIII); + + return ret; +} + + +int +machine_at_portableiii386_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/portableiii/109738-002.bin", + L"roms/machines/portableiii/109737-002.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_compaq_init(model, COMPAQ_PORTABLEIII386); + + return ret; +} +#endif diff --git a/src/machine/m_at_headland.c b/src/machine/m_at_headland.c deleted file mode 100644 index 90e55bce0..000000000 --- a/src/machine/m_at_headland.c +++ /dev/null @@ -1,568 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include -#include -#include -#include -#include "../86box.h" -#include "../cpu/cpu.h" -#include "../cpu/x86.h" -#include "../io.h" -#include "../mem.h" -#include "../rom.h" -#include "../device.h" -#include "../keyboard.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "machine.h" -#include "../video/video.h" -#include "../video/vid_et4000.h" -#include "../video/vid_oak_oti.h" - - -static int headland_index; -static uint8_t headland_regs[256]; -static uint8_t headland_port_92 = 0xFC, headland_ems_mar = 0, headland_cri = 0; -static uint8_t headland_regs_cr[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; -static uint16_t headland_ems_mr[64]; - -static mem_mapping_t headland_low_mapping; -static mem_mapping_t headland_ems_mapping[64]; -static mem_mapping_t headland_mid_mapping; -static mem_mapping_t headland_high_mapping; -static mem_mapping_t headland_4000_9FFF_mapping[24]; - -/* TODO - Headland chipset's memory address mapping emulation isn't fully implemented yet, - so memory configuration is hardcoded now. */ -static int headland_mem_conf_cr0[41] = { 0x00, 0x00, 0x20, 0x40, 0x60, 0xA0, 0x40, 0xE0, - 0xA0, 0xC0, 0xE0, 0xE0, 0xC0, 0xE0, 0xE0, 0xE0, - 0xE0, 0x20, 0x40, 0x40, 0xA0, 0xC0, 0xE0, 0xE0, - 0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, - 0x20, 0x40, 0x60, 0x60, 0xC0, 0xE0, 0xE0, 0xE0, - 0xE0 }; -static int headland_mem_conf_cr1[41] = { 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, - 0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, - 0x40 }; - - -static uint32_t -get_headland_addr(uint32_t addr, uint16_t *mr) -{ - if (mr && (headland_regs_cr[0] & 2) && (*mr & 0x200)) { - addr = (addr & 0x3fff) | ((*mr & 0x1F) << 14); - - if (headland_regs_cr[1] & 0x40) { - if ((headland_regs_cr[4] & 0x80) && (headland_regs_cr[6] & 1)) { - if (headland_regs_cr[0] & 0x80) { - addr |= (*mr & 0x60) << 14; - if (*mr & 0x100) - addr += ((*mr & 0xC00) << 13) + (((*mr & 0x80) + 0x80) << 15); - else - addr += (*mr & 0x80) << 14; - } else if (*mr & 0x100) - addr += ((*mr & 0xC00) << 13) + (((*mr & 0x80) + 0x20) << 15); - else - addr += (*mr & 0x80) << 12; - } else if (headland_regs_cr[0] & 0x80) - addr |= (*mr & 0x100) ? ((*mr & 0x80) + 0x400) << 12 : (*mr & 0xE0) << 14; - else - addr |= (*mr & 0x100) ? ((*mr & 0xE0) + 0x40) << 14 : (*mr & 0x80) << 12; - } else { - if ((headland_regs_cr[4] & 0x80) && (headland_regs_cr[6] & 1)) { - if (headland_regs_cr[0] & 0x80) { - addr |= ((*mr & 0x60) << 14); - if (*mr & 0x180) - addr += ((*mr & 0xC00) << 13) + (((*mr & 0x180) - 0x60) << 16); - } else - addr |= ((*mr & 0x60) << 14) | ((*mr & 0x180) << 16) | ((*mr & 0xC00) << 13); - } else if (headland_regs_cr[0] & 0x80) - addr |= (*mr & 0x1E0) << 14; - else - addr |= (*mr & 0x180) << 12; - } - } else if (mr == NULL && (headland_regs_cr[0] & 4) == 0 && mem_size >= 1024 && addr >= 0x100000) - addr -= 0x60000; - - return addr; -} - - -static void -headland_set_global_EMS_state(int state) -{ - int i; - uint32_t base_addr, virt_addr; - - for (i=0; i<32; i++) { - base_addr = (i + 16) << 14; - if (i >= 24) - base_addr += 0x20000; - if ((state & 2) && (headland_ems_mr[((state & 1) << 5) | i] & 0x200)) { - virt_addr = get_headland_addr(base_addr, &headland_ems_mr[((state & 1) << 5) | i]); - if (i < 24) - mem_mapping_disable(&headland_4000_9FFF_mapping[i]); - mem_mapping_disable(&headland_ems_mapping[(((state ^ 1) & 1) << 5) | i]); - mem_mapping_enable(&headland_ems_mapping[((state & 1) << 5) | i]); - if (virt_addr < (mem_size << 10)) - mem_mapping_set_exec(&headland_ems_mapping[((state & 1) << 5) | i], ram + virt_addr); - else - mem_mapping_set_exec(&headland_ems_mapping[((state & 1) << 5) | i], NULL); - } else { - mem_mapping_set_exec(&headland_ems_mapping[((state & 1) << 5) | i], ram + base_addr); - mem_mapping_disable(&headland_ems_mapping[(((state ^ 1) & 1) << 5) | i]); - mem_mapping_disable(&headland_ems_mapping[((state & 1) << 5) | i]); - - if (i < 24) - mem_mapping_enable(&headland_4000_9FFF_mapping[i]); - } - } - flushmmucache(); -} - - -static void -headland_memmap_state_update(void) -{ - int i; - uint32_t addr; - - for (i=0; i<24; i++) { - addr = get_headland_addr(0x40000 + (i << 14), NULL); - mem_mapping_set_exec(&headland_4000_9FFF_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); - } - - mem_set_mem_state(0xA0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - - if (mem_size > 640) { - if ((headland_regs_cr[0] & 4) == 0) { - mem_mapping_set_addr(&headland_mid_mapping, 0x100000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); - mem_mapping_set_exec(&headland_mid_mapping, ram + 0xA0000); - if (mem_size > 1024) { - mem_mapping_set_addr(&headland_high_mapping, 0x160000, (mem_size - 1024) << 10); - mem_mapping_set_exec(&headland_high_mapping, ram + 0x100000); - } - } else { - mem_mapping_set_addr(&headland_mid_mapping, 0xA0000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); - mem_mapping_set_exec(&headland_mid_mapping, ram + 0xA0000); - if (mem_size > 1024) { - mem_mapping_set_addr(&headland_high_mapping, 0x100000, (mem_size - 1024) << 10); - mem_mapping_set_exec(&headland_high_mapping, ram + 0x100000); - } - } - } - - headland_set_global_EMS_state(headland_regs_cr[0] & 3); -} - - -static void -headland_write(uint16_t addr, uint8_t val, void *priv) -{ - uint8_t old_val, index; - uint32_t base_addr, virt_addr; - - switch(addr) { - case 0x22: - headland_index = val; - break; - - case 0x23: - old_val = headland_regs[headland_index]; - if ((headland_index == 0xc1) && !is486) - val = 0; - headland_regs[headland_index] = val; - if (headland_index == 0x82) { - shadowbios = val & 0x10; - shadowbios_write = !(val & 0x10); - if (shadowbios) - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); - else - mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - } else if (headland_index == 0x87) { - if ((val & 1) && !(old_val & 1)) - softresetx86(); - } - break; - - case 0x92: - if ((mem_a20_alt ^ val) & 2) { - mem_a20_alt = val & 2; - mem_a20_recalc(); - } - if ((~headland_port_92 & val) & 1) { - softresetx86(); - cpu_set_edx(); - } - headland_port_92 = val | 0xFC; - break; - - case 0x1EC: - headland_ems_mr[headland_ems_mar & 0x3F] = val | 0xFF00; - index = headland_ems_mar & 0x1F; - base_addr = (index + 16) << 14; - if (index >= 24) - base_addr += 0x20000; - if ((headland_regs_cr[0] & 2) && ((headland_regs_cr[0] & 1) == ((headland_ems_mar & 0x20) >> 5))) { - virt_addr = get_headland_addr(base_addr, &headland_ems_mr[headland_ems_mar & 0x3F]); - if (index < 24) - mem_mapping_disable(&headland_4000_9FFF_mapping[index]); - if (virt_addr < (mem_size << 10)) - mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], ram + virt_addr); - else - mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], NULL); - mem_mapping_enable(&headland_ems_mapping[headland_ems_mar & 0x3F]); - flushmmucache(); - } - if (headland_ems_mar & 0x80) - headland_ems_mar++; - break; - - case 0x1ED: - headland_cri = val; - break; - - case 0x1EE: - headland_ems_mar = val; - break; - - case 0x1EF: - old_val = headland_regs_cr[headland_cri]; - switch(headland_cri) { - case 0: - headland_regs_cr[0] = (val & 0x1F) | headland_mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; - mem_set_mem_state(0xE0000, 0x10000, (val & 8 ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL) | MEM_WRITE_DISABLED); - mem_set_mem_state(0xF0000, 0x10000, (val & 0x10 ? MEM_READ_INTERNAL: MEM_READ_EXTERNAL) | MEM_WRITE_DISABLED); - headland_memmap_state_update(); - break; - case 1: - headland_regs_cr[1] = (val & 0xBF) | headland_mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; - headland_memmap_state_update(); - break; - case 2: - case 3: - case 5: - headland_regs_cr[headland_cri] = val; - headland_memmap_state_update(); - break; - case 4: - headland_regs_cr[4] = (headland_regs_cr[4] & 0xF0) | (val & 0x0F); - if (val & 1) { - mem_mapping_disable(&bios_mapping[0]); - mem_mapping_disable(&bios_mapping[1]); - mem_mapping_disable(&bios_mapping[2]); - mem_mapping_disable(&bios_mapping[3]); - } else { - mem_mapping_enable(&bios_mapping[0]); - mem_mapping_enable(&bios_mapping[1]); - mem_mapping_enable(&bios_mapping[2]); - mem_mapping_enable(&bios_mapping[3]); - } - break; - case 6: - if (headland_regs_cr[4] & 0x80) { - headland_regs_cr[headland_cri] = (val & 0xFE) | (mem_size > 8192 ? 1 : 0); - headland_memmap_state_update(); - } - break; - default: - break; - } - break; - - default: - break; - } -} - - -static void -headland_writew(uint16_t addr, uint16_t val, void *priv) -{ - uint8_t index; - uint32_t base_addr, virt_addr; - - switch(addr) { - case 0x1EC: - headland_ems_mr[headland_ems_mar & 0x3F] = val; - index = headland_ems_mar & 0x1F; - base_addr = (index + 16) << 14; - if (index >= 24) - base_addr += 0x20000; - if ((headland_regs_cr[0] & 2) && (headland_regs_cr[0] & 1) == ((headland_ems_mar & 0x20) >> 5)) { - if(val & 0x200) { - virt_addr = get_headland_addr(base_addr, &headland_ems_mr[headland_ems_mar & 0x3F]); - if (index < 24) - mem_mapping_disable(&headland_4000_9FFF_mapping[index]); - if (virt_addr < (mem_size << 10)) - mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], ram + virt_addr); - else - mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], NULL); - mem_mapping_enable(&headland_ems_mapping[headland_ems_mar & 0x3F]); - } else { - mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], ram + base_addr); - mem_mapping_disable(&headland_ems_mapping[headland_ems_mar & 0x3F]); - if (index < 24) - mem_mapping_enable(&headland_4000_9FFF_mapping[index]); - } - flushmmucache(); - } - if (headland_ems_mar & 0x80) - headland_ems_mar++; - break; - - default: - break; - } -} - - -static uint8_t -headland_read(uint16_t addr, void *priv) -{ - uint8_t val; - - switch(addr) { - case 0x22: - val = headland_index; - break; - - case 0x23: - if ((headland_index >= 0xc0 || headland_index == 0x20) && cpu_iscyrix) - val = 0xff; /*Don't conflict with Cyrix config registers*/ - else - val = headland_regs[headland_index]; - break; - - case 0x92: - val = headland_port_92 | 0xFC; - break; - - case 0x1EC: - val = headland_ems_mr[headland_ems_mar & 0x3F]; - if (headland_ems_mar & 0x80) - headland_ems_mar++; - break; - - case 0x1ED: - val = headland_cri; - break; - - case 0x1EE: - val = headland_ems_mar; - break; - - case 0x1EF: - switch(headland_cri) { - case 0: - val = (headland_regs_cr[0] & 0x1F) | headland_mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; - break; - case 1: - val = (headland_regs_cr[1] & 0xBF) | headland_mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; - break; - case 6: - if (headland_regs_cr[4] & 0x80) - val = (headland_regs_cr[6] & 0xFE) | (mem_size > 8192 ? 1 : 0); - else - val = 0; - break; - default: - val = headland_regs_cr[headland_cri]; - break; - } - break; - - default: - val = 0xFF; - break; - } - return val; -} - - -static uint16_t -headland_readw(uint16_t addr, void *priv) -{ - uint16_t val; - - switch(addr) { - case 0x1EC: - val = headland_ems_mr[headland_ems_mar & 0x3F] | ((headland_regs_cr[4] & 0x80) ? 0xF000 : 0xFC00); - if (headland_ems_mar & 0x80) - headland_ems_mar++; - break; - - default: - val = 0xFFFF; - break; - } - - return val; -} - - -static uint8_t -mem_read_headlandb(uint32_t addr, void *priv) -{ - uint8_t val = 0xff; - - addr = get_headland_addr(addr, priv); - if (addr < (mem_size << 10)) - val = ram[addr]; - - return val; -} - - -static uint16_t -mem_read_headlandw(uint32_t addr, void *priv) -{ - uint16_t val = 0xffff; - - addr = get_headland_addr(addr, priv); - if (addr < (mem_size << 10)) - val = *(uint16_t *)&ram[addr]; - - return val; -} - - -static uint32_t -mem_read_headlandl(uint32_t addr, void *priv) -{ - uint32_t val = 0xffffffff; - - addr = get_headland_addr(addr, priv); - if (addr < (mem_size << 10)) - val = *(uint32_t *)&ram[addr]; - - return val; -} - - -static void -mem_write_headlandb(uint32_t addr, uint8_t val, void *priv) -{ - addr = get_headland_addr(addr, priv); - if (addr < (mem_size << 10)) - ram[addr] = val; -} - - -static void -mem_write_headlandw(uint32_t addr, uint16_t val, void *priv) -{ - addr = get_headland_addr(addr, priv); - if (addr < (mem_size << 10)) - *(uint16_t *)&ram[addr] = val; -} - - -static void -mem_write_headlandl(uint32_t addr, uint32_t val, void *priv) -{ - addr = get_headland_addr(addr, priv); - if (addr < (mem_size << 10)) - *(uint32_t *)&ram[addr] = val; -} - - -static void -headland_init(int ht386) -{ - int i; - - for(i=0; i<8; i++) - headland_regs_cr[i] = 0; - headland_regs_cr[0] = 4; - - if (ht386) { - headland_regs_cr[4] = 0x20; - io_sethandler(0x0092, 0x0001, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); - } else - headland_regs_cr[4] = 0; - - io_sethandler(0x01EC, 0x0001, headland_read, headland_readw, NULL, headland_write, headland_writew, NULL, NULL); - io_sethandler(0x01ED, 0x0003, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); - - for(i=0; i<64; i++) - headland_ems_mr[i] = 0; - - mem_mapping_disable(&ram_low_mapping); - mem_mapping_disable(&ram_mid_mapping); - mem_mapping_disable(&ram_high_mapping); - - mem_mapping_add(&headland_low_mapping, 0, 0x40000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram, MEM_MAPPING_INTERNAL, NULL); - - if(mem_size > 640) { - mem_mapping_add(&headland_mid_mapping, 0xA0000, 0x60000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_enable(&headland_mid_mapping); - } - - if(mem_size > 1024) { - mem_mapping_add(&headland_high_mapping, 0x100000, ((mem_size - 1024) * 1024), mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_enable(&headland_high_mapping); - } - - for (i = 0; i < 24; i++) { - mem_mapping_add(&headland_4000_9FFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_enable(&headland_4000_9FFF_mapping[i]); - } - - for (i = 0; i < 64; i++) { - headland_ems_mr[i] = 0; - mem_mapping_add(&headland_ems_mapping[i], ((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14, 0x04000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram + (((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14), 0, &headland_ems_mr[i]); - mem_mapping_disable(&headland_ems_mapping[i]); - } - - headland_memmap_state_update(); -} - - -static void -machine_at_headland_common_init(int ht386) -{ - device_add(&keyboard_at_ami_device); - device_add(&fdc_at_device); - - headland_init(ht386); -} - -void -machine_at_headland_init(const machine_t *model) -{ - machine_at_common_ide_init(model); - - machine_at_headland_common_init(1); -} - - -void -machine_at_tg286m_init(const machine_t *model) -{ - machine_at_common_ide_init(model); - - machine_at_headland_common_init(0); -} - - -const device_t * -at_ama932j_get_device(void) -{ - return &oti067_ama932j_device; -} - - -void -machine_at_ama932j_init(const machine_t *model) -{ - machine_at_common_ide_init(model); - - machine_at_headland_common_init(1); - - if (gfxcard == VID_INTERNAL) - device_add(&oti067_ama932j_device); -} diff --git a/src/machine/m_at_scat.c b/src/machine/m_at_scat.c deleted file mode 100644 index 9cd99086b..000000000 --- a/src/machine/m_at_scat.c +++ /dev/null @@ -1,1393 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of Chips&Technology's SCAT (82C235) chipset. - * - * Re-worked version based on the 82C235 datasheet and errata. - * - * Version: @(#)m_at_scat.c 1.0.16 2018/09/02 - * - * Authors: Original by GreatPsycho for PCem. - * Fred N. van Kempen, - * - * Copyright 2017,2018 Fred N. van Kempen. - */ -#include -#include -#include -#include -#include "../86box.h" -#include "../device.h" -#include "../cpu/cpu.h" -#include "../cpu/x86.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "../keyboard.h" -#include "../io.h" -#include "../mem.h" -#include "../nmi.h" -#include "../rom.h" -#include "machine.h" - - -#define SCAT_DMA_WAIT_STATE_CONTROL 0x01 -#define SCAT_VERSION 0x40 -#define SCAT_CLOCK_CONTROL 0x41 -#define SCAT_PERIPHERAL_CONTROL 0x44 -#define SCAT_MISCELLANEOUS_STATUS 0x45 -#define SCAT_POWER_MANAGEMENT 0x46 -#define SCAT_ROM_ENABLE 0x48 -#define SCAT_RAM_WRITE_PROTECT 0x49 -#define SCAT_SHADOW_RAM_ENABLE_1 0x4A -#define SCAT_SHADOW_RAM_ENABLE_2 0x4B -#define SCAT_SHADOW_RAM_ENABLE_3 0x4C -#define SCAT_DRAM_CONFIGURATION 0x4D -#define SCAT_EXTENDED_BOUNDARY 0x4E -#define SCAT_EMS_CONTROL 0x4F - -#define SCATSX_LAPTOP_FEATURES 0x60 -#define SCATSX_FAST_VIDEO_CONTROL 0x61 -#define SCATSX_FAST_VIDEORAM_ENABLE 0x62 -#define SCATSX_HIGH_PERFORMANCE_REFRESH 0x63 -#define SCATSX_CAS_TIMING_FOR_DMA 0x64 - -typedef struct scat_t -{ - uint8_t regs_2x8; - uint8_t regs_2x9; -} scat_t; - - -static uint8_t scat_regs[256]; -static int scat_index; -static uint8_t scat_port_92 = 0; -static uint8_t scat_ems_reg_2xA = 0; -static mem_mapping_t scat_low_mapping[32]; -static mem_mapping_t scat_ems_mapping[32]; -static mem_mapping_t scat_high_mapping[16]; -static scat_t scat_stat[32]; -static uint32_t scat_xms_bound; -static mem_mapping_t scat_remap_mapping[6]; -static mem_mapping_t scat_4000_EFFF_mapping[44]; -static mem_mapping_t scat_low_ROMCS_mapping[8]; - - -static int scat_max_map[32] = { 0, 1, 1, 1, 2, 3, 4, 8, - 4, 8, 12, 16, 20, 24, 28, 32, - 0, 5, 9, 13, 6, 10, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 }; -static int scatsx_max_map[32] = { 0, 1, 2, 1, 3, 4, 6, 10, - 5, 9, 13, 4, 8, 12, 16, 14, - 18, 22, 26, 20, 24, 28, 32, 18, - 20, 32, 0, 0, 0, 0, 0, 0 }; - -static int external_is_RAS = 0; - -static int scatsx_external_is_RAS[33] = { 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0 }; - - -static uint8_t scat_read(uint16_t port, void *priv); -static void scat_write(uint16_t port, uint8_t val, void *priv); - - -static void -scat_romcs_state_update(uint8_t val) -{ - int i; - for(i = 0; i < 4; i++) { - if (val & 1) { - mem_mapping_enable(&scat_low_ROMCS_mapping[i << 1]); - mem_mapping_enable(&scat_low_ROMCS_mapping[(i << 1) + 1]); - } else { - mem_mapping_disable(&scat_low_ROMCS_mapping[i << 1]); - mem_mapping_disable(&scat_low_ROMCS_mapping[(i << 1) + 1]); - } - val >>= 1; - } - - for(i = 0; i < 4; i++) { - if (val & 1) { - mem_mapping_enable(&bios_mapping[i << 1]); - mem_mapping_enable(&bios_mapping[(i << 1) + 1]); - } else { - mem_mapping_disable(&bios_mapping[i << 1]); - mem_mapping_disable(&bios_mapping[(i << 1) + 1]); - } - val >>= 1; - } -} - - -static void -scat_shadow_state_update() -{ - int i, val; - - for (i = 0; i < 24; i++) { - val = ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_READ_INTERNAL | MEM_WRITE_INTERNAL : MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL; - mem_set_mem_state((i + 40) << 14, 0x4000, val); - } - - flushmmucache(); -} - - -static void -scat_set_xms_bound(uint8_t val) -{ - uint32_t max_xms_size = ((scat_regs[SCAT_VERSION] & 0xF0) != 0 && ((val & 0x10) != 0)) || (scat_regs[SCAT_VERSION] >= 4) ? 0xFE0000 : 0xFC0000; - - switch (val & 0x0F) { - case 1: - scat_xms_bound = 0x100000; - break; - case 2: - scat_xms_bound = 0x140000; - break; - case 3: - scat_xms_bound = 0x180000; - break; - case 4: - scat_xms_bound = 0x200000; - break; - case 5: - scat_xms_bound = 0x300000; - break; - case 6: - scat_xms_bound = 0x400000; - break; - case 7: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x600000 : 0x500000; - break; - case 8: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x800000 : 0x700000; - break; - case 9: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xA00000 : 0x800000; - break; - case 10: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xC00000 : 0x900000; - break; - case 11: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xE00000 : 0xA00000; - break; - case 12: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xB00000; - break; - case 13: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xC00000; - break; - case 14: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xD00000; - break; - case 15: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xF00000; - break; - default: - scat_xms_bound = max_xms_size; - break; - } - - if ((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (val & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 3)) { - if((val & 0x0F) == 0 || scat_xms_bound > 0x160000) - scat_xms_bound = 0x160000; - if (scat_xms_bound > 0x100000) - mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - if (scat_xms_bound < 0x160000) - mem_set_mem_state(scat_xms_bound, 0x160000 - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } else { - if (scat_xms_bound > max_xms_size) - scat_xms_bound = max_xms_size; - if (scat_xms_bound > 0x100000) - mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - if (scat_xms_bound < (mem_size << 10)) - mem_set_mem_state(scat_xms_bound, (mem_size << 10) - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } - - mem_mapping_set_addr(&scat_low_mapping[31], 0xF80000, ((scat_regs[SCAT_VERSION] & 0xF0) != 0 && ((val & 0x10) != 0)) || (scat_regs[SCAT_VERSION] >= 4) ? 0x60000 : 0x40000); - if(scat_regs[SCAT_VERSION] & 0xF0) { - int i; - for(i=0;i<8;i++) { - if(val & 0x10) - mem_mapping_disable(&scat_high_mapping[i]); - else - mem_mapping_enable(&scat_high_mapping[i]); - } - } -} - - -static uint32_t -get_scat_addr(uint32_t addr, scat_t *p) -{ - int nbank; - - if (p && (scat_regs[SCAT_EMS_CONTROL] & 0x80) && (p->regs_2x9 & 0x80)) - addr = (addr & 0x3fff) | (((p->regs_2x9 & 3) << 8) | p->regs_2x8) << 14; - - if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) { - switch((scat_regs[SCAT_EXTENDED_BOUNDARY] & ((scat_regs[SCAT_VERSION] & 0x0F) > 3 ? 0x40 : 0)) | (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F)) { - case 0x41: - nbank = addr >> 19; - if(nbank < 4) - nbank = 1; - else if(nbank == 4) - nbank = 0; - else - nbank -= 3; - break; - case 0x42: - nbank = addr >> 19; - if(nbank < 8) - nbank = 1 + (nbank >> 2); - else if(nbank == 8) - nbank = 0; - else - nbank -= 6; - break; - case 0x43: - nbank = addr >> 19; - if(nbank < 12) - nbank = 1 + (nbank >> 2); - else if(nbank == 12) - nbank = 0; - else - nbank -= 9; - break; - case 0x44: - nbank = addr >> 19; - if(nbank < 4) - nbank = 2; - else if(nbank < 6) - nbank -= 4; - else - nbank -= 3; - break; - case 0x45: - nbank = addr >> 19; - if(nbank < 8) - nbank = 2 + (nbank >> 2); - else if(nbank < 10) - nbank -= 8; - else - nbank -= 6; - break; - default: - nbank = addr >> (((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) < 8 && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) ? 19 : 21); - break; - } - nbank &= (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3; - if ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3 && nbank == 2 && (addr & 0x7FFFF) < 0x60000 && mem_size > 640) { - nbank = 1; - addr ^= 0x70000; - } - - if(external_is_RAS && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) { - if(nbank == 3) - nbank = 7; - else - return 0xFFFFFFFF; - } else if(!external_is_RAS && scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) { - switch(nbank) { - case 7: - nbank = 3; - break; - /* Note - In the following cases, the chipset accesses multiple memory banks - at the same time, so it's impossible to predict which memory bank - is actually accessed. */ - case 5: - case 1: - nbank = 1; - break; - case 3: - nbank = 2; - break; - default: - nbank = 0; - break; - } - } - - if((scat_regs[SCAT_VERSION] & 0x0F) > 3 && (mem_size > 2048) && (mem_size & 1536)) { - if((mem_size & 1536) == 512) { - if(nbank == 0) - addr &= 0x7FFFF; - else - addr = 0x80000 + ((addr & 0x1FFFFF) | ((nbank - 1) << 21)); - } else { - if(nbank < 2) - addr = (addr & 0x7FFFF) | (nbank << 19); - else - addr = 0x100000 + ((addr & 0x1FFFFF) | ((nbank - 2) << 21)); - } - } else { - int nbanks_2048k, nbanks_512k; - if (mem_size <= ((scat_regs[SCAT_VERSION] & 0x0F) > 3 ? 2048 : 4096) && (((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) < 8) || external_is_RAS)) { - nbanks_2048k = 0; - nbanks_512k = mem_size >> 9; - } else { - nbanks_2048k = mem_size >> 11; - nbanks_512k = (mem_size & 1536) >> 9; - } - if(nbank < nbanks_2048k || (nbanks_2048k > 0 && nbank >= nbanks_2048k + nbanks_512k + ((mem_size & 511) >> 7))) { - addr &= 0x1FFFFF; - addr |= (nbank << 21); - } else if(nbank < nbanks_2048k + nbanks_512k || nbank >= nbanks_2048k + nbanks_512k + ((mem_size & 511) >> 7)) { - addr &= 0x7FFFF; - addr |= (nbanks_2048k << 21) | ((nbank - nbanks_2048k) << 19); - } else { - addr &= 0x1FFFF; - addr |= (nbanks_2048k << 21) | (nbanks_512k << 19) | ((nbank - nbanks_2048k - nbanks_512k) << 17); - } - } - } else { - uint32_t addr2; - switch(scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) { - case 2: - case 4: - nbank = addr >> 19; - if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { - nbank = (addr >> 10) & 1; - addr2 = addr >> 11; - } else - addr2 = addr >> 10; - break; - case 3: - nbank = addr >> 19; - if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { - nbank = (addr >> 10) & 1; - addr2 = addr >> 11; - } else if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) == 2 && (addr & 0x7FFFF) < 0x60000) { - addr ^= 0x1F0000; - nbank = (addr >> 10) & 1; - addr2 = addr >> 11; - } else - addr2 = addr >> 10; - break; - case 5: - nbank = addr >> 19; - if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) { - nbank = (addr >> 10) & 3; - addr2 = addr >> 12; - } else - addr2 = addr >> 10; - break; - case 6: - nbank = addr >> 19; - if(nbank < 2) { - nbank = (addr >> 10) & 1; - addr2 = addr >> 11; - } else { - nbank = 2 + ((addr - 0x100000) >> 21); - addr2 = (addr - 0x100000) >> 11; - } - break; - case 7: - case 0x0F: - nbank = addr >> 19; - if(nbank < 2) { - nbank = (addr >> 10) & 1; - addr2 = addr >> 11; - } else if(nbank < 10) { - nbank = 2 + (((addr - 0x100000) >> 11) & 1); - addr2 = (addr - 0x100000) >> 12; - } else { - nbank = 4 + ((addr - 0x500000) >> 21); - addr2 = (addr - 0x500000) >> 11; - } - break; - case 8: - nbank = addr >> 19; - if(nbank < 4) { - nbank = 1; - addr2 = addr >> 11; - } else if(nbank == 4) { - nbank = 0; - addr2 = addr >> 10; - } else { - nbank -= 3; - addr2 = addr >> 10; - } - break; - case 9: - nbank = addr >> 19; - if(nbank < 8) { - nbank = 1 + ((addr >> 11) & 1); - addr2 = addr >> 12; - } else if(nbank == 8) { - nbank = 0; - addr2 = addr >> 10; - } else { - nbank -= 6; - addr2 = addr >> 10; - } - break; - case 0x0A: - nbank = addr >> 19; - if(nbank < 8) { - nbank = 1 + ((addr >> 11) & 1); - addr2 = addr >> 12; - } else if(nbank < 12) { - nbank = 3; - addr2 = addr >> 11; - } else if(nbank == 12) { - nbank = 0; - addr2 = addr >> 10; - } else { - nbank -= 9; - addr2 = addr >> 10; - } - break; - case 0x0B: - nbank = addr >> 21; - addr2 = addr >> 11; - break; - case 0x0C: - case 0x0D: - nbank = addr >> 21; - if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { - nbank = (addr >> 11) & 1; - addr2 = addr >> 12; - } else - addr2 = addr >> 11; - break; - case 0x0E: - case 0x13: - nbank = addr >> 21; - if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) { - nbank = (addr >> 11) & 3; - addr2 = addr >> 13; - } else - addr2 = addr >> 11; - break; - case 0x10: - case 0x11: - nbank = addr >> 19; - if(nbank < 2) { - nbank = (addr >> 10) & 1; - addr2 = addr >> 11; - } else if(nbank < 10) { - nbank = 2 + (((addr - 0x100000) >> 11) & 1); - addr2 = (addr - 0x100000) >> 12; - } else if(nbank < 18) { - nbank = 4 + (((addr - 0x500000) >> 11) & 1); - addr2 = (addr - 0x500000) >> 12; - } else { - nbank = 6 + ((addr - 0x900000) >> 21); - addr2 = (addr - 0x900000) >> 11; - } - break; - case 0x12: - nbank = addr >> 19; - if(nbank < 2) { - nbank = (addr >> 10) & 1; - addr2 = addr >> 11; - } else if(nbank < 10) { - nbank = 2 + (((addr - 0x100000) >> 11) & 1); - addr2 = (addr - 0x100000) >> 12; - } else { - nbank = 4 + (((addr - 0x500000) >> 11) & 3); - addr2 = (addr - 0x500000) >> 13; - } - break; - case 0x14: - case 0x15: - nbank = addr >> 21; - if((nbank & 7) < 4) { - nbank = (addr >> 11) & 3; - addr2 = addr >> 13; - } else if((nbank & 7) < 6) { - nbank = 4 + (((addr - 0x800000) >> 11) & 1); - addr2 = (addr - 0x800000) >> 12; - } else { - nbank = 6 + (((addr - 0xC00000) >> 11) & 3); - addr2 = (addr - 0xC00000) >> 13; - } - break; - case 0x16: - nbank = ((addr >> 21) & 4) | ((addr >> 11) & 3); - addr2 = addr >> 13; - break; - case 0x17: - if(external_is_RAS && (addr & 0x800) == 0) - return 0xFFFFFFFF; - nbank = addr >> 19; - if(nbank < 2) { - nbank = (addr >> 10) & 1; - addr2 = addr >> 11; - } else { - nbank = 2 + ((addr - 0x100000) >> 23); - addr2 = (addr - 0x100000) >> 12; - } - break; - case 0x18: - if(external_is_RAS && (addr & 0x800) == 0) - return 0xFFFFFFFF; - nbank = addr >> 21; - if(nbank < 4) { - nbank = 1; - addr2 = addr >> 12; - } else if(nbank == 4) { - nbank = 0; - addr2 = addr >> 11; - } else { - nbank -= 3; - addr2 = addr >> 11; - } - break; - case 0x19: - if(external_is_RAS && (addr & 0x800) == 0) - return 0xFFFFFFFF; - nbank = addr >> 23; - if((nbank & 3) < 2) { - nbank = (addr >> 12) & 1; - addr2 = addr >> 13; - } else - addr2 = addr >> 12; - break; - default: - if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 6) { - nbank = addr >> 19; - addr2 = (addr >> 10) & 0x1FF; - } else if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 0x17) { - nbank = addr >> 21; - addr2 = (addr >> 11) & 0x3FF; - } else { - nbank = addr >> 23; - addr2 = (addr >> 12) & 0x7FF; - } - break; - } - - nbank &= (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3; - if ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) > 0x16 && nbank == 3) - return 0xFFFFFFFF; - - if(external_is_RAS && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) { - if(nbank == 3) - nbank = 7; - else - return 0xFFFFFFFF; - } else if(!external_is_RAS && scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) { - switch(nbank) { - case 7: - nbank = 3; - break; - /* Note - In the following cases, the chipset accesses multiple memory banks - at the same time, so it's impossible to predict which memory bank - is actually accessed. */ - case 5: - case 1: - nbank = 1; - break; - case 3: - nbank = 2; - break; - default: - nbank = 0; - break; - } - } - - switch(mem_size & ~511) { - case 1024: - case 1536: - addr &= 0x3FF; - if(nbank < 2) - addr |= (nbank << 10) | ((addr2 & 0x1FF) << 11); - else - addr |= ((addr2 & 0x1FF) << 10) | (nbank << 19); - break; - case 2048: - if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 5) { - addr &= 0x3FF; - if(nbank < 4) - addr |= (nbank << 10) | ((addr2 & 0x1FF) << 12); - else - addr |= ((addr2 & 0x1FF) << 10) | (nbank << 19); - } else { - addr &= 0x7FF; - addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); - } - break; - case 2560: - if(nbank == 0) - addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); - else { - addr &= 0x7FF; - addr2 &= 0x3FF; - addr = addr + 0x80000 + ((addr2 << 11) | ((nbank - 1) << 21)); - } - break; - case 3072: - if(nbank < 2) - addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); - else - addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11) | ((nbank - 2) << 21)); - break; - case 4096: - case 6144: - addr &= 0x7FF; - if(nbank < 2) - addr |= (nbank << 11) | ((addr2 & 0x3FF) << 12); - else - addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); - break; - case 4608: - if(((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) >= 8 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) <= 0x0A) || ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 0x18)) { - if(nbank == 0) - addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); - else if(nbank < 3) - addr = 0x80000 + ((addr & 0x7FF) | ((nbank - 1) << 11) | ((addr2 & 0x3FF) << 12)); - else - addr = 0x480000 + ((addr & 0x3FF) | ((addr2 & 0x1FF) << 10) | ((nbank - 3) << 19)); - } else if(nbank == 0) - addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); - else { - addr &= 0x7FF; - addr2 &= 0x3FF; - addr = addr + 0x80000 + ((addr2 << 11) | ((nbank - 1) << 21)); - } - break; - case 5120: - case 7168: - if(nbank < 2) - addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); - else if(nbank < 4) - addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); - else - addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11) | ((nbank - 2) << 21)); - break; - case 6656: - if(((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) >= 8 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) <= 0x0A) || ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 0x18)) { - if(nbank == 0) - addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); - else if(nbank < 3) - addr = 0x80000 + ((addr & 0x7FF) | ((nbank - 1) << 11) | ((addr2 & 0x3FF) << 12)); - else if(nbank == 3) - addr = 0x480000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11)); - else - addr = 0x680000 + ((addr & 0x3FF) | ((addr2 & 0x1FF) << 10) | ((nbank - 4) << 19)); - } else if(nbank == 0) - addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); - else if(nbank == 1) { - addr &= 0x7FF; - addr2 &= 0x3FF; - addr = addr + 0x80000 + (addr2 << 11); - } else { - addr &= 0x7FF; - addr2 &= 0x3FF; - addr = addr + 0x280000 + ((addr2 << 12) | ((nbank & 1) << 11) | (((nbank - 2) & 6) << 21)); - } - break; - case 8192: - addr &= 0x7FF; - if(nbank < 4) - addr |= (nbank << 11) | ((addr2 & 0x3FF) << 13); - else - addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); - break; - case 9216: - if(nbank < 2) - addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); - else if(external_is_RAS) { - if(nbank < 6) - addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); - else - addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11) | ((nbank - 2) << 21)); - } else - addr = 0x100000 + ((addr & 0xFFF) | ((addr2 & 0x7FF) << 12) | ((nbank - 2) << 23)); - break; - case 10240: - if(external_is_RAS) { - addr &= 0x7FF; - if(nbank < 4) - addr |= (nbank << 11) | ((addr2 & 0x3FF) << 13); - else - addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); - } else if(nbank == 0) - addr = (addr & 0x7FF) | ((addr2 & 0x3FF) << 11); - else { - addr &= 0xFFF; - addr2 &= 0x7FF; - addr = addr + 0x200000 + ((addr2 << 12) | ((nbank - 1) << 23)); - } - break; - case 11264: - if(nbank < 2) - addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); - else if(nbank < 6) - addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); - else - addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11) | ((nbank - 2) << 21)); - break; - case 12288: - if(external_is_RAS) { - addr &= 0x7FF; - if(nbank < 4) - addr |= (nbank << 11) | ((addr2 & 0x3FF) << 13); - else if(nbank < 6) - addr |= ((nbank & 1) << 11) | ((addr2 & 0x3FF) << 12) | ((nbank & 4) << 21); - else - addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); - } else { - if(nbank < 2) - addr = (addr & 0x7FF) | (nbank << 11) | ((addr2 & 0x3FF) << 12); - else - addr = 0x400000 + ((addr & 0xFFF) | ((addr2 & 0x7FF) << 12) | ((nbank - 2) << 23)); - } - break; - case 13312: - if(nbank < 2) - addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); - else if(nbank < 4) - addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); - else - addr = 0x500000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 13) | ((nbank & 3) << 11)); - break; - case 14336: - addr &= 0x7FF; - if(nbank < 4) - addr |= (nbank << 11) | ((addr2 & 0x3FF) << 13); - else if(nbank < 6) - addr |= ((nbank & 1) << 11) | ((addr2 & 0x3FF) << 12) | ((nbank & 4) << 21); - else - addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); - break; - case 16384: - if(external_is_RAS) { - addr &= 0x7FF; - addr2 &= 0x3FF; - addr |= ((nbank & 3) << 11) | (addr2 << 13) | ((nbank & 4) << 21); - } else { - addr &= 0xFFF; - addr2 &= 0x7FF; - if(nbank < 2) - addr |= (addr2 << 13) | (nbank << 12); - else - addr |= (addr2 << 12) | (nbank << 23); - } - break; - default: - if(mem_size < 2048 || ((mem_size & 1536) == 512) || (mem_size == 2048 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 6)) { - addr &= 0x3FF; - addr2 &= 0x1FF; - addr |= (addr2 << 10) | (nbank << 19); - } else if(mem_size < 8192 || (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 0x17) { - addr &= 0x7FF; - addr2 &= 0x3FF; - addr |= (addr2 << 11) | (nbank << 21); - } else { - addr &= 0xFFF; - addr2 &= 0x7FF; - addr |= (addr2 << 12) | (nbank << 23); - } - break; - } - } - return addr; -} - - -static void -scat_set_global_EMS_state(int state) -{ - int i; - uint32_t base_addr, virt_addr; - - for(i=((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0 : 24; i<32; i++) { - base_addr = (i + 16) << 14; - if(i >= 24) - base_addr += 0x30000; - if(state && (scat_stat[i].regs_2x9 & 0x80)) { - virt_addr = get_scat_addr(base_addr, &scat_stat[i]); - if(i < 24) mem_mapping_disable(&scat_4000_EFFF_mapping[i]); - else mem_mapping_disable(&scat_4000_EFFF_mapping[i + 12]); - mem_mapping_enable(&scat_ems_mapping[i]); - if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&scat_ems_mapping[i], ram + virt_addr); - else mem_mapping_set_exec(&scat_ems_mapping[i], NULL); - } else { - mem_mapping_set_exec(&scat_ems_mapping[i], ram + base_addr); - mem_mapping_disable(&scat_ems_mapping[i]); - - int conf = (scat_regs[SCAT_VERSION] & 0xF0) ? (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) : (scat_regs[SCAT_DRAM_CONFIGURATION] & 0xF) | ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2); - if(i < 24) { - if(conf > 1 || (conf == 1 && i < 16)) - mem_mapping_enable(&scat_4000_EFFF_mapping[i]); - else - mem_mapping_disable(&scat_4000_EFFF_mapping[i]); - } else if(conf > 3 || ((scat_regs[SCAT_VERSION] & 0xF0) != 0 && conf == 2)) - mem_mapping_enable(&scat_4000_EFFF_mapping[i + 12]); - else - mem_mapping_disable(&scat_4000_EFFF_mapping[i + 12]); - } - } - flushmmucache(); -} - - -static void -scat_memmap_state_update() -{ - int i; - uint32_t addr; - - for(i=(((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0 : 16);i<44;i++) { - addr = get_scat_addr(0x40000 + (i << 14), NULL); - mem_mapping_set_exec(&scat_4000_EFFF_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); - } - addr = get_scat_addr(0, NULL); - mem_mapping_set_exec(&scat_low_mapping[0], addr < (mem_size << 10) ? ram + addr : NULL); - addr = get_scat_addr(0xF0000, NULL); - mem_mapping_set_exec(&scat_low_mapping[1], addr < (mem_size << 10) ? ram + addr : NULL); - for(i=2;i<32;i++) { - addr = get_scat_addr(i << 19, NULL); - mem_mapping_set_exec(&scat_low_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); - } - - if((scat_regs[SCAT_VERSION] & 0xF0) == 0) { - for(i=0;i < scat_max_map[(scat_regs[SCAT_DRAM_CONFIGURATION] & 0xF) | ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2)];i++) - mem_mapping_enable(&scat_low_mapping[i]); - for(;i<32;i++) mem_mapping_disable(&scat_low_mapping[i]); - - for(i=24;i<36;i++) { - if(((scat_regs[SCAT_DRAM_CONFIGURATION] & 0xF) | (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40)) < 4) - mem_mapping_disable(&scat_4000_EFFF_mapping[i]); - else - mem_mapping_enable(&scat_4000_EFFF_mapping[i]); - } - } else { - for(i=0;i < scatsx_max_map[scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F];i++) - mem_mapping_enable(&scat_low_mapping[i]); - for(;i<32;i++) mem_mapping_disable(&scat_low_mapping[i]); - - for(i=24;i<36;i++) { - if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 2 || (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 3) - mem_mapping_disable(&scat_4000_EFFF_mapping[i]); - else - mem_mapping_enable(&scat_4000_EFFF_mapping[i]); - } - } - - if((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) || ((scat_regs[SCAT_VERSION] & 0xF0) != 0)) { - if((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 3)) { - mem_mapping_disable(&scat_low_mapping[2]); - for(i=0;i<6;i++) { - addr = get_scat_addr(0x100000 + (i << 16), NULL); - mem_mapping_set_exec(&scat_remap_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); - mem_mapping_enable(&scat_remap_mapping[i]); - } - } else { - for(i=0;i<6;i++) - mem_mapping_disable(&scat_remap_mapping[i]); - if((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) > 4) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) > 3)) - mem_mapping_enable(&scat_low_mapping[2]); - } - } else { - for(i=0;i<6;i++) - mem_mapping_disable(&scat_remap_mapping[i]); - mem_mapping_enable(&scat_low_mapping[2]); - } - - scat_set_global_EMS_state(scat_regs[SCAT_EMS_CONTROL] & 0x80); -} - - -static void -scat_write(uint16_t port, uint8_t val, void *priv) -{ - uint8_t scat_reg_valid = 0, scat_shadow_update = 0, scat_map_update = 0, index; - uint32_t base_addr, virt_addr; - - switch (port) { - case 0x22: - scat_index = val; - break; - - case 0x23: - switch (scat_index) { - case SCAT_DMA_WAIT_STATE_CONTROL: - case SCAT_CLOCK_CONTROL: - case SCAT_PERIPHERAL_CONTROL: - scat_reg_valid = 1; - break; - case SCAT_EMS_CONTROL: - if(val & 0x40) { - if(val & 1) { - io_sethandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - io_removehandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - } else { - io_sethandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - io_removehandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - } - } else { - io_removehandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - io_removehandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - } - scat_set_global_EMS_state(val & 0x80); - scat_reg_valid = 1; - break; - case SCAT_POWER_MANAGEMENT: - /* TODO - Only use AUX parity disable bit for this version. - Other bits should be implemented later. */ - val &= (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x40 : 0x60; - scat_reg_valid = 1; - break; - case SCAT_DRAM_CONFIGURATION: - scat_map_update = 1; - - if((scat_regs[SCAT_VERSION] & 0xF0) == 0) { - cpu_waitstates = (val & 0x70) == 0 ? 1 : 2; - cpu_update_waitstates(); - } - - scat_reg_valid = 1; - break; - case SCAT_EXTENDED_BOUNDARY: - if((scat_regs[SCAT_VERSION] & 0xF0) == 0) { - if(scat_regs[SCAT_VERSION] < 4) { - val &= 0xBF; - scat_set_xms_bound(val & 0x0f); - } else { - val = (val & 0x7F) | 0x80; - scat_set_xms_bound(val & 0x4f); - } - } else - scat_set_xms_bound(val & 0x1f); - mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - if((val ^ scat_regs[SCAT_EXTENDED_BOUNDARY]) & 0xC0) scat_map_update = 1; - scat_reg_valid = 1; - break; - case SCAT_ROM_ENABLE: - scat_reg_valid = 1; - scat_romcs_state_update(val); - break; - case SCAT_RAM_WRITE_PROTECT: - scat_reg_valid = 1; - flushmmucache_cr3(); - break; - case SCAT_SHADOW_RAM_ENABLE_1: - case SCAT_SHADOW_RAM_ENABLE_2: - case SCAT_SHADOW_RAM_ENABLE_3: - scat_reg_valid = 1; - scat_shadow_update = 1; - break; - case SCATSX_LAPTOP_FEATURES: - if((scat_regs[SCAT_VERSION] & 0xF0) != 0) { - val = (val & ~8) | (scat_regs[SCATSX_LAPTOP_FEATURES] & 8); - scat_reg_valid = 1; - } - break; - case SCATSX_FAST_VIDEO_CONTROL: - case SCATSX_FAST_VIDEORAM_ENABLE: - case SCATSX_HIGH_PERFORMANCE_REFRESH: - case SCATSX_CAS_TIMING_FOR_DMA: - if((scat_regs[SCAT_VERSION] & 0xF0) != 0) scat_reg_valid = 1; - break; - default: - break; - } - if (scat_reg_valid) - scat_regs[scat_index] = val; - if (scat_shadow_update) - scat_shadow_state_update(); - if (scat_map_update) - scat_memmap_state_update(); - break; - - case 0x92: - if ((mem_a20_alt ^ val) & 2) { - mem_a20_alt = val & 2; - mem_a20_recalc(); - } - if ((~scat_port_92 & val) & 1) { - softresetx86(); - cpu_set_edx(); - } - scat_port_92 = val; - break; - - case 0x208: - case 0x218: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; - else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; - scat_stat[index].regs_2x8 = val; - base_addr = (index + 16) << 14; - if(index >= 24) - base_addr += 0x30000; - - if((scat_regs[SCAT_EMS_CONTROL] & 0x80) && (scat_stat[index].regs_2x9 & 0x80)) { - virt_addr = get_scat_addr(base_addr, &scat_stat[index]); - if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&scat_ems_mapping[index], ram + virt_addr); - else mem_mapping_set_exec(&scat_ems_mapping[index], NULL); - flushmmucache(); - } - } - break; - case 0x209: - case 0x219: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; - else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; - scat_stat[index].regs_2x9 = val; - base_addr = (index + 16) << 14; - if(index >= 24) - base_addr += 0x30000; - - if (scat_regs[SCAT_EMS_CONTROL] & 0x80) { - if (val & 0x80) { - virt_addr = get_scat_addr(base_addr, &scat_stat[index]); - if(index < 24) mem_mapping_disable(&scat_4000_EFFF_mapping[index]); - else mem_mapping_disable(&scat_4000_EFFF_mapping[index + 12]); - if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&scat_ems_mapping[index], ram + virt_addr); - else mem_mapping_set_exec(&scat_ems_mapping[index], NULL); - mem_mapping_enable(&scat_ems_mapping[index]); - } else { - mem_mapping_set_exec(&scat_ems_mapping[index], ram + base_addr); - mem_mapping_disable(&scat_ems_mapping[index]); - if(index < 24) mem_mapping_enable(&scat_4000_EFFF_mapping[index]); - else mem_mapping_enable(&scat_4000_EFFF_mapping[index + 12]); - } - flushmmucache(); - } - - if (scat_ems_reg_2xA & 0x80) - scat_ems_reg_2xA = (scat_ems_reg_2xA & 0xe0) | ((scat_ems_reg_2xA + 1) & (((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0x1f : 3)); - } - break; - case 0x20A: - case 0x21A: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) - scat_ems_reg_2xA = ((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? val : val & 0xc3; - break; - } -} - - -static uint8_t -scat_read(uint16_t port, void *priv) -{ - uint8_t val = 0xff, index; - switch (port) { - case 0x23: - switch (scat_index) { - case SCAT_MISCELLANEOUS_STATUS: - val = (scat_regs[scat_index] & 0x3f) | (~nmi_mask & 0x80) | ((mem_a20_key & 2) << 5); - break; - case SCAT_DRAM_CONFIGURATION: - if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) val = (scat_regs[scat_index] & 0x8f) | (cpu_waitstates == 1 ? 0 : 0x10); - else val = scat_regs[scat_index]; - break; - case SCAT_EXTENDED_BOUNDARY: - val = scat_regs[scat_index]; - if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) { - if((scat_regs[SCAT_VERSION] & 0x0F) >= 4) - val |= 0x80; - else - val &= 0xAF; - } - break; - default: - val = scat_regs[scat_index]; - break; - } - break; - - case 0x92: - val = scat_port_92; - break; - - case 0x208: - case 0x218: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; - else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; - val = scat_stat[index].regs_2x8; - } - break; - case 0x209: - case 0x219: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; - else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; - val = scat_stat[index].regs_2x9; - } - break; - case 0x20A: - case 0x21A: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) - val = scat_ems_reg_2xA; - break; - } - return val; -} - - -static uint8_t -mem_read_scatb(uint32_t addr, void *priv) -{ - uint8_t val = 0xff; - scat_t *stat = (scat_t *)priv; - - addr = get_scat_addr(addr, stat); - if (addr < (mem_size << 10)) - val = ram[addr]; - - return val; -} - - -static void -mem_write_scatb(uint32_t addr, uint8_t val, void *priv) -{ - scat_t *stat = (scat_t *)priv; - uint32_t oldaddr = addr, chkaddr; - - addr = get_scat_addr(addr, stat); - chkaddr = stat ? addr : oldaddr; - if (chkaddr >= 0xC0000 && chkaddr < 0x100000) { - if(scat_regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xC0000) >> 15))) return; - } - if (addr < (mem_size << 10)) - ram[addr] = val; -} - - -static uint16_t -mem_read_scatw(uint32_t addr, void *priv) -{ - uint16_t val = 0xffff; - scat_t *stat = (scat_t *)priv; - - addr = get_scat_addr(addr, stat); - if (addr < (mem_size << 10)) - val = *(uint16_t *)&ram[addr]; - - return val; -} - - -static void -mem_write_scatw(uint32_t addr, uint16_t val, void *priv) -{ - scat_t *stat = (scat_t *)priv; - uint32_t oldaddr = addr, chkaddr; - - addr = get_scat_addr(addr, stat); - chkaddr = stat ? addr : oldaddr; - if (chkaddr >= 0xC0000 && chkaddr < 0x100000) { - if(scat_regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xC0000) >> 15))) return; - } - if (addr < (mem_size << 10)) - *(uint16_t *)&ram[addr] = val; -} - - -static uint32_t -mem_read_scatl(uint32_t addr, void *priv) -{ - uint32_t val = 0xffffffff; - scat_t *stat = (scat_t *)priv; - - addr = get_scat_addr(addr, stat); - if (addr < (mem_size << 10)) - val = *(uint32_t *)&ram[addr]; - - return val; -} - - -static void -mem_write_scatl(uint32_t addr, uint32_t val, void *priv) -{ - scat_t *stat = (scat_t *)priv; - uint32_t oldaddr = addr, chkaddr; - - addr = get_scat_addr(addr, stat); - chkaddr = stat ? addr : oldaddr; - if (chkaddr >= 0xC0000 && chkaddr < 0x100000) { - if(scat_regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xC0000) >> 15))) return; - } - if (addr < (mem_size << 10)) - *(uint32_t *)&ram[addr] = val; -} - - -static void -scat_init() -{ - int i; - - io_sethandler(0x0022, 0x0002, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - io_sethandler(0x0092, 0x0001, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - - for (i = 0; i < 256; i++) - scat_regs[i] = 0xff; - - scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; - switch(romset) { - case ROM_GW286CT: - case ROM_SPC4216P: - scat_regs[SCAT_VERSION] = 4; - break; - default: - scat_regs[SCAT_VERSION] = 1; - break; - } - scat_regs[SCAT_CLOCK_CONTROL] = 2; - scat_regs[SCAT_PERIPHERAL_CONTROL] = 0x80; - scat_regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; - scat_regs[SCAT_POWER_MANAGEMENT] = 0; - scat_regs[SCAT_ROM_ENABLE] = 0xC0; - scat_regs[SCAT_RAM_WRITE_PROTECT] = 0; - scat_regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; - scat_regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; - scat_regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; - scat_regs[SCAT_DRAM_CONFIGURATION] = cpu_waitstates == 1 ? 2 : 0x12; - scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; - scat_regs[SCAT_EMS_CONTROL] = 0; - scat_port_92 = 0; - - mem_mapping_disable(&ram_low_mapping); - mem_mapping_disable(&ram_high_mapping); - for (i = 0; i < 4; i++) - mem_mapping_disable(&bios_mapping[i]); - mem_mapping_add(&scat_low_mapping[0], 0, 0x40000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_add(&scat_low_mapping[1], 0xF0000, 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + 0xF0000, MEM_MAPPING_INTERNAL, NULL); - for(i=2;i<32;i++) - mem_mapping_add(&scat_low_mapping[i], (i << 19), 0x80000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + (i << 19), MEM_MAPPING_INTERNAL, NULL); - mem_mapping_set_addr(&scat_low_mapping[31], 0xF80000, scat_regs[SCAT_VERSION] < 4 ? 0x40000 : 0x60000); - - for (i = 0; i < 44; i++) - mem_mapping_add(&scat_4000_EFFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); - for (i = 0; i < 8; i++) { - mem_mapping_add(&scat_low_ROMCS_mapping[i], 0xC0000 + (i << 14), 0x4000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, NULL); - mem_mapping_disable(&scat_low_ROMCS_mapping[i]); - } - - for (i = 0; i < 32; i++) { - scat_stat[i].regs_2x8 = 0xff; - scat_stat[i].regs_2x9 = 0x03; - mem_mapping_add(&scat_ems_mapping[i], (i + (i >= 24 ? 28 : 16)) << 14, 0x04000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + ((i + (i >= 24 ? 28 : 16)) << 14), 0, &scat_stat[i]); - } - - for (i = (scat_regs[SCAT_VERSION] < 4 ? 0 : 8); i < 16; i++) { - mem_mapping_add(&scat_high_mapping[i], (i << 14) + 0xFC0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), 0, NULL); - mem_mapping_enable(&scat_high_mapping[i]); - } - - for(i=0;i<6;i++) - mem_mapping_add(&scat_remap_mapping[i], 0x100000 + (i << 16), 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, mem_size >= 1024 ? ram + get_scat_addr(0x100000 + (i << 16), NULL) : NULL, MEM_MAPPING_INTERNAL, NULL); - - external_is_RAS = (scat_regs[SCAT_VERSION] > 3) || (((mem_size & ~2047) >> 11) + ((mem_size & 1536) >> 9) + ((mem_size & 511) >> 7)) > 4; - - scat_set_xms_bound(0); - scat_memmap_state_update(); - scat_shadow_state_update(); -} - - -static void -scatsx_init() -{ - int i; - - io_sethandler(0x0022, 0x0002, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - io_sethandler(0x0092, 0x0001, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - - for (i = 0; i < 256; i++) - scat_regs[i] = 0xff; - - scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; - scat_regs[SCAT_VERSION] = 0x13; - scat_regs[SCAT_CLOCK_CONTROL] = 6; - scat_regs[SCAT_PERIPHERAL_CONTROL] = 0; - scat_regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; - scat_regs[SCAT_POWER_MANAGEMENT] = 0; - scat_regs[SCAT_ROM_ENABLE] = 0xC0; - scat_regs[SCAT_RAM_WRITE_PROTECT] = 0; - scat_regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; - scat_regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; - scat_regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; - scat_regs[SCAT_DRAM_CONFIGURATION] = 1; - scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; - scat_regs[SCAT_EMS_CONTROL] = 0; - scat_regs[SCATSX_LAPTOP_FEATURES] = 0; - scat_regs[SCATSX_FAST_VIDEO_CONTROL] = 0; - scat_regs[SCATSX_FAST_VIDEORAM_ENABLE] = 0; - scat_regs[SCATSX_HIGH_PERFORMANCE_REFRESH] = 8; - scat_regs[SCATSX_CAS_TIMING_FOR_DMA] = 3; - scat_port_92 = 0; - - mem_mapping_disable(&ram_low_mapping); - mem_mapping_disable(&ram_high_mapping); - for (i = 0; i < 4; i++) - mem_mapping_disable(&bios_mapping[i]); - mem_mapping_add(&scat_low_mapping[0], 0, 0x80000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_add(&scat_low_mapping[1], 0xF0000, 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + 0xF0000, MEM_MAPPING_INTERNAL, NULL); - for(i=2;i<32;i++) - mem_mapping_add(&scat_low_mapping[i], (i << 19), 0x80000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + (i << 19), MEM_MAPPING_INTERNAL, NULL); - mem_mapping_set_addr(&scat_low_mapping[31], 0xF80000, 0x40000); - - for (i = 16; i < 44; i++) { - mem_mapping_add(&scat_4000_EFFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_enable(&scat_4000_EFFF_mapping[i]); - } - for (i = 0; i < 8; i++) { - mem_mapping_add(&scat_low_ROMCS_mapping[i], 0xC0000 + (i << 14), 0x4000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, NULL); - mem_mapping_disable(&scat_low_ROMCS_mapping[i]); - } - - for (i = 24; i < 32; i++) { - scat_stat[i].regs_2x8 = 0xff; - scat_stat[i].regs_2x9 = 0x03; - mem_mapping_add(&scat_ems_mapping[i], (i + 28) << 14, 0x04000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + ((i + 28) << 14), 0, &scat_stat[i]); - mem_mapping_disable(&scat_ems_mapping[i]); - } - - for (i = 0; i < 16; i++) { - mem_mapping_add(&scat_high_mapping[i], (i << 14) + 0xFC0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), 0, NULL); - mem_mapping_enable(&scat_high_mapping[i]); - } - - for(i=0;i<6;i++) - mem_mapping_add(&scat_remap_mapping[i], 0x100000 + (i << 16), 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, mem_size >= 1024 ? ram + get_scat_addr(0x100000 + (i << 16), NULL) : NULL, MEM_MAPPING_INTERNAL, NULL); - - external_is_RAS = scatsx_external_is_RAS[mem_size >> 9]; - - scat_set_xms_bound(0); - scat_memmap_state_update(); - scat_shadow_state_update(); -} - - -void -machine_at_scat_init(const machine_t *model) -{ - machine_at_init(model); - device_add(&fdc_at_device); - - scat_init(); -} - - -void -machine_at_scatsx_init(const machine_t *model) -{ - machine_at_common_init(model); - - device_add(&keyboard_at_ami_device); - device_add(&fdc_at_device); - - scatsx_init(); -} diff --git a/src/machine/m_at_sis_85c50x.c b/src/machine/m_at_sis_85c50x.c deleted file mode 100644 index d64ffa48a..000000000 --- a/src/machine/m_at_sis_85c50x.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * Emulation of the SiS 50x PCI chips. - * - * Version: @(#)m_at_sis_85c50x.c 1.0.7 2018/04/29 - * - * Author: Miran Grca, - * - * Copyright 2015-2018 Miran Grca. - */ -#include -#include -#include -#include -#include -#include "../86box.h" -#include "../io.h" -#include "../pci.h" -#include "../mem.h" -#include "machine.h" - - -typedef struct sis_85c501_t -{ - uint8_t pci_conf[256]; - uint8_t turbo_reg; -} sis_85c501_t; - -sis_85c501_t sis_85c501; - -typedef struct sis_85c503_t -{ - uint8_t pci_conf[256]; -} sis_85c503_t; - -sis_85c503_t sis_85c503; - -typedef struct sis_85c50x_t -{ - uint8_t isa_conf[12]; - uint8_t reg; -} sis_85c50x_isa_t; - -sis_85c50x_isa_t sis_85c50x_isa; - - -static void sis_85c501_recalcmapping(void) -{ - int c, d; - - for (c = 0; c < 1; c++) - { - for (d = 0; d < 4; d++) - { - uint32_t base = 0xe0000 + (d << 14); - if (sis_85c501.pci_conf[0x54 + c] & (1 << (d + 4))) - { - switch (sis_85c501.pci_conf[0x53] & 0x60) - { - case 0x00: - mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 0x20: - mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 0x40: - mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - case 0x60: - mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - } - } - else - mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } - } - - flushmmucache(); - shadowbios = 1; -} - - -static void sis_85c501_write(int func, int addr, uint8_t val, void *p) -{ - if (func) - return; - - if ((addr >= 0x10) && (addr < 0x4f)) - return; - - switch (addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0e: - return; - - case 0x04: /*Command register*/ - val &= 0x42; - val |= 0x04; - break; - case 0x05: - val &= 0x01; - break; - - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - val = 0x02; - break; - - case 0x54: /*Shadow configure*/ - if ((sis_85c501.pci_conf[0x54] & val) ^ 0xf0) - { - sis_85c501.pci_conf[0x54] = val; - sis_85c501_recalcmapping(); - } - break; - } - - sis_85c501.pci_conf[addr] = val; -} - - -static void sis_85c503_write(int func, int addr, uint8_t val, void *p) -{ - if (func > 0) - return; - - if (addr >= 0x0f && addr < 0x41) - return; - - switch(addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: - return; - - case 0x04: /*Command register*/ - val &= 0x08; - val |= 0x07; - break; - case 0x05: - val = 0; - break; - - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - val = 0x02; - break; - - case 0x41: - if (val & 0x80) - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTA, val & 0xf); - break; - case 0x42: - if (val & 0x80) - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTC, val & 0xf); - break; - case 0x43: - if (val & 0x80) - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTB, val & 0xf); - break; - case 0x44: - if (val & 0x80) - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTD, val & 0xf); - break; - } - - sis_85c503.pci_conf[addr] = val; -} - - -static void sis_85c50x_isa_write(uint16_t port, uint8_t val, void *priv) -{ - if (port & 1) - { - if (sis_85c50x_isa.reg <= 0xB) sis_85c50x_isa.isa_conf[sis_85c50x_isa.reg] = val; - } - else - { - sis_85c50x_isa.reg = val; - } -} - - -static uint8_t sis_85c501_read(int func, int addr, void *p) -{ - if (func) - return 0xff; - - return sis_85c501.pci_conf[addr]; -} - - -static uint8_t sis_85c503_read(int func, int addr, void *p) -{ - if (func > 0) - return 0xff; - - return sis_85c503.pci_conf[addr]; -} - - -static uint8_t sis_85c50x_isa_read(uint16_t port, void *priv) -{ - if (port & 1) - { - if (sis_85c50x_isa.reg <= 0xB) - return sis_85c50x_isa.isa_conf[sis_85c50x_isa.reg]; - else - return 0xff; - } - else - { - return sis_85c50x_isa.reg; - } -} - -static void sis_85c501_reset(void) -{ - memset(&sis_85c501, 0, sizeof(sis_85c501_t)); - sis_85c501.pci_conf[0x00] = 0x39; /*SiS*/ - sis_85c501.pci_conf[0x01] = 0x10; - sis_85c501.pci_conf[0x02] = 0x06; /*501/502*/ - sis_85c501.pci_conf[0x03] = 0x04; - - sis_85c501.pci_conf[0x04] = 7; - sis_85c501.pci_conf[0x05] = 0; - - sis_85c501.pci_conf[0x06] = 0x80; - sis_85c501.pci_conf[0x07] = 0x02; - - sis_85c501.pci_conf[0x08] = 0; /*Device revision*/ - - sis_85c501.pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ - sis_85c501.pci_conf[0x0a] = 0x00; - sis_85c501.pci_conf[0x0b] = 0x06; - - sis_85c501.pci_conf[0x0e] = 0x00; /*Single function device*/ - - sis_85c501.pci_conf[0x50] = 0xbc; - sis_85c501.pci_conf[0x51] = 0xfb; - sis_85c501.pci_conf[0x52] = 0xad; - sis_85c501.pci_conf[0x53] = 0xfe; - - shadowbios = 1; -} - -static void sis_85c501_init(void) -{ - pci_add_card(0, sis_85c501_read, sis_85c501_write, NULL); - - sis_85c501_reset(); - - pci_reset_handler.pci_master_reset = NULL; -} - -static void sis_85c503_reset(void) -{ - memset(&sis_85c503, 0, sizeof(sis_85c503_t)); - sis_85c503.pci_conf[0x00] = 0x39; /*SiS*/ - sis_85c503.pci_conf[0x01] = 0x10; - sis_85c503.pci_conf[0x02] = 0x08; /*503*/ - sis_85c503.pci_conf[0x03] = 0x00; - - sis_85c503.pci_conf[0x04] = 7; - sis_85c503.pci_conf[0x05] = 0; - - sis_85c503.pci_conf[0x06] = 0x80; - sis_85c503.pci_conf[0x07] = 0x02; - - sis_85c503.pci_conf[0x08] = 0; /*Device revision*/ - - sis_85c503.pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ - sis_85c503.pci_conf[0x0a] = 0x01; - sis_85c503.pci_conf[0x0b] = 0x06; - - sis_85c503.pci_conf[0x0e] = 0x00; /*Single function device*/ - - sis_85c503.pci_conf[0x41] = sis_85c503.pci_conf[0x42] = sis_85c503.pci_conf[0x43] = sis_85c503.pci_conf[0x44] = 0x80; -} - -static void sis_85c503_init(int card) -{ - - pci_add_card(card, sis_85c503_read, sis_85c503_write, NULL); - - sis_85c503_reset(); - - trc_init(); - - port_92_reset(); - - port_92_add(); - - pci_reset_handler.pci_set_reset = sis_85c503_reset; -} - - -static void sis_85c50x_isa_init(void) -{ - memset(&sis_85c50x_isa, 0, sizeof(sis_85c50x_isa_t)); - - io_sethandler(0x22, 0x0002, sis_85c50x_isa_read, NULL, NULL, sis_85c50x_isa_write, NULL, NULL, NULL); -} diff --git a/src/machine/m_at_socket4_5.c b/src/machine/m_at_socket4_5.c new file mode 100644 index 000000000..f5f3d2dd0 --- /dev/null +++ b/src/machine/m_at_socket4_5.c @@ -0,0 +1,355 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Socket 4 and 5 machines. + * + * Version: @(#)m_at_socket4_5.c 1.0.0 2019/05/16 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../chipset/chipset.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../timer.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../keyboard.h" +#include "../intel_flash.h" +#include "../intel_sio.h" +#include "../piix.h" +#include "../sio.h" +#include "../video/video.h" +#include "../video/vid_cl54xx.h" +#include "../video/vid_s3.h" +#include "machine.h" + + +static void +machine_at_premiere_common_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&sio_zb_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_ami_device); +} + + +static void +machine_at_award_common_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&ide_pci_2ch_device); + + pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x03, PCI_CARD_NORMAL, 1, 2, 3, 4); /* 03 = Slot 1 */ + pci_register_slot(0x04, PCI_CARD_NORMAL, 2, 3, 4, 1); /* 04 = Slot 2 */ + pci_register_slot(0x05, PCI_CARD_NORMAL, 3, 4, 1, 2); /* 05 = Slot 3 */ + pci_register_slot(0x06, PCI_CARD_NORMAL, 4, 1, 2, 3); /* 06 = Slot 4 */ + pci_register_slot(0x07, PCI_CARD_SCSI, 1, 2, 3, 4); /* 07 = SCSI */ + pci_register_slot(0x02, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&fdc_at_device); + device_add(&keyboard_ps2_pci_device); + device_add(&sio_device); + device_add(&intel_flash_bxt_device); +} + + +int +machine_at_batman_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/revenge/1009af2_.bio", + L"roms/machines/revenge/1009af2_.bi1", 0x1c000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_premiere_common_init(model); + + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_586mc1_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/586mc1/IS.34", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_award_common_init(model); + + device_add(&i430lx_device); + + return ret; +} + + +int +machine_at_plato_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/plato/1016ax1_.bio", + L"roms/machines/plato/1016ax1_.bi1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_premiere_common_init(model); + + device_add(&i430nx_device); + + return ret; +} + + +int +machine_at_430nx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/430nx/IP.20", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_award_common_init(model); + + device_add(&i430nx_device); + + return ret; +} + + +int +machine_at_p54tp4xe_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/p54tp4xe/t15i0302.awd", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + /* Award BIOS, SMC FDC37C665. */ + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_endeavor_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/endeavor/1006cb0_.bio", + L"roms/machines/endeavor/1006cb0_.bi1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + if (gfxcard == VID_INTERNAL) + device_add(&s3_phoenix_trio64_onboard_pci_device); + + return ret; +} + + +const device_t * +at_endeavor_get_device(void) +{ + return &s3_phoenix_trio64_onboard_pci_device; +} + + +int +machine_at_zappa_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/zappa/1006bs0_.bio", + L"roms/machines/zappa/1006bs0_.bi1", 0x20000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + return ret; +} + + +int +machine_at_mb500n_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/mb500n/031396s.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_president_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/president/bios.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83877f_president_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_VECTRA54) +int +machine_at_vectra54_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/vectra54/GT0724.22", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&fdc37c932qf_device); + device_add(&intel_flash_bxt_device); + + return ret; +} +#endif diff --git a/src/machine/m_at_socket7_s7.c b/src/machine/m_at_socket7_s7.c new file mode 100644 index 000000000..e9fa33fec --- /dev/null +++ b/src/machine/m_at_socket7_s7.c @@ -0,0 +1,452 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Socket 7 and Super Socket 7 machines. + * + * Version: @(#)m_at_socket7_s7.c 1.0.0 2019/05/16 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2010-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../chipset/chipset.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../keyboard.h" +#include "../intel_flash.h" +#include "../intel_sio.h" +#include "../piix.h" +#include "../sio.h" +#include "../video/video.h" +#include "../video/vid_cl54xx.h" +#include "../video/vid_s3.h" +#include "machine.h" + + +static void +machine_at_thor_common_init(const machine_t *model, int mr) +{ + machine_at_common_init_ex(model, mr); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 3, 2, 1); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); +} + + +int +machine_at_thor_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/thor/1006cn0_.bio", + L"roms/machines/thor/1006cn0_.bi1", 0x20000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_thor_common_init(model, 0); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_MRTHOR) +int +machine_at_mrthor_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/mrthor/mr_atx.bio", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_thor_common_init(model, 1); + + return ret; +} +#endif + + +int +machine_at_pb640_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined(L"roms/machines/pb640/1007CP0R.BIO", + L"roms/machines/pb640/1007CP0R.BI1", 0x1d000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_pb640_device); + device_add(&piix_pb640_device); + device_add(&ide_isa_2ch_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_ami_device); + + if (gfxcard == VID_INTERNAL) + device_add(&gd5440_onboard_pci_device); + + return ret; +} + + +const device_t * +at_pb640_get_device(void) +{ + return &gd5440_onboard_pci_device; +} + + +int +machine_at_acerm3a_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/acerm3a/r01-b3.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x1F, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x10, PCI_CARD_ONBOARD, 4, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c932fr_device); + device_add(&acerm3a_device); + + device_add(&intel_flash_bxb_device); + + return ret; +} + + +int +machine_at_acerv35n_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/acerv35n/v35nd1s1.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c932fr_device); + device_add(&acerm3a_device); + + device_add(&intel_flash_bxb_device); + + return ret; +} + + +int +machine_at_ap53_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ap53/ap53r2c0.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_ONBOARD, 1, 2, 3, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c669_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_p55t2p4_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/p55t2p4/0207_j2.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83877f_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_p55t2s_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/p55t2s/s6y08t.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_TC430HX) +int +machine_at_tc430hx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear_combined2(L"roms/machines/tc430hx/1007dh0_.bio", + L"roms/machines/tc430hx/1007dh0_.bi1", + L"roms/machines/tc430hx/1007dh0_.bi2", + L"roms/machines/tc430hx/1007dh0_.bi3", + L"roms/machines/tc430hx/1007dh0_.rcv", + 0x3a000, 128); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&pc87306_device); + device_add(&intel_flash_bxtw_ami_device); + + return ret; +} +#endif + + +int +machine_at_p55tvp4_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/p55tvp4/tv5i0204.awd", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&w83877f_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_i430vx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/430vx/55xwuq0e.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&um8669f_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_p55va_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/p55va/va021297.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c932fr_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_j656vxd_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/j656vxd/J656VXD.BIN", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c669_device); + device_add(&intel_flash_bxt_device); + + return ret; +} diff --git a/src/machine/m_at_socket8.c b/src/machine/m_at_socket8.c new file mode 100644 index 000000000..18e4355c0 --- /dev/null +++ b/src/machine/m_at_socket8.c @@ -0,0 +1,107 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Socket 8 machines. + * + * Version: @(#)m_at_socket8.c 1.0.0 2019/05/16 + * + * Authors: Miran Grca, + * + * Copyright 2016-2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../chipset/chipset.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../keyboard.h" +#include "../intel_flash.h" +#include "../intel_sio.h" +#include "../piix.h" +#include "../sio.h" +#include "../video/video.h" +#include "../video/vid_cl54xx.h" +#include "../video/vid_s3.h" +#include "machine.h" + + +#if defined(DEV_BRANCH) && defined(USE_I686) + + +int +machine_at_i440fx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/440fx/ntmaw501.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i440fx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_pci_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +int +machine_at_s1668_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/tpatx/s1668p.rom", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&i440fx_device); + device_add(&piix3_device); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&fdc37c665_device); + device_add(&intel_flash_bxt_device); + + return ret; +} + + +#endif diff --git a/src/machine/m_at_t3100e.c b/src/machine/m_at_t3100e.c index 567ab4a30..8f69fc951 100644 --- a/src/machine/m_at_t3100e.c +++ b/src/machine/m_at_t3100e.c @@ -153,11 +153,13 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../io.h" #include "../mouse.h" #include "../mem.h" #include "../device.h" #include "../keyboard.h" +#include "../rom.h" #include "../cpu/cpu.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" @@ -734,8 +736,16 @@ static void upper_write_raml(uint32_t addr, uint32_t val, void *priv) -void machine_at_t3100e_init(const machine_t *model) +int machine_at_t3100e_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/t3100e/t3100e.rom", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + int pg; memset(&t3100e_ems, 0, sizeof(t3100e_ems)); @@ -779,4 +789,6 @@ void machine_at_t3100e_init(const machine_t *model) mem_mapping_disable(&t3100e_ems.upper_mapping); device_add(&t3100e_device); + + return ret; } diff --git a/src/machine/m_at_t3100e_vid.c b/src/machine/m_at_t3100e_vid.c index 3b7dd8e48..6d00413db 100644 --- a/src/machine/m_at_t3100e_vid.c +++ b/src/machine/m_at_t3100e_vid.c @@ -28,9 +28,9 @@ * Miran Grca, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -71,6 +71,9 @@ #define T3100E_XSIZE 640 #define T3100E_YSIZE 400 +/*Very rough estimate*/ +#define VID_CLOCK (double)(651 * 416 * 60) + /* Mapping of attributes to colours */ static uint32_t amber, black; @@ -117,7 +120,7 @@ typedef struct t3100e_t int internal; /* Using internal display? */ uint8_t attrmap; /* Attribute mapping register */ - int dispontime, dispofftime; + uint64_t dispontime, dispofftime; int linepos, displine; int vc; @@ -201,7 +204,7 @@ void t3100e_write(uint32_t addr, uint8_t val, void *p) egawrites++; t3100e->vram[addr & 0x7fff] = val; - cycles -= 4; + sub_cycles(4); } @@ -210,7 +213,7 @@ uint8_t t3100e_read(uint32_t addr, void *p) { t3100e_t *t3100e = (t3100e_t *)p; egareads++; - cycles -= 4; + sub_cycles(4); return t3100e->vram[addr & 0x7fff]; } @@ -230,8 +233,8 @@ void t3100e_recalctimings(t3100e_t *t3100e) disptime = 651; _dispontime = 640; _dispofftime = disptime - _dispontime; - t3100e->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - t3100e->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + t3100e->dispontime = (uint64_t)(_dispontime * (cpuclock / VID_CLOCK) * (double)(1ull << 32)); + t3100e->dispofftime = (uint64_t)(_dispofftime * (cpuclock / VID_CLOCK) * (double)(1ull << 32)); } @@ -525,7 +528,7 @@ void t3100e_poll(void *p) if (!t3100e->linepos) { - t3100e->cga.vidtime += t3100e->dispofftime; + timer_advance_u64(&t3100e->cga.timer, t3100e->dispofftime); t3100e->cga.cgastat |= 1; t3100e->linepos = 1; if (t3100e->dispon) @@ -572,7 +575,7 @@ void t3100e_poll(void *p) { t3100e->cga.cgastat &= ~1; } - t3100e->cga.vidtime += t3100e->dispontime; + timer_advance_u64(&t3100e->cga.timer, t3100e->dispontime); t3100e->linepos = 0; if (t3100e->displine == 400) @@ -709,6 +712,7 @@ void *t3100e_init(const device_t *info) { t3100e_t *t3100e = malloc(sizeof(t3100e_t)); memset(t3100e, 0, sizeof(t3100e_t)); + loadfont(L"roms/machines/t3100e/t3100e_font.bin", 5); cga_init(&t3100e->cga); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_t3100e); @@ -717,7 +721,8 @@ void *t3100e_init(const device_t *info) /* 32k video RAM */ t3100e->vram = malloc(0x8000); - timer_add(t3100e_poll, &t3100e->cga.vidtime, TIMER_ALWAYS_ENABLED, t3100e); + timer_set_callback(&t3100e->cga.timer, t3100e_poll); + timer_set_p(&t3100e->cga.timer, t3100e); /* Occupy memory between 0xB8000 and 0xBFFFF */ mem_mapping_add(&t3100e->mapping, 0xb8000, 0x8000, t3100e_read, NULL, NULL, t3100e_write, NULL, NULL, NULL, 0, t3100e); diff --git a/src/machine/m_at_wd76c10.c b/src/machine/m_at_wd76c10.c deleted file mode 100644 index 646f9cf02..000000000 --- a/src/machine/m_at_wd76c10.c +++ /dev/null @@ -1,158 +0,0 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ -#include -#include -#include -#include -#include "../86box.h" -#include "../device.h" -#include "../io.h" -#include "../keyboard.h" -#include "../mem.h" -#include "../serial.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "../video/vid_paradise.h" -#include "machine.h" - - -static uint16_t wd76c10_0092; -static uint16_t wd76c10_2072; -static uint16_t wd76c10_2872; -static uint16_t wd76c10_5872; - -static serial_t *wd76c10_uart[2]; - - -static fdc_t *wd76c10_fdc; - - -static uint16_t -wd76c10_read(uint16_t port, void *priv) -{ - switch (port) - { - case 0x0092: - return wd76c10_0092; - - case 0x2072: - return wd76c10_2072; - - case 0x2872: - return wd76c10_2872; - - case 0x5872: - return wd76c10_5872; - } - return 0; -} - - -static void -wd76c10_write(uint16_t port, uint16_t val, void *priv) -{ - switch (port) - { - case 0x0092: - wd76c10_0092 = val; - - mem_a20_alt = val & 2; - mem_a20_recalc(); - break; - - case 0x2072: - wd76c10_2072 = val; - - serial_remove(wd76c10_uart[0]); - if (!(val & 0x10)) - { - switch ((val >> 5) & 7) - { - case 1: serial_setup(wd76c10_uart[0], 0x3f8, 4); break; - case 2: serial_setup(wd76c10_uart[0], 0x2f8, 4); break; - case 3: serial_setup(wd76c10_uart[0], 0x3e8, 4); break; - case 4: serial_setup(wd76c10_uart[0], 0x2e8, 4); break; - default: break; - } - } - serial_remove(wd76c10_uart[1]); - if (!(val & 0x01)) - { - switch ((val >> 1) & 7) - { - case 1: serial_setup(wd76c10_uart[1], 0x3f8, 3); break; - case 2: serial_setup(wd76c10_uart[1], 0x2f8, 3); break; - case 3: serial_setup(wd76c10_uart[1], 0x3e8, 3); break; - case 4: serial_setup(wd76c10_uart[1], 0x2e8, 3); break; - default: break; - } - } - break; - - case 0x2872: - wd76c10_2872 = val; - - fdc_remove(wd76c10_fdc); - if (!(val & 1)) - fdc_set_base(wd76c10_fdc, 0x03f0); - break; - - case 0x5872: - wd76c10_5872 = val; - break; - } -} - - -static uint8_t -wd76c10_readb(uint16_t port, void *priv) -{ - if (port & 1) - return wd76c10_read(port & ~1, priv) >> 8; - return wd76c10_read(port, priv) & 0xff; -} - - -static void -wd76c10_writeb(uint16_t port, uint8_t val, void *priv) -{ - uint16_t temp = wd76c10_read(port, priv); - if (port & 1) - wd76c10_write(port & ~1, (temp & 0x00ff) | (val << 8), priv); - else - wd76c10_write(port , (temp & 0xff00) | val, priv); -} - - -static void wd76c10_init(void) -{ - io_sethandler(0x0092, 2, - wd76c10_readb, wd76c10_read, NULL, - wd76c10_writeb, wd76c10_write, NULL, NULL); - io_sethandler(0x2072, 2, - wd76c10_readb, wd76c10_read, NULL, - wd76c10_writeb, wd76c10_write, NULL, NULL); - io_sethandler(0x2872, 2, - wd76c10_readb, wd76c10_read, NULL, - wd76c10_writeb, wd76c10_write, NULL, NULL); - io_sethandler(0x5872, 2, - wd76c10_readb, wd76c10_read, NULL, - wd76c10_writeb, wd76c10_write, NULL, NULL); -} - - -void -machine_at_wd76c10_init(const machine_t *model) -{ - machine_at_common_ide_init(model); - - device_add(&keyboard_ps2_quadtel_device); - wd76c10_fdc = device_add(&fdc_at_device); - wd76c10_uart[0] = device_add_inst(&i8250_device, 1); - wd76c10_uart[1] = device_add_inst(&i8250_device, 2); - - wd76c10_init(); - - device_add(¶dise_wd90c11_megapc_device); -} diff --git a/src/machine/m_europc.c b/src/machine/m_europc.c index 9986ddce6..7f1200e0c 100644 --- a/src/machine/m_europc.c +++ b/src/machine/m_europc.c @@ -119,6 +119,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../nmi.h" #include "../mem.h" #include "../pit.h" @@ -591,6 +592,7 @@ europc_boot(const device_t *info) * with values set by the user. */ b = (sys->nvr.regs[MRTC_CONF_D] & ~0x17); + video_reset(gfxcard); if (video_is_cga()) b |= 0x12; /* external video, CGA80 */ else if (video_is_mda()) @@ -730,9 +732,17 @@ const device_t europc_device = { * allows it to reset (dev init) and configured by the * user. */ -void +int machine_europc_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/europc/50145", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + machine_common_init(model); pit_set_out_func(&pit, 1, pit_refresh_timer_xt); @@ -756,4 +766,6 @@ machine_europc_init(const machine_t *model) /* Enable and set up the mainboard device. */ device_add(&europc_device); + + return ret; } diff --git a/src/machine/m_olivetti_m24.c b/src/machine/m_olivetti_m24.c index 5206acc2d..69d8b001b 100644 --- a/src/machine/m_olivetti_m24.c +++ b/src/machine/m_olivetti_m24.c @@ -25,17 +25,18 @@ #include #include #include "../86box.h" +#include "../timer.h" #include "../io.h" #include "../pic.h" #include "../pit.h" #include "../ppi.h" #include "../nmi.h" #include "../mem.h" -#include "../timer.h" #include "../device.h" #include "../nvr.h" #include "../keyboard.h" #include "../mouse.h" +#include "../rom.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "../game/gameport.h" @@ -70,13 +71,13 @@ typedef struct { int linepos, displine; int sc, vc; int con, coff, cursoron, blink; - int64_t vsynctime; + int vsynctime; int vadj; int lineff; uint16_t ma, maback; int dispon; - int64_t dispontime, dispofftime; - int64_t vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; /* Keyboard stuff. */ @@ -93,6 +94,7 @@ typedef struct { /* Mouse stuff. */ int mouse_mode; int x, y, b; + pc_timer_t send_delay_timer; } olim24_t; static video_timings_t timing_m24 = {VIDEO_ISA, 8,16,32, 8,16,32}; @@ -147,8 +149,8 @@ recalc_timings(olim24_t *m24) _dispofftime = disptime - _dispontime; _dispontime *= CGACONST / 2; _dispofftime *= CGACONST / 2; - m24->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - m24->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + m24->dispontime = (uint64_t)(_dispontime); + m24->dispofftime = (uint64_t)(_dispofftime); } @@ -234,10 +236,12 @@ static void vid_write(uint32_t addr, uint8_t val, void *priv) { olim24_t *m24 = (olim24_t *)priv; + int offset; m24->vram[addr & 0x7FFF]=val; - m24->charbuffer[ ((int)(((m24->dispontime - m24->vidtime) * 2) / (CGACONST / 2))) & 0xfc] = val; - m24->charbuffer[(((int)(((m24->dispontime - m24->vidtime) * 2) / (CGACONST / 2))) & 0xfc) | 1] = val; + offset = ((timer_get_remaining_u64(&m24->timer) / CGACONST) * 4) & 0xfc; + m24->charbuffer[offset] = m24->vram[addr & 0x7fff]; + m24->charbuffer[offset | 1] = m24->vram[addr & 0x7fff]; } @@ -265,7 +269,7 @@ vid_poll(void *priv) int oldsc; if (!m24->linepos) { - m24->vidtime += m24->dispofftime; + timer_advance_u64(&m24->timer, m24->dispofftime); m24->stat |= 1; m24->linepos = 1; oldsc = m24->sc; @@ -279,17 +283,17 @@ vid_poll(void *priv) for (c = 0; c < 8; c++) { if ((m24->cgamode & 0x12) == 0x12) { - buffer->line[m24->displine][c] = 0; + ((uint32_t *)buffer32->line[m24->displine])[c] = 0; if (m24->cgamode & 1) - buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = 0; + ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 3) + 8] = 0; else - buffer->line[m24->displine][c + (m24->crtc[1] << 4) + 8] = 0; + ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 4) + 8] = 0; } else { - buffer->line[m24->displine][c] = (m24->cgacol & 15) + 16; + ((uint32_t *)buffer32->line[m24->displine])[c] = (m24->cgacol & 15) + 16; if (m24->cgamode & 1) - buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = (m24->cgacol & 15) + 16; + ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 3) + 8] = (m24->cgacol & 15) + 16; else - buffer->line[m24->displine][c + (m24->crtc[1] << 4) + 8] = (m24->cgacol & 15) + 16; + ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 4) + 8] = (m24->cgacol & 15) + 16; } } if (m24->cgamode & 1) { @@ -308,10 +312,10 @@ vid_poll(void *priv) } if (drawcursor) { for (c = 0; c < 8; c++) - buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + ((uint32_t *)buffer32->line[m24->displine])[(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) - buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + ((uint32_t *)buffer32->line[m24->displine])[(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; } m24->ma++; } @@ -332,12 +336,12 @@ vid_poll(void *priv) m24->ma++; if (drawcursor) { for (c = 0; c < 8; c++) - buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = - buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) - buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = - buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; } } } else if (!(m24->cgamode & 16)) { @@ -361,8 +365,8 @@ vid_poll(void *priv) m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + 1 + m24->base]; m24->ma++; for (c = 0; c < 8; c++) { - buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = - buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; dat <<= 2; } } @@ -379,15 +383,15 @@ vid_poll(void *priv) dat = (m24->vram[((m24->ma << 1) & 0x1fff) + dat2] << 8) | m24->vram[((m24->ma << 1) & 0x1fff) + dat2 + 1]; m24->ma++; for (c = 0; c < 16; c++) { - buffer->line[m24->displine][(x << 4) + c + 8] = cols[dat >> 15]; + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + c + 8] = cols[dat >> 15]; dat <<= 1; } } } } else { cols[0] = ((m24->cgamode & 0x12) == 0x12) ? 0 : (m24->cgacol & 15) + 16; - if (m24->cgamode & 1) hline(buffer, 0, m24->displine, (m24->crtc[1] << 3) + 16, cols[0]); - else hline(buffer, 0, m24->displine, (m24->crtc[1] << 4) + 16, cols[0]); + if (m24->cgamode & 1) hline(buffer32, 0, m24->displine, (m24->crtc[1] << 3) + 16, cols[0]); + else hline(buffer32, 0, m24->displine, (m24->crtc[1] << 4) + 16, cols[0]); } if (m24->cgamode & 1) @@ -401,7 +405,7 @@ vid_poll(void *priv) m24->displine++; if (m24->displine >= 720) m24->displine = 0; } else { - m24->vidtime += m24->dispontime; + timer_advance_u64(&m24->timer, m24->dispontime); if (m24->dispon) m24->stat &= ~1; m24->linepos = 0; m24->lineff ^= 1; @@ -525,7 +529,7 @@ kbd_poll(void *priv) { olim24_t *m24 = (olim24_t *)priv; - keyboard_delay += (1000LL * TIMER_USEC); + timer_advance_u64(&m24->send_delay_timer, 1000 * TIMER_USEC); if (m24->wantirq) { m24->wantirq = 0; picint(2); @@ -634,9 +638,6 @@ kbd_write(uint16_t port, uint8_t val, void *priv) case 0x61: ppi.pb = val; - timer_process(); - timer_update_outstanding(); - speaker_update(); speaker_gated = val & 1; speaker_enable = val & 2; @@ -803,9 +804,39 @@ const device_t m24_device = { }; -void +static void +kbd_reset(void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + + /* Initialize the keyboard. */ + m24->status = STAT_LOCK | STAT_CD; + m24->wantirq = 0; + keyboard_scan = 1; + m24->param = m24->param_total = 0; + m24->mouse_mode = 0; + m24->scan[0] = 0x1c; + m24->scan[1] = 0x53; + m24->scan[2] = 0x01; + m24->scan[3] = 0x4b; + m24->scan[4] = 0x4d; + m24->scan[5] = 0x48; + m24->scan[6] = 0x50; +} + + +int machine_olim24_init(const machine_t *model) { + int ret; + + ret = bios_load_interleaved(L"roms/machines/olivetti_m24/olivetti_m24_version_1.43_low.bin", + L"roms/machines/olivetti_m24/olivetti_m24_version_1.43_high.bin", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + olim24_t *m24; m24 = (olim24_t *)malloc(sizeof(olim24_t)); @@ -823,31 +854,25 @@ machine_olim24_init(const machine_t *model) vid_read, NULL, NULL, vid_write, NULL, NULL, NULL, 0, m24); io_sethandler(0x03d0, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); - timer_add(vid_poll, &m24->vidtime, TIMER_ALWAYS_ENABLED, m24); + timer_add(&m24->timer, vid_poll, m24, 1); device_add_ex(&m24_device, m24); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_m24); /* Initialize the keyboard. */ - m24->status = STAT_LOCK | STAT_CD; - m24->scan[0] = 0x1c; - m24->scan[1] = 0x53; - m24->scan[2] = 0x01; - m24->scan[3] = 0x4b; - m24->scan[4] = 0x4d; - m24->scan[5] = 0x48; - m24->scan[6] = 0x50; io_sethandler(0x0060, 2, kbd_read, NULL, NULL, kbd_write, NULL, NULL, m24); io_sethandler(0x0064, 1, kbd_read, NULL, NULL, kbd_write, NULL, NULL, m24); - keyboard_set_table(scancode_xt); keyboard_send = kbd_adddata_ex; - keyboard_scan = 1; - timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, m24); + kbd_reset(m24); + timer_add(&m24->send_delay_timer, kbd_poll, m24, 1); /* Tell mouse driver about our internal mouse. */ mouse_reset(); mouse_set_poll(ms_poll, m24); + keyboard_set_table(scancode_xt); + if (joystick_type != 7) device_add(&gameport_device); @@ -855,25 +880,6 @@ machine_olim24_init(const machine_t *model) device_add(&at_nvr_device); nmi_init(); -} - -void machine_olim24_video_init(void) { - olim24_t *m24; - - m24 = (olim24_t *)malloc(sizeof(olim24_t)); - memset(m24, 0x00, sizeof(olim24_t)); - - video_inform(VIDEO_FLAG_TYPE_CGA, &timing_m24); - - /* Initialize the video adapter. */ - m24->vram = malloc(0x8000); - overscan_x = overscan_y = 16; - mem_mapping_add(&m24->mapping, 0xb8000, 0x08000, - vid_read, NULL, NULL, - vid_write, NULL, NULL, NULL, 0, m24); - io_sethandler(0x03d0, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); - io_sethandler(0x13c6, 1, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); - io_sethandler(0x23c6, 1, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); - timer_add(vid_poll, &m24->vidtime, TIMER_ALWAYS_ENABLED, m24); - device_add_ex(&m24_device, m24); + + return ret; } diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index 4eef6f095..8e59c8098 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -28,15 +28,16 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../cpu/cpu.h" +#include "../timer.h" #include "../io.h" #include "../nmi.h" #include "../pic.h" #include "../pit.h" #include "../mem.h" -#include "../timer.h" #include "../device.h" #include "../serial.h" #include "../keyboard.h" +#include "../rom.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "../sound/sound.h" @@ -77,10 +78,11 @@ typedef struct { int sc, vc; int dispon; int con, coff, cursoron, blink; - int64_t vsynctime; + int vsynctime; int vadj; uint16_t ma, maback; - int64_t dispontime, dispofftime, vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; int composite; @@ -91,6 +93,7 @@ typedef struct { int serial_pos; uint8_t pa; uint8_t pb; + pc_timer_t send_delay_timer; } pcjr_t; static video_timings_t timing_dram = {VIDEO_BUS, 0,0,0, 0,0,0}; /*No additional waitstates*/ @@ -136,8 +139,8 @@ recalc_timings(pcjr_t *pcjr) _dispofftime = disptime - _dispontime; _dispontime *= CGACONST; _dispofftime *= CGACONST; - pcjr->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - pcjr->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + pcjr->dispontime = (uint64_t)(_dispontime); + pcjr->dispofftime = (uint64_t)(_dispofftime); } @@ -249,7 +252,7 @@ vid_poll(void *p) int oldsc; if (! pcjr->linepos) { - pcjr->vidtime += pcjr->dispofftime; + timer_advance_u64(&pcjr->timer, pcjr->dispofftime); pcjr->stat &= ~1; pcjr->linepos = 1; oldsc = pcjr->sc; @@ -266,11 +269,11 @@ vid_poll(void *p) pcjr->lastline = pcjr->displine; cols[0] = (pcjr->array[2] & 0xf) + 16; for (c = 0; c < 8; c++) { - buffer->line[pcjr->displine][c] = cols[0]; + ((uint32_t *)buffer32->line[pcjr->displine])[c] = cols[0]; if (pcjr->array[0] & 1) - buffer->line[pcjr->displine][c + (pcjr->crtc[1] << 3) + 8] = cols[0]; + ((uint32_t *)buffer32->line[pcjr->displine])[c + (pcjr->crtc[1] << 3) + 8] = cols[0]; else - buffer->line[pcjr->displine][c + (pcjr->crtc[1] << 4) + 8] = cols[0]; + ((uint32_t *)buffer32->line[pcjr->displine])[c + (pcjr->crtc[1] << 4) + 8] = cols[0]; } switch (pcjr->addr_mode) { @@ -291,14 +294,14 @@ vid_poll(void *p) dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; pcjr->ma++; - buffer->line[pcjr->displine][(x << 3) + 8] = - buffer->line[pcjr->displine][(x << 3) + 9] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; - buffer->line[pcjr->displine][(x << 3) + 10] = - buffer->line[pcjr->displine][(x << 3) + 11] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; - buffer->line[pcjr->displine][(x << 3) + 12] = - buffer->line[pcjr->displine][(x << 3) + 13] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; - buffer->line[pcjr->displine][(x << 3) + 14] = - buffer->line[pcjr->displine][(x << 3) + 15] = pcjr->array[(dat & pcjr->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 8] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 9] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 10] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 11] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 12] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 13] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 14] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 15] = pcjr->array[(dat & pcjr->array[1]) + 16] + 16; } break; case 0x12: /*160x200x16*/ @@ -306,22 +309,22 @@ vid_poll(void *p) dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; pcjr->ma++; - buffer->line[pcjr->displine][(x << 4) + 8] = - buffer->line[pcjr->displine][(x << 4) + 9] = - buffer->line[pcjr->displine][(x << 4) + 10] = - buffer->line[pcjr->displine][(x << 4) + 11] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; - buffer->line[pcjr->displine][(x << 4) + 12] = - buffer->line[pcjr->displine][(x << 4) + 13] = - buffer->line[pcjr->displine][(x << 4) + 14] = - buffer->line[pcjr->displine][(x << 4) + 15] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; - buffer->line[pcjr->displine][(x << 4) + 16] = - buffer->line[pcjr->displine][(x << 4) + 17] = - buffer->line[pcjr->displine][(x << 4) + 18] = - buffer->line[pcjr->displine][(x << 4) + 19] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; - buffer->line[pcjr->displine][(x << 4) + 20] = - buffer->line[pcjr->displine][(x << 4) + 21] = - buffer->line[pcjr->displine][(x << 4) + 22] = - buffer->line[pcjr->displine][(x << 4) + 23] = pcjr->array[(dat & pcjr->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 8] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 9] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 10] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 11] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 12] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 13] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 14] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 15] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 16] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 17] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 18] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 19] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 20] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 21] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 22] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 23] = pcjr->array[(dat & pcjr->array[1]) + 16] + 16; } break; case 0x03: /*640x200x4*/ @@ -332,7 +335,7 @@ vid_poll(void *p) for (c = 0; c < 8; c++) { chr = (dat >> 7) & 1; chr |= ((dat >> 14) & 2); - buffer->line[pcjr->displine][(x << 3) + 8 + c] = pcjr->array[(chr & pcjr->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 8 + c] = pcjr->array[(chr & pcjr->array[1]) + 16] + 16; dat <<= 1; } } @@ -353,14 +356,14 @@ vid_poll(void *p) } if (pcjr->sc & 8) { for (c = 0; c < 8; c++) - buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[0]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + c + 8] = cols[0]; } else { for (c = 0; c < 8; c++) - buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + c + 8] = cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } if (drawcursor) { for (c = 0; c < 8; c++) - buffer->line[pcjr->displine][(x << 3) + c + 8] ^= 15; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + c + 8] ^= 15; } pcjr->ma++; } @@ -382,16 +385,16 @@ vid_poll(void *p) pcjr->ma++; if (pcjr->sc & 8) { for (c = 0; c < 8; c++) - buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = - buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[0]; } else { for (c = 0; c < 8; c++) - buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = - buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } if (drawcursor) { for (c = 0; c < 16; c++) - buffer->line[pcjr->displine][(x << 4) + c + 8] ^= 15; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + c + 8] ^= 15; } } break; @@ -405,8 +408,8 @@ vid_poll(void *p) pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; pcjr->ma++; for (c = 0; c < 8; c++) { - buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = - buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; dat <<= 2; } } @@ -419,7 +422,7 @@ vid_poll(void *p) pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; pcjr->ma++; for (c = 0; c < 16; c++) { - buffer->line[pcjr->displine][(x << 4) + c + 8] = cols[dat >> 15]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + c + 8] = cols[dat >> 15]; dat <<= 1; } } @@ -427,22 +430,18 @@ vid_poll(void *p) } } else { if (pcjr->array[3] & 4) { - if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, (pcjr->array[2] & 0xf) + 16); - else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, (pcjr->array[2] & 0xf) + 16); + if (pcjr->array[0] & 1) hline(buffer32, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, (pcjr->array[2] & 0xf) + 16); + else hline(buffer32, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, (pcjr->array[2] & 0xf) + 16); } else { cols[0] = pcjr->array[0 + 16] + 16; - if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, cols[0]); - else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, cols[0]); + if (pcjr->array[0] & 1) hline(buffer32, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, cols[0]); + else hline(buffer32, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, cols[0]); } } if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; else x = (pcjr->crtc[1] << 4) + 16; - if (pcjr->composite) { - for (c = 0; c < x; c++) - buffer32->line[pcjr->displine][c] = buffer->line[pcjr->displine][c] & 0xf; - - Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[pcjr->displine]); - } + if (pcjr->composite) + Composite_Process(pcjr->array[0], 0, x >> 2, ((uint32_t *)buffer32->line[pcjr->displine])); pcjr->sc = oldsc; if (pcjr->vc == pcjr->crtc[7] && !pcjr->sc) { pcjr->stat |= 8; @@ -451,7 +450,7 @@ vid_poll(void *p) if (pcjr->displine >= 360) pcjr->displine = 0; } else { - pcjr->vidtime += pcjr->dispontime; + timer_advance_u64(&pcjr->timer, pcjr->dispontime); if (pcjr->dispon) pcjr->stat |= 1; pcjr->linepos = 0; @@ -542,6 +541,9 @@ kbd_write(uint16_t port, uint8_t val, void *priv) { pcjr_t *pcjr = (pcjr_t *)priv; + if ((port >= 0xa0) && (port <= 0xa7)) + port = 0xa0; + switch (port) { case 0x60: pcjr->pa = val; @@ -550,9 +552,6 @@ kbd_write(uint16_t port, uint8_t val, void *priv) case 0x61: pcjr->pb = val; - timer_process(); - timer_update_outstanding(); - speaker_update(); speaker_gated = val & 1; speaker_enable = val & 2; @@ -585,6 +584,9 @@ kbd_read(uint16_t port, void *priv) pcjr_t *pcjr = (pcjr_t *)priv; uint8_t ret = 0xff; + if ((port >= 0xa0) && (port <= 0xa7)) + port = 0xa0; + switch (port) { case 0x60: ret = pcjr->pa; @@ -620,7 +622,7 @@ kbd_poll(void *priv) pcjr_t *pcjr = (pcjr_t *)priv; int c, p = 0, key; - keyboard_delay += (220LL * TIMER_USEC); + timer_advance_u64(&pcjr->send_delay_timer, 220 * TIMER_USEC); if (key_queue_start != key_queue_end && !pcjr->serial_pos && !pcjr->latched) { @@ -734,27 +736,31 @@ pcjr_get_device(void) } -void +int machine_pcjr_init(const machine_t *model) { int display_type; pcjr_t *pcjr; + int ret; + + ret = bios_load_linear(L"roms/machines/ibmpcjr/bios.rom", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + pcjr = malloc(sizeof(pcjr_t)); memset(pcjr, 0x00, sizeof(pcjr_t)); pcjr->memctrl = -1; display_type = machine_get_config_int("display_type"); pcjr->composite = (display_type != PCJR_RGB); - pic_init(); + pic_init_pcjr(); pit_init(); pit_set_out_func(&pit, 0, pit_irq0_timer_pcjr); cpu_set(); - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) - setrtcconst(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); - else - setrtcconst(14318184.0); /* Initialize the video controller. */ mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, @@ -762,7 +768,7 @@ machine_pcjr_init(const machine_t *model) vid_write, NULL, NULL, NULL, 0, pcjr); io_sethandler(0x03d0, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, pcjr); - timer_add(vid_poll, &pcjr->vidtime, TIMER_ALWAYS_ENABLED, pcjr); + timer_add(&pcjr->timer, vid_poll, pcjr, 1); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); device_add_ex(&pcjr_device, pcjr); @@ -773,13 +779,19 @@ machine_pcjr_init(const machine_t *model) kbd_read, NULL, NULL, kbd_write, NULL, NULL, pcjr); io_sethandler(0x00a0, 8, kbd_read, NULL, NULL, kbd_write, NULL, NULL, pcjr); - timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, pcjr); + timer_add(&pcjr->send_delay_timer, kbd_poll, pcjr, 1); keyboard_set_table(scancode_xt); keyboard_send = kbd_adddata_ex; - device_add(&sn76489_device); + /* Technically it's the SN76496N, but the NCR 8496 is a drop-in replacement for it. */ + device_add(&ncr8496_device); nmi_mask = 0x80; device_add(&fdc_pcjr_device); + + device_add(&i8250_pcjr_device); + serial_set_next_inst(2); /* So that serial_standalone_init() won't do anything. */ + + return ret; } diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 3012b8725..0b214f50a 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -28,15 +28,15 @@ * boot. Sometimes, they do, and then it shows an "Incorrect * DOS" error message?? --FvK * - * Version: @(#)m_ps1.c 1.0.14 2018/11/12 + * Version: @(#)m_ps1.c 1.0.15 2019/03/08 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -45,6 +45,7 @@ #include #include "../86box.h" #include "../cpu/cpu.h" +#include "../timer.h" #include "../io.h" #include "../dma.h" #include "../pic.h" @@ -52,7 +53,6 @@ #include "../mem.h" #include "../nmi.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "../nvr.h" #include "../game/gameport.h" @@ -74,7 +74,9 @@ typedef struct { sn76489_t sn76489; uint8_t status, ctrl; - int64_t timer_latch, timer_count, timer_enable; + uint64_t timer_latch; + pc_timer_t timer_count; + int timer_enable; uint8_t fifo[2048]; int fifo_read_idx, fifo_write_idx; int fifo_threshold; @@ -177,8 +179,10 @@ snd_write(uint16_t port, uint8_t val, void *priv) case 3: /* timer reload value */ snd->timer_latch = val; - snd->timer_count = (int64_t) ((0xff-val) * TIMER_USEC); - snd->timer_enable = (val != 0); + if (val) + timer_set_delay_u64(&snd->timer_count, ((0xff-val) * TIMER_USEC)); + else + timer_disable(&snd->timer_count); break; case 4: /* almost empty */ @@ -213,8 +217,8 @@ snd_callback(void *priv) snd->status |= 0x10; /*ADC data ready*/ update_irq_status(snd); - - snd->timer_count += snd->timer_latch * TIMER_USEC; + + timer_advance_u64(&snd->timer_count, snd->timer_latch * TIMER_USEC); } @@ -246,7 +250,7 @@ snd_init(const device_t *info) io_sethandler(0x0200, 1, snd_read,NULL,NULL, snd_write,NULL,NULL, snd); io_sethandler(0x0202, 6, snd_read,NULL,NULL, snd_write,NULL,NULL, snd); - timer_add(snd_callback, &snd->timer_count, &snd->timer_enable, snd); + timer_add(&snd->timer_count, snd_callback, snd, 0); sound_add_handler(snd_get_buffer, snd); @@ -449,7 +453,7 @@ ps1_setup(int model) io_sethandler(0x0190, 1, ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); - ps->uart = device_add_inst(&i8250_device, 1); + ps->uart = device_add_inst(&ns16450_device, 1); lpt1_remove(); lpt1_init(0x3bc); @@ -475,12 +479,8 @@ ps1_setup(int model) if (hdc_current == 1) { priv = device_add(&ps1_hdc_device); - ps1_hdc_inform(priv, ps); + ps1_hdc_inform(priv, &ps->ps1_91); } - - mem_mapping_add(&romext_mapping, 0xc8000, 0x08000, - mem_read_romext,mem_read_romextw,mem_read_romextl, - NULL,NULL, NULL, romext, 0, NULL); } if (model == 2121) { @@ -504,11 +504,13 @@ ps1_setup(int model) device_add(&snd_device); } +#if defined(DEV_BRANCH) && defined(USE_PS1M2133) if (model == 2133) { device_add(&fdc_at_device); device_add(&ide_isa_device); } +#endif } @@ -526,7 +528,7 @@ ps1_common_init(const machine_t *model) device_add(&ps_nvr_device); - device_add(&keyboard_ps2_device); + device_add(&keyboard_ps2_ps1_device); /* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */ if (joystick_type != 7) @@ -534,40 +536,62 @@ ps1_common_init(const machine_t *model) } -/* Set the Card Selected Flag */ -void -ps1_set_feedback(void *priv) -{ - ps1_t *ps = (ps1_t *)priv; - - ps->ps1_91 |= 0x01; -} - - -void +int machine_ps1_m2011_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/ibmps1es/f80000.bin", + 0x000e0000, 131072, 0x60000); + + if (bios_only || !ret) + return ret; + ps1_common_init(model); ps1_setup(2011); + + return ret; } -void +int machine_ps1_m2121_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/ibmps1_2121/fc0000.bin", + 0x000e0000, 131072, 0x20000); + + if (bios_only || !ret) + return ret; + ps1_common_init(model); ps1_setup(2121); + + return ret; } -void +#if defined(DEV_BRANCH) && defined(USE_PS1M2133) +int machine_ps1_m2133_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/ibmps1_2133/ps1_2133_52g2974_rom.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + ps1_common_init(model); ps1_setup(2133); nmi_mask = 0x80; + + return ret; } +#endif diff --git a/src/machine/m_ps1_hdc.c b/src/machine/m_ps1_hdc.c index e68e6b8fc..5c10ca69b 100644 --- a/src/machine/m_ps1_hdc.c +++ b/src/machine/m_ps1_hdc.c @@ -43,14 +43,14 @@ * Type table with the main code, so the user can only select * items from that list... * - * Version: @(#)m_ps1_hdc.c 1.0.7 2018/10/22 + * Version: @(#)m_ps1_hdc.c 1.0.8 2019/03/08 * * Author: Fred N. van Kempen, * * Based on my earlier HD20 driver for the EuroPC. * Thanks to Marco Bortolin for the help and feedback !! * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -93,11 +93,11 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../io.h" #include "../dma.h" #include "../pic.h" #include "../device.h" -#include "../timer.h" #include "../disk/hdc.h" #include "../disk/hdd.h" #include "../plat.h" @@ -105,7 +105,7 @@ #include "machine.h" -#define HDC_TIME (200*TIMER_USEC) +#define HDC_TIME (50*TIMER_USEC) #define HDC_TYPE_USER 47 /* user drive type */ @@ -387,10 +387,11 @@ typedef struct { status, /* Status register (ASR) */ intstat; /* Interrupt Status register (ISR) */ - void *sys; /* handle to system board */ + uint8_t *reg_91; /* handle to system board's register 0x91 */ /* Controller state. */ - int64_t callback; + uint64_t callback; + pc_timer_t timer; int8_t state, /* controller state */ reset; /* reset state counter */ @@ -492,6 +493,21 @@ ps1_hdc_log(const char *fmt, ...) #define ps1_hdc_log(fmt, ...) #endif +static void +hdc_set_callback(hdc_t *dev, uint64_t callback) +{ + if (!dev) { + return; + } + + if (callback) { + dev->callback = callback; + timer_set_delay_u64(&dev->timer, dev->callback); + } else { + dev->callback = 0; + timer_disable(&dev->timer); + } +} /* FIXME: we should use the disk/hdd_table.c code with custom tables! */ static int @@ -635,7 +651,7 @@ do_format(hdc_t *dev, drive_t *drive, ccb_t *ccb) /* Enable for PIO or DMA, as needed. */ #if NOT_USED if (dev->ctrl & ACR_DMA_EN) - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); else #endif dev->status |= ASR_DATA_REQ; @@ -655,7 +671,7 @@ do_format(hdc_t *dev, drive_t *drive, ccb_t *ccb) dev->buf_idx++; } dev->state = STATE_RDONE; - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); break; case STATE_RDONE: @@ -813,20 +829,20 @@ do_send: dev->buf_idx = 0; if (no_data) { /* Delay a bit, no actual transfer. */ - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); } else { if (dev->ctrl & ACR_DMA_EN) { /* DMA enabled. */ dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); } else { /* No DMA, do PIO. */ dev->status |= (ASR_DATA_REQ|ASR_DIR); /* Copy from sector to data. */ memcpy(dev->data, - dev->sector_buf, - (128<ssb.sect_size)); + dev->sector_buf, + dev->buf_len); dev->buf_ptr = dev->data; } } @@ -853,7 +869,7 @@ do_send: } } dev->state = STATE_SDONE; - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); break; case STATE_SDONE: @@ -941,12 +957,12 @@ do_recv: dev->buf_idx = 0; if (no_data) { /* Delay a bit, no actual transfer. */ - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); } else { if (dev->ctrl & ACR_DMA_EN) { /* DMA enabled. */ dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); } else { /* No DMA, do PIO. */ dev->buf_ptr = dev->data; @@ -976,14 +992,15 @@ do_recv: } } dev->state = STATE_RDONE; - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); break; case STATE_RDONE: /* Copy from data to sector if PIO. */ if (! (dev->ctrl & ACR_DMA_EN)) - memcpy(dev->sector_buf, dev->data, - (128<ssb.sect_size)); + memcpy(dev->sector_buf, + dev->data, + dev->buf_len); /* Get address of sector to write. */ if (get_sector(dev, drive, &addr)) { @@ -1100,7 +1117,7 @@ hdc_read(uint16_t port, void *priv) uint8_t ret = 0xff; /* TRM: tell system board we are alive. */ - ps1_set_feedback(dev->sys); + *dev->reg_91 |= 0x01; switch (port & 7) { case 0: /* DATA register */ @@ -1143,7 +1160,7 @@ hdc_write(uint16_t port, uint8_t val, void *priv) hdc_t *dev = (hdc_t *)priv; /* TRM: tell system board we are alive. */ - ps1_set_feedback(dev->sys); + *dev->reg_91 |= 0x01; switch (port & 7) { case 0: /* DATA register */ @@ -1176,7 +1193,7 @@ hdc_write(uint16_t port, uint8_t val, void *priv) dev->status |= ASR_BUSY; /* Schedule command execution. */ - dev->callback = HDC_TIME; + hdc_set_callback(dev, HDC_TIME); } } } @@ -1303,7 +1320,7 @@ ps1_hdc_init(const device_t *info) hdc_read,NULL,NULL, hdc_write,NULL,NULL, dev); /* Create a timer for command delays. */ - timer_add(hdc_callback, &dev->callback, &dev->callback, dev); + timer_add(&dev->timer, hdc_callback, dev, 0); return(dev); } @@ -1356,9 +1373,9 @@ const device_t ps1_hdc_device = { * agree that the current solution is nasty. */ void -ps1_hdc_inform(void *priv, void *arg) +ps1_hdc_inform(void *priv, uint8_t *reg_91) { hdc_t *dev = (hdc_t *)priv; - dev->sys = arg; + dev->reg_91 = reg_91; } diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c index 9dea86ee8..a9699ba5b 100644 --- a/src/machine/m_ps2_isa.c +++ b/src/machine/m_ps2_isa.c @@ -4,6 +4,7 @@ #include #include "../86box.h" #include "../cpu/cpu.h" +#include "../timer.h" #include "../io.h" #include "../dma.h" #include "../pic.h" @@ -14,14 +15,16 @@ #include "../nvr.h" #include "../keyboard.h" #include "../lpt.h" +#include "../port_92.h" #include "../serial.h" +#include "../disk/hdc.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "../video/vid_vga.h" #include "machine.h" -static uint8_t ps2_94, ps2_102, ps2_103, ps2_104, ps2_105, ps2_190; +static uint8_t ps2_91, ps2_94, ps2_102, ps2_103, ps2_104, ps2_105, ps2_190; static serial_t *ps2_uart; @@ -39,7 +42,9 @@ static uint8_t ps2_read(uint16_t port, void *p) switch (port) { case 0x91: - return 0; + temp = ps2_91; + ps2_91 = 0; + return temp; case 0x94: return ps2_94; case 0x102: @@ -136,9 +141,7 @@ static void ps2board_init(void) io_sethandler(0x0322, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); io_sethandler(0x0324, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); - port_92_reset(); - - port_92_add(); + device_add(&port_92_device); ps2_190 = 0; @@ -150,17 +153,36 @@ static void ps2board_init(void) } -void +int machine_ps2_m30_286_init(const machine_t *model) { + void *priv; + + int ret; + + ret = bios_load_linear(L"roms/machines/ibmps2_m30_286/33f5381a.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + machine_common_init(model); device_add(&fdc_at_ps1_device); pit_set_out_func(&pit, 1, pit_refresh_timer_at); dma16_init(); - device_add(&keyboard_ps2_device); + device_add(&keyboard_ps2_ps2_device); device_add(&ps_nvr_device); pic2_init(); ps2board_init(); device_add(&ps1vga_device); + + /* Enable the builtin HDC. */ + if (hdc_current == 1) { + priv = device_add(&ps1_hdc_device); + + ps1_hdc_inform(priv, &ps2_91); + } + + return ret; } diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 7a69901e4..7a467e863 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -43,8 +43,14 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#ifdef USE_NEW_DYNAREC +#include "../cpu_new/cpu.h" +#include "../cpu_new/x86.h" +#else #include "../cpu/cpu.h" #include "../cpu/x86.h" +#endif +#include "../timer.h" #include "../io.h" #include "../dma.h" #include "../pic.h" @@ -61,6 +67,7 @@ #include "../keyboard.h" #include "../lpt.h" #include "../mouse.h" +#include "../port_92.h" #include "../serial.h" #include "../video/video.h" #include "../video/vid_vga.h" @@ -609,7 +616,17 @@ uint8_t ps2_mca_read(uint16_t port, void *p) switch (port) { case 0x91: - fatal("Read 91 setup=%02x adapter=%02x\n", ps2.setup, ps2.adapter_setup); + // fatal("Read 91 setup=%02x adapter=%02x\n", ps2.setup, ps2.adapter_setup); + if (!(ps2.setup & PS2_SETUP_IO)) + temp = 0x00; + else if (!(ps2.setup & PS2_SETUP_VGA)) + temp = 0x00; + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + temp = 0x00; + else + temp = !mca_feedb(); + temp |= 0xfe; + break; case 0x94: temp = ps2.setup; break; @@ -769,10 +786,8 @@ static void ps2_mca_board_common_init() io_sethandler(0x0094, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); io_sethandler(0x0096, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); io_sethandler(0x0100, 0x0008, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); - - port_92_reset(); - port_92_add(); + device_add(&port_92_device); ps2.setup = 0xff; @@ -797,6 +812,11 @@ static void ps2_mem_expansion_write(int port, uint8_t val, void *p) mem_mapping_disable(&ps2.expansion_mapping); } +static uint8_t ps2_mem_expansion_feedb(void *p) +{ + return (ps2.mem_pos_regs[2] & 1); +} + static void ps2_mca_mem_fffc_init(int start_mb) { uint32_t planar_size, expansion_start; @@ -842,7 +862,7 @@ static void ps2_mca_mem_fffc_init(int start_mb) break; } - mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, NULL); + mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, ps2_mem_expansion_feedb, NULL); mem_mapping_add(&ps2.expansion_mapping, expansion_start, (mem_size - (start_mb << 10)) << 10, @@ -864,7 +884,8 @@ static void ps2_mca_board_model_50_init() mem_remap_top(384); mca_init(4); - + device_add(&keyboard_ps2_mca_2_device); + ps2.planar_read = model_50_read; ps2.planar_write = model_50_write; @@ -935,7 +956,8 @@ static void ps2_mca_board_model_55sx_init() } mca_init(4); - + device_add(&keyboard_ps2_mca_device); + ps2.planar_read = model_55sx_read; ps2.planar_write = model_55sx_write; @@ -1082,7 +1104,8 @@ static void ps2_mca_board_model_70_type34_init(int is_type4) ps2.split_addr = mem_size * 1024; mca_init(4); - + device_add(&keyboard_ps2_mca_device); + ps2.planar_read = model_70_type3_read; ps2.planar_write = model_70_type3_write; @@ -1160,6 +1183,7 @@ static void ps2_mca_board_model_80_type2_init(int is486) ps2.split_addr = mem_size * 1024; mca_init(8); + device_add(&keyboard_ps2_mca_device); ps2.planar_read = model_80_read; ps2.planar_write = model_80_write; @@ -1233,7 +1257,6 @@ machine_ps2_common_init(const machine_t *model) dma16_init(); ps2_dma_init(); - device_add(&keyboard_ps2_mca_device); device_add(&ps_nvr_device); pic2_init(); @@ -1241,49 +1264,110 @@ machine_ps2_common_init(const machine_t *model) nmi_mask = 0x80; - ps2.uart = device_add_inst(&i8250_device, 1); + ps2.uart = device_add_inst(&ns16550_device, 1); } -void +int machine_ps2_model_50_init(const machine_t *model) { + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmps2_m50/90x7420.zm13", + L"roms/machines/ibmps2_m50/90x7429.zm18", + 0x000f0000, 131072, 0); + ret &= bios_load_aux_interleaved(L"roms/machines/ibmps2_m50/90x7423.zm14", + L"roms/machines/ibmps2_m50/90x7426.zm16", + 0x000e0000, 65536, 0); + + if (bios_only || !ret) + return ret; + machine_ps2_common_init(model); ps2_mca_board_model_50_init(); + + return ret; } -void +int machine_ps2_model_55sx_init(const machine_t *model) { + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmps2_m55sx/33f8146.zm41", + L"roms/machines/ibmps2_m55sx/33f8145.zm40", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + machine_ps2_common_init(model); ps2_mca_board_model_55sx_init(); + + return ret; } -void + +int machine_ps2_model_70_type3_init(const machine_t *model) { + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmps2_m70_type3/70-a_even.bin", + L"roms/machines/ibmps2_m70_type3/70-a_odd.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + machine_ps2_common_init(model); ps2_mca_board_model_70_type34_init(0); + + return ret; } + #if defined(DEV_BRANCH) && defined(USE_PS2M70T4) -void +int machine_ps2_model_70_type4_init(const machine_t *model) { + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmps2_m70_type4/70-b_even.bin", + L"roms/machines/ibmps2_m70_type4/70-b_odd.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + machine_ps2_common_init(model); ps2_mca_board_model_70_type34_init(1); + + return ret; } #endif -void + +int machine_ps2_model_80_init(const machine_t *model) { + int ret; + + ret = bios_load_interleaved(L"roms/machines/ibmps2_m80/15f6637.bin", + L"roms/machines/ibmps2_m80/15f6639.bin", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + machine_ps2_common_init(model); ps2_mca_board_model_80_type2_init(0); + + return ret; } diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index bf1b13092..afd93cf6e 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -25,12 +25,12 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../io.h" #include "../pit.h" #include "../nmi.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "../nvr.h" #include "../floppy/fdd.h" @@ -45,8 +45,17 @@ #include "machine.h" -#define TANDY_RGB 0 -#define TANDY_COMPOSITE 1 +enum { + TANDY_RGB = 0, + TANDY_COMPOSITE +}; + + +enum { + TYPE_TANDY = 0, + TYPE_TANDY1000HX, + TYPE_TANDY1000SL2 +}; enum { @@ -82,13 +91,13 @@ typedef struct { int con, coff, cursoron, blink; - int64_t vsynctime; + int vsynctime; int vadj; uint16_t ma, maback; - int64_t dispontime, - dispofftime, - vidtime; + uint64_t dispontime, + dispofftime; + pc_timer_t timer; int firstline, lastline; @@ -96,7 +105,6 @@ typedef struct { } t1kvid_t; typedef struct { - int romset; wchar_t *path; int state; @@ -126,262 +134,262 @@ static video_timings_t timing_dram = {VIDEO_BUS, 0,0,0, 0,0,0}; /*No additio static const scancode scancode_tandy[512] = { - { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, - { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, - { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, - { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, - { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, - { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, - { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, - { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, - { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, - { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, - { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, - { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, - { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, - { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, - { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, - { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, - { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, - { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, - { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, - { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, - { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, - { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} }, - { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, - { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, - { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, - { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, - { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, - { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, - { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, - { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, - { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, - { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, - { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, - { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, - { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, - { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, - { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, - { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, - { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, - { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, - { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, - { {0x52, -1}, {0xd2, -1} }, { {0x56, -1}, {0xd6, -1} }, - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*054*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*058*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*05c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*060*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*064*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*068*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*06c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*070*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*074*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*078*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*07c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*080*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*084*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*088*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*08c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*090*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*094*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*098*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*09c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0a0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0a4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0a8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0ac*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0b0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0b4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0b8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0bc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0c0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0c4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0c8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0cc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0d0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0d4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0d8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0dc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0e0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0e4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0e8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0ec*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0f0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0f4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0f8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*0fc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*100*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*104*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*108*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*10c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*110*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*114*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*118*/ - { {0x57, -1}, {0xd7, -1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*11c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*120*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*124*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*128*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*12c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*130*/ - { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, - { {-1}, {-1} }, { {0x37, -1}, {0xb7, -1} }, /*134*/ - { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*138*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*13c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*140*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*144*/ - { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, - { {-1}, {-1} }, { {0x4b, -1}, {0xcb, -1} }, /*148*/ - { {-1}, {-1} }, { {0x4d, -1}, {0xcd, -1} }, - { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*14c*/ - { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, - { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*150*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*154*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*158*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*15c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*160*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*164*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*168*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*16c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*170*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*174*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*148*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*17c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*180*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*184*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*18c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*190*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*194*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*198*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*19c*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1a0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1a4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1a8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1ac*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1b0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1b4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1b8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1bc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1c0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1c4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1c8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1cc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1d0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1d4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1d8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1dc*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1e0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1e4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1e8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1ec*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1f0*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1f4*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} }, /*1f8*/ - { {-1}, {-1} }, { {-1}, {-1} }, - { {-1}, {-1} }, { {-1}, {-1} } /*1fc*/ + { {0}, {0} }, { {0x01, 0}, {0x81, 0} }, + { {0x02, 0}, {0x82, 0} }, { {0x03, 0}, {0x83, 0} }, + { {0x04, 0}, {0x84, 0} }, { {0x05, 0}, {0x85, 0} }, + { {0x06, 0}, {0x86, 0} }, { {0x07, 0}, {0x87, 0} }, + { {0x08, 0}, {0x88, 0} }, { {0x09, 0}, {0x89, 0} }, + { {0x0a, 0}, {0x8a, 0} }, { {0x0b, 0}, {0x8b, 0} }, + { {0x0c, 0}, {0x8c, 0} }, { {0x0d, 0}, {0x8d, 0} }, + { {0x0e, 0}, {0x8e, 0} }, { {0x0f, 0}, {0x8f, 0} }, + { {0x10, 0}, {0x90, 0} }, { {0x11, 0}, {0x91, 0} }, + { {0x12, 0}, {0x92, 0} }, { {0x13, 0}, {0x93, 0} }, + { {0x14, 0}, {0x94, 0} }, { {0x15, 0}, {0x95, 0} }, + { {0x16, 0}, {0x96, 0} }, { {0x17, 0}, {0x97, 0} }, + { {0x18, 0}, {0x98, 0} }, { {0x19, 0}, {0x99, 0} }, + { {0x1a, 0}, {0x9a, 0} }, { {0x1b, 0}, {0x9b, 0} }, + { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, + { {0x1e, 0}, {0x9e, 0} }, { {0x1f, 0}, {0x9f, 0} }, + { {0x20, 0}, {0xa0, 0} }, { {0x21, 0}, {0xa1, 0} }, + { {0x22, 0}, {0xa2, 0} }, { {0x23, 0}, {0xa3, 0} }, + { {0x24, 0}, {0xa4, 0} }, { {0x25, 0}, {0xa5, 0} }, + { {0x26, 0}, {0xa6, 0} }, { {0x27, 0}, {0xa7, 0} }, + { {0x28, 0}, {0xa8, 0} }, { {0x29, 0}, {0xa9, 0} }, + { {0x2a, 0}, {0xaa, 0} }, { {0x2b, 0}, {0xab, 0} }, + { {0x2c, 0}, {0xac, 0} }, { {0x2d, 0}, {0xad, 0} }, + { {0x2e, 0}, {0xae, 0} }, { {0x2f, 0}, {0xaf, 0} }, + { {0x30, 0}, {0xb0, 0} }, { {0x31, 0}, {0xb1, 0} }, + { {0x32, 0}, {0xb2, 0} }, { {0x33, 0}, {0xb3, 0} }, + { {0x34, 0}, {0xb4, 0} }, { {0x35, 0}, {0xb5, 0} }, + { {0x36, 0}, {0xb6, 0} }, { {0x37, 0}, {0xb7, 0} }, + { {0x38, 0}, {0xb8, 0} }, { {0x39, 0}, {0xb9, 0} }, + { {0x3a, 0}, {0xba, 0} }, { {0x3b, 0}, {0xbb, 0} }, + { {0x3c, 0}, {0xbc, 0} }, { {0x3d, 0}, {0xbd, 0} }, + { {0x3e, 0}, {0xbe, 0} }, { {0x3f, 0}, {0xbf, 0} }, + { {0x40, 0}, {0xc0, 0} }, { {0x41, 0}, {0xc1, 0} }, + { {0x42, 0}, {0xc2, 0} }, { {0x43, 0}, {0xc3, 0} }, + { {0x44, 0}, {0xc4, 0} }, { {0x45, 0}, {0xc5, 0} }, + { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, + { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, + { {0x4a, 0}, {0xca, 0} }, { {0x4b, 0}, {0xcb, 0} }, + { {0x4c, 0}, {0xcc, 0} }, { {0x4d, 0}, {0xcd, 0} }, + { {0x4e, 0}, {0xce, 0} }, { {0x4f, 0}, {0xcf, 0} }, + { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, + { {0x52, 0}, {0xd2, 0} }, { {0x56, 0}, {0xd6, 0} }, + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*054*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*058*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*05c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*060*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*064*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*068*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*06c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*070*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*074*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*078*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*07c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*080*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*084*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*088*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*08c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*090*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*094*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*098*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*09c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0a0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0a4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0a8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0ac*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0b0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0b4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0b8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0bc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0c0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0c4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0c8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0cc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0d0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0d4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0d8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0dc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0e0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0e4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0e8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0ec*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0f0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0f4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0f8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*0fc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*100*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*104*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*108*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*10c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*110*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*114*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*118*/ + { {0x57, 0}, {0xd7, 0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*11c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*120*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*124*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*128*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*12c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*130*/ + { {0}, {0} }, { {0x35, 0}, {0xb5, 0} }, + { {0}, {0} }, { {0x37, 0}, {0xb7, 0} }, /*134*/ + { {0x38, 0}, {0xb8, 0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*138*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*13c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*140*/ + { {0}, {0} }, { {0}, {0} }, + { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, /*144*/ + { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, + { {0}, {0} }, { {0x4b, 0}, {0xcb, 0} }, /*148*/ + { {0}, {0} }, { {0x4d, 0}, {0xcd, 0} }, + { {0}, {0} }, { {0x4f, 0}, {0xcf, 0} }, /*14c*/ + { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, + { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} }, /*150*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*154*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*158*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*15c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*160*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*164*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*168*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*16c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*170*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*174*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*148*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*17c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*180*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*184*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*88*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*18c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*190*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*194*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*198*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*19c*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1a0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1a4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1a8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1ac*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1b0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1b4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1b8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1bc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1c0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1c4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1c8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1cc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1d0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1d4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1d8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1dc*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1e0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1e4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1e8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1ec*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1f0*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1f4*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} }, /*1f8*/ + { {0}, {0} }, { {0}, {0} }, + { {0}, {0} }, { {0}, {0} } /*1fc*/ }; static uint8_t crtcmask[32] = { 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, @@ -461,8 +469,8 @@ recalc_timings(tandy_t *dev) _dispofftime = disptime - _dispontime; _dispontime *= CGACONST; _dispofftime *= CGACONST; - vid->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - vid->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + vid->dispontime = (uint64_t)(_dispontime); + vid->dispofftime = (uint64_t)(_dispofftime); } @@ -659,7 +667,7 @@ vid_poll(void *priv) int oldsc; if (! vid->linepos) { - vid->vidtime += vid->dispofftime; + timer_advance_u64(&vid->timer, vid->dispofftime); vid->stat |= 1; vid->linepos = 1; oldsc = vid->sc; @@ -675,23 +683,23 @@ vid_poll(void *priv) cols[0] = (vid->array[2] & 0xf) + 16; for (c = 0; c < 8; c++) { if (vid->array[3] & 4) { - buffer->line[vid->displine][c] = cols[0]; + ((uint32_t *)buffer32->line[vid->displine])[c] = cols[0]; if (vid->mode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = cols[0]; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 3) + 8] = cols[0]; else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = cols[0]; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 4) + 8] = cols[0]; } else if ((vid->mode & 0x12) == 0x12) { - buffer->line[vid->displine][c] = 0; + ((uint32_t *)buffer32->line[vid->displine])[c] = 0; if (vid->mode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = 0; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 3) + 8] = 0; else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = 0; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 4) + 8] = 0; } else { - buffer->line[vid->displine][c] = (vid->col & 15) + 16; + ((uint32_t *)buffer32->line[vid->displine])[c] = (vid->col & 15) + 16; if (vid->mode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; } } @@ -700,36 +708,36 @@ vid_poll(void *priv) dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; vid->ma++; - buffer->line[vid->displine][(x << 3) + 8] = - buffer->line[vid->displine][(x << 3) + 9] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 3) + 10] = - buffer->line[vid->displine][(x << 3) + 11] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 3) + 12] = - buffer->line[vid->displine][(x << 3) + 13] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 3) + 14] = - buffer->line[vid->displine][(x << 3) + 15] = vid->array[(dat & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 9] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 10] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 11] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 12] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 13] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 14] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 15] = vid->array[(dat & vid->array[1]) + 16] + 16; } } else if (vid->array[3] & 0x10) { /*160x200x16*/ for (x = 0; x < vid->crtc[1]; x++) { dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; vid->ma++; - buffer->line[vid->displine][(x << 4) + 8] = - buffer->line[vid->displine][(x << 4) + 9] = - buffer->line[vid->displine][(x << 4) + 10] = - buffer->line[vid->displine][(x << 4) + 11] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 4) + 12] = - buffer->line[vid->displine][(x << 4) + 13] = - buffer->line[vid->displine][(x << 4) + 14] = - buffer->line[vid->displine][(x << 4) + 15] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 4) + 16] = - buffer->line[vid->displine][(x << 4) + 17] = - buffer->line[vid->displine][(x << 4) + 18] = - buffer->line[vid->displine][(x << 4) + 19] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 4) + 20] = - buffer->line[vid->displine][(x << 4) + 21] = - buffer->line[vid->displine][(x << 4) + 22] = - buffer->line[vid->displine][(x << 4) + 23] = vid->array[(dat & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 9] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 10] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 11] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 12] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 13] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 14] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 15] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 16] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 17] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 18] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 19] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 20] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 21] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 22] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 23] = vid->array[(dat & vid->array[1]) + 16] + 16; } } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ for (x = 0; x < vid->crtc[1]; x++) { @@ -739,7 +747,7 @@ vid_poll(void *priv) for (c = 0; c < 8; c++) { chr = (dat >> 7) & 1; chr |= ((dat >> 14) & 2); - buffer->line[vid->displine][(x << 3) + 8 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 8 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; dat <<= 1; } } @@ -759,14 +767,14 @@ vid_poll(void *priv) } if (vid->sc & 8) { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] = cols[0]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + c + 8] = cols[0]; } else { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } if (drawcursor) { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] ^= 15; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + c + 8] ^= 15; } vid->ma++; } @@ -787,16 +795,16 @@ vid_poll(void *priv) vid->ma++; if (vid->sc & 8) { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[0]; } else { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } if (drawcursor) { for (c = 0; c < 16; c++) - buffer->line[vid->displine][(x << 4) + c + 8] ^= 15; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + c + 8] ^= 15; } } } else if (! (vid->mode& 16)) { @@ -820,8 +828,8 @@ vid_poll(void *priv) vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; vid->ma++; for (c = 0; c < 8; c++) { - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; dat <<= 2; } } @@ -833,7 +841,7 @@ vid_poll(void *priv) vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; vid->ma++; for (c = 0; c < 16; c++) { - buffer->line[vid->displine][(x << 4) + c + 8] = cols[dat >> 15]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + c + 8] = cols[dat >> 15]; dat <<= 1; } } @@ -841,15 +849,15 @@ vid_poll(void *priv) } else { if (vid->array[3] & 4) { if (vid->mode & 1) - hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); - else - hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, vid->displine, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + else + hline(buffer32, 0, vid->displine, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); } else { cols[0] = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; if (vid->mode & 1) - hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); - else - hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); + else + hline(buffer32, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); } } @@ -857,12 +865,8 @@ vid_poll(void *priv) x = (vid->crtc[1] << 3) + 16; else x = (vid->crtc[1] << 4) + 16; - if (vid->composite) { - for (c = 0; c < x; c++) - buffer32->line[vid->displine][c] = buffer->line[vid->displine][c] & 0xf; - - Composite_Process(vid->mode, 0, x >> 2, buffer32->line[vid->displine]); - } + if (vid->composite) + Composite_Process(vid->mode, 0, x >> 2, ((uint32_t *)buffer32->line[vid->displine])); vid->sc = oldsc; if (vid->vc == vid->crtc[7] && !vid->sc) vid->stat |= 8; @@ -870,7 +874,7 @@ vid_poll(void *priv) if (vid->displine >= 360) vid->displine = 0; } else { - vid->vidtime += vid->dispontime; + timer_advance_u64(&vid->timer, vid->dispontime); if (vid->dispon) vid->stat &= ~1; vid->linepos = 0; @@ -995,7 +999,7 @@ vid_poll_sl(void *priv) int oldsc; if (! vid->linepos) { - vid->vidtime += vid->dispofftime; + timer_advance_u64(&vid->timer, vid->dispofftime); vid->stat |= 1; vid->linepos = 1; oldsc = vid->sc; @@ -1010,23 +1014,23 @@ vid_poll_sl(void *priv) cols[0] = (vid->array[2] & 0xf) + 16; for (c = 0; c < 8; c++) { if (vid->array[3] & 4) { - buffer->line[vid->displine][c] = cols[0]; + ((uint32_t *)buffer32->line[vid->displine])[c] = cols[0]; if (vid->mode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = cols[0]; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 3) + 8] = cols[0]; else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = cols[0]; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 4) + 8] = cols[0]; } else if ((vid->mode & 0x12) == 0x12) { - buffer->line[vid->displine][c] = 0; + ((uint32_t *)buffer32->line[vid->displine])[c] = 0; if (vid->mode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = 0; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 3) + 8] = 0; else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = 0; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 4) + 8] = 0; } else { - buffer->line[vid->displine][c] = (vid->col & 15) + 16; + ((uint32_t *)buffer32->line[vid->displine])[c] = (vid->col & 15) + 16; if (vid->mode & 1) - buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; else - buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; + ((uint32_t *)buffer32->line[vid->displine])[c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; } } if (vid->array[5] & 1) { /*640x200x16*/ @@ -1034,46 +1038,46 @@ vid_poll_sl(void *priv) dat = (vid->vram[(vid->ma << 1) & 0xffff] << 8) | vid->vram[((vid->ma << 1) + 1) & 0xffff]; vid->ma++; - buffer->line[vid->displine][(x << 2) + 8] = vid->array[((dat >> 12) & 0xf)/*vid->array[1])*/ + 16] + 16; - buffer->line[vid->displine][(x << 2) + 9] = vid->array[((dat >> 8) & 0xf)/*vid->array[1])*/ + 16] + 16; - buffer->line[vid->displine][(x << 2) + 10] = vid->array[((dat >> 4) & 0xf)/*vid->array[1])*/ + 16] + 16; - buffer->line[vid->displine][(x << 2) + 11] = vid->array[(dat & 0xf)/*vid->array[1])*/ + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 2) + 8] = vid->array[((dat >> 12) & 0xf)/*vid->array[1])*/ + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 2) + 9] = vid->array[((dat >> 8) & 0xf)/*vid->array[1])*/ + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 2) + 10] = vid->array[((dat >> 4) & 0xf)/*vid->array[1])*/ + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 2) + 11] = vid->array[(dat & 0xf)/*vid->array[1])*/ + 16] + 16; } } else if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ for (x = 0; x < vid->crtc[1]; x++) { dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; vid->ma++; - buffer->line[vid->displine][(x << 3) + 8] = - buffer->line[vid->displine][(x << 3) + 9] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 3) + 10] = - buffer->line[vid->displine][(x << 3) + 11] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 3) + 12] = - buffer->line[vid->displine][(x << 3) + 13] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 3) + 14] = - buffer->line[vid->displine][(x << 3) + 15] = vid->array[(dat & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 9] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 10] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 11] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 12] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 13] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 14] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 15] = vid->array[(dat & vid->array[1]) + 16] + 16; } } else if (vid->array[3] & 0x10) { /*160x200x16*/ for (x = 0; x < vid->crtc[1]; x++) { dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; vid->ma++; - buffer->line[vid->displine][(x << 4) + 8] = - buffer->line[vid->displine][(x << 4) + 9] = - buffer->line[vid->displine][(x << 4) + 10] = - buffer->line[vid->displine][(x << 4) + 11] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 4) + 12] = - buffer->line[vid->displine][(x << 4) + 13] = - buffer->line[vid->displine][(x << 4) + 14] = - buffer->line[vid->displine][(x << 4) + 15] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 4) + 16] = - buffer->line[vid->displine][(x << 4) + 17] = - buffer->line[vid->displine][(x << 4) + 18] = - buffer->line[vid->displine][(x << 4) + 19] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; - buffer->line[vid->displine][(x << 4) + 20] = - buffer->line[vid->displine][(x << 4) + 21] = - buffer->line[vid->displine][(x << 4) + 22] = - buffer->line[vid->displine][(x << 4) + 23] = vid->array[(dat & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 9] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 10] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 11] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 12] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 13] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 14] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 15] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 16] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 17] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 18] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 19] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 20] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 21] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 22] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + 23] = vid->array[(dat & vid->array[1]) + 16] + 16; } } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ for (x = 0; x < vid->crtc[1]; x++) { @@ -1083,7 +1087,7 @@ vid_poll_sl(void *priv) for (c = 0; c < 8; c++) { chr = (dat >> 7) & 1; chr |= ((dat >> 14) & 2); - buffer->line[vid->displine][(x << 3) + 8 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + 8 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; dat <<= 1; } } @@ -1103,14 +1107,14 @@ vid_poll_sl(void *priv) } if (vid->sc & 8) { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] = cols[0]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + c + 8] = cols[0]; } else { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } if (drawcursor) { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 3) + c + 8] ^= 15; + ((uint32_t *)buffer32->line[vid->displine])[(x << 3) + c + 8] ^= 15; } vid->ma++; } @@ -1131,16 +1135,16 @@ vid_poll_sl(void *priv) vid->ma++; if (vid->sc & 8) { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[0]; } else { for (c = 0; c < 8; c++) - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } if (drawcursor) { for (c = 0; c < 16; c++) - buffer->line[vid->displine][(x << 4) + c + 8] ^= 15; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + c + 8] ^= 15; } } } else if (! (vid->mode & 16)) { @@ -1165,8 +1169,8 @@ vid_poll_sl(void *priv) vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; vid->ma++; for (c = 0; c < 8; c++) { - buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = - buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; dat <<= 2; } } @@ -1178,7 +1182,7 @@ vid_poll_sl(void *priv) vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; vid->ma++; for (c = 0; c < 16; c++) { - buffer->line[vid->displine][(x << 4) + c + 8] = cols[dat >> 15]; + ((uint32_t *)buffer32->line[vid->displine])[(x << 4) + c + 8] = cols[dat >> 15]; dat <<= 1; } } @@ -1186,15 +1190,15 @@ vid_poll_sl(void *priv) } else { if (vid->array[3] & 4) { if (vid->mode & 1) - hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); - else - hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, vid->displine, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + else + hline(buffer32, 0, vid->displine, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); } else { cols[0] = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; if (vid->mode & 1) - hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); - else - hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); + else + hline(buffer32, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); } } @@ -1210,7 +1214,7 @@ vid_poll_sl(void *priv) if (vid->displine >= 360) vid->displine = 0; } else { - vid->vidtime += vid->dispontime; + timer_advance_u64(&vid->timer, vid->dispontime); if (vid->dispon) vid->stat &= ~1; vid->linepos = 0; @@ -1367,12 +1371,12 @@ vid_init(tandy_t *dev) overscan_x = overscan_y = 16; io_sethandler(0x0065, 1, vid_in,NULL,NULL, vid_out,NULL,NULL, dev); - - timer_add(vid_poll_sl, &vid->vidtime, TIMER_ALWAYS_ENABLED, dev); + + timer_add(&vid->timer, vid_poll_sl, dev, 1); } else { vid->b8000_mask = 0x3fff; - timer_add(vid_poll, &vid->vidtime, TIMER_ALWAYS_ENABLED, dev); + timer_add(&vid->timer, vid_poll, dev, 1); } mem_mapping_add(&vid->mapping, 0xb8000, 0x08000, vid_read,NULL,NULL, vid_write,NULL,NULL, NULL, 0, dev); @@ -1533,13 +1537,13 @@ eep_init(const device_t *info) eep = (t1keep_t *)malloc(sizeof(t1keep_t)); memset(eep, 0x00, sizeof(t1keep_t)); - eep->romset = romset; - switch (romset) { - case ROM_TANDY1000HX: + + switch (info->local) { + case TYPE_TANDY1000HX: eep->path = L"tandy1000hx.bin"; break; - case ROM_TANDY1000SL2: + case TYPE_TANDY1000SL2: eep->path = L"tandy1000sl2.bin"; break; @@ -1573,9 +1577,18 @@ eep_close(void *priv) } -static const device_t eep_device = { - "Tandy 1000 EEPROM", - 0, 0, +static const device_t eep_1000hx_device = { + "Tandy 1000HX EEPROM", + 0, TYPE_TANDY1000HX, + eep_init, eep_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +static const device_t eep_1000sl2_device = { + "Tandy 1000SL2 EEPROM", + 0, TYPE_TANDY1000SL2, eep_init, eep_close, NULL, NULL, NULL, NULL, NULL @@ -1716,8 +1729,8 @@ init_rom(tandy_t *dev) } -void -machine_tandy1k_init(const machine_t *model) +static void +machine_tandy1k_init(const machine_t *model, int type) { tandy_t *dev; @@ -1742,8 +1755,8 @@ machine_tandy1k_init(const machine_t *model) device_add(&fdc_xt_device); - switch(romset) { - case ROM_TANDY: + switch(type) { + case TYPE_TANDY: io_sethandler(0x00a0, 1, tandy_read,NULL,NULL,tandy_write,NULL,NULL,dev); vid_init(dev); @@ -1751,16 +1764,16 @@ machine_tandy1k_init(const machine_t *model) device_add(&sn76489_device); break; - case ROM_TANDY1000HX: + case TYPE_TANDY1000HX: io_sethandler(0x00a0, 1, tandy_read,NULL,NULL,tandy_write,NULL,NULL,dev); vid_init(dev); device_add_ex(&vid_device, dev); device_add(&ncr8496_device); - device_add(&eep_device); + device_add(&eep_1000hx_device); break; - case ROM_TANDY1000SL2: + case TYPE_TANDY1000SL2: dev->is_sl2 = 1; init_rom(dev); io_sethandler(0xffe8, 8, @@ -1768,7 +1781,7 @@ machine_tandy1k_init(const machine_t *model) vid_init(dev); device_add_ex(&vid_device_sl, dev); device_add(&pssj_device); - device_add(&eep_device); + device_add(&eep_1000sl2_device); } if (joystick_type != 7) @@ -1783,3 +1796,55 @@ tandy1k_eeprom_read(void) { return(eep_data_out); } + + +int +machine_tandy_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linearr(L"roms/machines/tandy/tandy1t1.020", + 0x000f0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_tandy1k_init(model, TYPE_TANDY); + + return ret; +} + + +int +machine_tandy1000hx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/tandy1000hx/v020000.u12", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_tandy1k_init(model, TYPE_TANDY1000HX); + + return ret; +} + + +int +machine_tandy1000sl2_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/tandy1000sl2/8079047.hu1", + L"roms/machines/tandy1000sl2/8079048.hu2", + 0x000f0000, 65536, 0x18000); + + if (bios_only || !ret) + return ret; + + machine_tandy1k_init(model, TYPE_TANDY1000SL2); + + return ret; +} diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 06ede7582..ba9127327 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -4,13 +4,16 @@ #include #include "../86box.h" #include "../nmi.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../device.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "../game/gameport.h" +#include "../ibm_5161.h" #include "../keyboard.h" +#include "../rom.h" #include "machine.h" @@ -28,26 +31,71 @@ machine_xt_common_init(const machine_t *model) } -void +int machine_pc_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/ibmpc/BIOS_5150_24APR81_U33.BIN", + 0x000fe000, 40960, 0); + if (ret) { + bios_load_aux_linear(L"roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U29 - 5700019.bin", + 0x000f6000, 8192, 0); + bios_load_aux_linear(L"roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U30 - 5700027.bin", + 0x000f8000, 8192, 0); + bios_load_aux_linear(L"roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U31 - 5700035.bin", + 0x000fa000, 8192, 0); + bios_load_aux_linear(L"roms/machines/ibmpc/IBM 5150 - Cassette BASIC version C1.00 - U32 - 5700043.bin", + 0x000fc000, 8192, 0); + } + + if (bios_only || !ret) + return ret; + machine_xt_common_init(model); device_add(&keyboard_pc_device); + + return ret; } -void +int machine_pc82_init(const machine_t *model) { + int ret, ret2; + + ret = bios_load_linear(L"roms/machines/ibmpc82/pc102782.bin", + 0x000fe000, 40960, 0); + if (ret) { + ret2 = bios_load_aux_linear(L"roms/machines/ibmpc82/ibm-basic-1.10.rom", + 0x000f6000, 32768, 0); + if (!ret2) { + bios_load_aux_linear(L"roms/machines/ibmpc82/basicc11.f6", + 0x000f6000, 8192, 0); + bios_load_aux_linear(L"roms/machines/ibmpc82/basicc11.f8", + 0x000f8000, 8192, 0); + bios_load_aux_linear(L"roms/machines/ibmpc82/basicc11.fa", + 0x000fa000, 8192, 0); + bios_load_aux_linear(L"roms/machines/ibmpc82/basicc11.fc", + 0x000fc000, 8192, 0); + } + } + + if (bios_only || !ret) + return ret; + machine_xt_common_init(model); device_add(&keyboard_pc82_device); + device_add(&ibm_5161_device); + + return ret; } -void -machine_xt_init(const machine_t *model) +static void +machine_xt_init_ex(const machine_t *model) { machine_xt_common_init(model); @@ -55,10 +103,167 @@ machine_xt_init(const machine_t *model) } -void +int +machine_xt_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ibmxt/xt.rom", + 0x000f0000, 65536, 0); + if (!ret) { + ret = bios_load_linear(L"roms/machines/ibmxt/1501512.u18", + 0x000fe000, 65536, 0x6000); + if (ret) { + bios_load_aux_linear(L"roms/machines/ibmxt/1501512.u18", + 0x000f8000, 24576, 0); + bios_load_aux_linear(L"roms/machines/ibmxt/5000027.u19", + 0x000f0000, 32768, 0); + } + } + + if (bios_only || !ret) + return ret; + + machine_xt_init_ex(model); + + device_add(&ibm_5161_device); + + return ret; +} + + +int +machine_genxt_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/genxt/pcxt.rom", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_init_ex(model); + + return ret; +} + + +int machine_xt86_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", + 0x000fe000, 65536, 0x6000); + if (ret) { + bios_load_aux_linear(L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", + 0x000f8000, 24576, 0); + bios_load_aux_linear(L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U19_62X0819_68X4370_27256_F000.BIN", + 0x000f0000, 32768, 0); + } + + if (bios_only || !ret) + return ret; + + machine_xt_common_init(model); + + device_add(&keyboard_xt86_device); + device_add(&ibm_5161_device); + + return ret; +} + + +static void +machine_xt_clone_init(const machine_t *model) { machine_xt_common_init(model); device_add(&keyboard_xt86_device); } + + +int +machine_xt_amixt_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/amixt/ami_8088_bios_31jan89.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + + +int +machine_xt_dtk_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/dtk/dtk_erso_2.42_2764.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + + +int +machine_xt_jukopc_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/jukopc/000o001.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + + +int +machine_xt_open_xt_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/open_xt/pcxt31.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return ret; +} + + +int +machine_xt_pxxt_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear(L"roms/machines/pxxt/000p001.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + + machine_xt_clone_init(model); + + return 1; +} diff --git a/src/machine/m_xt_compaq.c b/src/machine/m_xt_compaq.c index 751e45da8..02af39d67 100644 --- a/src/machine/m_xt_compaq.c +++ b/src/machine/m_xt_compaq.c @@ -24,6 +24,7 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../nmi.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" @@ -36,23 +37,29 @@ #include "machine.h" -void +int machine_xt_compaq_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/portable/compaq portable plus 100666-001 rev c u47.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + machine_common_init(model); pit_set_out_func(&pit, 1, pit_refresh_timer_xt); - device_add(&keyboard_xt_device); + device_add(&keyboard_xt_compaq_device); device_add(&fdc_xt_device); nmi_init(); if (joystick_type != 7) device_add(&gameport_device); - switch(model->id) { - case ROM_PORTABLE: - lpt1_remove(); - lpt1_init(0x03bc); - break; - } + lpt1_remove(); + lpt1_init(0x03bc); + + return ret; } diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index 56a6d6ae6..ddf715fb3 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -8,10 +8,12 @@ #include "../io.h" #include "../mem.h" #include "../nmi.h" +#include "../timer.h" #include "../pit.h" #include "../rom.h" #include "machine.h" #include "../device.h" +#include "../timer.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" #include "../game/gameport.h" @@ -64,14 +66,6 @@ static void laserxt_write(uint16_t port, uint8_t val, void *priv) { laserxt_ems_baseaddr_index |= (laserxt_emscontrol[i] & 0x80) >> (7 - i); } - if(laserxt_ems_baseaddr_index < 3) - { - mem_mapping_disable(&romext_mapping); - } - else - { - mem_mapping_enable(&romext_mapping); - } mem_mapping_set_addr(&laserxt_ems_mapping[0], 0xC0000 + (((laserxt_ems_baseaddr_index + 4) & 0x0C) << 14), 0x4000); mem_mapping_set_addr(&laserxt_ems_mapping[1], 0xC4000 + (((laserxt_ems_baseaddr_index + 3) & 0x0C) << 14), 0x4000); @@ -140,18 +134,36 @@ static void laserxt_init(int is_lxt3) } -void +int machine_xt_laserxt_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/ltxt/27c64.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + machine_xt_init(model); laserxt_init(0); + + return ret; } -void +int machine_xt_lxt3_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/lxt3/27c64d.bin", + 0x000fe000, 8192, 0); + + if (bios_only || !ret) + return ret; + machine_common_init(model); pit_set_out_func(&pit, 1, pit_refresh_timer_xt); @@ -163,4 +175,6 @@ machine_xt_lxt3_init(const machine_t *model) device_add(&gameport_device); laserxt_init(1); + + return ret; } diff --git a/src/machine/m_xt_t1000.c b/src/machine/m_xt_t1000.c index c9c44b0b0..f6a6bd8df 100644 --- a/src/machine/m_xt_t1000.c +++ b/src/machine/m_xt_t1000.c @@ -90,6 +90,7 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../nmi.h" #include "../mem.h" @@ -601,7 +602,7 @@ read_ctl(uint16_t addr, void *priv) case 0x0f: /* Detect EMS board */ switch (sys->sys_ctl[0x0e]) { case 0x50: - if (mem_size > 512) break; + if (mem_size > 512) ret = (0x90 | sys->ems_port_index); break; @@ -847,12 +848,20 @@ t1000_get_device(void) } -void +int machine_xt_t1000_init(const machine_t *model) { FILE *f; int pg; + int ret; + + ret = bios_load_linear(L"roms/machines/t1000/t1000.rom", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + memset(&t1000, 0x00, sizeof(t1000)); t1000.is_t1200 = 0; t1000.turbo = 0xff; @@ -920,6 +929,8 @@ machine_xt_t1000_init(const machine_t *model) if (gfxcard == VID_INTERNAL) device_add(&t1000_video_device); + + return ret; } @@ -930,11 +941,19 @@ t1200_get_device(void) } -void +int machine_xt_t1200_init(const machine_t *model) { int pg; + int ret; + + ret = bios_load_linear(L"roms/machines/t1200/t1200_019e.ic15.bin", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + memset(&t1000, 0x00, sizeof(t1000)); t1000.is_t1200 = 1; t1000.ems_port_index = 7; /* EMS disabled */ @@ -978,6 +997,8 @@ machine_xt_t1200_init(const machine_t *model) if (gfxcard == VID_INTERNAL) device_add(&t1200_video_device); + + return ret; } diff --git a/src/machine/m_xt_t1000_vid.c b/src/machine/m_xt_t1000_vid.c index 336d9a846..0ee46a8fc 100644 --- a/src/machine/m_xt_t1000_vid.c +++ b/src/machine/m_xt_t1000_vid.c @@ -9,7 +9,7 @@ * Implementation of the Toshiba T1000 plasma display, which * has a fixed resolution of 640x200 pixels. * - * Version: @(#)m_xt_t1000_vid.c 1.0.9 2018/09/19 + * Version: @(#)m_xt_t1000_vid.c 1.0.10 2018/02/16 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -112,7 +112,7 @@ typedef struct t1000_t int internal; /* Using internal display? */ uint8_t attrmap; /* Attribute mapping register */ - int dispontime, dispofftime; + uint64_t dispontime, dispofftime; int linepos, displine; int vc; @@ -194,14 +194,14 @@ static void t1000_write(uint32_t addr, uint8_t val, void *p) egawrites++; t1000->vram[addr & 0x3fff] = val; - cycles -= 4; + sub_cycles(4); } static uint8_t t1000_read(uint32_t addr, void *p) { t1000_t *t1000 = (t1000_t *)p; egareads++; - cycles -= 4; + sub_cycles(4); return t1000->vram[addr & 0x3fff]; } @@ -221,8 +221,8 @@ static void t1000_recalctimings(t1000_t *t1000) disptime = 651; _dispontime = 640; _dispofftime = disptime - _dispontime; - t1000->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - t1000->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + t1000->dispontime = (uint64_t)(_dispontime * xt_cpu_multi); + t1000->dispofftime = (uint64_t)(_dispofftime * xt_cpu_multi); } /* Draw a row of text in 80-column mode */ @@ -493,7 +493,7 @@ static void t1000_poll(void *p) if (!t1000->linepos) { - t1000->cga.vidtime += t1000->dispofftime; + timer_advance_u64(&t1000->cga.timer, t1000->dispofftime); t1000->cga.cgastat |= 1; t1000->linepos = 1; if (t1000->dispon) @@ -540,7 +540,7 @@ static void t1000_poll(void *p) { t1000->cga.cgastat &= ~1; } - t1000->cga.vidtime += t1000->dispontime; + timer_advance_u64(&t1000->cga.timer, t1000->dispontime); t1000->linepos = 0; if (t1000->displine == 200) @@ -675,6 +675,7 @@ static void *t1000_init(const device_t *info) { t1000_t *t1000 = malloc(sizeof(t1000_t)); memset(t1000, 0, sizeof(t1000_t)); + loadfont(L"roms/machines/t1000/t1000font.bin", 2); cga_init(&t1000->cga); video_inform(VIDEO_FLAG_TYPE_CGA, &timing_t1000); @@ -683,7 +684,8 @@ static void *t1000_init(const device_t *info) /* 16k video RAM */ t1000->vram = malloc(0x4000); - timer_add(t1000_poll, &t1000->cga.vidtime, TIMER_ALWAYS_ENABLED, t1000); + timer_set_callback(&t1000->cga.timer, t1000_poll); + timer_set_p(&t1000->cga.timer, t1000); /* Occupy memory between 0xB8000 and 0xBFFFF */ mem_mapping_add(&t1000->mapping, 0xb8000, 0x8000, t1000_read, NULL, NULL, t1000_write, NULL, NULL, NULL, 0, t1000); diff --git a/src/machine/m_xt_xi8088.c b/src/machine/m_xt_xi8088.c index f1ce87919..101e8a0ae 100644 --- a/src/machine/m_xt_xi8088.c +++ b/src/machine/m_xt_xi8088.c @@ -3,6 +3,7 @@ #include #include #include "../86box.h" +#include "../timer.h" #include "../pic.h" #include "../pit.h" #include "../dma.h" @@ -15,7 +16,9 @@ #include "../game/gameport.h" #include "../keyboard.h" #include "../lpt.h" +#include "../rom.h" #include "../disk/hdc.h" +#include "../video/video.h" #include "machine.h" #include "../cpu/cpu.h" @@ -29,52 +32,54 @@ typedef struct xi8088_t int bios_128kb; } xi8088_t; -static xi8088_t xi8088; -uint8_t xi8088_turbo_get() +static xi8088_t xi8088; + + +uint8_t +xi8088_turbo_get() { - return xi8088.turbo; + return xi8088.turbo; } -void xi8088_turbo_set(uint8_t value) -{ - if (!xi8088.turbo_setting) - return; - xi8088.turbo = value; - if (!value) - { - pclog("Xi8088 turbo off\n"); - int c = cpu; - cpu = 0; /* 8088/4.77 */ - cpu_set(); - cpu = c; - } - else - { - pclog("Xi8088 turbo on\n"); - cpu_set(); - } +void +xi8088_turbo_set(uint8_t value) +{ + int c; + + if (!xi8088.turbo_setting) + return; + + xi8088.turbo = value; + if (!value) { + c = cpu; + cpu = 0; /* 8088/4.77 */ + cpu_set(); + cpu = c; + } else + cpu_set(); } -void xi8088_bios_128kb_set(int val) + +int +xi8088_bios_128kb(void) { - xi8088.bios_128kb = val; + return xi8088.bios_128kb; } -int xi8088_bios_128kb() + +static void * +xi8088_init(const device_t *info) { - return xi8088.bios_128kb; + /* even though the bios by default turns the turbo off when controlling by hotkeys, pcem always starts at full speed */ + xi8088.turbo = 1; + xi8088.turbo_setting = device_get_config_int("turbo_setting"); + xi8088.bios_128kb = device_get_config_int("bios_128kb"); + + return &xi8088; } -static void *xi8088_init() -{ - /* even though the bios by default turns the turbo off when controlling by hotkeys, pcem always starts at full speed */ - xi8088.turbo = 1; - xi8088.turbo_setting = device_get_config_int("turbo_setting"); - - return &xi8088; -} static const device_config_t xi8088_config[] = { @@ -95,6 +100,23 @@ static const device_config_t xi8088_config[] = }, .default_int = 0 }, + { + .name = "bios_128kb", + .description = "BIOS size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "64KB", + .value = 0 + }, + { + .description = "128KB", + .value = 1 + } + }, + .default_int = 1 + }, { .type = -1 } @@ -115,23 +137,46 @@ const device_t xi8088_device = xi8088_config }; + const device_t * xi8088_get_device(void) { return &xi8088_device; } -void machine_xt_xi8088_init(const machine_t *model) + +int +machine_xt_xi8088_init(const machine_t *model) { - /* TODO: set UMBs? See if PCem always sets when we have > 640KB ram and avoids conflicts when a peripheral uses the same memory space */ - if (xi8088_bios_128kb()) - mem_add_upper_bios(); - machine_common_init(model); - device_add(&fdc_xt_device); - device_add(&keyboard_ps2_xi8088_device); - nmi_init(); - device_add(&at_nvr_device); - pic2_init(); - if (joystick_type != 7) - device_add(&gameport_device); + int ret; + + if (bios_only) { + ret = bios_load_linear(L"roms/machines/xi8088/bios-xi8088.bin", + 0x000f0000, 65536, 0); + } else { + device_add(&xi8088_device); + + if (xi8088_bios_128kb()) { + ret = bios_load_linear_inverted(L"roms/machines/xi8088/bios-xi8088.bin", + 0x000e0000, 131072, 0); + } else { + ret = bios_load_linear(L"roms/machines/xi8088/bios-xi8088.bin", + 0x000f0000, 65536, 0); + } + } + + if (bios_only || !ret) + return ret; + + /* TODO: set UMBs? See if PCem always sets when we have > 640KB ram and avoids conflicts when a peripheral uses the same memory space */ + machine_common_init(model); + device_add(&fdc_at_device); + device_add(&keyboard_ps2_xi8088_device); + nmi_init(); + device_add(&ibmat_nvr_device); + pic2_init(); + if (joystick_type != 7) + device_add(&gameport_device); + + return ret; } diff --git a/src/machine/m_xt_zenith.c b/src/machine/m_xt_zenith.c index f818ddf81..033c8b77a 100644 --- a/src/machine/m_xt_zenith.c +++ b/src/machine/m_xt_zenith.c @@ -26,7 +26,10 @@ #include #include "../86box.h" #include "../cpu/cpu.h" +#include "../timer.h" +#include "../dma.h" #include "../nmi.h" +#include "../pic.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" @@ -36,24 +39,32 @@ #include "../game/gameport.h" #include "../keyboard.h" #include "../lpt.h" +#include "../serial.h" #include "machine.h" + typedef struct { mem_mapping_t scratchpad_mapping; uint8_t *scratchpad_ram; } zenith_t; -static uint8_t zenith_scratchpad_read(uint32_t addr, void *p) + +static uint8_t +zenith_scratchpad_read(uint32_t addr, void *p) { - zenith_t *dev = (zenith_t *)p; - return dev->scratchpad_ram[addr & 0x3fff]; + zenith_t *dev = (zenith_t *)p; + return dev->scratchpad_ram[addr & 0x3fff]; } -static void zenith_scratchpad_write(uint32_t addr, uint8_t val, void *p) + + +static void +zenith_scratchpad_write(uint32_t addr, uint8_t val, void *p) { - zenith_t *dev = (zenith_t *)p; - dev->scratchpad_ram[addr & 0x3fff] = val; + zenith_t *dev = (zenith_t *)p; + dev->scratchpad_ram[addr & 0x3fff] = val; } + static void * zenith_scratchpad_init(const device_t *info) { @@ -64,9 +75,6 @@ zenith_scratchpad_init(const device_t *info) dev->scratchpad_ram = malloc(0x4000); - mem_mapping_disable(&bios_mapping[4]); - mem_mapping_disable(&bios_mapping[5]); - mem_mapping_add(&dev->scratchpad_mapping, 0xf0000, 0x4000, zenith_scratchpad_read, NULL, NULL, zenith_scratchpad_write, NULL, NULL, @@ -75,13 +83,14 @@ zenith_scratchpad_init(const device_t *info) return dev; } + static void zenith_scratchpad_close(void *p) { - zenith_t *dev = (zenith_t *)p; + zenith_t *dev = (zenith_t *)p; - free(dev->scratchpad_ram); - free(dev); + free(dev->scratchpad_ram); + free(dev); } @@ -94,20 +103,30 @@ static const device_t zenith_scratchpad_device = { NULL }; -void + +int machine_xt_zenith_init(const machine_t *model) { + int ret; + + ret = bios_load_linear(L"roms/machines/zdsupers/z184m v3.1d.10d", + 0x000f8000, 32768, 0); + + if (bios_only || !ret) + return ret; + machine_common_init(model); - lpt2_remove(); /* only one parallel port */ - - device_add(&zenith_scratchpad_device); - - pit_set_out_func(&pit, 1, pit_refresh_timer_xt); - - device_add(&keyboard_xt_device); device_add(&fdc_xt_device); + lpt1_remove(); /* only one parallel port */ + lpt2_remove(); + lpt1_init(0x278); + device_add(&i8250_device); + serial_set_next_inst(2); /* So that serial_standalone_init() won't do anything. */ + device_add(&zenith_scratchpad_device); + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + device_add(&keyboard_xt_compaq_device); nmi_init(); - if (joystick_type != 7) - device_add(&gameport_device); -} \ No newline at end of file + + return ret; +} diff --git a/src/machine/machine.c b/src/machine/machine.c index da5d59615..80f34fa5b 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -26,6 +26,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../device.h" +#include "../timer.h" #include "../dma.h" #include "../pic.h" #include "../pit.h" @@ -38,9 +39,9 @@ #include "machine.h" +int bios_only = 0; int machine; int AT, PCI; -int romset; #ifdef ENABLE_MACHINE_LOG @@ -64,36 +65,57 @@ machine_log(const char *fmt, ...) #endif +static int +machine_init_ex(int m) +{ + int ret = 0; + + if (!bios_only) { + machine_log("Initializing as \"%s\"\n", machine_getname_ex(m)); + + /* Set up the architecture flags. */ + AT = IS_ARCH(machine, MACHINE_AT); + PCI = IS_ARCH(machine, MACHINE_PCI); + + /* Resize the memory. */ + mem_reset(); + + lpt_init(); + } + + /* All good, boot the machine! */ + if (machines[m].init) + ret = machines[m].init(&machines[m]); + + if (bios_only || !ret) + return ret; + + /* Reset the graphics card (or do nothing if it was already done + by the machine's init function). */ + video_reset(gfxcard); + + return ret; +} + + void machine_init(void) { - int MCA; - machine_log("Initializing as \"%s\"\n", machine_getname()); + bios_only = 0; + (void) machine_init_ex(machine); +} - /* Set up the architecture flags. */ - AT = IS_ARCH(machine, MACHINE_AT); - PCI = IS_ARCH(machine, MACHINE_PCI); - MCA = IS_ARCH(machine, MACHINE_MCA); - /* Resize the memory. */ - mem_reset(); +int +machine_available(int m) +{ + int ret; - /* Load the machine's ROM BIOS. */ - rom_load_bios(romset); - mem_add_bios(); + bios_only = 1; + ret = machine_init_ex(m); - /* If it's not a PCI or MCA machine, reset the video card - before initializing the machine, to please the EuroPC. */ - if (!PCI && !MCA) - video_reset(gfxcard); - - /* All good, boot the machine! */ - machines[machine].init(&machines[machine]); - - /* If it's a PCI or MCA machine, reset the video card - after initializing the machine, so the slots work correctly. */ - if (PCI || MCA) - video_reset(gfxcard); + bios_only = 0; + return ret; } @@ -103,14 +125,8 @@ machine_common_init(const machine_t *model) /* System devices first. */ pic_init(); dma_init(); - pit_init(); cpu_set(); - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) - setrtcconst(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); - else - setrtcconst(14318184.0); - if (lpt_enabled) - lpt_init(); + pit_init(); } diff --git a/src/machine/machine.h b/src/machine/machine.h index 3d2e6c3a0..5fbd735f5 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -8,21 +8,22 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.h 1.0.33 2019/02/08 + * Version: @(#)machine.h 1.0.34 2019/03/08 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_MACHINE_H # define EMU_MACHINE_H /* Machine feature flags. */ +#ifdef NEW_FLAGS #define MACHINE_PC 0x000000 /* PC architecture */ #define MACHINE_AT 0x000001 /* PC/AT architecture */ #define MACHINE_PS2 0x000002 /* PS/2 architecture */ @@ -34,17 +35,56 @@ #define MACHINE_PCI 0x000200 /* sys has PCI bus */ #define MACHINE_AGP 0x000400 /* sys has AGP bus */ #define MACHINE_HDC 0x001000 /* sys has int HDC */ -#define MACHINE_HDC_PS2 0x002000 /* sys has int PS/2 HDC */ -#define MACHINE_MOUSE 0x004000 /* sys has int mouse */ -#define MACHINE_VIDEO 0x008000 /* sys has int video */ +#define MACHINE_VIDEO 0x002000 /* sys has int video */ +#define MACHINE_VIDEO_FIXED 0x004000 /* sys has ONLY int video */ +#define MACHINE_MOUSE 0x008000 /* sys has int mouse */ #define MACHINE_NONMI 0x010000 /* sys does not have NMI's */ +#else +#define MACHINE_PC 0x000000 /* PC architecture */ +#define MACHINE_AT 0x000001 /* PC/AT architecture */ +#define MACHINE_PS2 0x000002 /* PS/2 architecture */ +#define MACHINE_ISA 0x000010 /* sys has ISA bus */ +#define MACHINE_CBUS 0x000020 /* sys has C-BUS bus */ +#define MACHINE_EISA 0x000040 /* sys has EISA bus */ +#define MACHINE_VLB 0x000080 /* sys has VL bus */ +#define MACHINE_MCA 0x000100 /* sys has MCA bus */ +#define MACHINE_PCI 0x000200 /* sys has PCI bus */ +#define MACHINE_AGP 0x000400 /* sys has AGP bus */ +#define MACHINE_HDC 0x001000 /* sys has int HDC */ +#define MACHINE_VIDEO 0x002000 /* sys has int video */ +#define MACHINE_VIDEO_FIXED 0x004000 /* sys has ONLY int video */ +#define MACHINE_MOUSE 0x008000 /* sys has int mouse */ +#define MACHINE_NONMI 0x010000 /* sys does not have NMI's */ +#endif #define IS_ARCH(m, a) (machines[(m)].flags & (a)) ? 1 : 0; +#ifdef NEW_STRUCT +typedef struct _machine_ { + const char *name; + const char *internal_name; +#ifdef EMU_DEVICE_H + const device_t *device; +#else + void *device; +#endif + struct { + const char *name; +#ifdef EMU_CPU_H + CPU *cpus; +#else + void *cpus; +#endif + } cpu[5]; + int flags; + uint32_t min_ram, max_ram; + int ram_granularity; + int nvrmask; +} machine_t; +#else typedef struct _machine_ { const char *name; - int id; const char *internal_name; struct { const char *name; @@ -54,39 +94,37 @@ typedef struct _machine_ { void *cpus; #endif } cpu[5]; - int fixed_gfxcard; int flags; uint32_t min_ram, max_ram; int ram_granularity; int nvrmask; - void (*init)(const struct _machine_ *); + int (*init)(const struct _machine_ *); #ifdef EMU_DEVICE_H const device_t *(*get_device)(void); #else void *get_device; #endif } machine_t; +#endif /* Global variables. */ extern const machine_t machines[]; +extern int bios_only; extern int machine; -extern int romset; extern int AT, PCI; /* Core functions. */ extern int machine_count(void); -extern int machine_getromset(void); -extern int machine_getmachine(int romset); +extern int machine_available(int m); extern char *machine_getname(void); extern char *machine_get_internal_name(void); extern int machine_get_machine_from_internal_name(char *s); extern void machine_init(void); #ifdef EMU_DEVICE_H -extern const device_t *machine_getdevice(int machine); +extern const device_t *machine_getdevice(int m); #endif -extern int machine_getromset_ex(int m); extern char *machine_get_internal_name_ex(int m); extern int machine_get_nvrmask(int m); extern void machine_close(void); @@ -95,126 +133,240 @@ extern void machine_close(void); /* Initialization functions for boards and systems. */ extern void machine_common_init(const machine_t *); +/* m_amstrad.c */ +extern int machine_pc1512_init(const machine_t *); +extern int machine_pc1640_init(const machine_t *); +extern int machine_pc200_init(const machine_t *); +extern int machine_ppc512_init(const machine_t *); +extern int machine_pc2086_init(const machine_t *); +extern int machine_pc3086_init(const machine_t *); + +#ifdef EMU_DEVICE_H +extern const device_t *pc1512_get_device(void); +extern const device_t *pc1640_get_device(void); +extern const device_t *pc200_get_device(void); +extern const device_t *ppc512_get_device(void); +extern const device_t *pc2086_get_device(void); +extern const device_t *pc3086_get_device(void); +#endif + +/* m_at.c */ +extern void machine_at_common_init_ex(const machine_t *, int is_ibm); extern void machine_at_common_init(const machine_t *); extern void machine_at_init(const machine_t *); -extern void machine_at_ibm_init(const machine_t *); extern void machine_at_ps2_init(const machine_t *); extern void machine_at_common_ide_init(const machine_t *); +extern void machine_at_ibm_common_ide_init(const machine_t *); extern void machine_at_ide_init(const machine_t *); extern void machine_at_ps2_ide_init(const machine_t *); -extern void machine_at_t3100e_init(const machine_t *); +extern int machine_at_ibm_init(const machine_t *); +extern int machine_at_ibmxt286_init(const machine_t *); -extern void machine_at_p54tp4xe_init(const machine_t *); -extern void machine_at_endeavor_init(const machine_t *); -extern void machine_at_zappa_init(const machine_t *); -extern void machine_at_mb500n_init(const machine_t *); -extern void machine_at_president_init(const machine_t *); -extern void machine_at_thor_init(const machine_t *); -extern void machine_at_pb640_init(const machine_t *); - -extern void machine_at_acerm3a_init(const machine_t *); -extern void machine_at_acerv35n_init(const machine_t *); -extern void machine_at_ap53_init(const machine_t *); -extern void machine_at_p55t2p4_init(const machine_t *); -extern void machine_at_p55t2s_init(const machine_t *); - -extern void machine_at_batman_init(const machine_t *); -extern void machine_at_plato_init(const machine_t *); - -extern void machine_at_p55tvp4_init(const machine_t *); -extern void machine_at_i430vx_init(const machine_t *); -extern void machine_at_p55va_init(const machine_t *); -extern void machine_at_j656vxd_init(const machine_t *); - -#if defined(DEV_BRANCH) && defined(USE_I686) -extern void machine_at_i440fx_init(const machine_t *); -extern void machine_at_s1668_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_OPEN_AT) +extern int machine_at_open_at_init(const machine_t *); #endif -extern void machine_at_ali1429_init(const machine_t *); -extern void machine_at_cmdpc_init(const machine_t *); -extern void machine_at_headland_init(const machine_t *); -extern void machine_at_tg286m_init(const machine_t *); -extern void machine_at_ama932j_init(const machine_t *); -extern void machine_at_neat_init(const machine_t *); -extern void machine_at_neat_ami_init(const machine_t *); -extern void machine_at_opti495_init(const machine_t *); -extern void machine_at_opti495_ami_init(const machine_t *); -extern void machine_at_scat_init(const machine_t *); -extern void machine_at_scatsx_init(const machine_t *); -extern void machine_at_compaq_init(const machine_t *); +/* m_at_286_386sx.c */ +#if defined(DEV_BRANCH) && defined(USE_AMI386SX) +extern int machine_at_headland_init(const machine_t *); +#endif +extern int machine_at_tg286m_init(const machine_t *); +extern int machine_at_ama932j_init(const machine_t *); -extern void machine_at_dtk486_init(const machine_t *); -extern void machine_at_r418_init(const machine_t *); +extern int machine_at_neat_init(const machine_t *); +extern int machine_at_neat_ami_init(const machine_t *); -extern void machine_at_wd76c10_init(const machine_t *); +extern int machine_at_award286_init(const machine_t *); +extern int machine_at_gw286ct_init(const machine_t *); +extern int machine_at_super286tr_init(const machine_t *); +extern int machine_at_spc4200p_init(const machine_t *); +extern int machine_at_spc4216p_init(const machine_t *); +extern int machine_at_kmxc02_init(const machine_t *); -extern void machine_pc_init(const machine_t *); -extern void machine_pc82_init(const machine_t *); +extern int machine_at_wd76c10_init(const machine_t *); -extern void machine_pcjr_init(const machine_t *); - -extern void machine_ps1_m2011_init(const machine_t *); #ifdef EMU_DEVICE_H -extern void ps1_hdc_inform(void *, void *); -extern void ps1_set_feedback(void *); -extern const device_t ps1_hdc_device; +extern const device_t *at_ama932j_get_device(void); #endif -extern void machine_ps1_m2121_init(const machine_t *); -extern void machine_ps1_m2133_init(const machine_t *); +/* m_at_386dx_486.c */ +extern int machine_at_pb410a_init(const machine_t *); -extern void machine_ps2_m30_286_init(const machine_t *); -extern void machine_ps2_model_50_init(const machine_t *); -extern void machine_ps2_model_55sx_init(const machine_t *); -extern void machine_ps2_model_70_type3_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(USE_PS2M70T4) -extern void machine_ps2_model_70_type4_init(const machine_t *); +extern int machine_at_ali1429_init(const machine_t *); +extern int machine_at_winbios1429_init(const machine_t *); + +extern int machine_at_opti495_init(const machine_t *); +extern int machine_at_opti495_ami_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_MR495) +extern int machine_at_opti495_mr_init(const machine_t *); #endif -extern void machine_ps2_model_80_init(const machine_t *); -extern void machine_amstrad_init(const machine_t *); +extern int machine_at_ami471_init(const machine_t *); +extern int machine_at_dtk486_init(const machine_t *); +extern int machine_at_px471_init(const machine_t *); +extern int machine_at_win471_init(const machine_t *); -extern void machine_europc_init(const machine_t *); +extern int machine_at_r418_init(const machine_t *); +extern int machine_at_alfredo_init(const machine_t *); + +/* m_at_commodore.c */ +extern int machine_at_cmdpc_init(const machine_t *); + +/* m_at_compaq.c */ +extern int machine_at_portableii_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) +extern int machine_at_portableiii_init(const machine_t *); +extern int machine_at_portableiii386_init(const machine_t *); +#endif + +/* m_at_socket4_5.c */ +extern int machine_at_batman_init(const machine_t *); +extern int machine_at_586mc1_init(const machine_t *); + +extern int machine_at_plato_init(const machine_t *); +extern int machine_at_430nx_init(const machine_t *); + +extern int machine_at_p54tp4xe_init(const machine_t *); +extern int machine_at_endeavor_init(const machine_t *); +extern int machine_at_zappa_init(const machine_t *); +extern int machine_at_mb500n_init(const machine_t *); +extern int machine_at_president_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_VECTRA54) +extern int machine_at_vectra54_init(const machine_t *); +#endif + +#ifdef EMU_DEVICE_H +extern const device_t *at_endeavor_get_device(void); +#endif + +/* m_at_socket7_s7.c */ +extern int machine_at_thor_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_MRTHOR) +extern int machine_at_mrthor_init(const machine_t *); +#endif +extern int machine_at_pb640_init(const machine_t *); + +extern int machine_at_acerm3a_init(const machine_t *); +extern int machine_at_acerv35n_init(const machine_t *); +extern int machine_at_ap53_init(const machine_t *); +extern int machine_at_p55t2p4_init(const machine_t *); +extern int machine_at_p55t2s_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_TC430HX) +extern int machine_at_tc430hx_init(const machine_t *); +#endif + +extern int machine_at_p55tvp4_init(const machine_t *); +extern int machine_at_i430vx_init(const machine_t *); +extern int machine_at_p55va_init(const machine_t *); +extern int machine_at_j656vxd_init(const machine_t *); + +#ifdef EMU_DEVICE_H +extern const device_t *at_pb640_get_device(void); +#endif + +/* m_at_socket8.c */ +#if defined(DEV_BRANCH) && defined(USE_I686) +extern int machine_at_i440fx_init(const machine_t *); +extern int machine_at_s1668_init(const machine_t *); +#endif + +/* m_at_t3100e.c */ +extern int machine_at_t3100e_init(const machine_t *); + +/* m_europc.c */ +extern int machine_europc_init(const machine_t *); #ifdef EMU_DEVICE_H extern const device_t europc_device; #endif -extern void machine_olim24_init(const machine_t *); -extern void machine_olim24_video_init(void); +/* m_oivetti_m24.c */ +extern int machine_olim24_init(const machine_t *); -extern void machine_tandy1k_init(const machine_t *); -extern int tandy1k_eeprom_read(void); +/* m_pcjr.c */ +extern int machine_pcjr_init(const machine_t *); -extern void machine_xt_init(const machine_t *); -extern void machine_xt86_init(const machine_t *); -extern void machine_xt_compaq_init(const machine_t *); -#if defined(DEV_BRANCH) && defined(USE_LASERXT) -extern void machine_xt_laserxt_init(const machine_t *); -extern void machine_xt_lxt3_init(const machine_t *); +#ifdef EMU_DEVICE_H +extern const device_t *pcjr_get_device(void); #endif -extern void machine_xt_t1000_init(const machine_t *); -extern void machine_xt_t1200_init(const machine_t *); +/* m_ps1.c */ +extern int machine_ps1_m2011_init(const machine_t *); +extern int machine_ps1_m2121_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_PS1M2133) +extern int machine_ps1_m2133_init(const machine_t *); +#endif -extern void machine_xt_xi8088_init(const machine_t *); -extern void machine_xt_zenith_init(const machine_t *); +/* m_ps1_hdc.c */ +#ifdef EMU_DEVICE_H +extern void ps1_hdc_inform(void *, uint8_t *); +extern const device_t ps1_hdc_device; +#endif + +/* m_ps2_isa.c */ +extern int machine_ps2_m30_286_init(const machine_t *); + +/* m_ps2_mca.c */ +extern int machine_ps2_model_50_init(const machine_t *); +extern int machine_ps2_model_55sx_init(const machine_t *); +extern int machine_ps2_model_70_type3_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_PS2M70T4) +extern int machine_ps2_model_70_type4_init(const machine_t *); +#endif +extern int machine_ps2_model_80_init(const machine_t *); + +/* m_tandy.c */ +extern int tandy1k_eeprom_read(void); +extern int machine_tandy_init(const machine_t *); +extern int machine_tandy1000hx_init(const machine_t *); +extern int machine_tandy1000sl2_init(const machine_t *); + +#ifdef EMU_DEVICE_H +extern const device_t *tandy1k_get_device(void); +extern const device_t *tandy1k_hx_get_device(void); +#endif + +/* m_xt.c */ +extern int machine_pc_init(const machine_t *); +extern int machine_pc82_init(const machine_t *); + +extern int machine_xt_init(const machine_t *); +extern int machine_genxt_init(const machine_t *); + +extern int machine_xt86_init(const machine_t *); + +extern int machine_xt_amixt_init(const machine_t *); +extern int machine_xt_dtk_init(const machine_t *); +extern int machine_xt_jukopc_init(const machine_t *); +extern int machine_xt_open_xt_init(const machine_t *); +extern int machine_xt_pxxt_init(const machine_t *); + +/* m_xt_compaq.c */ +extern int machine_xt_compaq_init(const machine_t *); + +/* m_xt_laserxt.c */ +#if defined(DEV_BRANCH) && defined(USE_LASERXT) +extern int machine_xt_laserxt_init(const machine_t *); +extern int machine_xt_lxt3_init(const machine_t *); +#endif + +/* m_xt_t1000.c */ +extern int machine_xt_t1000_init(const machine_t *); +extern int machine_xt_t1200_init(const machine_t *); + +#ifdef EMU_DEVICE_H +extern const device_t *t1000_get_device(void); +extern const device_t *t1200_get_device(void); +#endif + +/* m_xt_zenith.c */ +extern int machine_xt_zenith_init(const machine_t *); + +/* m_xt_xi8088.c */ +extern int machine_xt_xi8088_init(const machine_t *); #ifdef EMU_DEVICE_H extern const device_t *xi8088_get_device(void); - -extern const device_t *pcjr_get_device(void); - -extern const device_t *tandy1k_get_device(void); -extern const device_t *tandy1k_hx_get_device(void); - -extern const device_t *t1000_get_device(void); -extern const device_t *t1200_get_device(void); - -extern const device_t *at_endeavor_get_device(void); - -extern const device_t *at_ama932j_get_device(void); #endif diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index d95791c94..b89480658 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11,7 +11,7 @@ * 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.46 2019/02/08 + * Version: @(#)machine_table.c 1.0.47 2019/02/13 * * Authors: Sarah Walker, * Miran Grca, @@ -33,157 +33,168 @@ #include "machine.h" +#if defined(DEV_BRANCH) && defined(USE_AMD_K) +#define MACHINE_CPUS_PENTIUM_S5 {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}} +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) +#define MACHINE_CPUS_PENTIUM_S7 {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}} +#else +#define MACHINE_CPUS_PENTIUM_S7 {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"", NULL}, {"", NULL}} +#endif +#else +#define MACHINE_CPUS_PENTIUM_S5 {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}} +#if defined(DEV_BRANCH) && defined(USE_CYRIX_6X86) +#define MACHINE_CPUS_PENTIUM_S7 {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}} +#else +#define MACHINE_CPUS_PENTIUM_S7 {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}} +#endif +#endif + const machine_t machines[] = { - { "[8088] AMI XT clone", ROM_AMIXT, "amixt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Compaq Portable", ROM_PORTABLE, "portable", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL }, - { "[8088] DTK XT clone", ROM_DTKXT, "dtk", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] IBM PC (1981)", ROM_IBMPC, "ibmpc", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 16, 64, 16, 0, machine_pc_init, NULL }, - { "[8088] IBM PC (1982)", ROM_IBMPC82, "ibmpc82", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 256, 64, 0, machine_pc82_init, NULL }, - { "[8088] IBM PCjr", ROM_IBMPCJR, "ibmpcjr", {{"Intel", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device }, - { "[8088] IBM XT (1982)", ROM_IBMXT, "ibmxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 256, 64, 0, machine_xt_init, NULL }, - { "[8088] IBM XT (1986)", ROM_IBMXT86, "ibmxt86", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 640, 64, 0, machine_xt86_init, NULL }, - { "[8088] Generic XT clone", ROM_GENXT, "genxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Juko XT clone", ROM_JUKOPC, "jukopc", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Phoenix XT clone", ROM_PXXT, "pxxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, - { "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL }, - { "[8088] Tandy 1000", ROM_TANDY, "tandy", {{"Intel", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 128, 640, 128, 0, machine_tandy1k_init, tandy1k_get_device }, - { "[8088] Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", {{"Intel", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 256, 640, 128, 0, machine_tandy1k_init, tandy1k_hx_get_device }, - { "[8088] Toshiba T1000", ROM_T1000, "t1000", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, t1000_get_device }, + { "[8088] AMI XT clone", "amixt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_amixt_init, NULL }, + { "[8088] Compaq Portable", "portable", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL }, + { "[8088] DTK XT clone", "dtk", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_dtk_init, NULL }, + { "[8088] IBM PC (1981)", "ibmpc", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 16, 64, 16, 0, machine_pc_init, NULL }, + { "[8088] IBM PC (1982)", "ibmpc82", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 256, 256, 0, machine_pc82_init, NULL }, + { "[8088] IBM PCjr", "ibmpcjr", {{"Intel", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device }, + { "[8088] IBM XT (1982)", "ibmxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 256, 64, 0, machine_xt_init, NULL }, + { "[8088] IBM XT (1986)", "ibmxt86", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 64, 0, machine_xt86_init, NULL }, + { "[8088] Generic XT clone", "genxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_genxt_init, NULL }, + { "[8088] Juko XT clone", "jukopc", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_jukopc_init, NULL }, + { "[8088] OpenXT", "open_xt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_open_xt_init, NULL }, + { "[8088] Phoenix XT clone", "pxxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_pxxt_init, NULL }, + { "[8088] Schneider EuroPC", "europc", {{"Siemens", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_HDC | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL }, + { "[8088] Tandy 1000", "tandy", {{"Intel", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 128, 640, 128, 0, machine_tandy_init, tandy1k_get_device }, + { "[8088] Tandy 1000 HX", "tandy1000hx", {{"Intel", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 256, 640, 128, 0, machine_tandy1000hx_init, tandy1k_hx_get_device }, + { "[8088] Toshiba T1000", "t1000", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, t1000_get_device }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) - { "[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 640, 256, 0, machine_xt_laserxt_init, NULL }, + { "[8088] VTech Laser Turbo XT", "ltxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 256, 0, machine_xt_laserxt_init, NULL }, #endif - { "[8088] Xi8088", ROM_XI8088, "xi8088", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, NULL }, - { "[8088] Zenith Data SupersPort", ROM_ZD_SUPERS, "zdsupers", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 128, 640, 128, 0, machine_xt_zenith_init, NULL }, + { "[8088] Xi8088", "xi8088", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, xi8088_get_device }, + { "[8088] Zenith Data SupersPort", "zdsupers", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 128, 640, 128, 0, machine_xt_zenith_init, NULL }, - { "[8086] Amstrad PC1512", ROM_PC1512, "pc1512", {{"Intel", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL }, - { "[8086] Amstrad PC1640", ROM_PC1640, "pc1640", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, - { "[8086] Amstrad PC2086", ROM_PC2086, "pc2086", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, - { "[8086] Amstrad PC3086", ROM_PC3086, "pc3086", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, - { "[8086] Amstrad PC20(0)", ROM_PC200, "pc200", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL }, - { "[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL }, - { "[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 512, 768, 128, 0, machine_tandy1k_init, NULL }, - { "[8086] Toshiba T1200", ROM_T1200, "t1200", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, t1200_get_device }, + { "[8086] Amstrad PC1512", "pc1512", {{"Intel", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_pc1512_init, pc1512_get_device }, + { "[8086] Amstrad PC1640", "pc1640", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc1640_init, pc1640_get_device }, + { "[8086] Amstrad PC2086", "pc2086", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc2086_init, pc2086_get_device }, + { "[8086] Amstrad PC3086", "pc3086", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc3086_init, pc3086_get_device }, + { "[8086] Amstrad PC20(0)", "pc200", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_pc200_init, pc200_get_device }, + { "[8086] Amstrad PPC512/640", "ppc512", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_ppc512_init, ppc512_get_device }, + { "[8086] Olivetti M24", "olivetti_m24", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL }, + { "[8086] Tandy 1000 SL/2", "tandy1000sl2", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 512, 768, 128, 0, machine_tandy1000sl2_init, NULL }, + { "[8086] Toshiba T1200", "t1200", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, t1200_get_device }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) - { "[8086] VTech Laser XT3", ROM_LXT3, "lxt3", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 640, 256, 0, machine_xt_lxt3_init, NULL }, + { "[8086] VTech Laser XT3", "lxt3", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 256, 0, machine_xt_lxt3_init, NULL }, #endif - { "[286 ISA] AMI 286 clone", ROM_AMI286, "ami286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,8192, 128, 127, machine_at_neat_ami_init, NULL }, - { "[286 ISA] Award 286 clone", ROM_AWARD286, "award286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL }, - { "[286 ISA] Commodore PC 30 III", ROM_CMDPC30, "cmdpc30", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_cmdpc_init, NULL }, - { "[286 ISA] Compaq Portable II", ROM_PORTABLEII, "portableii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_compaq_init, NULL }, + { "[286 ISA] AMI 286 clone", "ami286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_ami_init, NULL }, + { "[286 ISA] Award 286 clone", "award286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_award286_init, NULL }, + { "[286 ISA] Commodore PC 30 III", "cmdpc30", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_cmdpc_init, NULL }, + { "[286 ISA] Compaq Portable II", "portableii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_portableii_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - { "[286 ISA] Compaq Portable III", ROM_PORTABLEIII, "portableiii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO, 640,16384, 128, 127, machine_at_compaq_init, NULL }, + { "[286 ISA] Compaq Portable III", "portableiii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 640,16384, 128, 127, machine_at_portableiii_init, NULL }, #endif - { "[286 ISA] GW-286CT GEAR", ROM_GW286CT, "gw286ct", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL }, - { "[286 ISA] Hyundai Super-286TR", ROM_SUPER286TR, "super286tr", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL }, - { "[286 ISA] IBM AT", ROM_IBMAT, "ibmat", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibm_init, NULL }, - { "[286 ISA] IBM PS/1 model 2011", ROM_IBMPS1_2011, "ibmps1es", {{"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_PS2 | MACHINE_HDC_PS2, 512,16384, 512, 63, machine_ps1_m2011_init, NULL }, - { "[286 ISA] IBM PS/2 model 30-286", ROM_IBMPS2_M30_286, "ibmps2_m30_286", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 16, 1, 127, machine_ps2_m30_286_init, NULL }, - { "[286 ISA] IBM XT Model 286", ROM_IBMXT286, "ibmxt286", {{"", cpus_ibmxt286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 127, machine_at_ibm_init, NULL }, - { "[286 ISA] Samsung SPC-4200P", ROM_SPC4200P, "spc4200p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 512, 2048, 128, 127, machine_at_scat_init, NULL }, - { "[286 ISA] Samsung SPC-4216P", ROM_SPC4216P, "spc4216p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 1, 5, 1, 127, machine_at_scat_init, NULL }, - { "[286 ISA] Toshiba T3100e", ROM_T3100E, "t3100e", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, - { "[286 ISA] Trigem 286M", ROM_TG286M, "tg286m", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_tg286m_init, NULL }, + { "[286 ISA] GW-286CT GEAR", "gw286ct", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_gw286ct_init, NULL }, + { "[286 ISA] Hyundai Super-286TR", "super286tr", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_super286tr_init, NULL }, + { "[286 ISA] IBM AT", "ibmat", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibm_init, NULL }, + { "[286 ISA] IBM PS/1 model 2011", "ibmps1es", {{"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC | MACHINE_PS2, 512,16384, 512, 63, machine_ps1_m2011_init, NULL }, + { "[286 ISA] IBM PS/2 model 30-286", "ibmps2_m30_286", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC | MACHINE_PS2, 1, 16, 1, 127, machine_ps2_m30_286_init, NULL }, + { "[286 ISA] IBM XT Model 286", "ibmxt286", {{"", cpus_ibmxt286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 127, machine_at_ibmxt286_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_OPEN_AT) + { "[286 ISA] OpenAT", "open_at", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_open_at_init, NULL }, +#endif + { "[286 ISA] Samsung SPC-4200P", "spc4200p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 512, 2048, 128, 127, machine_at_spc4200p_init, NULL }, + { "[286 ISA] Samsung SPC-4216P", "spc4216p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 1, 5, 1, 127, machine_at_spc4216p_init, NULL }, + { "[286 ISA] Toshiba T3100e", "t3100e", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, + { "[286 ISA] Trigem 286M", "tg286m", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_tg286m_init, NULL }, - { "[286 MCA] IBM PS/2 model 50", ROM_IBMPS2_M50, "ibmps2_m50", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 1, 10, 1, 63, machine_ps2_model_50_init, NULL }, + { "[286 MCA] IBM PS/2 model 50", "ibmps2_m50", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 10, 1, 63, machine_ps2_model_50_init, NULL }, - { "[386SX ISA] AMA-932J", ROM_AMA932J, "ama932j", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 512, 8192, 128, 127, machine_at_ama932j_init, at_ama932j_get_device }, - { "[386DX ISA] AMI 386SX clone", ROM_AMI386SX_OPTI495, "ami386sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 16, 1, 127, machine_at_opti495_ami_init, NULL }, - { "[386SX ISA] AMI Unknown 386SX", ROM_AMI386SX, "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, - { "[386SX ISA] Amstrad MegaPC", ROM_MEGAPC, "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 16, 1, 127, machine_at_wd76c10_init, NULL }, - { "[386SX ISA] Award 386SX clone", ROM_AWARD386SX_OPTI495, "award386sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 16, 1, 127, machine_at_opti495_init, NULL }, - { "[386SX ISA] DTK 386SX clone", ROM_DTK386, "dtk386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_neat_init, NULL }, - { "[386SX ISA] IBM PS/1 model 2121", ROM_IBMPS1_2121, "ibmps1_2121", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, - { "[386SX ISA] IBM PS/1 m.2121+ISA", ROM_IBMPS1_2121_ISA, "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, - { "[386SX ISA] KMX-C-02", ROM_KMXC02, "kmxc02", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 512, 127, machine_at_scatsx_init, NULL }, - { "[386DX ISA] MR 386SX clone", ROM_MR386SX_OPTI495, "mr386sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 16, 1, 127, machine_at_opti495_ami_init, NULL }, + { "[386SX ISA] AMA-932J", "ama932j", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 512, 8192, 128, 127, machine_at_ama932j_init, at_ama932j_get_device }, +#if defined(DEV_BRANCH) && defined(USE_AMI386SX) + { "[386SX ISA] AMI Unknown 386SX", "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, +#endif + { "[386SX ISA] Amstrad MegaPC", "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 32, 1, 127, machine_at_wd76c10_init, NULL }, + { "[386SX ISA] DTK 386SX clone", "dtk386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_neat_init, NULL }, + { "[386SX ISA] IBM PS/1 model 2121", "ibmps1_2121", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, + { "[386SX ISA] IBM PS/1 m.2121+ISA", "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, + { "[386SX ISA] KMX-C-02", "kmxc02", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 512, 127, machine_at_kmxc02_init, NULL }, - { "[386SX MCA] IBM PS/2 model 55SX", ROM_IBMPS2_M55SX, "ibmps2_m55sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 1, 8, 1, 63, machine_ps2_model_55sx_init, NULL }, + { "[386SX MCA] IBM PS/2 model 55SX", "ibmps2_m55sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 8, 1, 63, machine_ps2_model_55sx_init, NULL }, - { "[386DX ISA] AMI 386DX clone", ROM_AMI386DX_OPTI495, "ami386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_init, NULL }, - { "[386DX ISA] Amstrad MegaPC 386DX", ROM_MEGAPCDX, "megapcdx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 32, 1, 127, machine_at_wd76c10_init, NULL }, - { "[386DX ISA] Award 386DX clone", ROM_AWARD386DX_OPTI495, "award386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL }, - { "[386DX ISA] MR 386DX clone", ROM_MR386DX_OPTI495, "mr386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_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] Award 386DX clone", "award386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_MR495) + { "[386DX ISA] MR 386DX clone", "mr386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_mr_init, NULL }, +#endif #if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - { "[386DX ISA] Compaq Portable III (386)", ROM_PORTABLEIII386, "portableiii386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 1, 14, 1, 127, machine_at_compaq_init, NULL }, + { "[386DX ISA] Compaq Portable III (386)", "portableiii386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 1, 14, 1, 127, machine_at_portableiii386_init, NULL }, #endif - { "[386DX MCA] IBM PS/2 model 70 (type 3)", ROM_IBMPS2_M70_TYPE3, "ibmps2_m70_type3", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type3_init, NULL }, - { "[386DX MCA] IBM PS/2 model 80", ROM_IBMPS2_M80, "ibmps2_m80", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 1, 12, 1, 63, machine_ps2_model_80_init, NULL }, + { "[386DX MCA] IBM PS/2 model 70 (type 3)", "ibmps2_m70_type3", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", 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}, {"", NULL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 12, 1, 63, machine_ps2_model_80_init, NULL }, - { "[486 ISA] AMI 486 clone", ROM_AMI486_OPTI495, "ami486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_init, NULL }, - { "[486 ISA] AMI ALi 1429", ROM_AMI486, "ali1429", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ali1429_init, NULL }, - { "[486 ISA] AMI WinBIOS 486", ROM_WIN486, "win486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ali1429_init, NULL }, - { "[486 ISA] Award 486 clone", ROM_AWARD486_OPTI495, "award486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL }, - { "[486 ISA] DTK PKM-0038S E-2", ROM_DTK486, "dtk486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_dtk486_init, NULL }, - { "[486 ISA] IBM PS/1 model 2133", ROM_IBMPS1_2133, "ibmps1_2133", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_NONMI, 1, 64, 1, 127, machine_ps1_m2133_init, NULL }, - { "[486 ISA] MR 486 clone", ROM_MR486_OPTI495, "mr486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_init, NULL }, + { "[486 ISA] AMI 486 clone", "ami486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_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, 64, 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, 128, 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, 64, 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, 128, 1, 127, machine_at_win471_init, NULL }, + { "[486 ISA] Award 486 clone", "award486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_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, 128, 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_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_NONMI, 1, 64, 1, 127, machine_ps1_m2133_init, NULL }, +#endif +#if defined(DEV_BRANCH) && defined(USE_MR495) + { "[486 ISA] MR 486 clone", "mr486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_mr_init, NULL }, +#endif + { "[486 ISA] Packard Bell PB410A", "pb410a", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 64, 1, 127, machine_at_pb410a_init, NULL }, + { "[486 ISA] Phoenix SiS 471", "px471", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_px471_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_PS2M70T4) - { "[486 MCA] IBM PS/2 model 70 (type 4)", ROM_IBMPS2_M70_TYPE4, "ibmps2_m70_type4", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type4_init, NULL }, + { "[486 MCA] IBM PS/2 model 70 (type 4)", "ibmps2_m70_type4", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type4_init, NULL }, #endif - { "[486 PCI] Rise Computer R418", ROM_R418, "r418", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_r418_init, NULL }, + { "[486 PCI] Intel Classic/PCI", "alfredo", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_alfredo_init, NULL }, + { "[486 PCI] Rise Computer R418", "r418", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_r418_init, NULL }, - { "[Socket 4 LX] Intel Premiere/PCI", ROM_REVENGE, "revenge", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_batman_init, NULL }, + { "[Socket 4 LX] Intel Premiere/PCI", "revenge", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_batman_init, NULL }, + { "[Socket 4 LX] Micro Star 586MC1", "586mc1", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_586mc1_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_AMD_K) - { "[Socket 5 NX] Intel Premiere/PCI II", ROM_PLATO, "plato", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, + { "[Socket 5 NX] Intel Premiere/PCI II", "plato", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, + { "[Socket 5 NX] Gigabyte GA-586IP", "430nx", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_430nx_init, NULL }, - { "[Socket 5 FX] ASUS P/I-P54TP4XE", ROM_P54TP4XE, "p54tp4xe", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL }, - { "[Socket 5 FX] Intel Advanced/ZP", ROM_ZAPPA, "zappa", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, - { "[Socket 5 FX] PC Partner MB500N", ROM_MB500N, "mb500n", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL }, - { "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL }, + { "[Socket 5 FX] ASUS P/I-P54TP4XE", "p54tp4xe", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_VECTRA54) + { "[Socket 5 FX] HP Vectra VL 5 Series 4", "vectra54", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_vectra54_init, NULL }, +#endif + { "[Socket 5 FX] Intel Advanced/ZP", "zappa", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, + { "[Socket 5 FX] PC Partner MB500N", "mb500n", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL }, + { "[Socket 5 FX] President Award 430FX PCI","president", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL }, - { "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, + { "[Socket 7 FX] Intel Advanced/ATX", "thor", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_MRTHOR) - { "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, + { "[Socket 7 FX] MR Intel Advanced/ATX", "mrthor", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_mrthor_init, NULL }, #endif - { "[Socket 7 FX] Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, - { "[Socket 7 FX] Packard Bell PB640", ROM_PB640, "pb640", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_pb640_init, NULL }, + { "[Socket 7 FX] Intel Advanced/EV", "endeavor", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, + { "[Socket 7 FX] Packard Bell PB640", "pb640", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_pb640_init, at_pb640_get_device }, - { "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL }, - { "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL }, - { "[Socket 7 HX] AOpen AP53", ROM_AP53, "ap53", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL }, - { "[Socket 7 HX] ASUS P/I-P55T2P4", ROM_P55T2P4, "p55t2p4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_p55t2p4_init, NULL }, - { "[Socket 7 HX] SuperMicro Super P55T2S", ROM_P55T2S, "p55t2s", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL }, - - { "[Socket 7 VX] ASUS P/I-P55TVP4", ROM_P55TVP4, "p55tvp4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL }, - { "[Socket 7 VX] Award 430VX PCI", ROM_430VX, "430vx", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL }, - { "[Socket 7 VX] Epox P55-VA", ROM_P55VA, "p55va", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL }, - { "[Socket 7 VX] Jetway J656VXD", ROM_J656VXD, "j656vxd", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_j656vxd_init, NULL }, -#else - { "[Socket 5 NX] Intel Premiere/PCI II", ROM_PLATO, "plato", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, - - { "[Socket 5 FX] ASUS P/I-P54TP4XE", ROM_P54TP4XE, "p54tp4xe", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL }, - { "[Socket 5 FX] Intel Advanced/ZP", ROM_ZAPPA, "zappa", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, - { "[Socket 5 FX] PC Partner MB500N", ROM_MB500N, "mb500n", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL }, - { "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL }, - - { "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_MRTHOR) - { "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, + { "[Socket 7 HX] Acer M3a", "acerm3a", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL }, + { "[Socket 7 HX] Acer V35n", "acerv35n", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL }, + { "[Socket 7 HX] AOpen AP53", "ap53", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL }, + { "[Socket 7 HX] ASUS P/I-P55T2P4", "p55t2p4", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 256, 8, 127, machine_at_p55t2p4_init, NULL }, + { "[Socket 7 HX] SuperMicro Super P55T2S", "p55t2s", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_TC430HX) + { "[Socket 7 HX] TC430HX", "tc430hx", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_tc430hx_init, NULL }, #endif - { "[Socket 7 FX] Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, - { "[Socket 7 FX] Packard Bell PB640", ROM_PB640, "pb640", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_pb640_init, NULL }, - { "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL }, - { "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL }, - { "[Socket 7 HX] AOpen AP53", ROM_AP53, "ap53", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL }, - { "[Socket 7 HX] ASUS P/I-P55T2P4", ROM_P55T2P4, "p55t2p4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_p55t2p4_init, NULL }, - { "[Socket 7 HX] SuperMicro Super P55T2S", ROM_P55T2S, "p55t2s", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL }, - - { "[Socket 7 VX] ASUS P/I-P55TVP4", ROM_P55TVP4, "p55tvp4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL }, - { "[Socket 7 VX] Award 430VX PCI", ROM_430VX, "430vx", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL }, - { "[Socket 7 VX] Epox P55-VA", ROM_P55VA, "p55va", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL }, - { "[Socket 7 VX] Jetway J656VXD", ROM_J656VXD, "j656vxd", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_j656vxd_init, NULL }, -#endif + { "[Socket 7 VX] ASUS P/I-P55TVP4", "p55tvp4", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL }, + { "[Socket 7 VX] Epox P55-VA", "p55va", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL }, + { "[Socket 7 VX] Jetway J656VXD", "j656vxd", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_j656vxd_init, NULL }, + { "[Socket 7 VX] Shuttle HOT-557", "430vx", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_I686) - { "[Socket 8 FX] Tyan Titan-Pro AT", ROM_440FX, "440fx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_i440fx_init, NULL }, - { "[Socket 8 FX] Tyan Titan-Pro ATX", ROM_S1668, "tpatx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_s1668_init, NULL }, + { "[Socket 8 FX] Tyan Titan-Pro AT", "440fx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_i440fx_init, NULL }, + { "[Socket 8 FX] Tyan Titan-Pro ATX", "tpatx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_s1668_init, NULL }, #endif - { "", -1, "", {{"", 0}, {"", 0}, {"", 0}}, 0,0,0,0, 0 } + { NULL, NULL, {{"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}}, 0, 0, 0, 0, 0, NULL, NULL } }; @@ -194,35 +205,6 @@ machine_count(void) } -int -machine_getromset(void) -{ - return(machines[machine].id); -} - - -int -machine_getromset_ex(int m) -{ - return(machines[m].id); -} - - -int -machine_getmachine(int romset) -{ - int c = 0; - - while (machines[c].id != -1) { - if (machines[c].id == romset) - return(c); - c++; - } - - return(0); -} - - char * machine_getname(void) { @@ -230,11 +212,18 @@ machine_getname(void) } -const device_t * -machine_getdevice(int machine) +char * +machine_getname_ex(int m) { - if (machines[machine].get_device) - return(machines[machine].get_device()); + return((char *)machines[m].name); +} + + +const device_t * +machine_getdevice(int m) +{ + if (machines[m].get_device) + return(machines[m].get_device()); return(NULL); } @@ -266,7 +255,7 @@ machine_get_machine_from_internal_name(char *s) { int c = 0; - while (machines[c].id != -1) { + while (machines[c].init != NULL) { if (!strcmp(machines[c].internal_name, (const char *)s)) return(c); c++; diff --git a/src/machine/machine_table_new.c b/src/machine/machine_table_new.c new file mode 100644 index 000000000..86f508248 --- /dev/null +++ b/src/machine/machine_table_new.c @@ -0,0 +1,252 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Handling of the emulated machines. + * + * NOTES: OpenAT wip for 286-class machine with open BIOS. + * PS2_M80-486 wip, pending receipt of TRM's for machine. + * + * Version: @(#)machine_table.c 1.0.47 2019/02/13 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu_new/cpu.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "machine.h" + + +#define MACHINE_CPUS_PENTIUM_S5 {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}} +#define MACHINE_CPUS_PENTIUM_S7 {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}} + +const machine_t machines[] = { + { "[8088] AMI XT clone", "amixt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_amixt_init, NULL }, + { "[8088] Compaq Portable", "portable", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL }, + { "[8088] DTK XT clone", "dtk", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_dtk_init, NULL }, + { "[8088] IBM PC (1981)", "ibmpc", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 16, 64, 16, 0, machine_pc_init, NULL }, + { "[8088] IBM PC (1982)", "ibmpc82", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 256, 256, 0, machine_pc82_init, NULL }, + { "[8088] IBM PCjr", "ibmpcjr", {{"Intel", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device }, + { "[8088] IBM XT (1982)", "ibmxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 256, 64, 0, machine_xt_init, NULL }, + { "[8088] IBM XT (1986)", "ibmxt86", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 64, 0, machine_xt86_init, NULL }, + { "[8088] Generic XT clone", "genxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_genxt_init, NULL }, + { "[8088] Juko XT clone", "jukopc", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_jukopc_init, NULL }, + { "[8088] OpenXT", "open_xt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_open_xt_init, NULL }, + { "[8088] Phoenix XT clone", "pxxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 64, 640, 64, 0, machine_xt_pxxt_init, NULL }, + { "[8088] Schneider EuroPC", "europc", {{"Siemens", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_HDC | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL }, + { "[8088] Tandy 1000", "tandy", {{"Intel", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 128, 640, 128, 0, machine_tandy_init, tandy1k_get_device }, + { "[8088] Tandy 1000 HX", "tandy1000hx", {{"Intel", cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 256, 640, 128, 0, machine_tandy1000hx_init, tandy1k_hx_get_device }, + { "[8088] Toshiba T1000", "t1000", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, t1000_get_device }, +#if defined(DEV_BRANCH) && defined(USE_LASERXT) + { "[8088] VTech Laser Turbo XT", "ltxt", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 256, 0, machine_xt_laserxt_init, NULL }, +#endif + { "[8088] Xi8088", "xi8088", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, xi8088_get_device }, + { "[8088] Zenith Data SupersPort", "zdsupers", {{"Intel", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 128, 640, 128, 0, machine_xt_zenith_init, NULL }, + + { "[8086] Amstrad PC1512", "pc1512", {{"Intel", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_pc1512_init, pc1512_get_device }, + { "[8086] Amstrad PC1640", "pc1640", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc1640_init, pc1640_get_device }, + { "[8086] Amstrad PC2086", "pc2086", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc2086_init, pc2086_get_device }, + { "[8086] Amstrad PC3086", "pc3086", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 640, 640, 0, 63, machine_pc3086_init, pc3086_get_device }, + { "[8086] Amstrad PC20(0)", "pc200", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_pc200_init, pc200_get_device }, + { "[8086] Amstrad PPC512/640", "ppc512", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE | MACHINE_NONMI, 512, 640, 128, 63, machine_ppc512_init, ppc512_get_device }, + { "[8086] Olivetti M24", "olivetti_m24", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL }, + { "[8086] Tandy 1000 SL/2", "tandy1000sl2", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 512, 768, 128, 0, machine_tandy1000sl2_init, NULL }, + { "[8086] Toshiba T1200", "t1200", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, t1200_get_device }, +#if defined(DEV_BRANCH) && defined(USE_LASERXT) + { "[8086] VTech Laser XT3", "lxt3", {{"Intel", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA, 256, 640, 256, 0, machine_xt_lxt3_init, NULL }, +#endif + + { "[286 ISA] AMI 286 clone", "ami286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512, 8192, 128, 127, machine_at_neat_ami_init, NULL }, + { "[286 ISA] Award 286 clone", "award286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_award286_init, NULL }, + { "[286 ISA] Commodore PC 30 III", "cmdpc30", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_cmdpc_init, NULL }, + { "[286 ISA] Compaq Portable II", "portableii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_portableii_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + { "[286 ISA] Compaq Portable III", "portableiii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 640,16384, 128, 127, machine_at_portableiii_init, NULL }, +#endif + { "[286 ISA] GW-286CT GEAR", "gw286ct", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_gw286ct_init, NULL }, + { "[286 ISA] Hyundai Super-286TR", "super286tr", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_super286tr_init, NULL }, + { "[286 ISA] IBM AT", "ibmat", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibm_init, NULL }, + { "[286 ISA] IBM PS/1 model 2011", "ibmps1es", {{"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC | MACHINE_PS2, 512,16384, 512, 63, machine_ps1_m2011_init, NULL }, + { "[286 ISA] IBM PS/2 model 30-286", "ibmps2_m30_286", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC | MACHINE_PS2, 1, 16, 1, 127, machine_ps2_m30_286_init, NULL }, + { "[286 ISA] IBM XT Model 286", "ibmxt286", {{"", cpus_ibmxt286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 127, machine_at_ibmxt286_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_OPEN_AT) + { "[286 ISA] OpenAT", "open_at", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_open_at_init, NULL }, +#endif + { "[286 ISA] Samsung SPC-4200P", "spc4200p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 512, 2048, 128, 127, machine_at_spc4200p_init, NULL }, + { "[286 ISA] Samsung SPC-4216P", "spc4216p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 1, 5, 1, 127, machine_at_spc4216p_init, NULL }, + { "[286 ISA] Toshiba T3100e", "t3100e", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO | MACHINE_VIDEO_FIXED | MACHINE_HDC, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, + { "[286 ISA] Trigem 286M", "tg286m", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_tg286m_init, NULL }, + + { "[286 MCA] IBM PS/2 model 50", "ibmps2_m50", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 1, 10, 1, 63, machine_ps2_model_50_init, NULL }, + + { "[386SX ISA] AMA-932J", "ama932j", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 512, 8192, 128, 127, machine_at_ama932j_init, at_ama932j_get_device }, +#if defined(DEV_BRANCH) && defined(USE_AMI386SX) + { "[386SX ISA] AMI Unknown 386SX", "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, +#endif + { "[386SX ISA] Amstrad MegaPC", "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 32, 1, 127, machine_at_wd76c10_init, NULL }, + { "[386SX ISA] DTK 386SX clone", "dtk386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_neat_init, NULL }, + { "[386SX ISA] IBM PS/1 model 2121", "ibmps1_2121", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, + { "[386SX ISA] IBM PS/1 m.2121+ISA", "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, + { "[386SX ISA] KMX-C-02", "kmxc02", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT, 512,16384, 512, 127, machine_at_kmxc02_init, NULL }, + + { "[386SX MCA] IBM PS/2 model 55SX", "ibmps2_m55sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", 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] Award 386DX clone", "award386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_MR495) + { "[386DX ISA] MR 386DX clone", "mr386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_mr_init, NULL }, +#endif +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + { "[386DX ISA] Compaq Portable III (386)", "portableiii386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 1, 14, 1, 127, machine_at_portableiii386_init, NULL }, +#endif + + { "[386DX MCA] IBM PS/2 model 70 (type 3)", "ibmps2_m70_type3", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", 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}, {"", NULL}, {"", 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_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", 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, 64, 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, 128, 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, 64, 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, 128, 1, 127, machine_at_win471_init, NULL }, + { "[486 ISA] Award 486 clone", "award486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_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, 128, 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_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_NONMI, 1, 64, 1, 127, machine_ps1_m2133_init, NULL }, +#endif +#if defined(DEV_BRANCH) && defined(USE_MR495) + { "[486 ISA] MR 486 clone", "mr486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 32, 1, 127, machine_at_opti495_mr_init, NULL }, +#endif + { "[486 ISA] Packard Bell PB410A", "pb410a", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 64, 1, 127, machine_at_pb410a_init, NULL }, + { "[486 ISA] Phoenix SiS 471", "px471", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_px471_init, NULL }, + +#if defined(DEV_BRANCH) && defined(USE_PS2M70T4) + { "[486 MCA] IBM PS/2 model 70 (type 4)", "ibmps2_m70_type4", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO, 2, 16, 2, 63, machine_ps2_model_70_type4_init, NULL }, +#endif + + { "[486 PCI] Intel Classic/PCI", "alfredo", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_alfredo_init, NULL }, + { "[486 PCI] Rise Computer R418", "r418", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_r418_init, NULL }, + + { "[Socket 4 LX] Intel Premiere/PCI", "revenge", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_batman_init, NULL }, + { "[Socket 4 LX] Micro Star 586MC1", "586mc1", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_586mc1_init, NULL }, + + { "[Socket 5 NX] Intel Premiere/PCI II", "plato", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, + { "[Socket 5 NX] Gigabyte GA-586IP", "430nx", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_430nx_init, NULL }, + + { "[Socket 5 FX] ASUS P/I-P54TP4XE", "p54tp4xe", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_VECTRA54) + { "[Socket 5 FX] HP Vectra VL 5 Series 4", "vectra54", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_vectra54_init, NULL }, +#endif + { "[Socket 5 FX] Intel Advanced/ZP", "zappa", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, + { "[Socket 5 FX] PC Partner MB500N", "mb500n", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL }, + { "[Socket 5 FX] President Award 430FX PCI","president", MACHINE_CPUS_PENTIUM_S5, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL }, + + { "[Socket 7 FX] Intel Advanced/ATX", "thor", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_MRTHOR) + { "[Socket 7 FX] MR Intel Advanced/ATX", "mrthor", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_mrthor_init, NULL }, +#endif + { "[Socket 7 FX] Intel Advanced/EV", "endeavor", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, + { "[Socket 7 FX] Packard Bell PB640", "pb640", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_pb640_init, at_pb640_get_device }, + + { "[Socket 7 HX] Acer M3a", "acerm3a", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL }, + { "[Socket 7 HX] Acer V35n", "acerv35n", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL }, + { "[Socket 7 HX] AOpen AP53", "ap53", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL }, + { "[Socket 7 HX] ASUS P/I-P55T2P4", "p55t2p4", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 256, 8, 127, machine_at_p55t2p4_init, NULL }, + { "[Socket 7 HX] SuperMicro Super P55T2S", "p55t2s", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_TC430HX) + { "[Socket 7 HX] TC430HX", "tc430hx", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_tc430hx_init, NULL }, +#endif + + { "[Socket 7 VX] ASUS P/I-P55TVP4", "p55tvp4", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL }, + { "[Socket 7 VX] Epox P55-VA", "p55va", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL }, + { "[Socket 7 VX] Jetway J656VXD", "j656vxd", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_j656vxd_init, NULL }, + { "[Socket 7 VX] Shuttle HOT-557", "430vx", MACHINE_CPUS_PENTIUM_S7, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL }, + +#if defined(DEV_BRANCH) && defined(USE_I686) + { "[Socket 8 FX] Tyan Titan-Pro AT", "440fx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_i440fx_init, NULL }, + { "[Socket 8 FX] Tyan Titan-Pro ATX", "tpatx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_s1668_init, NULL }, +#endif + { NULL, NULL, {{"", 0}, {"", 0}, {"", 0}, {"", 0}, {"", 0}}, 0, 0, 0, 0, 0, NULL, NULL } +}; + + +int +machine_count(void) +{ + return((sizeof(machines) / sizeof(machine)) - 1); +} + + +char * +machine_getname(void) +{ + return((char *)machines[machine].name); +} + + +char * +machine_getname_ex(int m) +{ + return((char *)machines[m].name); +} + + +const device_t * +machine_getdevice(int m) +{ + if (machines[m].get_device) + return(machines[m].get_device()); + + return(NULL); +} + + +char * +machine_get_internal_name(void) +{ + return((char *)machines[machine].internal_name); +} + + +char * +machine_get_internal_name_ex(int m) +{ + return((char *)machines[m].internal_name); +} + + +int +machine_get_nvrmask(int m) +{ + return(machines[m].nvrmask); +} + + +int +machine_get_machine_from_internal_name(char *s) +{ + int c = 0; + + while (machines[c].init != NULL) { + if (!strcmp(machines[c].internal_name, (const char *)s)) + return(c); + c++; + } + + return(0); +} diff --git a/src/mca.c b/src/mca.c index 3d0677b26..73e227b8e 100644 --- a/src/mca.c +++ b/src/mca.c @@ -8,6 +8,7 @@ void (*mca_card_write[8])(int addr, uint8_t val, void *priv); uint8_t (*mca_card_read[8])(int addr, void *priv); +uint8_t (*mca_card_feedb[8])(void *priv); void *mca_priv[8]; static int mca_index; @@ -51,7 +52,15 @@ void mca_write(uint16_t port, uint8_t val) mca_card_write[mca_index](port, val, mca_priv[mca_index]); } -void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void *priv) +uint8_t mca_feedb(void) +{ + if (mca_card_feedb[mca_index]) + return !!(mca_card_feedb[mca_index](mca_priv[mca_index])); + else + return 0; +} + +void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), uint8_t (*feedb)(void *priv), void *priv) { int c; @@ -61,6 +70,7 @@ void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint { mca_card_read[c] = read; mca_card_write[c] = write; + mca_card_feedb[c] = feedb; mca_priv[c] = priv; return; } diff --git a/src/mca.h b/src/mca.h index dd88c1f98..d38156352 100644 --- a/src/mca.h +++ b/src/mca.h @@ -1,7 +1,8 @@ extern void mca_init(int nr_cards); -extern void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void *priv); +extern void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), uint8_t (*feedb)(void *priv), void *priv); extern void mca_set_index(int index); extern uint8_t mca_read(uint16_t port); extern void mca_write(uint16_t port, uint8_t val); +extern uint8_t mca_feedb(void); extern void ps2_cache_clean(void); \ No newline at end of file diff --git a/src/mem.c b/src/mem.c index 03bb9e13b..1674acc07 100644 --- a/src/mem.c +++ b/src/mem.c @@ -1,10 +1,10 @@ /* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the VARCem Project. + * This file is part of the 86Box distribution. * * Memory handling and MMU. * @@ -12,33 +12,15 @@ * the DYNAMIC_TABLES=1 enables this. Will eventually go * away, either way... * - * Version: @(#)mem.c 1.0.19 2018/11/18 + * Version: @(#)mem.c 1.0.20 2019/03/24 * - * Authors: Fred N. van Kempen, + * Authors: Sarah Walker, * Miran Grca, - * Sarah Walker, + * Fred N. van Kempen, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -80,9 +62,8 @@ mem_mapping_t base_mapping, ram_high_mapping, /* 1024K+ mapping */ ram_remapped_mapping, ram_split_mapping, - bios_mapping[8], - bios_high_mapping[8], - romext_mapping; + bios_mapping, + bios_high_mapping; page_t *pages, /* RAM page table */ **page_lookup; /* pagetable lookup */ @@ -92,8 +73,7 @@ uint8_t *ram; /* the virtual RAM */ uint32_t rammask; uint8_t *rom; /* the virtual ROM */ -uint8_t romext[32768]; -uint32_t biosmask; +uint32_t biosmask, biosaddr; uint32_t pccache; uint8_t *pccache2; @@ -113,11 +93,8 @@ int shadowbios = 0, shadowbios_write; int readlnum = 0, writelnum = 0; -int pctrans = 0; int cachesize = 256; -uint32_t ram_mapped_addr[64]; - uint32_t get_phys_virt, get_phys_phys; @@ -130,27 +107,21 @@ int mmu_perm = 4; /* FIXME: re-do this with a 'mem_ops' struct. */ -static uint8_t (*_mem_read_b[0x40000])(uint32_t addr, void *priv); -static uint16_t (*_mem_read_w[0x40000])(uint32_t addr, void *priv); -static uint32_t (*_mem_read_l[0x40000])(uint32_t addr, void *priv); -static void (*_mem_write_b[0x40000])(uint32_t addr, uint8_t val, void *priv); -static void (*_mem_write_w[0x40000])(uint32_t addr, uint16_t val, void *priv); -static void (*_mem_write_l[0x40000])(uint32_t addr, uint32_t val, void *priv); -static uint8_t *_mem_exec[0x40000]; -static void *_mem_priv_r[0x40000]; -static void *_mem_priv_w[0x40000]; -static mem_mapping_t *_mem_mapping_r[0x40000]; -static mem_mapping_t *_mem_mapping_w[0x40000]; -static int _mem_state[0x40000]; +static mem_mapping_t *read_mapping[MEM_MAPPINGS_NO]; +static mem_mapping_t *write_mapping[MEM_MAPPINGS_NO]; +static uint8_t *_mem_exec[MEM_MAPPINGS_NO]; +static int _mem_state[MEM_MAPPINGS_NO]; #if FIXME -static uint8_t ff_array[0x1000]; +#if (MEM_GRANULARITY_BITS >= 12) +static uint8_t ff_array[MEM_GRANULARITY_SIZE]; +#else +static uint8_t ff_array[4096]; /* Must be at least one page. */ +#endif #else static uint8_t ff_pccache[4] = { 0xff, 0xff, 0xff, 0xff }; #endif -static int port_92_reg = 0; - #ifdef ENABLE_MEM_LOG int mem_do_log = ENABLE_MEM_LOG; @@ -172,6 +143,15 @@ mem_log(const char *fmt, ...) #endif +int +mem_addr_is_ram(uint32_t addr) +{ + mem_mapping_t *mapping = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + return (mapping == &ram_low_mapping) || (mapping == &ram_high_mapping) || (mapping == &ram_mid_mapping) || (mapping == &ram_remapped_mapping); +} + + void resetreadlookup(void) { @@ -297,7 +277,7 @@ mem_flush_write_page(uint32_t addr, uint32_t virt) #define mmutranslate_read(addr) mmutranslatereal(addr,0) #define mmutranslate_write(addr) mmutranslatereal(addr,1) -#define rammap(x) ((uint32_t *)(_mem_exec[(x) >> 14]))[((x) >> 2) & 0xfff] +#define rammap(x) ((uint32_t *)(_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 2) & MEM_GRANULARITY_QMASK] uint32_t mmutranslatereal(uint32_t addr, int rw) @@ -437,7 +417,7 @@ addreadlookup(uint32_t virt, uint32_t phys) readlookup[readlnext++] = virt >> 12; readlnext &= (cachesize-1); - cycles -= 9; + sub_cycles(9); } @@ -466,7 +446,7 @@ addwritelookup(uint32_t virt, uint32_t phys) writelookup[writelnext++] = virt >> 12; writelnext &= (cachesize - 1); - cycles -= 9; + sub_cycles(9); } @@ -477,31 +457,22 @@ getpccache(uint32_t a) a2 = a; - if (a2 < 0x100000 && ram_mapped_addr[a2 >> 14]) { - a = (ram_mapped_addr[a2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? a2 : (ram_mapped_addr[a2 >> 14] & ~0x3FFF) + (a2 & 0x3FFF); - return &ram[(uintptr_t)(a & 0xFFFFF000) - (uintptr_t)(a2 & ~0xFFF)]; - } - - a2 = a; - if (cr0 >> 31) { - pctrans=1; a = mmutranslate_read(a); - pctrans = 0; if (a == 0xffffffff) return ram; } a &= rammask; - if (_mem_exec[a >> 14]) { + if (_mem_exec[a >> MEM_GRANULARITY_BITS]) { if (is286) { - if (_mem_mapping_r[a >> 14]->flags & MEM_MAPPING_ROM) + if (read_mapping[a >> MEM_GRANULARITY_BITS] && (read_mapping[a >> MEM_GRANULARITY_BITS]->flags & MEM_MAPPING_ROM)) cpu_prefetch_cycles = cpu_rom_prefetch_cycles; else cpu_prefetch_cycles = cpu_mem_prefetch_cycles; } - return &_mem_exec[a >> 14][(uintptr_t)(a & 0x3000) - (uintptr_t)(a2 & ~0xfff)]; + return &_mem_exec[a >> MEM_GRANULARITY_BITS][(uintptr_t)(a & MEM_GRANULARITY_PAGE) - (uintptr_t)(a2 & ~0xfff)]; } mem_log("Bad getpccache %08X\n", a); @@ -517,13 +488,9 @@ getpccache(uint32_t a) uint8_t readmembl(uint32_t addr) { - mem_logical_addr = addr; + mem_mapping_t *map; - if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if(addr < (uint32_t) (mem_size * 1024)) return ram[addr]; - return 0xff; - } + mem_logical_addr = addr; if (cr0 >> 31) { addr = mmutranslate_read(addr); @@ -531,8 +498,9 @@ readmembl(uint32_t addr) } addr &= rammask; - if (_mem_read_b[addr >> 14]) - return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->read_b) + return map->read_b(addr, map->p); return 0xff; } @@ -541,15 +509,9 @@ readmembl(uint32_t addr) void writemembl(uint32_t addr, uint8_t val) { + mem_mapping_t *map; mem_logical_addr = addr; - if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if (addr < (uint32_t) (mem_size * 1024)) - ram[addr] = val; - return; - } - if (page_lookup[addr>>12]) { page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); @@ -562,11 +524,11 @@ writemembl(uint32_t addr, uint8_t val) } addr &= rammask; - if (_mem_write_b[addr >> 14]) - _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->write_b) + map->write_b(addr, val, map->p); } - uint8_t readmemb386l(uint32_t seg, uint32_t addr) { @@ -576,26 +538,7 @@ readmemb386l(uint32_t seg, uint32_t addr) return -1; } - mem_logical_addr = addr = addr + seg; - if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if (addr < (uint32_t) (mem_size * 1024)) - return ram[addr]; - return 0xff; - } - - if (cr0 >> 31) { - addr = mmutranslate_read(addr); - if (addr == 0xffffffff) - return 0xff; - } - - addr &= rammask; - - if (_mem_read_b[addr >> 14]) - return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); - - return 0xff; + return readmembl(addr + seg); } @@ -607,35 +550,14 @@ writememb386l(uint32_t seg, uint32_t addr, uint8_t val) return; } - mem_logical_addr = addr = addr + seg; - if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if (addr < (uint32_t) (mem_size * 1024)) - ram[addr] = val; - return; - } - - if (page_lookup[addr>>12]) { - page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); - - return; - } - - if (cr0 >> 31) { - addr = mmutranslate_write(addr); - if (addr == 0xffffffff) return; - } - - addr &= rammask; - - if (_mem_write_b[addr >> 14]) - _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); + writemembl(addr + seg, val); } uint16_t readmemwl(uint32_t seg, uint32_t addr) { + mem_mapping_t *map; uint32_t addr2 = mem_logical_addr = seg + addr; if (seg == (uint32_t) -1) { @@ -645,7 +567,7 @@ readmemwl(uint32_t seg, uint32_t addr) if (addr2 & 1) { if (!cpu_cyrix_alignment || (addr2 & 7) == 7) - cycles -= timing_misaligned; + sub_cycles(timing_misaligned); if ((addr2 & 0xFFF) > 0xffe) { if (cr0 >> 31) { if (mmutranslate_read(addr2) == 0xffffffff) return 0xffff; @@ -658,31 +580,26 @@ readmemwl(uint32_t seg, uint32_t addr) return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2); } - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < (uint32_t) (mem_size * 1024)) - return *((uint16_t *)&ram[addr]); - return 0xffff; - } - if (cr0 >> 31) { addr2 = mmutranslate_read(addr2); if (addr2 == 0xffffffff) return 0xFFFF; - } + } - addr2 &= rammask; + addr2 &= rammask; - if (_mem_read_w[addr2 >> 14]) - return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + map = read_mapping[addr2 >> MEM_GRANULARITY_BITS]; - if (_mem_read_b[addr2 >> 14]) { - if (AT) - return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | - ((uint16_t) (_mem_read_b[(addr2 + 1) >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14])) << 8); - else - return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | - ((uint16_t) (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 14](seg + ((addr + 1) & 0xffff), _mem_priv_r[addr2 >> 14])) << 8); + if (map && map->read_w) + return map->read_w(addr2, map->p); + + if (map && map->read_b) { + if (AT) + return map->read_b(addr2, map->p) | + ((uint16_t) (map->read_b(addr2 + 1, map->p)) << 8); + else + return map->read_b(addr2, map->p) | + ((uint16_t) (map->read_b(seg + ((addr + 1) & 0xffff), map->p)) << 8); } return 0xffff; @@ -692,6 +609,7 @@ readmemwl(uint32_t seg, uint32_t addr) void writememwl(uint32_t seg, uint32_t addr, uint16_t val) { + mem_mapping_t *map; uint32_t addr2 = mem_logical_addr = seg + addr; if (seg == (uint32_t) -1) { @@ -699,16 +617,9 @@ writememwl(uint32_t seg, uint32_t addr, uint16_t val) return; } - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - *((uint16_t *)&ram[addr]) = val; - return; - } - if (addr2 & 1) { if (!cpu_cyrix_alignment || (addr2 & 7) == 7) - cycles -= timing_misaligned; + sub_cycles(timing_misaligned); if ((addr2 & 0xFFF) > 0xffe) { if (cr0 >> 31) { if (mmutranslate_write(addr2) == 0xffffffff) return; @@ -740,19 +651,16 @@ writememwl(uint32_t seg, uint32_t addr, uint16_t val) addr2 &= rammask; -#if 0 - if (addr2 >= 0xa0000 && addr2 < 0xc0000) - mem_log("writememwl %08X %02X\n", addr2, val); -#endif + map = write_mapping[addr2 >> MEM_GRANULARITY_BITS]; - if (_mem_write_w[addr2 >> 14]) { - _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + if (map && map->write_w) { + map->write_w(addr2, val, map->p); return; } - if (_mem_write_b[addr2 >> 14]) { - _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_b[(addr2 + 1) >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + if (map && map->write_b) { + map->write_b(addr2, val, map->p); + map->write_b(addr2 + 1, val >> 8, map->p); return; } } @@ -761,6 +669,7 @@ writememwl(uint32_t seg, uint32_t addr, uint16_t val) uint32_t readmemll(uint32_t seg, uint32_t addr) { + mem_mapping_t *map; uint32_t addr2 = mem_logical_addr = seg + addr; if (seg == (uint32_t) -1) { @@ -768,16 +677,9 @@ readmemll(uint32_t seg, uint32_t addr) return -1; } - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - return *((uint32_t *)&ram[addr]); - return 0xffffffff; - } - if (addr2 & 3) { if (!cpu_cyrix_alignment || (addr2 & 7) > 4) - cycles -= timing_misaligned; + sub_cycles(timing_misaligned); if ((addr2 & 0xfff) > 0xffc) { if (cr0 >> 31) { if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; @@ -796,18 +698,20 @@ readmemll(uint32_t seg, uint32_t addr) addr2 &= rammask; - if (_mem_read_l[addr2 >> 14]) - return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + map = read_mapping[addr2 >> MEM_GRANULARITY_BITS]; - if (_mem_read_w[addr2 >> 14]) - return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | - ((uint32_t) (_mem_read_w[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14])) << 16); + if (map && map->read_l) + return map->read_l(addr2, map->p); - if (_mem_read_b[addr2 >> 14]) - return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | - ((uint32_t) (_mem_read_b[addr2 >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14])) << 8) | - ((uint32_t) (_mem_read_b[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14])) << 16) | - ((uint32_t) (_mem_read_b[addr2 >> 14](addr2 + 3, _mem_priv_r[addr2 >> 14])) << 24); + if (map && map->read_w) + return map->read_w(addr2, map->p) | + ((uint32_t) (map->read_w(addr2 + 2, map->p)) << 16); + + if (map && map->read_b) + return map->read_b(addr2, map->p) | + ((uint32_t) (map->read_b(addr2 + 1, map->p)) << 8) | + ((uint32_t) (map->read_b(addr2 + 2, map->p)) << 16) | + ((uint32_t) (map->read_b(addr2 + 3, map->p)) << 24); return 0xffffffff; } @@ -816,6 +720,7 @@ readmemll(uint32_t seg, uint32_t addr) void writememll(uint32_t seg, uint32_t addr, uint32_t val) { + mem_mapping_t *map; uint32_t addr2 = mem_logical_addr = seg + addr; if (seg == (uint32_t) -1) { @@ -823,16 +728,9 @@ writememll(uint32_t seg, uint32_t addr, uint32_t val) return; } - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - *((uint32_t *)&ram[addr]) = val; - return; - } - if (addr2 & 3) { if (!cpu_cyrix_alignment || (addr2 & 7) > 4) - cycles -= timing_misaligned; + sub_cycles(timing_misaligned); if ((addr2 & 0xfff) > 0xffc) { if (cr0 >> 31) { if (mmutranslate_write(addr2) == 0xffffffff) return; @@ -859,20 +757,22 @@ writememll(uint32_t seg, uint32_t addr, uint32_t val) addr2 &= rammask; - if (_mem_write_l[addr2 >> 14]) { - _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + map = write_mapping[addr2 >> MEM_GRANULARITY_BITS]; + + if (map && map->write_l) { + map->write_l(addr2, val, map->p); return; } - if (_mem_write_w[addr2 >> 14]) { - _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + if (map && map->write_w) { + map->write_w(addr2, val, map->p); + map->write_w(addr2 + 2, val >> 16, map->p); return; } - if (_mem_write_b[addr2 >> 14]) { - _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); + if (map && map->write_b) { + map->write_b(addr2, val, map->p); + map->write_b(addr2 + 1, val >> 8, map->p); + map->write_b(addr2 + 2, val >> 16, map->p); + map->write_b(addr2 + 3, val >> 24, map->p); return; } } @@ -881,6 +781,7 @@ writememll(uint32_t seg, uint32_t addr, uint32_t val) uint64_t readmemql(uint32_t seg, uint32_t addr) { + mem_mapping_t *map; uint32_t addr2 = mem_logical_addr = seg + addr; if (seg == (uint32_t) -1) { @@ -888,15 +789,8 @@ readmemql(uint32_t seg, uint32_t addr) return -1; } - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - return *((uint64_t *)&ram[addr]); - return -1; - } - if (addr2 & 7) { - cycles -= timing_misaligned; + sub_cycles(timing_misaligned); if ((addr2 & 0xfff) > 0xff8) { if (cr0 >> 31) { if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; @@ -915,9 +809,9 @@ readmemql(uint32_t seg, uint32_t addr) addr2 &= rammask; - if (_mem_read_l[addr2 >> 14]) - return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | - ((uint64_t)_mem_read_l[addr2 >> 14](addr2 + 4, _mem_priv_r[addr2 >> 14]) << 32); + map = read_mapping[addr2 >> MEM_GRANULARITY_BITS]; + if (map && map->read_l) + return map->read_l(addr2, map->p) | ((uint64_t)map->read_l(addr2 + 4, map->p) << 32); return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32); } @@ -926,6 +820,7 @@ readmemql(uint32_t seg, uint32_t addr) void writememql(uint32_t seg, uint32_t addr, uint64_t val) { + mem_mapping_t *map; uint32_t addr2 = mem_logical_addr = seg + addr; if (seg == (uint32_t) -1) { @@ -933,15 +828,8 @@ writememql(uint32_t seg, uint32_t addr, uint64_t val) return; } - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - *((uint64_t *)&ram[addr]) = val; - return; - } - if (addr2 & 7) { - cycles -= timing_misaligned; + sub_cycles(timing_misaligned); if ((addr2 & 0xfff) > 0xff8) { if (cr0 >> 31) { if (mmutranslate_write(addr2) == 0xffffffff) return; @@ -969,39 +857,44 @@ writememql(uint32_t seg, uint32_t addr, uint64_t val) addr2 &= rammask; - if (_mem_write_l[addr2 >> 14]) { - _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_l[addr2 >> 14](addr2+4, val >> 32, _mem_priv_w[addr2 >> 14]); + map = write_mapping[addr2 >> MEM_GRANULARITY_BITS]; + + if (map && map->write_l) { + map->write_l(addr2, val, map->p); + map->write_l(addr2+4, val >> 32, map->p); return; } - if (_mem_write_w[addr2 >> 14]) { - _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); - _mem_write_w[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); - _mem_write_w[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); + if (map && map->write_w) { + map->write_w(addr2, val, map->p); + map->write_w(addr2 + 2, val >> 16, map->p); + map->write_w(addr2 + 4, val >> 32, map->p); + map->write_w(addr2 + 6, val >> 48, map->p); return; } - if (_mem_write_b[addr2 >> 14]) { - _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 5, val >> 40, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 7, val >> 56, _mem_priv_w[addr2 >> 14]); + if (map && map->write_b) { + map->write_b(addr2, val, map->p); + map->write_b(addr2 + 1, val >> 8, map->p); + map->write_b(addr2 + 2, val >> 16, map->p); + map->write_b(addr2 + 3, val >> 24, map->p); + map->write_b(addr2 + 4, val >> 32, map->p); + map->write_b(addr2 + 5, val >> 40, map->p); + map->write_b(addr2 + 6, val >> 48, map->p); + map->write_b(addr2 + 7, val >> 56, map->p); return; } } +#if 0 uint8_t mem_readb_phys(uint32_t addr) { - if (_mem_exec[addr >> 14]) - return _mem_exec[addr >> 14][addr & 0x3fff]; - else if (_mem_read_b[addr >> 14]) - return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + return _mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK]; + else if (map && map->read_b) + return map->read_b(addr, map->p); else return 0xff; } @@ -1010,12 +903,13 @@ mem_readb_phys(uint32_t addr) uint16_t mem_readw_phys(uint32_t addr) { + mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; uint16_t temp; - if (_mem_exec[addr >> 14]) - return ((uint16_t *) _mem_exec[addr >> 14])[(addr >> 1) & 0x1fff]; - else if (_mem_read_w[addr >> 14]) - return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]); + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + return ((uint16_t *) _mem_exec[addr >> MEM_GRANULARITY_BITS])[(addr >> 1) & MEM_GRANULARITY_HMASK]; + else if (map && map->read_w) + return map->read_w(addr, map->p); else { temp = mem_readb_phys(addr + 1) << 8; temp |= mem_readb_phys(addr); @@ -1028,11 +922,53 @@ mem_readw_phys(uint32_t addr) void mem_writeb_phys(uint32_t addr, uint8_t val) { - if (_mem_exec[addr >> 14]) - _mem_exec[addr >> 14][addr & 0x3fff] = val; - else if (_mem_write_b[addr >> 14]) - _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); + mem_mapping_t *map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + if (_mem_exec[addr >> MEM_GRANULARITY_BITS]) + _mem_exec[addr >> MEM_GRANULARITY_BITS][addr & MEM_GRANULARITY_MASK] = val; + else if (map && map->write_b) + map->write_b(addr, val, map->p); } +#else +uint8_t +mem_readb_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + mem_logical_addr = 0xffffffff; + + if (map && map->read_b) + return map->read_b(addr, map->p); + + return 0xff; +} + + +uint16_t +mem_readw_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + mem_logical_addr = 0xffffffff; + + if (map && map->read_w) + return map->read_w(addr, map->p); + + return mem_readb_phys(addr) | (mem_readb_phys(addr + 1) << 8); +} + + +void +mem_writeb_phys(uint32_t addr, uint8_t val) +{ + mem_mapping_t *map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + mem_logical_addr = 0xffffffff; + + if (map && map->write_b) + map->write_b(addr, val, map->p); +} +#endif uint8_t @@ -1201,46 +1137,42 @@ mem_write_remappedl(uint32_t addr, uint32_t val, void *priv) uint8_t mem_read_bios(uint32_t addr, void *priv) { - return rom[addr & biosmask]; + uint8_t ret = 0xff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = rom[addr - biosaddr]; + + return ret; } uint16_t mem_read_biosw(uint32_t addr, void *priv) { - return *(uint16_t *)&rom[addr & biosmask]; + uint16_t ret = 0xffff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = *(uint16_t *)&rom[addr - biosaddr]; + + return ret; } uint32_t mem_read_biosl(uint32_t addr, void *priv) { - return *(uint32_t *)&rom[addr & biosmask]; -} + uint32_t ret = 0xffffffff; + addr &= 0x000fffff; -uint8_t -mem_read_romext(uint32_t addr, void *priv) -{ - return romext[addr & 0x7fff]; -} + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = *(uint32_t *)&rom[addr - biosaddr]; - -uint16_t -mem_read_romextw(uint32_t addr, void *priv) -{ - uint16_t *p = (uint16_t *)&romext[addr & 0x7fff]; - - return *p; -} - - -uint32_t -mem_read_romextl(uint32_t addr, void *priv) -{ - uint32_t *p = (uint32_t *)&romext[addr & 0x7fff]; - - return *p; + return ret; } @@ -1285,6 +1217,9 @@ static __inline int mem_mapping_read_allowed(uint32_t flags, int state) { switch (state & MEM_READ_MASK) { + case MEM_READ_DISABLED: + return 0; + case MEM_READ_ANY: return 1; @@ -1331,17 +1266,10 @@ mem_mapping_recalc(uint64_t base, uint64_t size) if (! size) return; /* Clear out old mappings. */ - for (c = base; c < base + size; c += 0x4000) { - _mem_read_b[c >> 14] = NULL; - _mem_read_w[c >> 14] = NULL; - _mem_read_l[c >> 14] = NULL; - _mem_priv_r[c >> 14] = NULL; - _mem_mapping_r[c >> 14] = NULL; - _mem_write_b[c >> 14] = NULL; - _mem_write_w[c >> 14] = NULL; - _mem_write_l[c >> 14] = NULL; - _mem_priv_w[c >> 14] = NULL; - _mem_mapping_w[c >> 14] = NULL; + for (c = base; c < base + size; c += MEM_GRANULARITY_SIZE) { + read_mapping[c >> MEM_GRANULARITY_BITS] = NULL; + write_mapping[c >> MEM_GRANULARITY_BITS] = NULL; + _mem_exec[c >> MEM_GRANULARITY_BITS] = NULL; } /* Walk mapping list. */ @@ -1353,27 +1281,18 @@ mem_mapping_recalc(uint64_t base, uint64_t size) if (start < map->base) start = map->base; - for (c = start; c < end; c += 0x4000) { + for (c = start; c < end; c += MEM_GRANULARITY_SIZE) { if ((map->read_b || map->read_w || map->read_l) && - mem_mapping_read_allowed(map->flags, _mem_state[c >> 14])) { - _mem_read_b[c >> 14] = map->read_b; - _mem_read_w[c >> 14] = map->read_w; - _mem_read_l[c >> 14] = map->read_l; + mem_mapping_read_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS])) { if (map->exec) - _mem_exec[c >> 14] = map->exec + (c - map->base); + _mem_exec[c >> MEM_GRANULARITY_BITS] = map->exec + (c - map->base); else - _mem_exec[c >> 14] = NULL; - _mem_priv_r[c >> 14] = map->p; - _mem_mapping_r[c >> 14] = map; + _mem_exec[c >> MEM_GRANULARITY_BITS] = NULL; + read_mapping[c >> MEM_GRANULARITY_BITS] = map; } if ((map->write_b || map->write_w || map->write_l) && - mem_mapping_write_allowed(map->flags, _mem_state[c >> 14])) { - _mem_write_b[c >> 14] = map->write_b; - _mem_write_w[c >> 14] = map->write_w; - _mem_write_l[c >> 14] = map->write_l; - _mem_priv_w[c >> 14] = map->p; - _mem_mapping_w[c >> 14] = map; - } + mem_mapping_write_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS])) + write_mapping[c >> MEM_GRANULARITY_BITS] = map; } } map = map->next; @@ -1400,6 +1319,7 @@ mem_mapping_del(mem_mapping_t *map) } } + void mem_mapping_add(mem_mapping_t *map, uint32_t base, @@ -1526,105 +1446,35 @@ mem_set_mem_state(uint32_t base, uint32_t size, int state) { uint32_t c; - for (c = 0; c < size; c += 0x4000) - _mem_state[(c + base) >> 14] = state; + for (c = 0; c < size; c += MEM_GRANULARITY_SIZE) + _mem_state[(c + base) >> MEM_GRANULARITY_BITS] = state; mem_mapping_recalc(base, size); } -void -mem_add_upper_bios(void) -{ - mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom,MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x4000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[2], 0xe8000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x8000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[3], 0xec000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0xc000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); -} - - void mem_add_bios(void) { - if (AT) - mem_add_upper_bios(); + if (biosmask > 0x1ffff) { + /* 256k+ BIOS'es only have low mappings at E0000-FFFFF. */ + mem_mapping_add(&bios_mapping, 0xe0000, 0x20000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + &rom[0x20000], MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + } else { + mem_mapping_add(&bios_mapping, biosaddr, biosmask + 1, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + } - mem_mapping_add(&bios_mapping[4], 0xf0000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x10000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[5], 0xf4000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x14000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[6], 0xf8000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x18000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[7], 0xfc000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x1c000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - - mem_mapping_add(&bios_high_mapping[0], - (AT && cpu_16bitbus) ? 0xfe0000 : 0xfffe0000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom, MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[1], - (AT && cpu_16bitbus) ? 0xfe4000 : 0xfffe4000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x4000 & biosmask), MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[2], - (AT && cpu_16bitbus) ? 0xfe8000 : 0xfffe8000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x8000 & biosmask), MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[3], - (AT && cpu_16bitbus) ? 0xfec000 : 0xfffec000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0xc000 & biosmask), MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[4], - (AT && cpu_16bitbus) ? 0xff0000 : 0xffff0000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x10000 & biosmask), MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[5], - (AT && cpu_16bitbus) ? 0xff4000 : 0xffff4000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x14000 & biosmask), MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[6], - (AT && cpu_16bitbus) ? 0xff8000 : 0xffff8000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x18000 & biosmask), MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[7], - (AT && cpu_16bitbus) ? 0xffc000 : 0xffffc000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x1c000 & biosmask), MEM_MAPPING_ROM, 0); + if (AT) { + mem_mapping_add(&bios_high_mapping, biosaddr | (cpu_16bitbus ? 0x00f00000 : 0xfff00000), biosmask + 1, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + } } @@ -1649,13 +1499,6 @@ mem_reset(void) { uint32_t c, m; - /* Free the ROM memory and reset size mask. */ - if (rom != NULL) { - free(rom); - rom = NULL; - } - biosmask = 0xffff; - m = 1024UL * mem_size; if (ram != NULL) { free(ram); @@ -1733,12 +1576,6 @@ mem_log("MEM: reset: new pages=%08lx, pages_sz=%i\n", pages, pages_sz); pages[c].write_l = mem_write_raml_page; } - memset(_mem_read_b, 0x00, sizeof(_mem_read_b)); - memset(_mem_read_w, 0x00, sizeof(_mem_read_w)); - memset(_mem_read_l, 0x00, sizeof(_mem_read_l)); - memset(_mem_write_b, 0x00, sizeof(_mem_write_b)); - memset(_mem_write_w, 0x00, sizeof(_mem_write_w)); - memset(_mem_write_l, 0x00, sizeof(_mem_write_l)); memset(_mem_exec, 0x00, sizeof(_mem_exec)); memset(&base_mapping, 0x00, sizeof(base_mapping)); @@ -1812,8 +1649,6 @@ mem_init(void) writelookup2 = malloc((1<<20)*sizeof(uintptr_t)); #endif - memset(ram_mapped_addr, 0x00, 64 * sizeof(uint32_t)); - #if FIXME memset(ff_array, 0xff, sizeof(ff_array)); #endif @@ -1899,61 +1734,3 @@ mem_a20_recalc(void) mem_a20_state = state; } - - -uint8_t -port_92_read(uint16_t port, void *priv) -{ - return port_92_reg; -} - - -void -port_92_write(uint16_t port, uint8_t val, void *priv) -{ - if ((mem_a20_alt ^ val) & 2) { - mem_a20_alt = (val & 2); - mem_a20_recalc(); - } - - if ((~port_92_reg & val) & 1) { - softresetx86(); - cpu_set_edx(); - } - - port_92_reg = val; -} - - -void -port_92_clear_reset(void) -{ - port_92_reg &= 2; -} - - -void -port_92_add(void) -{ - io_sethandler(0x0092, 1, - port_92_read,NULL,NULL, port_92_write, NULL,NULL,NULL); -} - - -void -port_92_remove(void) -{ - io_removehandler(0x0092, 1, - port_92_read,NULL,NULL, port_92_write,NULL,NULL, NULL); -} - - -void -port_92_reset(void) -{ - port_92_reg = 0; - mem_a20_alt = 0; - mem_a20_recalc(); - - flushmmucache(); -} diff --git a/src/mem.h b/src/mem.h index e07383c71..8ec7f7458 100644 --- a/src/mem.h +++ b/src/mem.h @@ -8,7 +8,7 @@ * * Definitions for the memory interface. * - * Version: @(#)mem.h 1.0.8 2018/11/18 + * Version: @(#)mem.h 1.0.9 2019/02/11 * * Authors: Fred N. van Kempen, * Sarah Walker, @@ -49,6 +49,7 @@ #define MEM_READ_ANY 0x00 #define MEM_READ_INTERNAL 0x10 #define MEM_READ_EXTERNAL 0x20 +#define MEM_READ_DISABLED 0x30 #define MEM_READ_MASK 0xf0 #define MEM_WRITE_ANY 0x00 @@ -57,6 +58,27 @@ #define MEM_WRITE_DISABLED 0x03 #define MEM_WRITE_MASK 0x0f +/* #define's for memory granularity, currently 16k, but may + change in the future - 4k works, less does not because of + internal 4k pages. */ +#ifdef DEFAULT_GRANULARITY +#define MEM_GRANULARITY_BITS 14 +#define MEM_GRANULARITY_SIZE (1 << MEM_GRANULARITY_BITS) +#define MEM_GRANULARITY_MASK (MEM_GRANULARITY_SIZE - 1) +#define MEM_GRANULARITY_HMASK ((1 << (MEM_GRANULARITY_BITS - 1)) - 1) +#define MEM_GRANULARITY_QMASK ((1 << (MEM_GRANULARITY_BITS - 2)) - 1) +#define MEM_MAPPINGS_NO ((0x100000 >> MEM_GRANULARITY_BITS) << 12) +#define MEM_GRANULARITY_PAGE (MEM_GRANULARITY_MASK & ~0xfff) +#else +#define MEM_GRANULARITY_BITS 12 +#define MEM_GRANULARITY_SIZE (1 << MEM_GRANULARITY_BITS) +#define MEM_GRANULARITY_MASK (MEM_GRANULARITY_SIZE - 1) +#define MEM_GRANULARITY_HMASK ((1 << (MEM_GRANULARITY_BITS - 1)) - 1) +#define MEM_GRANULARITY_QMASK ((1 << (MEM_GRANULARITY_BITS - 2)) - 1) +#define MEM_MAPPINGS_NO ((0x100000 >> MEM_GRANULARITY_BITS) << 12) +#define MEM_GRANULARITY_PAGE (MEM_GRANULARITY_MASK & ~0xfff) +#endif + typedef struct _mem_mapping_ { struct _mem_mapping_ *prev, *next; @@ -82,6 +104,45 @@ typedef struct _mem_mapping_ { void *dev; /* backpointer to memory device */ } mem_mapping_t; +#ifdef USE_NEW_DYNAREC +extern uint64_t *byte_dirty_mask; +extern uint64_t *byte_code_present_mask; + +#define PAGE_BYTE_MASK_SHIFT 6 +#define PAGE_BYTE_MASK_OFFSET_MASK 63 +#define PAGE_BYTE_MASK_MASK 63 + +#define EVICT_NOT_IN_LIST ((uint32_t)-1) +typedef struct page_t +{ + void (*write_b)(uint32_t addr, uint8_t val, struct page_t *p); + void (*write_w)(uint32_t addr, uint16_t val, struct page_t *p); + void (*write_l)(uint32_t addr, uint32_t val, struct page_t *p); + + uint8_t *mem; + + uint16_t block, block_2; + + /*Head of codeblock tree associated with this page*/ + uint16_t head; + + uint64_t code_present_mask, dirty_mask; + + uint32_t evict_prev, evict_next; + + uint64_t *byte_dirty_mask; + uint64_t *byte_code_present_mask; +} page_t; + +extern uint32_t purgable_page_list_head; +static inline int +page_in_evict_list(page_t *p) +{ + return (p->evict_prev != EVICT_NOT_IN_LIST); +} +void page_remove_from_evict_list(page_t *p); +void page_add_to_evict_list(page_t *p); +#else typedef struct _page_ { void (*write_b)(uint32_t addr, uint8_t val, struct _page_ *p); void (*write_w)(uint32_t addr, uint16_t val, struct _page_ *p); @@ -97,14 +158,14 @@ typedef struct _page_ { /*Head of codeblock tree associated with this page*/ struct codeblock_t *head; } page_t; +#endif extern uint8_t *ram; extern uint32_t rammask; extern uint8_t *rom; -extern uint8_t romext[32768]; -extern uint32_t biosmask; +extern uint32_t biosmask, biosaddr; extern int readlookup[256], readlookupp[256]; @@ -123,9 +184,8 @@ mem_mapping_t base_mapping, #endif ram_remapped_mapping, ram_high_mapping, - bios_mapping[8], - bios_high_mapping[8], - romext_mapping; + bios_mapping, + bios_high_mapping; extern uint32_t mem_logical_addr; @@ -148,11 +208,11 @@ extern int mem_a20_state, mem_a20_key; +#ifndef USE_NEW_DYNAREC #define readmemb(a) ((readlookup2[(a)>>12]==-1)?readmembl(a):*(uint8_t *)(readlookup2[(a) >> 12] + (a))) #define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl(s,a):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) #define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) - extern uint8_t readmembl(uint32_t addr); extern void writemembl(uint32_t addr, uint8_t val); extern uint8_t readmemb386l(uint32_t seg, uint32_t addr); @@ -163,13 +223,22 @@ extern uint32_t readmemll(uint32_t seg, uint32_t addr); extern void writememll(uint32_t seg, uint32_t addr, uint32_t val); extern uint64_t readmemql(uint32_t seg, uint32_t addr); extern void writememql(uint32_t seg, uint32_t addr, uint64_t val); +#else +uint8_t readmembl(uint32_t addr); +void writemembl(uint32_t addr, uint8_t val); +uint16_t readmemwl(uint32_t addr); +void writememwl(uint32_t addr, uint16_t val); +uint32_t readmemll(uint32_t addr); +void writememll(uint32_t addr, uint32_t val); +uint64_t readmemql(uint32_t addr); +void writememql(uint32_t addr, uint64_t val); +#endif extern uint8_t *getpccache(uint32_t a); extern uint32_t mmutranslatereal(uint32_t addr, int rw); extern void addreadlookup(uint32_t virt, uint32_t phys); extern void addwritelookup(uint32_t virt, uint32_t phys); - extern void mem_mapping_del(mem_mapping_t *); extern void mem_mapping_add(mem_mapping_t *, @@ -206,10 +275,8 @@ extern void mem_mapping_enable(mem_mapping_t *); extern void mem_set_mem_state(uint32_t base, uint32_t size, int state); extern uint8_t mem_readb_phys(uint32_t addr); -extern uint8_t mem_readb_phys_dma(uint32_t addr); extern uint16_t mem_readw_phys(uint32_t addr); extern void mem_writeb_phys(uint32_t addr, uint8_t val); -extern void mem_writeb_phys_dma(uint32_t addr, uint8_t val); extern uint8_t mem_read_ram(uint32_t addr, void *priv); extern uint16_t mem_read_ramw(uint32_t addr, void *priv); @@ -222,14 +289,12 @@ extern uint8_t mem_read_bios(uint32_t addr, void *priv); extern uint16_t mem_read_biosw(uint32_t addr, void *priv); extern uint32_t mem_read_biosl(uint32_t addr, void *priv); -extern uint8_t mem_read_romext(uint32_t addr, void *priv); -extern uint16_t mem_read_romextw(uint32_t addr, void *priv); -extern uint32_t mem_read_romextl(uint32_t addr, void *priv); - extern void mem_write_null(uint32_t addr, uint8_t val, void *p); extern void mem_write_nullw(uint32_t addr, uint16_t val, void *p); extern void mem_write_nulll(uint32_t addr, uint32_t val, void *p); +extern int mem_addr_is_ram(uint32_t addr); + extern uint32_t mmutranslate_noabrt(uint32_t addr, int rw); extern void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr); @@ -255,44 +320,47 @@ extern void mem_init(void); extern void mem_reset(void); extern void mem_remap_top(int kb); -extern uint8_t port_92_read(uint16_t port, void *priv); -extern void port_92_write(uint16_t port, uint8_t val, void *priv); -extern void port_92_clear_reset(void); -extern void port_92_add(void); -extern void port_92_remove(void); -extern void port_92_reset(void); - #ifdef EMU_CPU_H static __inline uint32_t get_phys(uint32_t addr) { - if (! ((addr ^ get_phys_virt) & ~0xfff)) + if (!((addr ^ get_phys_virt) & ~0xfff)) return get_phys_phys | (addr & 0xfff); get_phys_virt = addr; - - if (! (cr0 >> 31)) { + + if (!(cr0 >> 31)) { get_phys_phys = (addr & rammask) & ~0xfff; - return addr & rammask; } - get_phys_phys = (mmutranslatereal(addr, 0) & rammask) & ~0xfff; + if (((int) (readlookup2[addr >> 12])) != -1) + get_phys_phys = ((uintptr_t)readlookup2[addr >> 12] + (addr & ~0xfff)) - (uintptr_t)ram; + else { + get_phys_phys = (mmutranslatereal(addr, 0) & rammask) & ~0xfff; + if (!cpu_state.abrt && mem_addr_is_ram(get_phys_phys)) + addreadlookup(get_phys_virt, get_phys_phys); + } -#if 1 return get_phys_phys | (addr & 0xfff); -#else - return mmutranslatereal(addr, 0) & rammask; -#endif } static __inline uint32_t get_phys_noabrt(uint32_t addr) { - if (! (cr0 >> 31)) + uint32_t phys_addr; + + if (!(cr0 >> 31)) return addr & rammask; - return mmutranslate_noabrt(addr, 0) & rammask; + if (((int) (readlookup2[addr >> 12])) != -1) + return ((uintptr_t)readlookup2[addr >> 12] + addr) - (uintptr_t)ram; + + phys_addr = mmutranslate_noabrt(addr, 0) & rammask; + if (phys_addr != 0xffffffff && mem_addr_is_ram(phys_addr)) + addreadlookup(addr, phys_addr); + + return phys_addr; } #endif diff --git a/src/mem_new.c b/src/mem_new.c new file mode 100644 index 000000000..941c2f676 --- /dev/null +++ b/src/mem_new.c @@ -0,0 +1,1712 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Memory handling and MMU. + * + * NOTE: Experimenting with dynamically allocated lookup tables; + * the DYNAMIC_TABLES=1 enables this. Will eventually go + * away, either way... + * + * Version: @(#)mem.c 1.0.20 2019/03/24 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu_new/cpu.h" +#include "cpu_new/x86_ops.h" +#include "cpu_new/x86.h" +#include "machine/machine.h" +#include "machine/m_xt_xi8088.h" +#include "config.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#ifdef USE_DYNAREC +# include "cpu_new/codegen.h" +#else +# define PAGE_MASK_INDEX_MASK 3 +# define PAGE_MASK_INDEX_SHIFT 10 +# define PAGE_MASK_MASK 63 +# define PAGE_MASK_SHIFT 4 +#endif + + +#define FIXME 0 +#define DYNAMIC_TABLES 0 /* experimental */ + + +mem_mapping_t base_mapping, + ram_low_mapping, /* 0..640K mapping */ +#if 1 + ram_mid_mapping, +#endif + ram_remapped_mapping, /* 640..1024K mapping */ + ram_high_mapping, /* 1024K+ mapping */ + ram_remapped_mapping, + ram_split_mapping, + bios_mapping, + bios_high_mapping; + +page_t *pages, /* RAM page table */ + **page_lookup; /* pagetable lookup */ +uint32_t pages_sz; /* #pages in table */ + +uint8_t *ram; /* the virtual RAM */ +uint32_t rammask; + +uint8_t *rom; /* the virtual ROM */ +uint32_t biosmask, biosaddr; + +uint32_t pccache; +uint8_t *pccache2; + +int readlnext; +int readlookup[256], + readlookupp[256]; +uintptr_t *readlookup2; +int writelnext; +int writelookup[256], + writelookupp[256]; +uintptr_t *writelookup2; + +uint32_t mem_logical_addr; + +int shadowbios = 0, + shadowbios_write; +int readlnum = 0, + writelnum = 0; +int cachesize = 256; + +uint32_t get_phys_virt, + get_phys_phys; + +int mem_a20_key = 0, + mem_a20_alt = 0, + mem_a20_state = 0; + +int mmuflush = 0; +int mmu_perm = 4; + +uint64_t *byte_dirty_mask; +uint64_t *byte_code_present_mask; + +uint32_t purgable_page_list_head = 0; +int purgeable_page_count = 0; + + +/* FIXME: re-do this with a 'mem_ops' struct. */ +static mem_mapping_t *read_mapping[MEM_MAPPINGS_NO]; +static mem_mapping_t *write_mapping[MEM_MAPPINGS_NO]; +static uint8_t *_mem_exec[MEM_MAPPINGS_NO]; +static int _mem_state[MEM_MAPPINGS_NO]; + +#if FIXME +#if (MEM_GRANULARITY_BITS >= 12) +static uint8_t ff_array[MEM_GRANULARITY_SIZE]; +#else +static uint8_t ff_array[4096]; /* Must be at least one page. */ +#endif +#else +static uint8_t ff_pccache[4] = { 0xff, 0xff, 0xff, 0xff }; +#endif + + +#ifdef ENABLE_MEM_LOG +int mem_do_log = ENABLE_MEM_LOG; + + +static void +mem_log(const char *fmt, ...) +{ + va_list ap; + + if (mem_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define mem_log(fmt, ...) +#endif + + +int +mem_addr_is_ram(uint32_t addr) +{ + mem_mapping_t *mapping = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + return (mapping == &ram_low_mapping) || (mapping == &ram_high_mapping) || (mapping == &ram_mid_mapping) || (mapping == &ram_remapped_mapping); +} + + +void +resetreadlookup(void) +{ + int c; + + /* This is NULL after app startup, when mem_init() has not yet run. */ +#if DYNAMIC_TABLES +mem_log("MEM: reset_lookup: pages=%08lx, lookup=%08lx, pages_sz=%i\n", pages, page_lookup, pages_sz); +#endif + + /* Initialize the page lookup table. */ +#if DYNAMIC_TABLES + memset(page_lookup, 0x00, pages_sz*sizeof(page_t *)); +#else + memset(page_lookup, 0x00, (1<<20)*sizeof(page_t *)); +#endif + + /* Initialize the tables for lower (<= 1024K) RAM. */ + for (c = 0; c < 256; c++) { + readlookup[c] = 0xffffffff; + writelookup[c] = 0xffffffff; + } + + /* Initialize the tables for high (> 1024K) RAM. */ +#if DYNAMIC_TABLES + memset(readlookup2, 0xff, pages_sz*sizeof(uintptr_t)); + memset(writelookup2, 0xff, pages_sz*sizeof(uintptr_t)); +#else + memset(readlookup2, 0xff, (1<<20)*sizeof(uintptr_t)); + memset(writelookup2, 0xff, (1<<20)*sizeof(uintptr_t)); +#endif + + readlnext = 0; + writelnext = 0; + pccache = 0xffffffff; +} + + +void +flushmmucache(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != (int) 0xffffffff) { + readlookup2[readlookup[c]] = -1; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xffffffff; + } + } + mmuflush++; + + pccache = (uint32_t)0xffffffff; + pccache2 = (uint8_t *)0xffffffff; + +#ifdef USE_DYNAREC + codegen_flush(); +#endif +} + + +void +flushmmucache_nopc(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != (int) 0xffffffff) { + readlookup2[readlookup[c]] = -1; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xffffffff; + } + } +} + + +void +flushmmucache_cr3(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != (int) 0xffffffff) { + readlookup2[readlookup[c]] = -1; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xffffffff; + } + } +} + + +void +mem_flush_write_page(uint32_t addr, uint32_t virt) +{ + page_t *page_target = &pages[addr >> 12]; + int c; + + for (c = 0; c < 256; c++) { + if (writelookup[c] != (int) 0xffffffff) { + uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xfff) - (virt & ~0xfff)]; + + if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) { + writelookup2[writelookup[c]] = -1; + page_lookup[writelookup[c]] = NULL; + writelookup[c] = 0xffffffff; + } + } + } +} + + +#define mmutranslate_read(addr) mmutranslatereal(addr,0) +#define mmutranslate_write(addr) mmutranslatereal(addr,1) +#define rammap(x) ((uint32_t *)(_mem_exec[(x) >> MEM_GRANULARITY_BITS]))[((x) >> 2) & MEM_GRANULARITY_QMASK] + +uint32_t +mmutranslatereal(uint32_t addr, int rw) +{ + uint32_t temp,temp2,temp3; + uint32_t addr2; + + if (cpu_state.abrt) return -1; + + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp = temp2 = rammap(addr2); + if (! (temp&1)) { + cr2 = addr; + temp &= 1; + if (CPL == 3) temp |= 4; + if (rw) temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + return -1; + } + + if ((temp & 0x80) && (cr4 & CR4_PSE)) { + /*4MB page*/ + if ((CPL == 3 && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && ((CPL == 3 && !cpl_override) || cr0 & WP_FLAG))) { + cr2 = addr; + temp &= 1; + if (CPL == 3) + temp |= 4; + if (rw) + temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + + return -1; + } + + mmu_perm = temp & 4; + rammap(addr2) |= 0x20; + + return (temp & ~0x3fffff) + (addr & 0x3fffff); + } + + temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); + temp3 = temp & temp2; + if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && ((CPL == 3 && !cpl_override) || cr0&WP_FLAG))) { + cr2 = addr; + temp &= 1; + if (CPL == 3) temp |= 4; + if (rw) temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + return -1; + } + + mmu_perm = temp & 4; + rammap(addr2) |= 0x20; + rammap((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) |= (rw?0x60:0x20); + + return (temp&~0xfff)+(addr&0xfff); +} + + +uint32_t +mmutranslate_noabrt(uint32_t addr, int rw) +{ + uint32_t temp,temp2,temp3; + uint32_t addr2; + + if (cpu_state.abrt) + return -1; + + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp = temp2 = rammap(addr2); + + if (! (temp & 1)) + return -1; + + if ((temp & 0x80) && (cr4 & CR4_PSE)) { + /*4MB page*/ + if ((CPL == 3 && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (CPL == 3 || cr0 & WP_FLAG))) + return -1; + + return (temp & ~0x3fffff) + (addr & 0x3fffff); + } + + temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); + temp3 = temp & temp2; + + if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG))) + return -1; + + return (temp & ~0xfff) + (addr & 0xfff); +} + + +void +mmu_invalidate(uint32_t addr) +{ + flushmmucache_cr3(); +} + + +uint8_t +mem_addr_range_match(uint32_t addr, uint32_t start, uint32_t len) +{ + if (addr < start) + return 0; + else if (addr >= (start + len)) + return 0; + else + return 1; +} + + +uint32_t +mem_addr_translate(uint32_t addr, uint32_t chunk_start, uint32_t len) +{ + uint32_t mask = len - 1; + + return chunk_start + (addr & mask); +} + + +void +addreadlookup(uint32_t virt, uint32_t phys) +{ + if (virt == 0xffffffff) return; + + if (readlookup2[virt>>12] != (uintptr_t) -1) return; + + if (readlookup[readlnext] != (int) 0xffffffff) + readlookup2[readlookup[readlnext]] = -1; + + readlookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + + readlookupp[readlnext] = mmu_perm; + readlookup[readlnext++] = virt >> 12; + readlnext &= (cachesize-1); + + sub_cycles(9); +} + + +void +addwritelookup(uint32_t virt, uint32_t phys) +{ + if (virt == 0xffffffff) return; + + if (page_lookup[virt >> 12]) return; + + if (writelookup[writelnext] != -1) { + page_lookup[writelookup[writelnext]] = NULL; + writelookup2[writelookup[writelnext]] = -1; + } + + if (pages[phys >> 12].block || (phys & ~0xfff) == recomp_page) + page_lookup[virt >> 12] = &pages[phys >> 12];//(uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + else + writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + + writelookupp[writelnext] = mmu_perm; + writelookup[writelnext++] = virt >> 12; + writelnext &= (cachesize - 1); + + sub_cycles(9); +} + + +uint8_t * +getpccache(uint32_t a) +{ + uint32_t a2; + + a2 = a; + + if (cr0 >> 31) { + a = mmutranslate_read(a); + + if (a == 0xffffffff) return ram; + } + a &= rammask; + + if (_mem_exec[a >> MEM_GRANULARITY_BITS]) { + if (is286) { + if (read_mapping[a >> MEM_GRANULARITY_BITS] && (read_mapping[a >> MEM_GRANULARITY_BITS]->flags & MEM_MAPPING_ROM)) + cpu_prefetch_cycles = cpu_rom_prefetch_cycles; + else + cpu_prefetch_cycles = cpu_mem_prefetch_cycles; + } + + return &_mem_exec[a >> MEM_GRANULARITY_BITS][(uintptr_t)(a & MEM_GRANULARITY_PAGE) - (uintptr_t)(a2 & ~0xfff)]; + } + + mem_log("Bad getpccache %08X\n", a); + +#if FIXME + return &ff_array[0-(uintptr_t)(a2 & ~0xfff)]; +#else + return (uint8_t *)&ff_pccache; +#endif +} + + +uint8_t +readmembl(uint32_t addr) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + if (cr0 >> 31) { + addr = mmutranslate_read(addr); + if (addr == 0xFFFFFFFF) return 0xFF; + } + addr &= rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->read_b) + return map->read_b(addr, map->p); + return 0xFF; +} + + +void +writemembl(uint32_t addr, uint8_t val) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (page_lookup[addr>>12]) { + page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); + return; + } + if (cr0 >> 31) { + addr = mmutranslate_write(addr); + if (addr == 0xFFFFFFFF) + return; + } + addr &= rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->write_b) + return map->write_b(addr, val, map->p); +} + + +uint16_t +readmemwl(uint32_t addr) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 1) { + if (!cpu_cyrix_alignment || (addr & 7) == 7) + sub_cycles(timing_misaligned); + if ((addr & 0xFFF) > 0xFFE) { + if (cr0 >> 31) { + if (mmutranslate_read(addr) == 0xffffffff) + return 0xffff; + if (mmutranslate_read(addr+1) == 0xffffffff) + return 0xffff; + } + return readmembl(addr)|(readmembl(addr+1)<<8); + } else if (readlookup2[addr >> 12] != -1) + return *(uint16_t *)(readlookup2[addr >> 12] + addr); + } + if (cr0>>31) { + addr = mmutranslate_read(addr); + if (addr==0xFFFFFFFF) + return 0xFFFF; + } + + addr &= rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + if (map->read_w) + return map->read_w(addr, map->p); + + if (map->read_b) + return map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8); + } + + return 0xffff; +} + + +void +writememwl(uint32_t addr, uint16_t val) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 1) { + if (!cpu_cyrix_alignment || (addr & 7) == 7) + sub_cycles(timing_misaligned); + if ((addr & 0xFFF) > 0xFFE) { + if (cr0 >> 31) { + if (mmutranslate_write(addr) == 0xffffffff) + return; + if (mmutranslate_write(addr+1) == 0xffffffff) + return; + } + writemembl(addr,val); + writemembl(addr+1,val>>8); + return; + } else if (writelookup2[addr >> 12] != -1) { + *(uint16_t *)(writelookup2[addr >> 12] + addr) = val; + return; + } + } + + if (page_lookup[addr>>12]) { + page_lookup[addr>>12]->write_w(addr, val, page_lookup[addr>>12]); + return; + } + if (cr0>>31) { + addr = mmutranslate_write(addr); + if (addr==0xFFFFFFFF) + return; + } + + addr &= rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + if (map->write_w) + map->write_w(addr, val, map->p); + else if (map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + } + } +} + + +uint32_t +readmemll(uint32_t addr) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 3) { + if (!cpu_cyrix_alignment || (addr & 7) > 4) + sub_cycles(timing_misaligned); + if ((addr&0xFFF)>0xFFC) { + if (cr0>>31) { + if (mmutranslate_read(addr) == 0xffffffff) + return 0xffffffff; + if (mmutranslate_read(addr+3) == 0xffffffff) + return 0xffffffff; + } + return readmemwl(addr)|(readmemwl(addr+2)<<16); + } else if (readlookup2[addr >> 12] != -1) + return *(uint32_t *)(readlookup2[addr >> 12] + addr); + } + + if (cr0>>31) { + addr = mmutranslate_read(addr); + if (addr==0xFFFFFFFF) + return 0xFFFFFFFF; + } + + addr&=rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + if (map->read_l) + return map->read_l(addr, map->p); + + if (map->read_w) + return map->read_w(addr, map->p) | (map->read_w(addr + 2, map->p) << 16); + + if (map->read_b) + return map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8) | + (map->read_b(addr + 2, map->p) << 16) | (map->read_b(addr + 3, map->p) << 24); + } + + return 0xffffffff; +} + + +void +writememll(uint32_t addr, uint32_t val) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 3) { + if (!cpu_cyrix_alignment || (addr & 7) > 4) + sub_cycles(timing_misaligned); + if ((addr & 0xFFF) > 0xFFC) { + if (cr0>>31) { + if (mmutranslate_write(addr) == 0xffffffff) + return; + if (mmutranslate_write(addr+3) == 0xffffffff) + return; + } + writememwl(addr,val); + writememwl(addr+2,val>>16); + return; + } else if (writelookup2[addr >> 12] != -1) { + *(uint32_t *)(writelookup2[addr >> 12] + addr) = val; + return; + } + } + if (page_lookup[addr>>12]) { + page_lookup[addr>>12]->write_l(addr, val, page_lookup[addr>>12]); + return; + } + if (cr0>>31) { + addr = mmutranslate_write(addr); + if (addr==0xFFFFFFFF) + return; + } + + addr&=rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + if (map->write_l) + map->write_l(addr, val, map->p); + else if (map->write_w) { + map->write_w(addr, val, map->p); + map->write_w(addr + 2, val >> 16, map->p); + } else if (map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + map->write_b(addr + 2, val >> 16, map->p); + map->write_b(addr + 3, val >> 24, map->p); + } + } +} + + +uint64_t +readmemql(uint32_t addr) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 7) { + sub_cycles(timing_misaligned); + if ((addr & 0xFFF) > 0xFF8) { + if (cr0>>31) { + if (mmutranslate_read(addr) == 0xffffffff) + return 0xffffffff; + if (mmutranslate_read(addr+7) == 0xffffffff) + return 0xffffffff; + } + return readmemll(addr)|((uint64_t)readmemll(addr+4)<<32); + } else if (readlookup2[addr >> 12] != -1) + return *(uint64_t *)(readlookup2[addr >> 12] + addr); + } + + if (cr0>>31) { + addr = mmutranslate_read(addr); + if (addr==0xFFFFFFFF) + return 0xFFFFFFFF; + } + + addr&=rammask; + + map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map && map->read_l) + return map->read_l(addr, map->p) | ((uint64_t)map->read_l(addr + 4, map->p) << 32); + + return readmemll(addr) | ((uint64_t)readmemll(addr+4)<<32); +} + + +void +writememql(uint32_t addr, uint64_t val) +{ + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 7) { + sub_cycles(timing_misaligned); + if ((addr & 0xFFF) > 0xFF8) { + if (cr0>>31) { + if (mmutranslate_write(addr) == 0xffffffff) + return; + if (mmutranslate_write(addr+7) == 0xffffffff) + return; + } + writememll(addr, val); + writememll(addr+4, val >> 32); + return; + } else if (writelookup2[addr >> 12] != -1) { + *(uint64_t *)(writelookup2[addr >> 12] + addr) = val; + return; + } + } + if (page_lookup[addr>>12]) { + page_lookup[addr>>12]->write_l(addr, val, page_lookup[addr>>12]); + page_lookup[addr>>12]->write_l(addr + 4, val >> 32, page_lookup[addr>>12]); + return; + } + if (cr0>>31) { + addr = mmutranslate_write(addr); + if (addr==0xFFFFFFFF) + return; + } + + addr&=rammask; + + map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + if (map) { + if (map->write_l) { + map->write_l(addr, val, map->p); + map->write_l(addr + 4, val >> 32, map->p); + } else if (map->write_w) { + map->write_w(addr, val, map->p); + map->write_w(addr + 2, val >> 16, map->p); + map->write_w(addr + 4, val >> 32, map->p); + map->write_w(addr + 6, val >> 48, map->p); + } else if (map->write_b) { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + map->write_b(addr + 2, val >> 16, map->p); + map->write_b(addr + 3, val >> 24, map->p); + map->write_b(addr + 4, val >> 32, map->p); + map->write_b(addr + 5, val >> 40, map->p); + map->write_b(addr + 6, val >> 48, map->p); + map->write_b(addr + 7, val >> 56, map->p); + } + } +} + + +uint8_t +mem_readb_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + mem_logical_addr = 0xffffffff; + + if (map && map->read_b) + return map->read_b(addr, map->p); + + return 0xff; +} + + +uint16_t +mem_readw_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping[addr >> MEM_GRANULARITY_BITS]; + + mem_logical_addr = 0xffffffff; + + if (map && map->read_w) + return map->read_w(addr, map->p); + + return mem_readb_phys(addr) | (mem_readb_phys(addr + 1) << 8); +} + + +void +mem_writeb_phys(uint32_t addr, uint8_t val) +{ + mem_mapping_t *map = write_mapping[addr >> MEM_GRANULARITY_BITS]; + + mem_logical_addr = 0xffffffff; + + if (map && map->write_b) + map->write_b(addr, val, map->p); +} + + +uint8_t +mem_read_ram(uint32_t addr, void *priv) +{ + addreadlookup(mem_logical_addr, addr); + + return ram[addr]; +} + + +uint16_t +mem_read_ramw(uint32_t addr, void *priv) +{ + addreadlookup(mem_logical_addr, addr); + + return *(uint16_t *)&ram[addr]; +} + + +uint32_t +mem_read_raml(uint32_t addr, void *priv) +{ + addreadlookup(mem_logical_addr, addr); + + return *(uint32_t *)&ram[addr]; +} + + +static inline int +page_index(page_t *p) +{ + return ((uintptr_t)p - (uintptr_t)pages) / sizeof(page_t); +} + + +void +page_add_to_evict_list(page_t *p) +{ + pages[purgable_page_list_head].evict_prev = page_index(p); + p->evict_next = purgable_page_list_head; + p->evict_prev = 0; + purgable_page_list_head = pages[purgable_page_list_head].evict_prev; + purgeable_page_count++; +} + + +void +page_remove_from_evict_list(page_t *p) +{ + if (!page_in_evict_list(p)) + fatal("page_remove_from_evict_list: not in evict list!\n"); + if (p->evict_prev) + pages[p->evict_prev].evict_next = p->evict_next; + else + purgable_page_list_head = p->evict_next; + if (p->evict_next) + pages[p->evict_next].evict_prev = p->evict_prev; + p->evict_prev = EVICT_NOT_IN_LIST; + purgeable_page_count--; +} + + +void +mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) +{ + if (val != p->mem[addr & 0xfff] || codegen_in_recompile) { + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + uint64_t byte_mask = (uint64_t)1 << (addr & PAGE_BYTE_MASK_MASK); + + p->mem[addr & 0xfff] = val; + p->dirty_mask |= mask; + if ((p->code_present_mask & mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + p->byte_dirty_mask[byte_offset] |= byte_mask; + if ((p->byte_code_present_mask[byte_offset] & byte_mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + } +} + + +void +mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) +{ + if (val != *(uint16_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + uint64_t byte_mask = (uint64_t)1 << (addr & PAGE_BYTE_MASK_MASK); + + if ((addr & 0xf) == 0xf) + mask |= (mask << 1); + *(uint16_t *)&p->mem[addr & 0xfff] = val; + p->dirty_mask |= mask; + if ((p->code_present_mask & mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + if ((addr & PAGE_BYTE_MASK_MASK) == PAGE_BYTE_MASK_MASK) { + p->byte_dirty_mask[byte_offset+1] |= 1; + if ((p->byte_code_present_mask[byte_offset+1] & 1) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + } else + byte_mask |= (byte_mask << 1); + + p->byte_dirty_mask[byte_offset] |= byte_mask; + + if ((p->byte_code_present_mask[byte_offset] & byte_mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + } +} + + +void +mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) +{ + if (val != *(uint32_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + uint64_t byte_mask = (uint64_t)0xf << (addr & PAGE_BYTE_MASK_MASK); + + if ((addr & 0xf) >= 0xd) + mask |= (mask << 1); + *(uint32_t *)&p->mem[addr & 0xfff] = val; + p->dirty_mask |= mask; + p->byte_dirty_mask[byte_offset] |= byte_mask; + if (!page_in_evict_list(p) && ((p->code_present_mask & mask) || (p->byte_code_present_mask[byte_offset] & byte_mask))) + page_add_to_evict_list(p); + if ((addr & PAGE_BYTE_MASK_MASK) > (PAGE_BYTE_MASK_MASK-3)) { + uint32_t byte_mask_2 = 0xf >> (4 - (addr & 3)); + + p->byte_dirty_mask[byte_offset+1] |= byte_mask_2; + if ((p->byte_code_present_mask[byte_offset+1] & byte_mask_2) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + } + } +} + + +void +mem_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[addr >> 12]); +} + + +void +mem_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[addr >> 12]); +} + + +void +mem_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[addr >> 12]); +} + + +static uint8_t +mem_read_remapped(uint32_t addr, void *priv) +{ + if(addr >= (mem_size * 1024) && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} + + +static uint16_t +mem_read_remappedw(uint32_t addr, void *priv) +{ + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *)&ram[addr]; +} + + +static uint32_t +mem_read_remappedl(uint32_t addr, void *priv) +{ + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *)&ram[addr]; +} + + +static void +mem_write_remapped(uint32_t addr, uint8_t val, void *priv) +{ + uint32_t oldaddr = addr; + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]); +} + + +static void +mem_write_remappedw(uint32_t addr, uint16_t val, void *priv) +{ + uint32_t oldaddr = addr; + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]); +} + + +static void +mem_write_remappedl(uint32_t addr, uint32_t val, void *priv) +{ + uint32_t oldaddr = addr; + if(addr >= mem_size * 1024 && addr < ((mem_size + 384) * 1024)) + addr = 0xA0000 + (addr - (mem_size * 1024)); + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[oldaddr >> 12]); +} + + +uint8_t +mem_read_bios(uint32_t addr, void *priv) +{ + uint8_t ret = 0xff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = rom[addr - biosaddr]; + + return ret; +} + + +uint16_t +mem_read_biosw(uint32_t addr, void *priv) +{ + uint16_t ret = 0xffff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = *(uint16_t *)&rom[addr - biosaddr]; + + return ret; +} + + +uint32_t +mem_read_biosl(uint32_t addr, void *priv) +{ + uint32_t ret = 0xffffffff; + + addr &= 0x000fffff; + + if ((addr >= biosaddr) && (addr <= (biosaddr + biosmask))) + ret = *(uint32_t *)&rom[addr - biosaddr]; + + return ret; +} + + +void +mem_write_null(uint32_t addr, uint8_t val, void *p) +{ +} + + +void +mem_write_nullw(uint32_t addr, uint16_t val, void *p) +{ +} + + +void +mem_write_nulll(uint32_t addr, uint32_t val, void *p) +{ +} + + +void +mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) +{ + uint64_t mask; + page_t *p; + + start_addr &= ~PAGE_MASK_MASK; + end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + + for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) { + if ((start_addr >> 12) >= pages_sz) + continue; + + mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + + p = &pages[start_addr >> 12]; + + p->dirty_mask |= mask; + if ((p->code_present_mask & mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + } +} + + +static __inline int +mem_mapping_read_allowed(uint32_t flags, int state) +{ + switch (state & MEM_READ_MASK) { + case MEM_READ_DISABLED: + return 0; + + case MEM_READ_ANY: + return 1; + + case MEM_READ_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL); + + case MEM_READ_INTERNAL: + return !(flags & MEM_MAPPING_EXTERNAL); + + default: + fatal("mem_mapping_read_allowed : bad state %x\n", state); + } + + return 0; +} + + +static __inline int +mem_mapping_write_allowed(uint32_t flags, int state) +{ + switch (state & MEM_WRITE_MASK) { + case MEM_WRITE_DISABLED: + return 0; + case MEM_WRITE_ANY: + return 1; + case MEM_WRITE_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL); + case MEM_WRITE_INTERNAL: + return !(flags & MEM_MAPPING_EXTERNAL); + default: + fatal("mem_mapping_write_allowed : bad state %x\n", state); + } + + return 0; +} + + +static void +mem_mapping_recalc(uint64_t base, uint64_t size) +{ + mem_mapping_t *map = base_mapping.next; + uint64_t c; + + if (! size) return; + + /* Clear out old mappings. */ + for (c = base; c < base + size; c += MEM_GRANULARITY_SIZE) { + read_mapping[c >> MEM_GRANULARITY_BITS] = NULL; + write_mapping[c >> MEM_GRANULARITY_BITS] = NULL; + _mem_exec[c >> MEM_GRANULARITY_BITS] = NULL; + } + + /* Walk mapping list. */ + while (map != NULL) { + /*In range?*/ + if (map->enable && (uint64_t)map->base < ((uint64_t)base + (uint64_t)size) && ((uint64_t)map->base + (uint64_t)map->size) > (uint64_t)base) { + uint64_t start = (map->base < base) ? map->base : base; + uint64_t end = (((uint64_t)map->base + (uint64_t)map->size) < (base + size)) ? ((uint64_t)map->base + (uint64_t)map->size) : (base + size); + if (start < map->base) + start = map->base; + + for (c = start; c < end; c += MEM_GRANULARITY_SIZE) { + if ((map->read_b || map->read_w || map->read_l) && + mem_mapping_read_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS])) { + read_mapping[c >> MEM_GRANULARITY_BITS] = map; + if (map->exec) + _mem_exec[c >> MEM_GRANULARITY_BITS] = map->exec + (c - map->base); + else + _mem_exec[c >> MEM_GRANULARITY_BITS] = NULL; + } + if ((map->write_b || map->write_w || map->write_l) && + mem_mapping_write_allowed(map->flags, _mem_state[c >> MEM_GRANULARITY_BITS])) + write_mapping[c >> MEM_GRANULARITY_BITS] = map; + } + } + map = map->next; + } + + flushmmucache_cr3(); +} + + +void +mem_mapping_del(mem_mapping_t *map) +{ + mem_mapping_t *ptr; + + /* Disable the entry. */ + mem_mapping_disable(map); + + /* Zap it from the list. */ + for (ptr = &base_mapping; ptr->next != NULL; ptr = ptr->next) { + if (ptr->next == map) { + ptr->next = map->next; + break; + } + } +} + + +void +mem_mapping_add(mem_mapping_t *map, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t fl, + void *p) +{ + mem_mapping_t *dest = &base_mapping; + + /* Add mapping to the end of the list.*/ + while (dest->next) + dest = dest->next; + dest->next = map; + map->prev = dest; + + if (size) + map->enable = 1; + else + map->enable = 0; + map->base = base; + map->size = size; + map->read_b = read_b; + map->read_w = read_w; + map->read_l = read_l; + map->write_b = write_b; + map->write_w = write_w; + map->write_l = write_l; + map->exec = exec; + map->flags = fl; + map->p = p; + map->dev = NULL; + map->next = NULL; + + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_mapping_set_handler(mem_mapping_t *map, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p)) +{ + map->read_b = read_b; + map->read_w = read_w; + map->read_l = read_l; + map->write_b = write_b; + map->write_w = write_w; + map->write_l = write_l; + + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_mapping_set_addr(mem_mapping_t *map, uint32_t base, uint32_t size) +{ + /* Remove old mapping. */ + map->enable = 0; + mem_mapping_recalc(map->base, map->size); + + /* Set new mapping. */ + map->enable = 1; + map->base = base; + map->size = size; + + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_mapping_set_exec(mem_mapping_t *map, uint8_t *exec) +{ + map->exec = exec; + + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_mapping_set_p(mem_mapping_t *map, void *p) +{ + map->p = p; +} + + +void +mem_mapping_set_dev(mem_mapping_t *map, void *p) +{ + map->dev = p; +} + + +void +mem_mapping_disable(mem_mapping_t *map) +{ + map->enable = 0; + + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_mapping_enable(mem_mapping_t *map) +{ + map->enable = 1; + + mem_mapping_recalc(map->base, map->size); +} + + +void +mem_set_mem_state(uint32_t base, uint32_t size, int state) +{ + uint32_t c; + + for (c = 0; c < size; c += MEM_GRANULARITY_SIZE) + _mem_state[(c + base) >> MEM_GRANULARITY_BITS] = state; + + mem_mapping_recalc(base, size); +} + + +void +mem_add_bios(void) +{ + if (biosmask > 0x1ffff) { + /* 256k+ BIOS'es only have low mappings at E0000-FFFFF. */ + mem_mapping_add(&bios_mapping, 0xe0000, 0x20000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + &rom[0x20000], MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + } else { + mem_mapping_add(&bios_mapping, biosaddr, biosmask + 1, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + } + + if (AT) { + mem_mapping_add(&bios_high_mapping, biosaddr | (cpu_16bitbus ? 0x00f00000 : 0xfff00000), biosmask + 1, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom, + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + } +} + + +void +mem_a20_init(void) +{ + if (AT) { + rammask = cpu_16bitbus ? 0xefffff : 0xffefffff; + flushmmucache(); + mem_a20_state = mem_a20_key | mem_a20_alt; + } else { + rammask = 0xfffff; + flushmmucache(); + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + } +} + + +/* Reset the memory state. */ +void +mem_reset(void) +{ + uint32_t c, m; + + m = 1024UL * mem_size; + if (ram != NULL) { + free(ram); + ram = NULL; + } + ram = (uint8_t *)malloc(m); /* allocate and clear the RAM block */ + memset(ram, 0x00, m); + + /* + * Allocate the page table based on how much RAM we have. + * We re-allocate the table on each (hard) reset, as the + * memory amount could have changed. + */ + if (AT) { + if (cpu_16bitbus) { + /* 80186/286; maximum address space is 16MB. */ + m = 4096; + } else { + /* 80386+; maximum address space is 4GB. */ + m = (mem_size + 384) >> 2; + if ((m << 2) < (mem_size + 384)) + m++; + if (m < 4096) + m = 4096; + } + } else { + /* 8088/86; maximum address space is 1MB. */ + m = 256; + } + + /* + * Allocate and initialize the (new) page table. + * We only do this if the size of the page table has changed. + */ +#if DYNAMIC_TABLES +mem_log("MEM: reset: previous pages=%08lx, pages_sz=%i\n", pages, pages_sz); +#endif + if (pages_sz != m) { + pages_sz = m; + if (pages) { + free(pages); + pages = NULL; + } + pages = (page_t *)malloc(m*sizeof(page_t)); +#if DYNAMIC_TABLES +mem_log("MEM: reset: new pages=%08lx, pages_sz=%i\n", pages, pages_sz); +#endif + +#if DYNAMIC_TABLES + /* Allocate the (new) lookup tables. */ + if (page_lookup != NULL) free(page_lookup); + page_lookup = (page_t **)malloc(pages_sz*sizeof(page_t *)); + + if (readlookup2 != NULL) free(readlookup2); + readlookup2 = malloc(pages_sz*sizeof(uintptr_t)); + + if (writelookup2 != NULL) free(writelookup2); + writelookup2 = malloc(pages_sz*sizeof(uintptr_t)); + +#endif + } + +#if DYNAMIC_TABLES + memset(page_lookup, 0x00, pages_sz * sizeof(page_t *)); +#else + memset(page_lookup, 0x00, (1 << 20) * sizeof(page_t *)); +#endif + + memset(pages, 0x00, pages_sz*sizeof(page_t)); + + if (byte_dirty_mask) { + free(byte_dirty_mask); + byte_dirty_mask = NULL; + } + byte_dirty_mask = malloc((mem_size * 1024) / 8); + memset(byte_dirty_mask, 0, (mem_size * 1024) / 8); + + if (byte_code_present_mask) { + free(byte_code_present_mask); + byte_code_present_mask = NULL; + } + byte_code_present_mask = malloc((mem_size * 1024) / 8); + memset(byte_code_present_mask, 0, (mem_size * 1024) / 8); + + for (c = 0; c < pages_sz; c++) { + pages[c].mem = &ram[c << 12]; + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + pages[c].evict_prev = EVICT_NOT_IN_LIST; + pages[c].byte_dirty_mask = &byte_dirty_mask[c * 64]; + pages[c].byte_code_present_mask = &byte_code_present_mask[c * 64]; + } + + memset(_mem_exec, 0x00, sizeof(_mem_exec)); + + memset(&base_mapping, 0x00, sizeof(base_mapping)); + + memset(_mem_state, 0x00, sizeof(_mem_state)); + + mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(0x0c0000, 0x40000, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + mem_mapping_add(&ram_low_mapping, 0x00000, + (mem_size > 640) ? 0xa0000 : mem_size * 1024, + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram, MEM_MAPPING_INTERNAL, NULL); + + if (mem_size > 1024) { + if (cpu_16bitbus && mem_size > 16256) { + mem_set_mem_state(0x100000, (16256 - 1024) * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_high_mapping, 0x100000, + ((16256 - 1024) * 1024), + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + } else { + mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_high_mapping, 0x100000, + ((mem_size - 1024) * 1024), + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + } + } + + if (mem_size > 768) + mem_mapping_add(&ram_mid_mapping, 0xc0000, 0x40000, + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + 0xc0000, MEM_MAPPING_INTERNAL, NULL); + + mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 256 * 1024, + mem_read_remapped,mem_read_remappedw,mem_read_remappedl, + mem_write_remapped,mem_write_remappedw,mem_write_remappedl, + ram + 0xa0000, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_disable(&ram_remapped_mapping); + + mem_a20_init(); +} + + +void +mem_init(void) +{ + /* Perform a one-time init. */ + ram = rom = NULL; + pages = NULL; +#if DYNAMIC_TABLES + page_lookup = NULL; + readlookup2 = NULL; + writelookup2 = NULL; + +#else + /* Allocate the lookup tables. */ + page_lookup = (page_t **)malloc((1<<20)*sizeof(page_t *)); + + readlookup2 = malloc((1<<20)*sizeof(uintptr_t)); + + writelookup2 = malloc((1<<20)*sizeof(uintptr_t)); +#endif + +#if FIXME + memset(ff_array, 0xff, sizeof(ff_array)); +#endif + + /* Reset the memory state. */ + mem_reset(); +} + + +void +mem_remap_top(int kb) +{ + int c; + uint32_t start = (mem_size >= 1024) ? mem_size : 1024; + int offset, size = mem_size - 640; + + mem_log("MEM: remapping top %iKB (mem=%i)\n", kb, mem_size); + if (mem_size <= 640) return; + + if (kb == 0) { + /* Called to disable the mapping. */ + mem_mapping_disable(&ram_remapped_mapping); + + return; + } + + if (size > kb) + size = kb; + + for (c = ((start * 1024) >> 12); c < (((start + size) * 1024) >> 12); c++) { + offset = c - ((start * 1024) >> 12); + pages[c].mem = &ram[0xA0000 + (offset << 12)]; + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + pages[c].evict_prev = EVICT_NOT_IN_LIST; + pages[c].byte_dirty_mask = &byte_dirty_mask[offset * 64]; + pages[c].byte_code_present_mask = &byte_code_present_mask[offset * 64]; + } + + mem_set_mem_state(start * 1024, size * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_set_addr(&ram_remapped_mapping, start * 1024, size * 1024); + mem_mapping_set_exec(&ram_remapped_mapping, ram + (start * 1024)); + + flushmmucache(); +} + +void +mem_reset_page_blocks(void) +{ + uint32_t c; + + if (pages == NULL) return; + + for (c = 0; c < pages_sz; c++) { + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + pages[c].block = BLOCK_INVALID; + pages[c].block_2 = BLOCK_INVALID; + } +} + + +void +mem_a20_recalc(void) +{ + int state; + + if (! AT) { + rammask = 0xfffff; + flushmmucache(); + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + + return; + } + + state = mem_a20_key | mem_a20_alt; + if (state && !mem_a20_state) { + rammask = (AT && cpu_16bitbus) ? 0xffffff : 0xffffffff; + flushmmucache(); + } else if (!state && mem_a20_state) { + rammask = (AT && cpu_16bitbus) ? 0xefffff : 0xffefffff; + flushmmucache(); + } + + mem_a20_state = state; +} diff --git a/src/memregs.c b/src/memregs.c deleted file mode 100644 index 52cd8b702..000000000 --- a/src/memregs.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Emulation of the memory I/O scratch registers on ports 0xE1 - * and 0xE2, used by just about any emulated machine. - * - * Version: @(#)memregs.c 1.0.7 2018/10/02 - * - * Author: Miran Grca, - * - * Copyright 2016-2018 Miran Grca. - */ -#include -#include -#include -#include -#include "86box.h" -#include "io.h" -#include "memregs.h" - - -static uint8_t mem_regs[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - -static uint8_t mem_reg_ffff = 0; - - -void memregs_write(uint16_t port, uint8_t val, void *priv) -{ - if (port == 0xffff) - { - mem_reg_ffff = 0; - } - - mem_regs[port & 0xf] = val; -} - -uint8_t memregs_read(uint16_t port, void *priv) -{ - if (port == 0xffff) - { - return mem_reg_ffff; - } - - return mem_regs[port & 0xf]; -} - -void memregs_init(void) -{ - io_sethandler(0x00e1, 0x0002, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); -} - -void powermate_memregs_init(void) -{ - io_sethandler(0x00ed, 0x0002, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); - io_sethandler(0xffff, 0x0001, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); -} diff --git a/src/mouse.c b/src/mouse.c index 74f8e9cf5..bd01892f7 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -132,7 +132,7 @@ mouse_close(void) void mouse_reset(void) { - if ((mouse_curr != NULL) || (mouse_type == MOUSE_TYPE_INTERNAL)) + if (mouse_curr != NULL) return; /* Mouse already initialized. */ mouse_log("MOUSE: reset(type=%d, '%s')\n", @@ -165,7 +165,7 @@ mouse_process(void) { static int poll_delay = 2; - if ((mouse_curr == NULL) || (mouse_type == MOUSE_TYPE_INTERNAL)) + if (mouse_curr == NULL) return; if (--poll_delay) return; diff --git a/src/mouse_bus.c b/src/mouse_bus.c index e5551ef26..3cb59ebac 100644 --- a/src/mouse_bus.c +++ b/src/mouse_bus.c @@ -18,6 +18,7 @@ * of the real hardware, testing of drivers, and the old code. * * Logitech Bus Mouse verified with: + * Linux Slackware 3.0 * Logitech LMouse.com 3.12 * Logitech LMouse.com 3.30 * Logitech LMouse.com 3.41 @@ -44,12 +45,15 @@ * Microsoft Mouse.com 8.21J * Microsoft Windows 1.00 DR5 * Microsoft Windows 3.10.026 + * Microsoft Windows 3.10.068 both MOUSE.DRV and LMOUSE.DRV * Microsoft Windows NT 3.1 * Microsoft Windows 95 * * InPort verified with: + * Linux Slackware 3.0 * Logitech LMouse.com 6.12 * Logitech LMouse.com 6.41 + * Microsoft Windows 3.10.068 both MOUSE.DRV and LMOUSE.DRV * Microsoft Windows NT 3.1 * Microsoft Windows 98 SE * @@ -124,23 +128,24 @@ #define FLAG_TIMER_INT (1 << 3) #define FLAG_DATA_INT (1 << 4) -static const double periods[4] = { 30.0, 50.0, 100.0, 200.0 }; +static const uint8_t periods[4] = { 30, 50, 100, 200 }; /* Our mouse device. */ typedef struct mouse { + uint8_t current_b, control_val, + config_val, sig_val, + command_val, pad; + + int8_t current_x, current_y; + int base, irq, bn, flags, mouse_delayed_dx, mouse_delayed_dy, - mouse_buttons, - current_x, current_y, - current_b, - control_val, mouse_buttons_last, - config_val, sig_val, - command_val, toggle_counter; + mouse_buttons, mouse_buttons_last, + toggle_counter, timer_enabled; double period; - - int64_t timer_enabled, timer; /* mouse event timer */ + pc_timer_t timer; /* mouse event timer */ } mouse_t; @@ -178,15 +183,19 @@ lt_read(uint16_t port, void *priv) switch (dev->control_val & 0x60) { case READ_X_LOW: value = dev->current_x & 0x0F; + dev->current_x &= ~0x0F; break; case READ_X_HIGH: value = (dev->current_x >> 4) & 0x0F; + dev->current_x &= ~0xF0; break; case READ_Y_LOW: value = dev->current_y & 0x0F; + dev->current_y &= ~0x0F; break; case READ_Y_HIGH: value = (dev->current_y >> 4) & 0x0F; + dev->current_y &= ~0xF0; break; default: bm_log("ERROR: Reading data port in unsupported mode 0x%02x\n", dev->control_val); @@ -232,13 +241,15 @@ ms_read(uint16_t port, void *priv) case INP_PORT_DATA: switch (dev->command_val) { case INP_CTRL_READ_BUTTONS: - value = dev->current_b | 0x80; + value = dev->current_b; break; case INP_CTRL_READ_X: value = dev->current_x; + dev->current_x = 0; break; case INP_CTRL_READ_Y: value = dev->current_y; + dev->current_y = 0; break; case INP_CTRL_COMMAND: value = dev->control_val; @@ -335,7 +346,10 @@ lt_write(uint16_t port, uint8_t val, void *priv) if (val & DEVICE_ACTIVE) { /* Mode set/reset - enable this */ dev->config_val = val; - dev->flags |= (FLAG_ENABLED | FLAG_TIMER_INT); + if (dev->timer_enabled) + dev->flags |= (FLAG_ENABLED | FLAG_TIMER_INT); + else + dev->flags |= FLAG_ENABLED; dev->control_val = 0x0F & ~IRQ_MASK; } else { /* Single bit set/reset */ @@ -398,17 +412,19 @@ ms_write(uint16_t port, uint8_t val, void *priv) switch(val & INP_PERIOD_MASK) { case 0: dev->period = 0.0; - dev->timer = 0LL; - dev->timer_enabled = 0LL; + timer_disable(&dev->timer); + dev->timer_enabled = 0; break; case 1: case 2: case 3: case 4: - dev->period = 1000000.0 / periods[(val & INP_PERIOD_MASK) - 1]; - dev->timer = ((int64_t) dev->period) * TIMER_USEC; - dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? 1LL : 0LL; + dev->period = (1000000.0 / (double)periods[(val & INP_PERIOD_MASK) - 1]); + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? 1 : 0; + timer_disable(&dev->timer); + if (dev->timer_enabled) + timer_set_delay_u64(&dev->timer, (uint64_t) (dev->period * (double)TIMER_USEC)); bm_log("DEBUG: Timer is now %sabled at period %i\n", (val & INP_ENABLE_TIMER_IRQ) ? "en" : "dis", (int32_t) dev->period); break; @@ -510,34 +526,35 @@ bm_update_data(mouse_t *dev) int delta_x, delta_y; int xor; - /* Update the deltas and the delays. */ - if (dev->mouse_delayed_dx > 127) { - delta_x = 127; - dev->mouse_delayed_dx -= 127; - } else if (dev->mouse_delayed_dx < -128) { - delta_x = -128; - dev->mouse_delayed_dx += 128; - } else { - delta_x = dev->mouse_delayed_dx; - dev->mouse_delayed_dx = 0; - } - - if (dev->mouse_delayed_dy > 127) { - delta_y = 127; - dev->mouse_delayed_dy -= 127; - } else if (dev->mouse_delayed_dy < -128) { - delta_y = -128; - dev->mouse_delayed_dy += 128; - } else { - delta_y = dev->mouse_delayed_dy; - dev->mouse_delayed_dy = 0; - } - /* If the counters are not frozen, update them. */ if (!(dev->flags & FLAG_HOLD)) { - dev->current_x = (uint8_t) delta_x; - dev->current_y = (uint8_t) delta_y; - } + /* Update the deltas and the delays. */ + if (dev->mouse_delayed_dx > 127) { + delta_x = 127; + dev->mouse_delayed_dx -= 127; + } else if (dev->mouse_delayed_dx < -128) { + delta_x = -128; + dev->mouse_delayed_dx += 128; + } else { + delta_x = dev->mouse_delayed_dx; + dev->mouse_delayed_dx = 0; + } + + if (dev->mouse_delayed_dy > 127) { + delta_y = 127; + dev->mouse_delayed_dy -= 127; + } else if (dev->mouse_delayed_dy < -128) { + delta_y = -128; + dev->mouse_delayed_dy += 128; + } else { + delta_y = dev->mouse_delayed_dy; + dev->mouse_delayed_dy = 0; + } + + dev->current_x = (int8_t) delta_x; + dev->current_y = (int8_t) delta_y; + } else + delta_x = delta_y = 0; if (dev->flags & FLAG_INPORT) { /* This is an InPort mouse in timer mode, so update current_b always, @@ -564,7 +581,7 @@ bm_timer(void *priv) /* The period is configured either via emulator settings (for MS/Logitech Bus mouse) or via software (for InPort mouse). */ - dev->timer += ((int64_t) dev->period) * TIMER_USEC; + timer_advance_u64(&dev->timer, (uint64_t) (dev->period * (double)TIMER_USEC)); if (dev->flags & FLAG_TIMER_INT) { picint(1 << dev->irq); @@ -591,6 +608,7 @@ static void * bm_init(const device_t *info) { mouse_t *dev; + int hz; dev = (mouse_t *)malloc(sizeof(mouse_t)); memset(dev, 0x00, sizeof(mouse_t)); @@ -611,37 +629,44 @@ bm_init(const device_t *info) dev->mouse_buttons_last = 0; dev->sig_val = 0; /* the signature port value */ dev->current_x = - dev->current_y = + dev->current_y = 0; dev->current_b = 0; dev->command_val = 0; /* command byte */ dev->toggle_counter = 0; /* signature byte / IRQ bit toggle */ + dev->period = 0.0; + + timer_add(&dev->timer, bm_timer, dev, 0); if (dev->flags & FLAG_INPORT) { dev->control_val = 0; /* the control port value */ dev->flags |= FLAG_ENABLED; - dev->period = 0.0; io_sethandler(dev->base, 4, ms_read, NULL, NULL, ms_write, NULL, NULL, dev); - dev->timer = 0LL; - dev->timer_enabled = 0LL; + dev->timer_enabled = 0; } else { dev->control_val = 0x0f; /* the control port value */ dev->config_val = 0x9b; /* the config port value - 0x9b is the default state of the 8255: all ports are set to input */ - dev->period = 1000000.0 / ((double) device_get_config_int("hz")); + + hz = device_get_config_int("hz"); + if (hz > 0) + dev->period = (1000000.0 / (double)hz); io_sethandler(dev->base, 4, lt_read, NULL, NULL, lt_write, NULL, NULL, dev); - dev->timer = ((int64_t) dev->period) * TIMER_USEC; - dev->timer_enabled = 1LL; + if (hz > 0) { + timer_set_delay_u64(&dev->timer, (uint64_t) (dev->period * (double)TIMER_USEC)); + dev->timer_enabled = 1; + } else { + dev->flags |= FLAG_DATA_INT; + dev->timer_enabled = 0; + } } - timer_add(bm_timer, &dev->timer, &dev->timer_enabled, dev); - if (dev->flags & FLAG_INPORT) bm_log("MS Inport BusMouse initialized\n"); else @@ -693,6 +718,9 @@ static const device_config_t lt_config[] = { }, { "hz", "Hz", CONFIG_SELECTION, "", 45, { + { + "Non-timed (original)", 0 + }, { "30 Hz (JMP2 = 1)", 30 }, diff --git a/src/mouse_serial.c b/src/mouse_serial.c index d2b088e62..f2038c368 100644 --- a/src/mouse_serial.c +++ b/src/mouse_serial.c @@ -10,7 +10,7 @@ * * TODO: Add the Genius Serial Mouse. * - * Version: @(#)mouse_serial.c 1.0.27 2018/11/11 + * Version: @(#)mouse_serial.c 1.0.28 2019/03/23 * * Author: Fred N. van Kempen, */ @@ -63,9 +63,10 @@ typedef struct { oldb, lastb; int command_pos, command_phase, - report_pos, report_phase; - int64_t command_delay, transmit_period, - report_delay, report_period; + report_pos, report_phase, + command_enabled, report_enabled; + double transmit_period, report_period; + pc_timer_t command_timer, report_timer; serial_t *serial; } mouse_t; @@ -97,6 +98,71 @@ mouse_serial_log(const char *fmt, ...) #endif +static void +sermouse_timer_on(mouse_t *dev, double period, int report) +{ + pc_timer_t *timer; + int *enabled; + + if (report) { + timer = &dev->report_timer; + enabled = &dev->report_enabled; + } else { + timer = &dev->command_timer; + enabled = &dev->command_enabled; + } + + if (*enabled) + timer_advance_u64(timer, (uint64_t) (period * (double)TIMER_USEC)); + else + timer_set_delay_u64(timer, (uint64_t) (period * (double)TIMER_USEC)); + + *enabled = 1; +} + + +static double +sermouse_transmit_period(mouse_t *dev, int bps, int rps) +{ + double dbps = (double) bps; + double temp = 0.0; + int word_len; + + switch (dev->format) { + case 0: + case 1: /* Mouse Systems and Three Byte Packed formats: 8 data, no parity, 2 stop, 1 start */ + word_len = 11; + break; + case 2: /* Hexadecimal format - 8 data, no parity, 1 stop, 1 start - number of stop bits is a guess because + it is not documented anywhere. */ + word_len = 10; + break; + case 3: + case 6: /* Bit Pad One formats: 7 data, even parity, 2 stop, 1 start */ + word_len = 11; + break; + case 5: /* MM Series format: 8 data, odd parity, 1 stop, 1 start */ + word_len = 11; + break; + default: + case 7: /* Microsoft-compatible format: 7 data, no parity, 1 stop, 1 start */ + word_len = 9; + break; + } + + if (rps == -1) + temp = (double) word_len; + else { + temp = (double) rps; + temp = (9600.0 - (temp * 33.0)); + temp /= rps; + } + temp = (1000000.0 / dbps) * temp; + + return temp; +} + + /* Callback from serial driver: RTS was toggled. */ static void sermouse_callback(struct serial_s *serial, void *priv) @@ -106,7 +172,16 @@ sermouse_callback(struct serial_s *serial, void *priv) /* Start a timer to wake us up in a little while. */ dev->command_pos = 0; dev->command_phase = PHASE_ID; - dev->command_delay = dev->transmit_period; + if (dev->id[0] != 'H') + dev->format = 7; + dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); + timer_disable(&dev->command_timer); + sub_cycles(ISA_CYCLES(8)); +#ifdef USE_NEW_DYNAREC + sermouse_timer_on(dev, 5000.0, 0); +#else + sermouse_timer_on(dev, dev->transmit_period, 0); +#endif } @@ -130,8 +205,8 @@ static uint8_t sermouse_data_3bp(mouse_t *dev, int x, int y, int b) { dev->data[0] |= (b & 0x01) ? 0x00 : 0x04; /* left button */ - dev->data[0] |= (b & 0x02) ? 0x00 : 0x02; /* middle button */ - dev->data[0] |= (b & 0x04) ? 0x00 : 0x01; /* right button */ + dev->data[0] |= (b & 0x04) ? 0x00 : 0x02; /* middle button */ + dev->data[0] |= (b & 0x02) ? 0x00 : 0x01; /* right button */ dev->data[1] = x; dev->data[2] = -y; @@ -153,8 +228,8 @@ sermouse_data_mmseries(mouse_t *dev, int x, int y, int b) if (y < 0) dev->data[0] |= 0x08; dev->data[0] |= (b & 0x01) ? 0x04 : 0x00; /* left button */ - dev->data[0] |= (b & 0x02) ? 0x02 : 0x00; /* middle button */ - dev->data[0] |= (b & 0x04) ? 0x01 : 0x00; /* right button */ + dev->data[0] |= (b & 0x04) ? 0x02 : 0x00; /* middle button */ + dev->data[0] |= (b & 0x02) ? 0x01 : 0x00; /* right button */ dev->data[1] = abs(x); dev->data[2] = abs(y); @@ -167,8 +242,8 @@ sermouse_data_bp1(mouse_t *dev, int x, int y, int b) { dev->data[0] = 0x80; dev->data[0] |= (b & 0x01) ? 0x10 : 0x00; /* left button */ - dev->data[0] |= (b & 0x02) ? 0x08 : 0x00; /* middle button */ - dev->data[0] |= (b & 0x04) ? 0x04 : 0x00; /* right button */ + dev->data[0] |= (b & 0x04) ? 0x08 : 0x00; /* middle button */ + dev->data[0] |= (b & 0x02) ? 0x04 : 0x00; /* right button */ dev->data[1] = (x & 0x3f); dev->data[2] = (x >> 6); dev->data[3] = (y & 0x3f); @@ -226,8 +301,8 @@ sermouse_data_hex(mouse_t *dev, int x, int y, int b) uint8_t i, but = 0x00; but |= (b & 0x01) ? 0x04 : 0x00; /* left button */ - but |= (b & 0x02) ? 0x02 : 0x00; /* middle button */ - but |= (b & 0x04) ? 0x01 : 0x00; /* right button */ + but |= (b & 0x04) ? 0x02 : 0x00; /* middle button */ + but |= (b & 0x02) ? 0x01 : 0x00; /* right button */ sprintf(ret, "%02X%02X%01X", (int8_t) y, (int8_t) x, but & 0x0f); @@ -245,6 +320,10 @@ sermouse_report(int x, int y, int z, int b, mouse_t *dev) memset(dev->data, 0, 5); + /* If the mouse is 2-button, ignore the middle button. */ + if (dev->but == 2) + b &= ~0x04; + switch (dev->format) { case 0: len = sermouse_data_msystems(dev, x, y, b); @@ -276,9 +355,9 @@ sermouse_report(int x, int y, int z, int b, mouse_t *dev) static void sermouse_command_phase_idle(mouse_t *dev) { - dev->command_delay = 0LL; dev->command_pos = 0; dev->command_phase = PHASE_IDLE; + dev->command_enabled = 0; } @@ -288,7 +367,7 @@ sermouse_command_pos_check(mouse_t *dev, int len) if (++dev->command_pos == len) sermouse_command_phase_idle(dev); else - dev->command_delay += dev->transmit_period; + timer_advance_u64(&dev->command_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC)); } @@ -308,50 +387,6 @@ sermouse_last_button_status(mouse_t *dev) } -static int64_t -sermouse_transmit_period(mouse_t *dev, int bps, int rps) -{ - double dbps = (double) bps; - double dusec = (double) TIMER_USEC; - double temp = 0.0; - int word_len; - - switch (dev->format) { - case 0: - case 1: /* Mouse Systems and Three Byte Packed formats: 8 data, no parity, 2 stop, 1 start */ - word_len = 11; - break; - case 2: /* Hexadecimal format - 8 data, no parity, 1 stop, 1 start - number of stop bits is a guess because - it is not documented anywhere. */ - word_len = 10; - break; - case 3: - case 6: /* Bit Pad One formats: 7 data, even parity, 2 stop, 1 start */ - word_len = 11; - break; - case 5: /* MM Series format: 8 data, odd parity, 1 stop, 1 start */ - word_len = 11; - break; - default: - case 7: /* Microsoft-compatible format: 7 data, no parity, 1 stop, 1 start */ - word_len = 9; - break; - } - - if (rps == -1) - temp = (double) word_len; - else { - temp = (double) rps; - temp = (9600.0 - (temp * 33.0)); - temp /= rps; - } - temp = (1000000.0 / dbps) * temp; - temp *= dusec; - - return (int64_t) temp; -} - - static void sermouse_update_delta(mouse_t *dev, int *local, int *global) { @@ -403,6 +438,16 @@ sermouse_update_data(mouse_t *dev) } +static double +sermouse_report_period(mouse_t *dev) +{ + if (dev->report_period == 0) + return dev->transmit_period; + else + return dev->report_period; +} + + static void sermouse_report_prepare(mouse_t *dev) { @@ -410,13 +455,10 @@ sermouse_report_prepare(mouse_t *dev) /* Start sending data. */ dev->report_phase = REPORT_PHASE_TRANSMIT; dev->report_pos = 0; - dev->report_delay += dev->transmit_period; + sermouse_timer_on(dev, dev->transmit_period, 1); } else { dev->report_phase = REPORT_PHASE_PREPARE; - if (dev->report_period == 0LL) - dev->report_delay += dev->transmit_period; - else - dev->report_delay += dev->report_period; + sermouse_timer_on(dev, sermouse_report_period(dev), 1); } } @@ -436,17 +478,14 @@ sermouse_report_timer(void *priv) sermouse_update_data(dev); serial_write_fifo(dev->serial, dev->data[dev->report_pos]); if (++dev->report_pos == dev->data_len) { - if (dev->report_delay == 0LL) + if (!dev->report_enabled) sermouse_report_prepare(dev); else { - if (dev->report_period == 0LL) - dev->report_delay += dev->transmit_period; - else - dev->report_delay += dev->report_period; + sermouse_timer_on(dev, sermouse_report_period(dev), 1); dev->report_phase = REPORT_PHASE_PREPARE; } } else - dev->report_delay += dev->transmit_period; + sermouse_timer_on(dev, dev->transmit_period, 1); } } @@ -463,10 +502,7 @@ sermouse_command_timer(void *priv) sermouse_command_pos_check(dev, dev->id_len); if ((dev->command_phase == PHASE_IDLE) && (dev->type != MOUSE_TYPE_MSYSTEMS)) { /* This resets back to Microsoft-compatible mode. */ - dev->report_delay = 0LL; dev->report_phase = REPORT_PHASE_PREPARE; - dev->format = 7; - dev->transmit_period = sermouse_transmit_period(dev, 1200, -1); sermouse_report_timer((void *) dev); } break; @@ -549,6 +585,8 @@ ltsermouse_prompt_mode(mouse_t *dev, int prompt) dev->status &= 0xBF; if (prompt) dev->status |= 0x40; + /* timer_disable(&dev->report_timer); + dev->report_enabled = 0; */ } @@ -557,14 +595,17 @@ ltsermouse_command_phase(mouse_t *dev, int phase) { dev->command_pos = 0; dev->command_phase = phase; - dev->command_delay = dev->transmit_period; + timer_disable(&dev->command_timer); + sermouse_timer_on(dev, dev->transmit_period, 0); } static void ltsermouse_set_report_period(mouse_t *dev, int rps) { - dev->report_delay = dev->report_period = sermouse_transmit_period(dev, 9600, rps); + dev->report_period = sermouse_transmit_period(dev, 9600, rps); + timer_disable(&dev->report_timer); + sermouse_timer_on(dev, dev->report_period, 1); ltsermouse_prompt_mode(dev, 0); dev->report_phase = REPORT_PHASE_PREPARE; } @@ -577,7 +618,6 @@ ltsermouse_write(struct serial_s *serial, void *priv, uint8_t data) /* Stop reporting when we're processing a command. */ dev->report_phase = REPORT_PHASE_PREPARE; - dev->report_delay = 0LL; if (dev->want_data) switch (dev->want_data) { case 0x2A: @@ -640,7 +680,8 @@ ltsermouse_write(struct serial_s *serial, void *priv, uint8_t data) break; case 0x4F: ltsermouse_prompt_mode(dev, 0); - dev->report_delay = dev->report_period = 0LL; + dev->report_period = 0; + timer_disable(&dev->report_timer); dev->report_phase = REPORT_PHASE_PREPARE; sermouse_report_timer((void *) dev); break; @@ -679,6 +720,26 @@ ltsermouse_write(struct serial_s *serial, void *priv, uint8_t data) } +static void +sermouse_speed_changed(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->report_enabled) { + timer_disable(&dev->report_timer); + if (dev->report_phase == REPORT_PHASE_TRANSMIT) + sermouse_timer_on(dev, dev->transmit_period, 1); + else + sermouse_timer_on(dev, sermouse_report_period(dev), 1); + } + + if (dev->command_enabled) { + timer_disable(&dev->command_timer); + sermouse_timer_on(dev, dev->transmit_period, 0); + } +} + + static void sermouse_close(void *priv) { @@ -740,16 +801,10 @@ sermouse_init(const device_t *info) /* Default: Continuous reporting = no delay between reports. */ dev->report_phase = REPORT_PHASE_PREPARE; - dev->report_period = 0LL; - - if (info->local == MOUSE_TYPE_MSYSTEMS) - dev->report_delay = dev->transmit_period; - else - dev->report_delay = 0LL; + dev->report_period = 0; /* Default: Doing nothing - command transmit timer deactivated. */ dev->command_phase = PHASE_IDLE; - dev->command_delay = 0LL; dev->port = device_get_config_int("port"); @@ -761,8 +816,13 @@ sermouse_init(const device_t *info) mouse_serial_log("%s: port=COM%d\n", dev->name, dev->port + 1); - timer_add(sermouse_report_timer, &dev->report_delay, &dev->report_delay, dev); - timer_add(sermouse_command_timer, &dev->command_delay, &dev->command_delay, dev); + timer_add(&dev->report_timer, sermouse_report_timer, dev, 0); + timer_add(&dev->command_timer, sermouse_command_timer, dev, 0); + + if (info->local == MOUSE_TYPE_MSYSTEMS) { + sermouse_timer_on(dev, dev->transmit_period, 1); + dev->report_enabled = 1; + } /* Tell them how many buttons we have. */ mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); @@ -846,7 +906,7 @@ const device_t mouse_mssystems_device = { 0, MOUSE_TYPE_MSYSTEMS, sermouse_init, sermouse_close, NULL, - sermouse_poll, NULL, NULL, + sermouse_poll, sermouse_speed_changed, NULL, mssermouse_config }; @@ -855,7 +915,7 @@ const device_t mouse_msserial_device = { 0, 0, sermouse_init, sermouse_close, NULL, - sermouse_poll, NULL, NULL, + sermouse_poll, sermouse_speed_changed, NULL, mssermouse_config }; @@ -864,6 +924,6 @@ const device_t mouse_ltserial_device = { 0, 1, sermouse_init, sermouse_close, NULL, - sermouse_poll, NULL, NULL, + sermouse_poll, sermouse_speed_changed, NULL, ltsermouse_config }; diff --git a/src/network/net_3c503.c b/src/network/net_3c503.c index 04a471712..282219ab3 100644 --- a/src/network/net_3c503.c +++ b/src/network/net_3c503.c @@ -430,11 +430,10 @@ threec503_nic_hi_write(uint16_t addr, uint8_t val, void *priv) case 0x05: if ((dev->regs.gacfr & 0x0f) != (val & 0x0f)) { - mem_mapping_disable(&dev->ram_mapping); - switch (val & 0x0f) { case 0: /*ROM mapping*/ /* FIXME: Implement this when a BIOS is found/generated. */ + mem_mapping_disable(&dev->ram_mapping); break; case 9: /*RAM mapping*/ @@ -442,6 +441,7 @@ threec503_nic_hi_write(uint16_t addr, uint8_t val, void *priv) break; default: /*No ROM mapping*/ + mem_mapping_disable(&dev->ram_mapping); break; } } @@ -613,7 +613,8 @@ threec503_nic_init(const device_t *info) threec503_ram_read, NULL, NULL, threec503_ram_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, dev); - mem_mapping_disable(&dev->ram_mapping); + // mem_mapping_disable(&dev->ram_mapping); + dev->regs.gacfr = 0x09; /* Start with RAM mapping enabled. */ /* Attach ourselves to the network module. */ network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx); diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 853c39f04..0fd45626c 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -1147,8 +1147,8 @@ nic_mca_write(int port, uint8_t val, void *priv) /* Save the MCA register value. */ dev->pos_regs[port & 7] = val; - nic_ioremove(dev, dev->base_address); - + nic_ioremove(dev, dev->base_address); + /* This is always necessary so that the old handler doesn't remain. */ /* Get the new assigned I/O base address. */ dev->base_address = base[(dev->pos_regs[2] & 0xE0) >> 4]; @@ -1180,6 +1180,16 @@ nic_mca_write(int port, uint8_t val, void *priv) } } + +static uint8_t +nic_mca_feedb(void *priv) +{ + nic_t *dev = (nic_t *)priv; + + return (dev->pos_regs[2] & 0x01); +} + + static void * nic_init(const device_t *info) { @@ -1228,7 +1238,7 @@ nic_init(const device_t *info) } } else { - mca_add(nic_mca_read, nic_mca_write, dev); + mca_add(nic_mca_read, nic_mca_write, nic_mca_feedb, dev); } } diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index 7741378d4..39a2b5a71 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -612,19 +612,24 @@ wd_mca_write(int port, uint8_t val, void *priv) dev->irq = irq[dev->pos_regs[5] & 0x02]; /* Initialize the device if fully configured. */ - if (dev->pos_regs[2] & 0x01) { - /* Card enabled; register (new) I/O handler. */ - wd_io_set(dev, dev->base_address); + /* Register (new) I/O handler. */ + wd_io_set(dev, dev->base_address); - mem_mapping_set_addr(&dev->ram_mapping, dev->ram_addr, dev->ram_size); - if (dev->msr & WE_MSR_ENABLE_RAM) - mem_mapping_enable(&dev->ram_mapping); - else - mem_mapping_disable(&dev->ram_mapping); + mem_mapping_set_addr(&dev->ram_mapping, dev->ram_addr, dev->ram_size); + if (dev->msr & WE_MSR_ENABLE_RAM) + mem_mapping_enable(&dev->ram_mapping); + else + mem_mapping_disable(&dev->ram_mapping); - wdlog("%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, - dev->base_address, dev->irq, dev->ram_addr); - } + wdlog("%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name, + dev->base_address, dev->irq, dev->ram_addr); +} + + +static uint8_t +wd_mca_feedb(void *priv) +{ + return 1; } @@ -669,7 +674,7 @@ wd_init(const device_t *info) } if ((dev->board == WD8003ETA) || (dev->board == WD8003EA)) - mca_add(wd_mca_read, wd_mca_write, dev); + mca_add(wd_mca_read, wd_mca_write, wd_mca_feedb, dev); else { dev->base_address = device_get_config_hex16("base"); dev->irq = device_get_config_int("irq"); @@ -761,10 +766,8 @@ wd_init(const device_t *info) wd_ram_writeb, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, dev); } - if (dev->msr & WE_MSR_ENABLE_RAM) - mem_mapping_enable(&dev->ram_mapping); - else - mem_mapping_disable(&dev->ram_mapping); + + mem_mapping_disable(&dev->ram_mapping); /* Attach ourselves to the network module. */ network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx); diff --git a/src/network/slirp/ip.h b/src/network/slirp/ip.h index 4ced4ef17..f21178360 100644 --- a/src/network/slirp/ip.h +++ b/src/network/slirp/ip.h @@ -276,6 +276,10 @@ struct ipq { * * Note: ipf_next must be at same offset as ipq_next above */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + struct ipasfrag { #ifdef WORDS_BIGENDIAN u_char ip_v:4, @@ -298,7 +302,11 @@ struct ipasfrag { u_int16_t ip_sum; ipasfragp_32 ipf_next; /* next fragment */ ipasfragp_32 ipf_prev; /* previous fragment */ -}; +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) //WAS 0 +#endif /* * Structure stored in mbuf in inpcb.ip_options diff --git a/src/nmi.h b/src/nmi.h index e5e7c891d..72c2f507f 100644 --- a/src/nmi.h +++ b/src/nmi.h @@ -7,4 +7,5 @@ extern int nmi_auto_clear; extern void nmi_init(void); + extern void nmi_write(uint16_t port, uint8_t val, void *p); diff --git a/src/nvr.c b/src/nvr.c index ca55ed626..fe0cfd006 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -8,13 +8,13 @@ * * Implement a generic NVRAM/CMOS/RTC device. * - * Version: @(#)nvr.c 1.0.17 2018/11/02 + * Version: @(#)nvr.c 1.0.18 2019/03/16 * * Authors: Fred N. van Kempen, , * David Hrdlička, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2018 David Hrdlička. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2018,2019 David Hrdlička. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -156,7 +156,7 @@ onesec_timer(void *priv) nvr->onesec_cnt = 0; } - nvr->onesec_time += (int64_t)(10000 * TIMER_USEC); + timer_advance_u64(&nvr->onesec_time, (10000ULL * TIMER_USEC)); } @@ -194,7 +194,7 @@ nvr_init(nvr_t *nvr) } /* Set up our timer. */ - timer_add(onesec_timer, &nvr->onesec_time, TIMER_ALWAYS_ENABLED, nvr); + timer_add(&nvr->onesec_time, onesec_timer, nvr, 1); /* It does not need saving yet. */ nvr_dosave = 0; @@ -316,13 +316,9 @@ nvr_save(void) void -nvr_period_recalc(void) +nvr_close(void) { - /* Make sure we have been initialized. */ - if (saved_nvr == NULL) return; - - if ((saved_nvr->size != 0) && saved_nvr->recalc) - saved_nvr->recalc(saved_nvr); + saved_nvr = NULL; } diff --git a/src/nvr.h b/src/nvr.h index 7ede9b3ff..f315b7a51 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.10 2018/10/06 + * Version: @(#)nvr.h 1.0.11 2019/03/16 * * Author: Fred N. van Kempen, , * David Hrdlička, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2018 David Hrdlička. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2018,2019 David Hrdlička. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -70,7 +70,7 @@ typedef struct _nvr_ { int8_t irq; uint8_t onesec_cnt; - int64_t onesec_time; + pc_timer_t onesec_time; void *data; /* local data */ @@ -78,8 +78,6 @@ typedef struct _nvr_ { void (*reset)(struct _nvr_ *); void (*start)(struct _nvr_ *); void (*tick)(struct _nvr_ *); - void (*recalc)(struct _nvr_ *); - void (*ven_save)(void); uint8_t regs[NVR_MAXSIZE]; /* these are the registers */ @@ -102,6 +100,7 @@ extern void nvr_init(nvr_t *); extern wchar_t *nvr_path(wchar_t *str); extern FILE *nvr_fopen(wchar_t *str, wchar_t *mode); extern int nvr_load(void); +extern void nvr_close(void); extern void nvr_set_ven_save(void (*ven_save)(void)); extern int nvr_save(void); @@ -109,7 +108,6 @@ extern int nvr_is_leap(int year); extern int nvr_get_days(int month, int year); extern void nvr_time_get(struct tm *); extern void nvr_time_set(struct tm *); -extern void nvr_period_recalc(void); #endif /*EMU_NVR_H*/ diff --git a/src/nvr_at.c b/src/nvr_at.c index 455e6839f..b023ca332 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.14 2018/10/06 + * Version: @(#)nvr_at.c 1.0.15 2019/03/16 * * Authors: Fred N. van Kempen, * Miran Grca, * Mahod, * Sarah Walker, * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2019 Sarah Walker. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -232,9 +232,9 @@ #include "mem.h" #include "nmi.h" #include "pic.h" +#include "timer.h" #include "pit.h" #include "rom.h" -#include "timer.h" #include "device.h" #include "nvr.h" @@ -292,8 +292,10 @@ typedef struct { uint8_t addr; - int64_t ecount, - rtctime; + uint64_t ecount, + rtc_time; + pc_timer_t update_timer, + rtc_timer; } local_t; @@ -406,6 +408,8 @@ timer_update(void *priv) local_t *local = (local_t *)nvr->data; struct tm tm; + local->ecount = 0LL; + if (! (nvr->regs[RTC_REGB] & REGB_SET)) { /* Get the current time from the internal clock. */ nvr_time_get(&tm); @@ -443,27 +447,47 @@ timer_update(void *priv) picint(1 << nvr->irq); } } - - local->ecount = 0; } -/* Re-calculate the timer values. */ -static void -timer_recalc(nvr_t *nvr, int add) +static double +timer_nvr_period(nvr_t *nvr) { - local_t *local = (local_t *)nvr->data; - int64_t c, nt; + double dusec = (double) TIMER_USEC; - c = 1ULL << ((nvr->regs[RTC_REGA] & REGA_RS) - 1); - nt = (int64_t)(RTCCONST * c * (1<rtctime = nt; - return; - } else if (add == 1) - local->rtctime += nt; - else if (local->rtctime > nt) - local->rtctime = nt; + switch (nvr->regs[RTC_REGA] & REGA_RS) { + case 0: + default: + return 0.0; + case 1: + case 8: + return 3906.25 * dusec; + case 2: + case 9: + return 7812.5 * dusec; + case 3: + return 122.070 * dusec; + case 4: + return 244.141 * dusec; + case 5: + return 488.281 * dusec; + case 6: + return 976.5625 * dusec; + case 7: + return 1953.125 * dusec; + case 10: + return 15625.0 * dusec; + case 11: + return 31250.0 * dusec; + case 12: + return 62500.0 * dusec; + case 13: + return 125000.0 * dusec; + case 14: + return 250000.0 * dusec; + case 15: + return 500000.0 * dusec; + } } @@ -473,14 +497,14 @@ timer_intr(void *priv) nvr_t *nvr = (nvr_t *)priv; local_t *local = (local_t *)nvr->data; - if (! (nvr->regs[RTC_REGA] & REGA_RS)) { - local->rtctime = 0x7fffffff; + if (nvr->regs[RTC_REGA] & REGA_RS) { + local->rtc_time = timer_nvr_period(nvr); + timer_advance_u64(&local->rtc_timer, (uint64_t) local->rtc_time); + } else { + local->rtc_time = 0ULL; return; } - /* Update our timer interval. */ - timer_recalc(nvr, 1); - nvr->regs[RTC_REGC] |= REGC_PF; if (nvr->regs[RTC_REGB] & REGB_PIE) { nvr->regs[RTC_REGC] |= REGC_IRQF; @@ -506,7 +530,22 @@ timer_tick(nvr_t *nvr) rtc_tick(); /* Schedule the actual update. */ - local->ecount = (int64_t)((244.0 + 1984.0) * TIMER_USEC); + local->ecount = (244ULL + 1984ULL) * TIMER_USEC; + timer_set_delay_u64(&local->update_timer, local->ecount); + } +} + + +static void +nvr_pie_start(nvr_t *nvr) +{ + local_t *local = (local_t *)nvr->data; + + local->rtc_time = 0ULL; + timer_disable(&local->rtc_timer); + if ((nvr->regs[RTC_REGA] & REGA_RS) && ((nvr->regs[RTC_REGA] & 0x70) == 0x20)) { + local->rtc_time = timer_nvr_period(nvr); + timer_set_delay_u64(&local->rtc_timer, local->rtc_time); } } @@ -520,17 +559,14 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) struct tm tm; uint8_t old; - cycles -= ISA_CYCLES(8); + sub_cycles(ISA_CYCLES(8)); if (addr & 1) { old = nvr->regs[local->addr]; switch(local->addr) { case RTC_REGA: nvr->regs[RTC_REGA] = val; - if (val & REGA_RS) - timer_recalc(nvr, 1); - else - local->rtctime = 0x7fffffff; + nvr_pie_start(nvr); break; case RTC_REGB: @@ -544,7 +580,7 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) case RTC_REGC: /* R/O */ case RTC_REGD: /* R/O */ - break; + break; default: /* non-RTC registers are just NVRAM */ if (nvr->regs[local->addr] != val) { @@ -567,7 +603,7 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) } else { local->addr = (val & (nvr->size - 1)); if (!(machines[machine].flags & MACHINE_MCA) && - (machines[machine].flags & MACHINE_NONMI)) + !(machines[machine].flags & MACHINE_NONMI)) nmi_mask = (~val & 0x80); } } @@ -581,9 +617,9 @@ nvr_read(uint16_t addr, void *priv) local_t *local = (local_t *)nvr->data; uint8_t ret; - cycles -= ISA_CYCLES(8); + sub_cycles(ISA_CYCLES(8)); - if (addr & 1) switch(local->addr) { + if (addr & 1) switch(local->addr) { case RTC_REGA: ret = (nvr->regs[RTC_REGA] & 0x7f) | local->stat; break; @@ -602,9 +638,8 @@ nvr_read(uint16_t addr, void *priv) default: ret = nvr->regs[local->addr]; break; - } else { + } else ret = local->addr; - } return(ret); } @@ -630,7 +665,20 @@ nvr_reset(nvr_t *nvr) static void nvr_start(nvr_t *nvr) { + int i; + local_t *local = (local_t *) nvr->data; + struct tm tm; + int default_found = 0; + + for (i = 0; i < nvr->size; i++) { + if (nvr->regs[i] == local->def) + default_found++; + } + + if (default_found == nvr->size) + nvr->regs[0x0e] = 0xff; /* If load failed or it loaded an uninitialized NVR, + mark everything as bad. */ /* Initialize the internal and chip times. */ if (time_sync & TIME_SYNC_ENABLED) { @@ -646,14 +694,25 @@ nvr_start(nvr_t *nvr) /* Start the RTC. */ nvr->regs[RTC_REGA] = (REGA_RS2|REGA_RS1); nvr->regs[RTC_REGB] = REGB_2412; - timer_recalc(nvr, 1); } static void -nvr_recalc(nvr_t *nvr) +nvr_at_speed_changed(void *priv) { - timer_recalc(nvr, 0); + nvr_t *nvr = (nvr_t *) priv; + local_t *local = (local_t *) nvr->data; + + timer_disable(&local->rtc_timer); + if (local->rtc_time > 0ULL) + timer_set_delay_u64(&local->rtc_timer, local->rtc_time); + + timer_disable(&local->update_timer); + if (local->ecount > 0ULL) + timer_set_delay_u64(&local->update_timer, local->ecount); + + timer_disable(&nvr->onesec_time); + timer_set_delay_u64(&nvr->onesec_time, (10000ULL * TIMER_USEC)); } @@ -709,14 +768,13 @@ nvr_at_init(const device_t *info) nvr->reset = nvr_reset; nvr->start = nvr_start; nvr->tick = timer_tick; - nvr->recalc = nvr_recalc; /* Initialize the generic NVR. */ nvr_init(nvr); /* Start the timers. */ - timer_add(timer_update, &local->ecount, &local->ecount, nvr); - timer_add(timer_intr, &local->rtctime, TIMER_ALWAYS_ENABLED, nvr); + timer_add(&local->update_timer, timer_update, nvr, 0); + timer_add(&local->rtc_timer, timer_intr, nvr, 0); /* Set up the I/O handler for this device. */ io_sethandler(0x0070, 2, @@ -729,7 +787,14 @@ nvr_at_init(const device_t *info) static void nvr_at_close(void *priv) { - nvr_t *nvr = (nvr_t *)priv; + nvr_t *nvr = (nvr_t *) priv; + local_t *local = (local_t *) nvr->data; + + nvr_close(); + + timer_disable(&local->rtc_timer); + timer_disable(&local->update_timer); + timer_disable(&nvr->onesec_time); if (nvr->fn != NULL) free(nvr->fn); @@ -746,7 +811,7 @@ const device_t at_nvr_old_device = { DEVICE_ISA | DEVICE_AT, 0, nvr_at_init, nvr_at_close, NULL, - NULL, NULL, + NULL, nvr_at_speed_changed, NULL }; @@ -755,7 +820,7 @@ const device_t at_nvr_device = { DEVICE_ISA | DEVICE_AT, 1, nvr_at_init, nvr_at_close, NULL, - NULL, NULL, + NULL, nvr_at_speed_changed, NULL }; @@ -764,7 +829,7 @@ const device_t ps_nvr_device = { DEVICE_PS2, 2, nvr_at_init, nvr_at_close, NULL, - NULL, NULL, + NULL, nvr_at_speed_changed, NULL }; @@ -773,7 +838,7 @@ const device_t amstrad_nvr_device = { MACHINE_ISA | MACHINE_AT, 3, nvr_at_init, nvr_at_close, NULL, - NULL, NULL, + NULL, nvr_at_speed_changed, NULL }; @@ -782,6 +847,6 @@ const device_t ibmat_nvr_device = { DEVICE_ISA | DEVICE_AT, 4, nvr_at_init, nvr_at_close, NULL, - NULL, NULL, + NULL, nvr_at_speed_changed, NULL }; diff --git a/src/nvr_ps2.c b/src/nvr_ps2.c index e9823ac0b..5c943a0eb 100644 --- a/src/nvr_ps2.c +++ b/src/nvr_ps2.c @@ -44,6 +44,7 @@ #include "device.h" #include "io.h" #include "mem.h" +#include "timer.h" #include "nvr.h" #include "nvr_ps2.h" #include "rom.h" diff --git a/src/pc.c b/src/pc.c index a1aa9a5a1..4616050a1 100644 --- a/src/pc.c +++ b/src/pc.c @@ -29,17 +29,26 @@ #define HAVE_STDARG_H #include "86box.h" #include "config.h" +#include "mem.h" +#ifdef USE_NEW_DYNAREC +#ifdef USE_DYNAREC +#include "cpu_new/cpu.h" +# include "cpu_new/codegen.h" +#endif +#include "cpu_new/x86_ops.h" +#else #include "cpu/cpu.h" #ifdef USE_DYNAREC # include "cpu/codegen.h" #endif #include "cpu/x86_ops.h" +#endif #include "io.h" -#include "mem.h" #include "rom.h" #include "dma.h" #include "pci.h" #include "pic.h" +#include "timer.h" #include "pit.h" #include "random.h" #include "timer.h" @@ -108,7 +117,6 @@ int vid_cga_contrast = 0, /* (C) video */ enable_overscan = 0, /* (C) video */ force_43 = 0; /* (C) video */ int serial_enabled[SERIAL_MAX] = {0,0}, /* (C) enable serial ports */ - lpt_enabled = 0, /* (C) enable LPT ports */ bugger_enabled = 0, /* (C) enable ISAbugger */ isamem_type[ISAMEM_MAX] = { 0,0,0,0 }, /* (C) enable ISA mem cards */ isartc_type = 0; /* (C) enable ISA RTC card */ @@ -136,7 +144,6 @@ int fps, framecount; /* emulator % */ int CPUID; int output; int atfullspeed; -int cpuspeed2; int clockrate; wchar_t exe_path[1024]; /* path (dir) of executable */ @@ -146,7 +153,6 @@ FILE *stdlog = NULL; /* file to log output to */ int scrnsz_x = SCREEN_RES_X, /* current screen size, X */ scrnsz_y = SCREEN_RES_Y; /* current screen size, Y */ int config_changed; /* config has changed */ -int romset; /* current machine ID */ int title_update; int64_t main_time; @@ -465,9 +471,6 @@ usage: wcscpy(usr_path, cfg); else wcscat(usr_path, cfg); - - /* Make sure we have a trailing backslash. */ - plat_path_slash(usr_path); } /* At this point, we can safely create the full path name. */ @@ -507,26 +510,23 @@ usage: void -pc_full_speed(void) +pc_speed_changed(void) { - cpuspeed2 = cpuspeed; - - if (! atfullspeed) { - pc_log("Set fullspeed - %i %i %i\n", is386, AT, cpuspeed2); - setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); - } - atfullspeed = 1; - - nvr_period_recalc(); + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) + pit_set_clock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); + else + pit_set_clock(14318184.0); } void -pc_speed_changed(void) +pc_full_speed(void) { - setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); - - nvr_period_recalc(); + if (! atfullspeed) { + pc_log("Set fullspeed - %i %i\n", is386, AT); + pc_speed_changed(); + } + atfullspeed = 1; } @@ -534,12 +534,13 @@ pc_speed_changed(void) int pc_init_modules(void) { - int c, i; + int c, m; pc_log("Scanning for ROM images:\n"); - for (c=0,i=0; i= CPU_286) ? 2 : 1; atfullspeed = 0; random_init(); @@ -617,6 +609,8 @@ again2: hdc_init(); + video_reset_close(); + return(1); } @@ -665,9 +659,13 @@ pc_reset_hard_close(void) { ui_sb_set_ready(0); + /* Turn off timer processing to avoid potential segmentation faults. */ + timer_close(); + suppress_overscan = 0; nvr_save(); + nvr_close(); mouse_close(); @@ -686,6 +684,8 @@ pc_reset_hard_close(void) scsi_disk_close(); closeal(); + + video_reset_close(); } @@ -706,7 +706,9 @@ pc_reset_hard_init(void) /* Reset the general machine support modules. */ io_init(); - timer_reset(); + + /* Turn on and (re)initialize timer processing. */ + timer_init(); device_init(); @@ -765,9 +767,9 @@ pc_reset_hard_init(void) if (joystick_type != 7) gameport_update_joystick_type(); - if (config_changed) { - ui_sb_update_panes(); + ui_sb_update_panes(); + if (config_changed) { config_save(); config_changed = 0; @@ -784,9 +786,8 @@ pc_reset_hard_init(void) pic_reset(); cpu_cache_int_enabled = cpu_cache_ext_enabled = 0; + atfullspeed = 0; pc_full_speed(); - - setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); } @@ -838,12 +839,18 @@ pc_close(thread_t *ptr) plat_delay_ms(200); } +#ifdef USE_NEW_DYNAREC + codegen_close(); +#endif + nvr_save(); config_save(); plat_mouse_capture(0); + timer_close(); + lpt_devices_close(); for (i=0; i 0x0f) { - pci_log("pci_set_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); - return; + irq_line = pci_irqs[irq_routing]; } - irq_line = pci_irqs[irq_routing]; - pci_log("pci_set_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); + if (irq_line > 0x0f) { + pci_log("pci_set_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); + return; + } else + pci_log("pci_set_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); if (pci_irq_is_level(irq_line) && (pci_irq_hold[irq_line] & (1ULL << card))) { /* IRQ already held, do nothing. */ @@ -413,12 +417,18 @@ 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); - level = pci_irq_is_level(irq_line); + if (pci_type & PCI_NO_IRQ_STEERING) + level = 0; + else + level = pci_irq_is_level(irq_line); if (!level || !pci_irq_hold[irq_line]) { pci_log("pci_set_irq(%02X, %02X): Issuing %s-triggered IRQ (%sheld)\n", card, pci_int, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not "); /* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */ - picintlevel(1 << irq_line); + if (level) + picintlevel(1 << irq_line); + else + picint(1 << irq_line); } else if (level && pci_irq_hold[irq_line]) { pci_log("pci_set_irq(%02X, %02X): IRQ line already being held\n", card, pci_int); } @@ -509,15 +519,20 @@ pci_clear_irq(uint8_t card, uint8_t pci_int) return; } - irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3; - pci_log("pci_clear_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); + if (pci_type & PCI_NO_IRQ_STEERING) + irq_line = pci_cards[slot].read(0, 0x3c, pci_cards[slot].priv); + else { + irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3; + pci_log("pci_clear_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); - if (pci_irqs[irq_routing] > 0x0f) { + irq_line = pci_irqs[irq_routing]; + } + + if (irq_line > 0x0f) { pci_log("pci_clear_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); return; } - irq_line = pci_irqs[irq_routing]; pci_log("pci_clear_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); if (pci_irq_is_level(irq_line) && @@ -527,7 +542,10 @@ pci_clear_irq(uint8_t card, uint8_t pci_int) return; } - level = pci_irq_is_level(irq_line); + if (pci_type & PCI_NO_IRQ_STEERING) + level = 0; + else + level = pci_irq_is_level(irq_line); if (level) { pci_log("pci_clear_irq(%02X, %02X): Releasing this card's hold on the IRQ\n", card, pci_int); pci_irq_hold[irq_line] &= ~(1 << card); @@ -598,7 +616,12 @@ trc_reset(uint8_t val) if (val & 2) { device_reset_all_pci(); - port_92_reset(); + cpu_alt_reset = 0; + + mem_a20_alt = 0; + mem_a20_recalc(); + + flushmmucache(); pci_reset(); } @@ -642,10 +665,14 @@ pci_init(int type) trc_init(); - io_sethandler(0x04d0, 0x0002, - elcr_read,NULL,NULL, elcr_write,NULL,NULL, NULL); + pci_type = type; - if (type == PCI_CONFIG_TYPE_1) { + if (!(type & PCI_NO_IRQ_STEERING)) { + io_sethandler(0x04d0, 0x0002, + elcr_read,NULL,NULL, elcr_write,NULL,NULL, NULL); + } + + if ((type & PCI_CONFIG_TYPE_MASK) == PCI_CONFIG_TYPE_1) { io_sethandler(0x0cf8, 1, NULL,NULL,pci_cf8_read, NULL,NULL,pci_cf8_write, NULL); io_sethandler(0x0cfc, 4, @@ -660,7 +687,7 @@ pci_init(int type) for (c = 0; c < 4; c++) pci_irqs[c] = PCI_IRQ_DISABLED; - for (c = 0; c < 2; c++) { + for (c = 0; c < 3; c++) { pci_mirqs[c].enabled = 0; pci_mirqs[c].irq_line = PCI_IRQ_DISABLED; } @@ -699,12 +726,12 @@ pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), pci_log("pci_add_card(): Adding PCI CARD at specific slot %02X [SPECIFIC]\n", add_type); if (! PCI) { - pci_log("pci_add_card(): Adding PCI CARD failed (non-PCI machine) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); + pci_log("pci_add_card(): Adding PCI CARD failed (non-PCI machine) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : "SPECIFIC"))); return 0xff; } if (! last_pci_card) { - pci_log("pci_add_card(): Adding PCI CARD failed (no PCI slots) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); + pci_log("pci_add_card(): Adding PCI CARD failed (no PCI slots) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : "SPECIFIC"))); return 0xff; } @@ -714,17 +741,18 @@ pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), if (!dev->read && !dev->write) { if (((dev->type == PCI_CARD_NORMAL) && (add_type >= PCI_ADD_NORMAL)) || ((dev->type == PCI_CARD_ONBOARD) && (add_type == PCI_ADD_VIDEO)) || + ((dev->type == PCI_CARD_SCSI) && (add_type == PCI_ADD_SCSI)) || ((dev->id == add_type) && (add_type < PCI_ADD_NORMAL))) { dev->read = read; dev->write = write; dev->priv = priv; - pci_log("pci_add_card(): Adding PCI CARD to pci_cards[%i] (slot %02X) [%s]\n", i, dev->id, (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); + pci_log("pci_add_card(): Adding PCI CARD to pci_cards[%i] (slot %02X) [%s]\n", i, dev->id, (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : "SPECIFIC"))); return dev->id; } } } - pci_log("pci_add_card(): Adding PCI CARD failed (unable to find a suitable PCI slot) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); + pci_log("pci_add_card(): Adding PCI CARD failed (unable to find a suitable PCI slot) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : ((add_type == PCI_ADD_SCSI) ? "SCSI" : "SPECIFIC"))); return 0xff; } diff --git a/src/pci.h b/src/pci.h index 6e516aa1f..4476a970c 100644 --- a/src/pci.h +++ b/src/pci.h @@ -27,9 +27,13 @@ #define PCI_COMMAND_IO 0x01 #define PCI_COMMAND_MEM 0x02 +#define PCI_NO_IRQ_STEERING 0x8000 + #define PCI_CONFIG_TYPE_1 1 #define PCI_CONFIG_TYPE_2 2 +#define PCI_CONFIG_TYPE_MASK 0x7fff + #define PCI_INTA 1 #define PCI_INTB 2 #define PCI_INTC 3 @@ -37,18 +41,21 @@ #define PCI_MIRQ0 0 #define PCI_MIRQ1 1 +#define PCI_MIRQ2 2 #define PCI_IRQ_DISABLED -1 enum { PCI_CARD_NORMAL = 0, PCI_CARD_ONBOARD, + PCI_CARD_SCSI, PCI_CARD_SPECIAL }; #define PCI_ADD_NORMAL 0x80 #define PCI_ADD_VIDEO 0x81 +#define PCI_ADD_SCSI 0x82 typedef union { uint32_t addr; diff --git a/src/pic.c b/src/pic.c index 1a07fe01c..b0d872e00 100644 --- a/src/pic.c +++ b/src/pic.c @@ -21,10 +21,12 @@ #include #define HAVE_STDARG_H #include "86box.h" +#include "cpu/cpu.h" #include "machine/machine.h" #include "io.h" #include "pci.h" #include "pic.h" +#include "timer.h" #include "pit.h" @@ -124,6 +126,7 @@ picint_is_level(uint16_t irq) } +/* Should this really EOI *ALL* IRQ's at once? */ static void pic_autoeoi() { @@ -139,10 +142,12 @@ pic_autoeoi() pic.pend |= pic.icw3; } +#if 0 if ((pic_current & (1 << c)) && picint_is_level(c)) { if (((1 << c) != pic.icw3) || !AT) pic.pend |= 1 << c; } +#endif pic_updatepending(); return; @@ -155,7 +160,11 @@ void pic_write(uint16_t addr, uint8_t val, void *priv) { int c; + + addr &= ~0x06; + if (addr&1) { + pic_log("%04X:%04X: write: %02X\n", CS, cpu_state.pc, val); switch (pic.icw) { case 0: /*OCW1*/ pic.mask=val; @@ -163,27 +172,36 @@ pic_write(uint16_t addr, uint8_t val, void *priv) break; case 1: /*ICW2*/ pic.vector=val&0xF8; + pic_log("ICW%i ->", pic.icw + 1); if (pic.icw1 & 2) pic.icw=3; else pic.icw=2; + pic_log("ICW%i\n", pic.icw + 1); break; case 2: /*ICW3*/ pic.icw3 = val; pic_log("PIC1 ICW3 now %02X\n", val); + pic_log("ICW%i ->", pic.icw + 1); if (pic.icw1 & 1) pic.icw=3; else pic.icw=0; + pic_log("ICW%i\n", pic.icw + 1); break; case 3: /*ICW4*/ + pic_log("ICW%i ->", pic.icw + 1); pic.icw4 = val; pic.icw=0; + pic_log("ICW%i\n", pic.icw + 1); break; } } else { if (val & 16) { /*ICW1*/ pic.mask = 0; pic.mask2 = 0; + pic_log("ICW%i ->", pic.icw + 1); pic.icw = 1; pic.icw1 = val; + pic_log("ICW%i\n", pic.icw + 1); pic.ins = 0; + pic.pend = 0; /* Pending IRQ's are cleared. */ pic_updatepending(); } else if (!(val & 8)) { /*OCW2*/ @@ -195,10 +213,12 @@ pic_write(uint16_t addr, uint8_t val, void *priv) pic.pend |= pic.icw3; } +#if 0 if ((pic_current & (1 << (val & 7))) && picint_is_level(val & 7)) { if ((((1 << (val & 7)) != pic.icw3) || !AT)) pic.pend |= 1 << (val & 7); } +#endif pic_updatepending(); } else { @@ -212,10 +232,12 @@ pic_write(uint16_t addr, uint8_t val, void *priv) pic.pend |= pic.icw3; } +#if 0 if ((pic_current & (1 << c)) && picint_is_level(c)) { if ((((1 << c) != pic.icw3) || !AT)) pic.pend |= 1 << c; } +#endif if ((c == 1) && keywaiting) intclear &= ~1; @@ -235,16 +257,23 @@ pic_write(uint16_t addr, uint8_t val, void *priv) uint8_t pic_read(uint16_t addr, void *priv) { + addr &= ~0x06; + if (addr & 1) { pic_log("Read PIC mask %02X\n", pic.mask); + pic_log("%04X:%04X: Read PIC mask %02X\n", CS, cpu_state.pc, pic.mask); return pic.mask; } if (pic.read) { pic_log("Read PIC ins %02X\n", pic.ins); +#if 0 if (AT) return pic.ins | (pic2.ins ? 4 : 0); else return pic.ins; +#else + return pic.ins | (pic2.ins ? 4 : 0); +#endif } return pic.pend; } @@ -257,6 +286,13 @@ pic_init() } +void +pic_init_pcjr() +{ + io_sethandler(0x0020, 0x0008, pic_read, NULL, NULL, pic_write, NULL, NULL, NULL); +} + + static void pic2_autoeoi() { @@ -267,10 +303,12 @@ pic2_autoeoi() pic2.ins &= ~(1 << c); pic_update_mask(&pic2.mask2, pic2.ins); +#if 0 if (pic_current & (0x100 << c) && picint_is_level(c + 8)) { pic2.pend |= (1 << c); pic.pend |= (1 << pic2.icw3); } +#endif pic_updatepending(); return; @@ -309,20 +347,24 @@ pic2_write(uint16_t addr, uint8_t val, void *priv) } else { if (val & 16) { /*ICW1*/ pic2.mask = 0; - pic2.mask2=0; - pic2.icw=1; + pic2.mask2 = 0; + pic2.icw = 1; pic2.icw1 = val; pic2.ins = 0; + pic2.pend = 0; /* Pending IRQ's are cleared. */ + pic.pend &= ~4; pic_updatepending(); } else if (!(val & 8)) { /*OCW2*/ if ((val & 0xE0) == 0x60) { pic2.ins &= ~(1 << (val & 7)); pic_update_mask(&pic2.mask2, pic2.ins); +#if 0 if (pic_current & (0x100 << (val & 7)) && picint_is_level((val & 7) + 8)) { pic2.pend |= (1 << (val & 7)); pic.pend |= (1 << pic2.icw3); } +#endif pic_updatepending(); } else { @@ -331,10 +373,12 @@ pic2_write(uint16_t addr, uint8_t val, void *priv) pic2.ins &= ~(1<pend & ~target_pic->mask; + int ret = -1; int pic_int = c & 7; int pic_int_num = 1 << pic_int; int in_service = 0; -#if 0 + + in_service = (target_pic->ins & (pic_int_num - 1)); /* Is anything of higher priority already in service? */ + in_service |= (target_pic->ins & pic_int_num); /* Is the current IRQ already in service? */ if (AT) { - in_service = (target_pic->ins & (pic_int_num - 1)); + /* AT-specific stuff. */ if (c >= 8) - in_service |= (pic.ins & 0x03); + in_service |= (pic.ins & 0x03); /* IRQ 8 to 15, are IRQ's with higher priorities than the + cascade IRQ already in service? */ + /* For IRQ 0 to 7, the cascade IRQ's in service bit indicates that one or + more IRQ's between 8 and 15 are already in service. */ } - if (!AT) - in_service = (target_pic->ins & (pic_int_num - 1)); -#else - in_service = (target_pic->ins & (pic_int_num - 1)); - if (AT && (c >= 8)) - in_service |= (pic.ins & 0x03); -#endif if ((pending & pic_int_num) && !in_service) { - target_pic->pend &= ~pic_int_num; + if (!((pic_current & (1 << c)) && picint_is_level(c))) + target_pic->pend &= ~pic_int_num; target_pic->ins |= pic_int_num; pic_update_mask(&target_pic->mask2, target_pic->ins); if (AT && (c >= 8)) { + if (!((target_pic->pend & ~target_pic->mask) & ~target_pic->mask2)) + pic.pend &= ~(1 << pic2.icw3); pic.ins |= (1 << pic2.icw3); /*Cascade IRQ*/ pic_update_mask(&pic.mask2, pic.ins); } @@ -517,30 +563,31 @@ pic_process_interrupt(PIC* target_pic, int c) if (!c) pit_set_gate(&pit2, 0, 0); - return pic_int + target_pic->vector; - } else - return 0xFF; + ret = pic_int + target_pic->vector; + } + + return ret; } -uint8_t +int picinterrupt() { int c, d; - uint8_t ret; + int ret; for (c = 0; c <= 7; c++) { if (AT && ((1 << c) == pic.icw3)) { for (d = 8; d <= 15; d++) { ret = pic_process_interrupt(&pic2, d); - if (ret != 0xFF) return ret; + if (ret != -1) return ret; } } else { ret = pic_process_interrupt(&pic, c); - if (ret != 0xFF) return ret; + if (ret != -1) return ret; } } - return 0xFF; + return -1; } diff --git a/src/pic.h b/src/pic.h index b300c11a9..c164a0aa9 100644 --- a/src/pic.h +++ b/src/pic.h @@ -15,13 +15,14 @@ extern int pic_intpending; extern void pic_init(void); +extern void pic_init_pcjr(void); extern void pic2_init(void); extern void pic_reset(void); extern void picint(uint16_t num); extern void picintlevel(uint16_t num); extern void picintc(uint16_t num); -extern uint8_t picinterrupt(void); +extern int picinterrupt(void); extern void picclear(int num); extern void dumppic(void); diff --git a/src/piix.h b/src/piix.h index 1cfc22c8a..6de1d65b3 100644 --- a/src/piix.h +++ b/src/piix.h @@ -19,8 +19,3 @@ extern const device_t piix_device; extern const device_t piix_pb640_device; extern const device_t piix3_device; - -extern int piix_bus_master_dma_read(int channel, uint8_t *data, int transfer_length, void *priv); -extern int piix_bus_master_dma_write(int channel, uint8_t *data, int transfer_length, void *priv); - -extern void piix_bus_master_set_irq(int channel, void *priv); diff --git a/src/pit.c b/src/pit.c index 99e0e97b6..f260541d1 100644 --- a/src/pit.c +++ b/src/pit.c @@ -3,6 +3,9 @@ Write aa55 Expects aa55 back*/ #include +#if 1 +#include +#endif #include #include #include @@ -13,6 +16,7 @@ #include "io.h" #include "nmi.h" #include "pic.h" +#include "timer.h" #include "pit.h" #include "ppi.h" #include "device.h" @@ -23,694 +27,772 @@ #include "video/video.h" -/*B0 to 40, two writes to 43, then two reads - value does not change!*/ -/*B4 to 40, two writes to 43, then two reads - value _does_ change!*/ -int64_t displine; +PIT pit, pit2; +double cpuclock, PITCONSTD, + SYSCLK, + isa_timing, bus_timing; -PIT pit, - pit2; -float cpuclock; -float /*isa_timing, */bus_timing; +uint64_t PITCONST, + CGACONST, + MDACONST, HERCCONST, + VGACONST1, VGACONST2, + RTCCONST; -double PITCONST; -float CGACONST; -float MDACONST; -float VGACONST1, - VGACONST2; -float RTCCONST; +int io_delay = 5; -int64_t firsttime=1; -void setrtcconst(float clock) + +int64_t firsttime = 1; + + +static void pit_dump_and_disable_timer(PIT *pit, int t); + + +static void +pit_set_out(PIT *pit, int t, int out) { - /* Set default CPU/crystal clock and xt_cpu_multi. */ - cpuclock = 14318184.0; - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) { - cpuclock = clock; - PITCONST=cpuclock/1193182.0; - CGACONST=(cpuclock/(19687503.0/11.0)); - xt_cpu_multi = 1; - } else { - PITCONST=12.0; - CGACONST=8.0; - xt_cpu_multi = 3; - switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed) { - case 7159092: - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_flags & CPU_ALTERNATE_XTAL) { - cpuclock = 28636368.0; - xt_cpu_multi = 4; - } else - xt_cpu_multi = 2; - break; - case 8000000: - cpuclock = 24000000.0; - break; - case 9545456: - cpuclock = 28636368.0; - break; - case 10000000: - cpuclock = 30000000.0; - break; - case 12000000: - cpuclock = 36000000.0; - break; - case 16000000: - cpuclock = 48000000.0; - break; - default: - if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_flags & CPU_ALTERNATE_XTAL) { - cpuclock = 28636368.0; - xt_cpu_multi = 6; + pit->set_out_funcs[t](out, pit->out[t]); + pit->out[t] = out; +} + + +static void +pit_set_gate_no_timer(PIT *pit, int t, int gate) +{ + int64_t l = pit->l[t] ? pit->l[t] : 0x10000LL; + + if (pit->disabled[t]) { + pit->gate[t] = gate; + return; + } + + switch (pit->m[t]) { + case 0: /*Interrupt on terminal count*/ + case 4: /*Software triggered strobe*/ + if (pit->using_timer[t] && !pit->running[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); + pit->enabled[t] = gate; + break; + case 1: /*Hardware retriggerable one-shot*/ + case 5: /*Hardware triggered stobe*/ + if (gate && !pit->gate[t]) { + pit->count[t] = l; + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); + pit_set_out(pit, t, 0); + pit->thit[t] = 0; + pit->enabled[t] = 1; + } + break; + case 2: /*Rate generator*/ + if (gate && !pit->gate[t]) { + pit->count[t] = l - 1; + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); + pit_set_out(pit, t, 1); + pit->thit[t] = 0; + } + pit->enabled[t] = gate; + break; + case 3: /*Square wave mode*/ + if (gate && !pit->gate[t]) { + pit->count[t] = l; + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(((l + 1) >> 1) * PITCONST)); + pit_set_out(pit, t, 1); + pit->thit[t] = 0; + } + pit->enabled[t] = gate; + break; + } + + pit->gate[t] = gate; + pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; + if (pit->using_timer[t] && !pit->running[t]) + pit_dump_and_disable_timer(pit, t); +} + + +static void +pit_over(PIT *pit, int t) +{ + int64_t l = pit->l[t] ? pit->l[t] : 0x10000; + + if (pit->disabled[t]) { + pit->count[t] += 0xffff; + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST)); + return; + } + + switch (pit->m[t]) { + case 0: /*Interrupt on terminal count*/ + case 1: /*Hardware retriggerable one-shot*/ + if (!pit->thit[t]) + pit_set_out(pit, t, 1); + pit->thit[t] = 1; + pit->count[t] += 0xffff; + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST)); + break; + case 2: /*Rate generator*/ + pit->count[t] += l; + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); + pit_set_out(pit, t, 0); + pit_set_out(pit, t, 1); + break; + case 3: /*Square wave mode*/ + if (pit->out[t]) { + pit_set_out(pit, t, 0); + pit->count[t] += (l >> 1); + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)((l >> 1) * PITCONST)); + } else { + pit_set_out(pit, t, 1); + pit->count[t] += ((l + 1) >> 1); + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(((l + 1) >> 1) * PITCONST)); + } + break; + case 4: /*Software triggered strobe*/ + if (!pit->thit[t]) { + pit_set_out(pit, t, 0); + pit_set_out(pit, t, 1); + } + if (pit->newcount[t]) { + pit->newcount[t] = 0; + pit->count[t] += l; + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); + } else { + pit->thit[t] = 1; + pit->count[t] += 0xffff; + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST)); + } + break; + case 5: /*Hardware triggered strobe*/ + if (!pit->thit[t]) { + pit_set_out(pit, t, 0); + pit_set_out(pit, t, 1); + } + pit->thit[t] = 1; + pit->count[t] += 0xffff; + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST)); + break; + } + + pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; + if (pit->using_timer[t] && !pit->running[t]) + pit_dump_and_disable_timer(pit, t); +} + + +static void +pit_clock(PIT *pit, int t) +{ + if (pit->thit[t] || !pit->enabled[t]) return; + + if (pit->using_timer[t]) return; + + pit->count[t] -= (pit->m[t] == 3) ? 2 : 1; + if (pit->count[t] == 0) + pit_over(pit, t); +} + + +static void +pit_timer_over(void *p) +{ + PIT_nr *pit_nr = (PIT_nr *)p; + PIT *pit = pit_nr->pit; + int t = pit_nr->nr; + + pit_over(pit, t); +} + + +static int +pit_read_timer(PIT *pit, int t) +{ + int read; + + if (pit->using_timer[t] && !(pit->m[t] == 3 && !pit->gate[t]) && timer_is_enabled(&pit->timer[t])) { + // read = (int)((timer_get_remaining_u64(&pit->timer[t])) / PITCONST); + read = (int) round(((double) timer_get_remaining_u64(&pit->timer[t])) / (PITCONSTD * 4294967296.0)); + if (pit->m[t] == 2) + read++; + if (read < 0) + read = 0; + if (read > 0x10000) + read = 0x10000; + if (pit->m[t] == 3) + read <<= 1; + return read; + } + if (pit->m[t] == 2) + return pit->count[t] + 1; + return pit->count[t]; +} + + +/*Dump timer count back to pit->count[], and disable timer. This should be used + when stopping a PIT timer, to ensure the correct value can be read back.*/ +static void +pit_dump_and_disable_timer(PIT *pit, int t) +{ + if (pit->using_timer[t] && timer_is_enabled(&pit->timer[t])) { + pit->count[t] = pit_read_timer(pit, t); + timer_disable(&pit->timer[t]); + } +} + + +static void +pit_load(PIT *pit, int t) +{ + int l = pit->l[t] ? pit->l[t] : 0x10000; + + pit->newcount[t] = 0; + pit->disabled[t] = 0; + + switch (pit->m[t]) { + case 0: /*Interrupt on terminal count*/ + pit->count[t] = l; + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); + pit_set_out(pit, t, 0); + pit->thit[t] = 0; + pit->enabled[t] = pit->gate[t]; + break; + case 1: /*Hardware retriggerable one-shot*/ + pit->enabled[t] = 1; + break; + case 2: /*Rate generator*/ + if (pit->initial[t]) { + pit->count[t] = l - 1; + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)((l - 1) * PITCONST)); + pit_set_out(pit, t, 1); + pit->thit[t] = 0; + } + pit->enabled[t] = pit->gate[t]; + break; + case 3: /*Square wave mode*/ + if (pit->initial[t]) { + pit->count[t] = l; + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(((l + 1) >> 1) * PITCONST)); + pit_set_out(pit, t, 1); + pit->thit[t] = 0; + } + pit->enabled[t] = pit->gate[t]; + break; + case 4: /*Software triggered strobe*/ + if (!pit->thit[t] && !pit->initial[t]) + pit->newcount[t] = 1; + else { + pit->count[t] = l; + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); + pit_set_out(pit, t, 0); + pit->thit[t] = 0; + } + pit->enabled[t] = pit->gate[t]; + break; + case 5: /*Hardware triggered strobe*/ + pit->enabled[t] = 1; + break; + } + + pit->initial[t] = 0; + pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; + if (pit->using_timer[t] && !pit->running[t]) + pit_dump_and_disable_timer(pit, t); +} + + +static void +pit_write(uint16_t addr, uint8_t val, void *priv) +{ + PIT *pit = (PIT *)priv; + double sv = 0.0; + int t; + + switch (addr & 3) { + case 3: /* control */ + if ((val & 0xC0) == 0xC0) { + if (!(val & 0x20)) { + if (val & 2) + pit->rl[0] = (uint32_t)pit_read_timer(pit, 0); + if (val & 4) + pit->rl[1] = (uint32_t)pit_read_timer(pit, 1); + if (val & 8) + pit->rl[2] = (uint32_t)pit_read_timer(pit, 2); + } + if (!(val & 0x10)) { + if (val & 2) { + pit->read_status[0] = (pit->ctrls[0] & 0x3f) | (pit->out[0] ? 0x80 : 0); + pit->do_read_status[0] = 1; } + if (val & 4) { + pit->read_status[1] = (pit->ctrls[1] & 0x3f) | (pit->out[1] ? 0x80 : 0); + pit->do_read_status[1] = 1; + } + if (val & 8) { + pit->read_status[2] = (pit->ctrls[2] & 0x3f) | (pit->out[2] ? 0x80 : 0); + pit->do_read_status[2] = 1; + } + } + return; + } + t = val >> 6; + pit->ctrl = val; + if ((val >> 7) == 3) + return; + + if (!(pit->ctrl & 0x30)) { + pit->rl[t] = (uint32_t)pit_read_timer(pit, t); + pit->ctrl |= 0x30; + pit->rereadlatch[t] = 0; + pit->rm[t] = 3; + pit->latched[t] = 1; + } else { + pit->ctrls[t] = val; + pit->rm[t] = pit->wm[t] = (pit->ctrl >> 4) & 3; + pit->m[t] = (val >> 1) & 7; + if (pit->m[t] > 5) + pit->m[t] &= 3; + if (!(pit->rm[t])) { + pit->rm[t] = 3; + pit->rl[t] = (uint32_t)pit_read_timer(pit, t); + } + pit->rereadlatch[t] = 1; + pit->initial[t] = 1; + if (!pit->m[t]) + pit_set_out(pit, t, 0); + else + pit_set_out(pit, t, 1); + pit->disabled[t] = 1; + } + pit->wp = 0; + pit->thit[t] = 0; + break; + + case 0: + case 1: + case 2: /* the actual timers */ + t = addr & 3; + switch (pit->wm[t]) { + case 0: + pit->l[t] &= 0xff; + pit->l[t] |= (val << 8); + pit_load(pit, t); + pit->wm[t] = 3; + break; + case 1: + pit->l[t] = val; + pit_load(pit, t); + break; + case 2: + pit->l[t] = (val << 8); + pit_load(pit, t); + break; + case 3: + pit->l[t] &= 0xFF00; + pit->l[t] |= val; + pit->wm[t] = 0; break; } - if (cpuclock == 28636368.0) { - PITCONST=24.0; - CGACONST=16.0; - } else if (cpuclock != 14318184.0) { - PITCONST=cpuclock/1193182.0; - CGACONST=(cpuclock/(19687503.0/11.0)); - } - } - xt_cpu_multi <<= TIMER_SHIFT; - MDACONST=(cpuclock/2032125.0); - VGACONST1=(cpuclock/25175000.0); - VGACONST2=(cpuclock/28322000.0); - RTCCONST=cpuclock/32768.0; - TIMER_USEC = (int64_t)((cpuclock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); - bus_timing = cpuclock/(double)cpu_busspeed; -} - -void setpitclock(float clock) -{ - video_update_timing(); - device_speed_changed(); -} - -void pit_reset(PIT *pit) -{ - void (*old_set_out_funcs[3])(int new_out, int old_out); - PIT_nr old_pit_nr[3]; - - memcpy(old_set_out_funcs, pit->set_out_funcs, 3 * sizeof(void *)); - memcpy(old_pit_nr, pit->pit_nr, 3 * sizeof(PIT_nr)); - memset(pit, 0, sizeof(PIT)); - memcpy(pit->set_out_funcs, old_set_out_funcs, 3 * sizeof(void *)); - memcpy(pit->pit_nr, old_pit_nr, 3 * sizeof(PIT_nr)); - - pit->l[0] = 0xFFFF; pit->c[0] = 0xFFFF*PITCONST; - pit->l[1] = 0xFFFF; pit->c[1] = 0xFFFF*PITCONST; - pit->l[2] = 0xFFFF; pit->c[2] = 0xFFFF*PITCONST; - pit->m[0] = pit->m[1] = pit->m[2] = 0; - pit->ctrls[0] = pit->ctrls[1] = pit->ctrls[2] = 0; - pit->thit[0]=1; - pit->gate[0] = pit->gate[1] = 1; - pit->gate[2] = 0; - pit->using_timer[0] = pit->using_timer[1] = pit->using_timer[2] = 1; -} - -void clearpit() -{ - pit.c[0]=(pit.l[0]<<2); -} - -static void pit_set_out(PIT *pit, int t, int out) -{ - pit->set_out_funcs[t](out, pit->out[t]); - pit->out[t] = out; -} - -static void pit_load(PIT *pit, int t) -{ - int l = pit->l[t] ? pit->l[t] : 0x10000; - timer_clock(); - pit->newcount[t] = 0; - pit->disabled[t] = 0; - switch (pit->m[t]) - { - case 0: /*Interrupt on terminal count*/ - pit->count[t] = l; - pit->c[t] = (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 0); - pit->thit[t] = 0; - pit->enabled[t] = pit->gate[t]; - break; - case 1: /*Hardware retriggerable one-shot*/ - pit->enabled[t] = 1; - break; - case 2: /*Rate generator*/ - if (pit->initial[t]) - { - pit->count[t] = l - 1; - pit->c[t] = (int64_t)(((((int64_t) l) - 1LL) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 1); - pit->thit[t] = 0; - } - pit->enabled[t] = pit->gate[t]; - break; - case 3: /*Square wave mode*/ - if (pit->initial[t]) - { - pit->count[t] = l; - pit->c[t] = (int64_t)((((((int64_t) l) + 1LL) >> 1) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 1); - pit->thit[t] = 0; - } - pit->enabled[t] = pit->gate[t]; - break; - case 4: /*Software triggered stobe*/ - if (!pit->thit[t] && !pit->initial[t]) - pit->newcount[t] = 1; - else - { - pit->count[t] = l; - pit->c[t] = (int64_t)((l << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 0); - pit->thit[t] = 0; - } - pit->enabled[t] = pit->gate[t]; - break; - case 5: /*Hardware triggered stobe*/ - pit->enabled[t] = 1; - break; - } - pit->initial[t] = 0; - pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; - timer_update_outstanding(); -} - -void pit_set_gate_no_timer(PIT *pit, int t, int gate) -{ - int64_t l = pit->l[t] ? pit->l[t] : 0x10000; - - if (pit->disabled[t]) - { - pit->gate[t] = gate; - return; - } - - switch (pit->m[t]) - { - case 0: /*Interrupt on terminal count*/ - case 4: /*Software triggered stobe*/ - pit->enabled[t] = gate; - break; - case 1: /*Hardware retriggerable one-shot*/ - case 5: /*Hardware triggered stobe*/ - if (gate && !pit->gate[t]) - { - pit->count[t] = l; - pit->c[t] = (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 0); - pit->thit[t] = 0; - pit->enabled[t] = 1; - } - break; - case 2: /*Rate generator*/ - if (gate && !pit->gate[t]) - { - pit->count[t] = l - 1; - pit->c[t] = (int64_t)(((((int64_t) l) - 1LL) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 1); - pit->thit[t] = 0; - } - pit->enabled[t] = gate; - break; - case 3: /*Square wave mode*/ - if (gate && !pit->gate[t]) - { - pit->count[t] = l; - pit->c[t] = (int64_t)((((((int64_t) l) + 1LL) >> 1) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 1); - pit->thit[t] = 0; - } - pit->enabled[t] = gate; - break; - } - pit->gate[t] = gate; - pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; -} - -void pit_set_gate(PIT *pit, int t, int gate) -{ - if (pit->disabled[t]) - { - pit->gate[t] = gate; - return; - } - - timer_process(); - - pit_set_gate_no_timer(pit, t, gate); - - timer_update_outstanding(); -} - -static void pit_over(PIT *pit, int t) -{ - int64_t l = pit->l[t] ? pit->l[t] : 0x10000; - if (pit->disabled[t]) - { - pit->count[t] += 0xffff; - pit->c[t] += (int64_t)((0xffffLL << TIMER_SHIFT) * PITCONST); - return; - } - - switch (pit->m[t]) - { - case 0: /*Interrupt on terminal count*/ - case 1: /*Hardware retriggerable one-shot*/ - if (!pit->thit[t]) - pit_set_out(pit, t, 1); - pit->thit[t] = 1; - pit->count[t] += 0xffff; - pit->c[t] += (int64_t)((0xffffLL << TIMER_SHIFT) * PITCONST); - break; - case 2: /*Rate generator*/ - pit->count[t] += l; - pit->c[t] += (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST); - pit_set_out(pit, t, 0); - pit_set_out(pit, t, 1); - break; - case 3: /*Square wave mode*/ - if (pit->out[t]) - { - pit_set_out(pit, t, 0); - pit->count[t] += (l >> 1); - pit->c[t] += (int64_t)(((((int64_t) l) >> 1) << TIMER_SHIFT) * PITCONST); - } - else - { - pit_set_out(pit, t, 1); - pit->count[t] += ((l + 1) >> 1); - pit->c[t] = (int64_t)((((((int64_t) l) + 1LL) >> 1) << TIMER_SHIFT) * PITCONST); - } - break; - case 4: /*Software triggered strove*/ - if (!pit->thit[t]) - { - pit_set_out(pit, t, 0); - pit_set_out(pit, t, 1); - } - if (pit->newcount[t]) - { - pit->newcount[t] = 0; - pit->count[t] += l; - pit->c[t] += (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST); - } - else - { - pit->thit[t] = 1; - pit->count[t] += 0xffff; - pit->c[t] += (int64_t)((0xffffLL << TIMER_SHIFT) * PITCONST); - } - break; - case 5: /*Hardware triggered strove*/ - if (!pit->thit[t]) - { - pit_set_out(pit, t, 0); - pit_set_out(pit, t, 1); - } - pit->thit[t] = 1; - pit->count[t] += 0xffff; - pit->c[t] += (int64_t)((0xffffLL << TIMER_SHIFT) * PITCONST); - break; - } - pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; -} - -int pit_get_timer_0() -{ - int read = (int)((pit.c[0] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; - if (pit.m[0] == 2) - read++; - if (read < 0) - read = 0; - if (read > 0x10000) - read = 0x10000; - if (pit.m[0] == 3) - read <<= 1; - return read; -} - -static int pit_read_timer(PIT *pit, int t) -{ - timer_clock(); - if (pit->using_timer[t] && !(pit->m[t] == 3 && !pit->gate[t])) - { - int read = (int)((pit->c[t] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; - if (pit->m[t] == 2) - read++; - if (read < 0) - read = 0; - if (read > 0x10000) - read = 0x10000; - if (pit->m[t] == 3) - read <<= 1; - return read; - } - if (pit->m[t] == 2) - return pit->count[t] + 1; - return pit->count[t]; -} - -void pit_write(uint16_t addr, uint8_t val, void *p) -{ - PIT *pit = (PIT *)p; - int t; - double sv = 0.0; - - switch (addr&3) - { - case 3: /*CTRL*/ - if ((val&0xC0)==0xC0) - { - if (!(val&0x20)) - { - if (val & 2) - pit->rl[0] = pit_read_timer(pit, 0); - if (val & 4) - pit->rl[1] = pit_read_timer(pit, 1); - if (val & 8) - pit->rl[2] = pit_read_timer(pit, 2); - } - if (!(val & 0x10)) - { - if (val & 2) - { - pit->read_status[0] = (pit->ctrls[0] & 0x3f) | (pit->out[0] ? 0x80 : 0); - pit->do_read_status[0] = 1; - } - if (val & 4) - { - pit->read_status[1] = (pit->ctrls[1] & 0x3f) | (pit->out[1] ? 0x80 : 0); - pit->do_read_status[1] = 1; - } - if (val & 8) - { - pit->read_status[2] = (pit->ctrls[2] & 0x3f) | (pit->out[2] ? 0x80 : 0); - pit->do_read_status[2] = 1; - } - } - return; - } - t = val >> 6; - pit->ctrl=val; - if ((val>>7)==3) - { - return; - } - if (!(pit->ctrl&0x30)) - { - pit->rl[t] = pit_read_timer(pit, t); - pit->ctrl |= 0x30; - pit->rereadlatch[t] = 0; - pit->rm[t] = 3; - pit->latched[t] = 1; - } - else - { - pit->ctrls[t] = val; - pit->rm[t]=pit->wm[t]=(pit->ctrl>>4)&3; - pit->m[t]=(val>>1)&7; - if (pit->m[t]>5) - pit->m[t]&=3; - if (!(pit->rm[t])) - { - pit->rm[t]=3; - pit->rl[t] = pit_read_timer(pit, t); - } - pit->rereadlatch[t]=1; - pit->initial[t] = 1; - if (!pit->m[t]) - pit_set_out(pit, t, 0); - else - pit_set_out(pit, t, 1); - pit->disabled[t] = 1; - } - pit->wp=0; - pit->thit[t]=0; - break; - case 0: case 1: case 2: /*Timers*/ - t=addr&3; - switch (pit->wm[t]) - { - case 1: - pit->l[t]=val; - pit_load(pit, t); - break; - case 2: - pit->l[t]=(val<<8); - pit_load(pit, t); - break; - case 0: - pit->l[t]&=0xFF; - pit->l[t]|=(val<<8); - pit_load(pit, t); - pit->wm[t]=3; - break; - case 3: - pit->l[t]&=0xFF00; - pit->l[t]|=val; - pit->wm[t]=0; - break; - } /* PIT latches are in fractions of 60 ms, so convert to sample using the formula below. */ sv = (((double) pit->l[2]) / 60.0) * 16384.0; speakval = ((int) sv) - 0x2000; - if (speakval>0x2000) speakval=0x2000; - break; - } + if (speakval > 0x2000) + speakval = 0x2000; + break; + } } -uint8_t pit_read(uint16_t addr, void *p) + +static uint8_t +pit_read(uint16_t addr, void *priv) { - PIT *pit = (PIT *)p; - int64_t t; - uint8_t temp = 0xff; - switch (addr&3) - { - case 0: case 1: case 2: /*Timers*/ - t = addr & 3; - if (pit->do_read_status[t]) - { - pit->do_read_status[t] = 0; - temp = pit->read_status[t]; - break; - } - if (pit->rereadlatch[addr & 3] && !pit->latched[addr & 3]) - { - pit->rereadlatch[addr & 3] = 0; - pit->rl[t] = pit_read_timer(pit, t); - } - switch (pit->rm[addr & 3]) - { - case 0: - temp = pit->rl[addr & 3] >> 8; - pit->rm[addr & 3] = 3; - pit->latched[addr & 3] = 0; - pit->rereadlatch[addr & 3] = 1; - break; - case 1: - temp = (pit->rl[addr & 3]) & 0xFF; - pit->latched[addr & 3] = 0; - pit->rereadlatch[addr & 3] = 1; - break; - case 2: - temp = (pit->rl[addr & 3]) >> 8; - pit->latched[addr & 3] = 0; - pit->rereadlatch[addr & 3] = 1; - break; - case 3: - temp = (pit->rl[addr & 3]) & 0xFF; - if (pit->m[addr & 3] & 0x80) - pit->m[addr & 3] &= 7; - else - pit->rm[addr & 3] = 0; - break; - } - break; - case 3: /*Control*/ - temp = pit->ctrl; - break; - } - return temp; + PIT *pit = (PIT *)priv; + uint8_t temp = 0xff; + int t; + + switch (addr & 3) { + case 3: /* control */ + temp = pit->ctrl; + break; + + case 0: + case 1: + case 2: /*the actual timers */ + t = addr & 3; + if (pit->do_read_status[t]) { + pit->do_read_status[t] = 0; + temp = pit->read_status[t]; + break; + } + if (pit->rereadlatch[addr & 3] && !pit->latched[addr & 3]) { + pit->rereadlatch[addr & 3] = 0; + pit->rl[t] = pit_read_timer(pit, t); + } + switch (pit->rm[addr & 3]) { + case 0: + temp = pit->rl[addr & 3] >> 8; + pit->rm[addr & 3] = 3; + pit->latched[addr & 3] = 0; + pit->rereadlatch[addr & 3] = 1; + break; + + case 1: + temp = (pit->rl[addr & 3]) & 0xff; + pit->latched[addr & 3] = 0; + pit->rereadlatch[addr & 3] = 1; + break; + + case 2: + temp = (pit->rl[addr & 3]) >> 8; + pit->latched[addr & 3] = 0; + pit->rereadlatch[addr & 3] = 1; + break; + + case 3: + temp = (pit->rl[addr & 3]) & 0xff; + if (pit->m[addr & 3] & 0x80) + pit->m[addr & 3] &= 7; + else + pit->rm[addr & 3] = 0; + break; + } + break; + } + + return temp; } -void pit_timer_over(void *p) -{ - PIT_nr *pit_nr = (PIT_nr *)p; - PIT *pit = pit_nr->pit; - int64_t timer = pit_nr->nr; - pit_over(pit, timer); +/* FIXME: Should be removed. */ +static void +pit_null_timer(int new_out, int old_out) +{ } -void pit_clock(PIT *pit, int t) + +/* FIXME: Should be moved to machine.c (default for most machine). */ +static void +pit_irq0_timer(int new_out, int old_out) { - if (pit->thit[t] || !pit->enabled[t]) - return; - - if (pit->using_timer[t]) - return; - - pit->count[t] -= (pit->m[t] == 3) ? 2 : 1; - if (!pit->count[t]) - pit_over(pit, t); + if (new_out && !old_out) + picint(1); + + if (!new_out) + picintc(1); } -static int64_t pit_read_timer_ex(PIT *pit, int t) + +static void +pit_speaker_timer(int new_out, int old_out) { - int64_t read; - timer_clock(); - if (pit->using_timer[t] && !(pit->m[t] == 3 && !pit->gate[t])) - { - read = (int)(pit->c[t] + ((1 << TIMER_SHIFT) - 1)); - if (pit->m[t] == 2) - read += (1LL << TIMER_SHIFT) * PITCONST; - if (read < 0) - read = 0; - if (read > ((0x10000LL << TIMER_SHIFT) * PITCONST)) - read = ((0x10000LL << TIMER_SHIFT) * PITCONST); - if (pit->m[t] == 3) - read <<= 1; - return read; - } - if (pit->m[t] == 2) { - read = (int64_t) (((pit->count[t] + 1LL) << TIMER_SHIFT) * PITCONST); - return read; + int l; + + speaker_update(); + + l = pit.l[2] ? pit.l[2] : 0x10000; + if (l < 25) + speakon = 0; + else + speakon = new_out; + + ppispeakon = new_out; +} + + +void +pit_init(void) +{ + int i; + + pit_reset(&pit); + + for (i = 0; i < 3; i++) { + pit.pit_nr[i].nr = i; + pit.pit_nr[i].pit = &pit; + + pit.gate[i] = 1; + pit.using_timer[i] = 1; + + timer_add(&pit.timer[i], pit_timer_over, (void *)&pit.pit_nr[i], 0); + } + + io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit); + + /* Timer 0: The TOD clock. */ + pit_set_out_func(&pit, 0, pit_irq0_timer); + + /* Timer 1: Unused. */ + pit_set_out_func(&pit, 1, pit_null_timer); + + /* Timer 2: speaker and cassette. */ + pit_set_out_func(&pit, 2, pit_speaker_timer); + pit.gate[2] = 0; +} + + +static void +pit_irq0_ps2(int new_out, int old_out) +{ + if (new_out && !old_out) { + picint(1); + pit_set_gate_no_timer(&pit2, 0, 1); + } + + if (!new_out) + picintc(1); + + if (!new_out && old_out) + pit_clock(&pit2, 0); +} + + +static void +pit_nmi_ps2(int new_out, int old_out) +{ + nmi = new_out; + + if (nmi) + nmi_auto_clear = 1; +} + + +void +pit_ps2_init() +{ + pit_reset(&pit2); + + pit2.gate[0] = 0; + pit2.using_timer[0] = 0; + pit2.disabled[0] = 1; + + pit2.pit_nr[0].nr = 0; + pit2.pit_nr[0].pit = &pit2; + + timer_add(&pit2.timer[0], pit_timer_over, (void *)&pit2.pit_nr[0], 0); + + io_sethandler(0x0044, 0x0001, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit2); + io_sethandler(0x0047, 0x0001, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit2); + + pit_set_out_func(&pit, 0, pit_irq0_ps2); + pit_set_out_func(&pit2, 0, pit_nmi_ps2); +} + + +void +pit_reset(PIT *pit) +{ + int i; + + memset(pit, 0, sizeof(PIT)); + + for (i = 0; i < 3; i++) { + pit->ctrls[i] = 0; + pit->thit[i] = 0; /* Should be only thit[0]? */ + + pit->m[i] = 0; + pit->gate[i] = 1; + pit->l[i] = 0xffff; + pit->using_timer[i] = 1; + } + + pit->thit[0] = 1; + + /* Disable speaker gate. */ + pit->gate[2] = 0; +} + + +void +pit_set_clock(int clock) +{ + /* Set default CPU/crystal clock and xt_cpu_multi. */ + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) { +#if 0 + cpuclock = (double) clock; +#else + if (clock == 66666666) + cpuclock = 200000000.0 / 3.0; + else if (clock == 33333333) + cpuclock = 100000000.0 / 3.0; + else + cpuclock = (double) clock; +#endif + +#if 0 + PITCONST = (uint64_t) (cpuclock / 1193182.0 * (double)(1ull << 32)); +#else + PITCONSTD = (cpuclock / 1193182.0); + PITCONST = (uint64_t) (PITCONSTD * (double)(1ull << 32)); +#endif + CGACONST = (uint64_t) ((cpuclock / (19687503.0/11.0)) * (double)(1ull << 32)); + xt_cpu_multi = 1ULL; + } else { + cpuclock = 14318184.0; +#if 1 + PITCONSTD = 12.0; +#endif + PITCONST = (12ULL << 32ULL); + CGACONST = (8ULL << 32ULL); + xt_cpu_multi = 3ULL; + + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed) { + case 7159092: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_flags & CPU_ALTERNATE_XTAL) { + cpuclock = 28636368.0; + xt_cpu_multi = 4ULL; + } else + xt_cpu_multi = 2ULL; + break; + + case 8000000: + cpuclock = 24000000.0; + break; + case 9545456: + cpuclock = 28636368.0; + break; + case 10000000: + cpuclock = 30000000.0; + break; + case 12000000: + cpuclock = 36000000.0; + break; + case 16000000: + cpuclock = 48000000.0; + break; + + default: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_flags & CPU_ALTERNATE_XTAL) { + cpuclock = 28636368.0; + xt_cpu_multi = 6ULL; + } + break; } - read = (int64_t) ((pit->count[t] << TIMER_SHIFT) * PITCONST); - return read; + + if (cpuclock == 28636368.0) { +#if 1 + PITCONSTD = 24.0; +#endif + PITCONST = (24ULL << 32LL); + CGACONST = (16ULL << 32LL); + } else if (cpuclock != 14318184.0) { +#if 0 + PITCONST = (uint64_t) ((cpuclock/1193182.0 * (double)(1ull << 32))); +#else + PITCONSTD = (cpuclock / 1193182.0); + PITCONST = (uint64_t) (PITCONSTD * (double)(1ull << 32)); +#endif + CGACONST = (uint64_t) (((cpuclock/(19687503.0/11.0)) * (double)(1ull << 32))); + } + } + xt_cpu_multi <<= 32ULL; + + /* Delay for empty I/O ports. */ + io_delay = (int) round(((double) machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed) / 1000000.0); + + MDACONST = (uint64_t) (cpuclock / 2032125.0 * (double)(1ull << 32)); + HERCCONST = MDACONST; + VGACONST1 = (uint64_t) (cpuclock / 25175000.0 * (double)(1ull << 32)); + VGACONST2 = (uint64_t) (cpuclock / 28322000.0 * (double)(1ull << 32)); + RTCCONST = (uint64_t) (cpuclock / 32768.0 * (double)(1ull << 32)); + + TIMER_USEC = (uint64_t)((cpuclock / 1000000.0) * (double)(1ull << 32)); + + isa_timing = (cpuclock / (double)8000000.0); + bus_timing = (cpuclock / (double)cpu_busspeed); + + if (cpu_busspeed >= 30000000) + SYSCLK = bus_timing * 4.0; + else + SYSCLK = bus_timing * 3.0; + + video_update_timing(); + + device_speed_changed(); } -void pit_set_using_timer(PIT *pit, int t, int using_timer) + +void +clearpit(void) { - timer_process(); - if (pit->using_timer[t] && !using_timer) - pit->count[t] = pit_read_timer(pit, t); - if (!pit->using_timer[t] && using_timer) - pit->c[t] = pit_read_timer_ex(pit, t); - // pit->c[t] = (int64_t)((((int64_t) pit->count[t]) << TIMER_SHIFT) * PITCONST); - pit->using_timer[t] = using_timer; - pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; - timer_update_outstanding(); + // pit.c[0] = (pit.l[0] << 2); } -void pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out)) + +void +pit_set_gate(PIT *pit, int t, int gate) { - pit->set_out_funcs[t] = func; + if (pit->disabled[t]) { + pit->gate[t] = gate; + return; + } + + pit_set_gate_no_timer(pit, t, gate); } -void pit_null_timer(int new_out, int old_out) + +void +pit_set_using_timer(PIT *pit, int t, int using_timer) { + timer_process(); + + if (pit->using_timer[t] && !using_timer) + pit->count[t] = pit_read_timer(pit, t); + + pit->running[t] = pit->enabled[t] && using_timer && !pit->disabled[t]; + + if (!pit->using_timer[t] && using_timer && pit->running[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(pit->count[t] * PITCONST)); + else if (!pit->running[t]) + timer_disable(&pit->timer[t]); + + pit->using_timer[t] = using_timer; } -void pit_irq0_timer(int new_out, int old_out) + +void +pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out)) { - if (new_out && !old_out) - picint(1); - if (!new_out) - picintc(1); + pit->set_out_funcs[t] = func; } -void pit_irq0_timer_pcjr(int new_out, int old_out) + +void +pit_irq0_timer_pcjr(int new_out, int old_out) { - if (new_out && !old_out) - { - picint(1); - pit_clock(&pit, 1); - } - if (!new_out) - picintc(1); + if (new_out && !old_out) { + picint(1); + pit_clock(&pit, 1); + } + + if (!new_out) + picintc(1); } -void pit_irq0_ps2(int new_out, int old_out) + +void +pit_refresh_timer_xt(int new_out, int old_out) { - if (new_out && !old_out) - { - picint(1); - pit_set_gate_no_timer(&pit2, 0, 1); - } - if (!new_out) - picintc(1); - if (!new_out && old_out) - pit_clock(&pit2, 0); + if (new_out && !old_out) + dma_channel_read(0); } -void pit_refresh_timer_xt(int new_out, int old_out) + +void +pit_refresh_timer_at(int new_out, int old_out) { - if (new_out && !old_out) - dma_channel_read(0); -} - -void pit_refresh_timer_at(int new_out, int old_out) -{ - if (new_out && !old_out) - ppi.pb ^= 0x10; -} - -void pit_speaker_timer(int new_out, int old_out) -{ - int64_t l; - - speaker_update(); - - l = pit.l[2] ? pit.l[2] : 0x10000; - if (l < 25) - speakon = 0; - else - speakon = new_out; - ppispeakon = new_out; -} - - -void pit_nmi_ps2(int new_out, int old_out) -{ - nmi = new_out; - if (nmi) - nmi_auto_clear = 1; -} - -void pit_init() -{ - pit_reset(&pit); - - io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit); - pit.gate[0] = pit.gate[1] = 1; - pit.gate[2] = 0; - pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1; - - pit.pit_nr[0].nr = 0; - pit.pit_nr[1].nr = 1; - pit.pit_nr[2].nr = 2; - pit.pit_nr[0].pit = pit.pit_nr[1].pit = pit.pit_nr[2].pit = &pit; - - timer_add(pit_timer_over, &pit.c[0], &pit.running[0], (void *)&pit.pit_nr[0]); - timer_add(pit_timer_over, &pit.c[1], &pit.running[1], (void *)&pit.pit_nr[1]); - timer_add(pit_timer_over, &pit.c[2], &pit.running[2], (void *)&pit.pit_nr[2]); - - pit_set_out_func(&pit, 0, pit_irq0_timer); - pit_set_out_func(&pit, 1, pit_null_timer); - pit_set_out_func(&pit, 2, pit_speaker_timer); -} - -void pit_ps2_init() -{ - pit_reset(&pit2); - - io_sethandler(0x0044, 0x0001, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit2); - io_sethandler(0x0047, 0x0001, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit2); - - pit2.gate[0] = 0; - pit2.using_timer[0] = 0; - pit2.disabled[0] = 1; - - pit2.pit_nr[0].nr = 0; - pit2.pit_nr[0].pit = &pit2; - - timer_add(pit_timer_over, &pit2.c[0], &pit2.running[0], (void *)&pit2.pit_nr[0]); - - pit_set_out_func(&pit, 0, pit_irq0_ps2); - pit_set_out_func(&pit2, 0, pit_nmi_ps2); + if (new_out && !old_out) + ppi.pb ^= 0x10; } diff --git a/src/pit.h b/src/pit.h index 00297eb26..72554306e 100644 --- a/src/pit.h +++ b/src/pit.h @@ -3,13 +3,13 @@ typedef struct { - int64_t nr; + int nr; struct PIT *pit; } PIT_nr; typedef struct PIT { uint32_t l[3]; - int64_t c[3]; + pc_timer_t timer[3]; uint8_t m[3]; uint8_t ctrl, ctrls[3]; @@ -22,7 +22,7 @@ typedef struct PIT { int rereadlatch[3]; int gate[3]; int out[3]; - int64_t running[3]; + int running[3]; int enabled[3]; int newcount[3]; int count[3]; @@ -42,9 +42,13 @@ typedef struct PIT { extern PIT pit, pit2; -extern double PITCONST; -extern float CGACONST, + +extern double SYSCLK; + +extern uint64_t PITCONST, + CGACONST, MDACONST, + HERCCONST, VGACONST1, VGACONST2, RTCCONST; @@ -56,19 +60,13 @@ extern void pit_reset(PIT *pit); extern void pit_set_gate(PIT *pit, int channel, int gate); extern void pit_set_using_timer(PIT *pit, int t, int using_timer); extern void pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out)); -extern void pit_clock(PIT *pit, int t); -extern void setrtcconst(float clock); - -extern void setpitclock(float clock); extern float pit_timer0_freq(void); - -extern void pit_null_timer(int new_out, int old_out); -extern void pit_irq0_timer(int new_out, int old_out); extern void pit_irq0_timer_pcjr(int new_out, int old_out); extern void pit_refresh_timer_xt(int new_out, int old_out); extern void pit_refresh_timer_at(int new_out, int old_out); -extern void pit_speaker_timer(int new_out, int old_out); + +extern void pit_set_clock(int clock); #endif /*EMU_PIT_H*/ diff --git a/src/plat.h b/src/plat.h index 9d7bad792..065d50aa0 100644 --- a/src/plat.h +++ b/src/plat.h @@ -8,13 +8,13 @@ * * Define the various platform support functions. * - * Version: @(#)plat.h 1.0.27 2018/10/17 + * Version: @(#)plat.h 1.0.28 2019/03/06 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_PLAT_H # define EMU_PLAT_H @@ -68,11 +68,14 @@ GLOBAL int unscaled_size_x, /* current unscaled size X */ /* System-related functions. */ extern wchar_t *fix_exe_path(wchar_t *str); extern FILE *plat_fopen(wchar_t *path, wchar_t *mode); +extern FILE *plat_fopen64(const wchar_t *path, const wchar_t *mode); extern void plat_remove(wchar_t *path); extern int plat_getcwd(wchar_t *bufp, int max); extern int plat_chdir(wchar_t *path); extern void plat_tempfile(wchar_t *bufp, wchar_t *prefix, wchar_t *suffix); extern void plat_get_exe_name(wchar_t *s, int size); +extern wchar_t *plat_get_basename(const wchar_t *path); +extern void plat_get_dirname(wchar_t *dest, const wchar_t *path); extern wchar_t *plat_get_filename(wchar_t *s); extern wchar_t *plat_get_extension(wchar_t *s); extern void plat_append_filename(wchar_t *dest, wchar_t *s1, wchar_t *s2); @@ -92,6 +95,7 @@ extern int plat_setvid(int api); extern void plat_vidsize(int x, int y); extern void plat_setfullscreen(int on); extern void plat_resize(int x, int y); +extern void plat_vidapi_enable(int enabled); /* Resource management. */ diff --git a/src/plat_dynld.h b/src/plat_dynld.h index 74af2e8f8..72bc75c2f 100644 --- a/src/plat_dynld.h +++ b/src/plat_dynld.h @@ -23,8 +23,16 @@ typedef struct { } dllimp_t; +#ifdef __cplusplus +extern "C" { +#endif + extern void *dynld_module(const char *, dllimp_t *); extern void dynld_close(void *); +#ifdef __cplusplus +} +#endif + #endif /*PLAT_DYNLD_H*/ diff --git a/src/port_92.c b/src/port_92.c new file mode 100644 index 000000000..1c5f1b2bf --- /dev/null +++ b/src/port_92.c @@ -0,0 +1,252 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of Port 92 used by PS/2 machines and 386+ + * clones. + * + * Version: @(#)port_92.c 1.0.0 2019/05/14 + * + * Authors: Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "device.h" +#ifdef USE_NEW_DYNAREC +#include "cpu_new/cpu.h" +#else +#include "cpu/cpu.h" +#endif +#include "timer.h" +#include "io.h" +#include "keyboard.h" +#include "mem.h" +#include "pit.h" +#include "port_92.h" + + +#define PORT_92_INV 1 +#define PORT_92_WORD 2 +#define PORT_92_PCI 4 +#define PORT_92_RESET 8 +#define PORT_92_A20 16 + + +static uint8_t +port_92_readb(uint16_t port, void *priv) +{ + uint8_t ret = 0x00; + port_92_t *dev = (port_92_t *) priv; + + if (port == 0x92) { + /* Return bit 1 directly from mem_a20_alt, so the + pin can be reset independently of the device. */ + ret = (dev->reg & ~0x03) | (mem_a20_alt & 2) | + (cpu_alt_reset & 1); + + if (dev->flags & PORT_92_INV) + ret |= 0xfc; + else if (dev->flags & PORT_92_PCI) + ret |= 0x24; /* Intel SIO datasheet says bits 2 and 5 are always 1. */ + } else if (dev->flags & PORT_92_INV) + ret = 0xff; + + return ret; +} + + +static uint16_t +port_92_readw(uint16_t port, void *priv) +{ + return port_92_readb(port, priv); +} + + +static void +port_92_pulse(void *priv) +{ + softresetx86(); + cpu_set_edx(); +} + + +static void +port_92_writeb(uint16_t port, uint8_t val, void *priv) +{ + port_92_t *dev = (port_92_t *) priv; + + if (port != 0x92) + return; + + dev->reg = val & 0x03; + + if ((mem_a20_alt ^ val) & 2) { + mem_a20_alt = (val & 2); + mem_a20_recalc(); + } + + if ((~cpu_alt_reset & val) & 1) + timer_set_delay_u64(&dev->pulse_timer, dev->pulse_period); + else if (!(val & 1)) + timer_disable(&dev->pulse_timer); + + cpu_alt_reset = (val & 1); + + if (dev->flags & PORT_92_INV) + dev->reg |= 0xfc; +} + + +static void +port_92_writew(uint16_t port, uint16_t val, void *priv) +{ + port_92_writeb(port, val & 0xff, priv); +} + + +void +port_92_set_period(void *priv, uint64_t pulse_period) +{ + port_92_t *dev = (port_92_t *) priv; + + dev->pulse_period = pulse_period; +} + + +void +port_92_set_features(void *priv, int reset, int a20) +{ + port_92_t *dev = (port_92_t *) priv; + + dev->flags &= ~(PORT_92_RESET | PORT_92_A20); + + if (reset) + dev->flags |= PORT_92_RESET; + + timer_disable(&dev->pulse_timer); + + if (a20) { + dev->flags |= PORT_92_A20; + mem_a20_alt = (dev->reg & 2); + } else + mem_a20_alt = 0; + + mem_a20_recalc(); +} + + +void +port_92_add(void *priv) +{ + port_92_t *dev = (port_92_t *) priv; + + if (dev->flags & PORT_92_WORD) + io_sethandler(0x0092, 2, + port_92_readb, port_92_readw, NULL, port_92_writeb, port_92_writew, NULL, dev); + else + io_sethandler(0x0092, 1, + port_92_readb, NULL, NULL, port_92_writeb, NULL, NULL, dev); +} + + +void +port_92_remove(void *priv) +{ + port_92_t *dev = (port_92_t *) priv; + + if (dev->flags & PORT_92_WORD) + io_removehandler(0x0092, 2, + port_92_readb, port_92_readw, NULL, port_92_writeb, port_92_writew, NULL, dev); + else + io_removehandler(0x0092, 1, + port_92_readb, NULL, NULL, port_92_writeb, NULL, NULL, dev); +} + + +static void +port_92_close(void *priv) +{ + port_92_t *dev = (port_92_t *) priv; + + timer_disable(&dev->pulse_timer); + + free(dev); +} + + +void * +port_92_init(const device_t *info) +{ + port_92_t *dev = (port_92_t *) malloc(sizeof(port_92_t)); + memset(dev, 0, sizeof(port_92_t)); + + dev->flags = info->local & 0xff; + + timer_add(&dev->pulse_timer, port_92_pulse, dev, 0); + + dev->reg = 0; + mem_a20_alt = 0; + mem_a20_recalc(); + + cpu_alt_reset = 0; + + flushmmucache(); + + port_92_add(dev); + + dev->pulse_period = (uint64_t) (4.0 * SYSCLK * (double)(1ULL << 32ULL)); + + dev->flags |= (PORT_92_RESET | PORT_92_A20); + + return dev; +} + + +const device_t port_92_device = { + "Port 92 Register", + 0, + 0, + port_92_init, port_92_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t port_92_inv_device = { + "Port 92 Register (inverted bits 2-7)", + 0, + PORT_92_INV, + port_92_init, port_92_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t port_92_word_device = { + "Port 92 Register (16-bit)", + 0, + PORT_92_WORD, + port_92_init, port_92_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t port_92_pci_device = { + "Port 92 Register (PCI)", + 0, + PORT_92_PCI, + port_92_init, port_92_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/port_92.h b/src/port_92.h new file mode 100644 index 000000000..4b41eb09d --- /dev/null +++ b/src/port_92.h @@ -0,0 +1,47 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header for the implementation of Port 92 used by PS/2 + * machines and 386+ clones. + * + * Version: @(#)port_92.h 1.0.0 2019/05/14 + * + * Authors: Miran Grca, + * + * Copyright 2019 Miran Grca. + */ +#ifndef EMU_PORT_92_H +# define EMU_PORT_92_H + + +#ifdef _TIMER_H_ +typedef struct +{ + uint8_t reg, flags; + + pc_timer_t pulse_timer; + + uint64_t pulse_period; +} port_92_t; +#endif + + +extern void port_92_set_period(void *priv, uint64_t pulse_period); +extern void port_92_set_features(void *priv, int reset, int a20); + +extern void port_92_add(void *priv); +extern void port_92_remove(void *priv); + + +extern const device_t port_92_device; +extern const device_t port_92_inv_device; +extern const device_t port_92_word_device; +extern const device_t port_92_pci_device; + + +#endif /*EMU_PORT_92_H*/ diff --git a/src/ppi.c b/src/ppi.c index ef81ee19c..e91b445d2 100644 --- a/src/ppi.c +++ b/src/ppi.c @@ -11,6 +11,7 @@ #include #include #include +#include "timer.h" #include "pit.h" #include "ppi.h" diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 0a711e2ea..febad8307 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -199,7 +199,9 @@ typedef struct { typedef struct { const char *name; - int64_t timeout; + void *lpt; + + pc_timer_t timeout_timer; wchar_t page_fn[260]; uint8_t color; @@ -431,7 +433,7 @@ timeout_timer(void *priv) if (dev->page->dirty) new_page(dev, 1, 1); - dev->timeout = 0LL; + timer_disable(&dev->timeout_timer); } @@ -517,7 +519,7 @@ static void reset_printer_hard(escp_t *dev) { dev->char_read = 0; - dev->timeout = 0LL; + timer_disable(&dev->timeout_timer); reset_printer(dev); } @@ -1588,6 +1590,7 @@ handle_char(escp_t *dev, uint8_t ch) double x_advance; dev->char_read = 1; + lpt_irq(dev->lpt, 1); if (dev->page == NULL) return; @@ -1977,7 +1980,7 @@ write_ctrl(uint8_t val, void *priv) /* ACK it, will be read on next READ STATUS. */ dev->ack = 1; - dev->timeout = 500000LL * TIMER_USEC; + timer_set_delay_u64(&dev->timeout_timer, 500000 * TIMER_USEC); } dev->ctrl = val; @@ -2020,14 +2023,12 @@ read_status(void *priv) static void * -escp_init(const lpt_device_t *INFO) +escp_init(void *lpt) { const char *fn = PATH_FREETYPE_DLL; escp_t *dev; int i; - escp_log("ESC/P: LPT printer '%s' initializing\n", INFO->name); - /* Dynamically load FreeType. */ if (ft_handle == NULL) { ft_handle = dynld_module(fn, ft_imports); @@ -2050,8 +2051,8 @@ escp_init(const lpt_device_t *INFO) /* Initialize a device instance. */ dev = (escp_t *)malloc(sizeof(escp_t)); memset(dev, 0x00, sizeof(escp_t)); - dev->name = INFO->name; dev->ctrl = 0x04; + dev->lpt = lpt; /* Create a full pathname for the font files. */ wcscpy(dev->fontpath, exe_path); @@ -2109,7 +2110,7 @@ escp_init(const lpt_device_t *INFO) escp_log("ESC/P: created a virtual page of dimensions %d x %d pixels.\n", dev->page->w, dev->page->h); - timer_add(timeout_timer, &dev->timeout, &dev->timeout, dev); + timer_add(&dev->timeout_timer, timeout_timer, dev, 0); return(dev); } diff --git a/src/printer/prt_text.c b/src/printer/prt_text.c index ec862f2dc..5f24f9587 100644 --- a/src/printer/prt_text.c +++ b/src/printer/prt_text.c @@ -96,13 +96,15 @@ typedef struct { typedef struct { - const char *name; + const char *name; + + void * lpt; /* Output file name. */ wchar_t filename[1024]; /* Printer timeout. */ - int64_t timeout; + pc_timer_t timeout_timer; /* page data (TODO: make configurable) */ double page_width, /* all in inches */ @@ -204,7 +206,7 @@ timeout_timer(void *priv) if (dev->page->dirty) new_page(dev); - dev->timeout = 0LL; + timer_disable(&dev->timeout_timer); } @@ -237,7 +239,7 @@ reset_printer(prnt_t *dev) /* Create a file for this page. */ plat_tempfile(dev->filename, NULL, L".txt"); - dev->timeout = 0LL; + timer_disable(&dev->timeout_timer); } @@ -392,8 +394,9 @@ write_ctrl(uint8_t val, void *priv) /* ACK it, will be read on next READ STATUS. */ dev->ack = 1; + lpt_irq(dev->lpt, 1); - dev->timeout = 500000LL * TIMER_USEC; + timer_set_delay_u64(&dev->timeout_timer, 500000 * TIMER_USEC); } dev->ctrl = val; @@ -422,17 +425,15 @@ read_status(void *priv) static void * -prnt_init(const lpt_device_t *INFO) +prnt_init(void *lpt) { prnt_t *dev; /* Initialize a device instance. */ dev = (prnt_t *)malloc(sizeof(prnt_t)); memset(dev, 0x00, sizeof(prnt_t)); - dev->name = INFO->name; dev->ctrl = 0x04; - - //INFO("PRNT: LPT printer '%s' initializing\n", dev->name); + dev->lpt = lpt; /* Initialize parameters. */ reset_printer(dev); @@ -444,9 +445,7 @@ prnt_init(const lpt_device_t *INFO) dev->page->chars = (char *)malloc(dev->page->w * dev->page->h); memset(dev->page->chars, 0x00, dev->page->w * dev->page->h); - //DEBUG("PRNT: created a virtual %ix%i page.\n", dev->page->w, dev->page->h); - - timer_add(timeout_timer, &dev->timeout, &dev->timeout, dev); + timer_add(&dev->timeout_timer, timeout_timer, dev, 0); return(dev); } diff --git a/src/rom.c b/src/rom.c index e4db89a6d..204fd0eee 100644 --- a/src/rom.c +++ b/src/rom.c @@ -11,17 +11,16 @@ * NOTES: - pc2386 BIOS is corrupt (JMP at F000:FFF0 points to RAM) * - pc2386 video BIOS is underdumped (16k instead of 24k) * - c386sx16 BIOS fails checksum - * - the loadfont() calls should be done elsewhere * - * Version: @(#)rom.c 1.0.44 2019/02/08 + * Version: @(#)rom.c 1.0.45 2019/03/03 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 Fred N. van Kempen. */ #include #include @@ -33,14 +32,11 @@ #include "86box.h" #include "mem.h" #include "rom.h" -#include "video/video.h" /* for loadfont() */ #include "plat.h" +#include "machine/machine.h" #include "machine/m_xt_xi8088.h" -int romspresent[ROM_MAX]; - - #ifdef ENABLE_ROM_LOG int rom_do_log = ENABLE_ROM_LOG; @@ -118,6 +114,10 @@ rom_read(uint32_t addr, void *priv) rom_log("ROM: read byte from BIOS at %06lX\n", addr); #endif + if (addr < rom->mapping.base) + return 0xff; + if (addr >= (rom->mapping.base + rom->sz)) + return 0xff; return(rom->rom[addr & rom->mask]); } @@ -132,6 +132,10 @@ rom_readw(uint32_t addr, void *priv) rom_log("ROM: read word from BIOS at %06lX\n", addr); #endif + if (addr < (rom->mapping.base - 1)) + return 0xffff; + if (addr >= (rom->mapping.base + rom->sz)) + return 0xffff; return(*(uint16_t *)&rom->rom[addr & rom->mask]); } @@ -146,6 +150,10 @@ rom_readl(uint32_t addr, void *priv) rom_log("ROM: read long from BIOS at %06lX\n", addr); #endif + if (addr < (rom->mapping.base - 3)) + return 0xffffffff; + if (addr >= (rom->mapping.base + rom->sz)) + return 0xffffffff; return(*(uint32_t *)&rom->rom[addr & rom->mask]); } @@ -171,8 +179,11 @@ rom_load_linear(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) addr &= 0x03ffff; } - (void)fseek(f, off, SEEK_SET); - (void)fread(ptr+addr, sz, 1, f); + if (ptr != NULL) { + (void)fseek(f, off, SEEK_SET); + (void)fread(ptr+addr, sz, 1, f); + } + (void)fclose(f); return(1); @@ -206,9 +217,12 @@ rom_load_linear_inverted(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *p return(0); } - (void)fseek(f, off, SEEK_SET); - (void)fread(ptr+addr+0x10000, sz >> 1, 1, f); - (void)fread(ptr+addr, sz >> 1, 1, f); + if (ptr != NULL) { + (void)fseek(f, off, SEEK_SET); + (void)fread(ptr+addr+0x10000, sz >> 1, 1, f); + (void)fread(ptr+addr, sz >> 1, 1, f); + } + (void)fclose(f); return(1); @@ -242,12 +256,15 @@ rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int off, addr &= 0x03ffff; } - (void)fseek(fl, off, SEEK_SET); - (void)fseek(fh, off, SEEK_SET); - for (c=0; c 0x0000; 0x4000 -> 0x4000; 0x6000 -> 0x4000 */ + int temp_n = n & ~MEM_GRANULARITY_MASK; + + /* 0x2000 -> 0x4000; 0x4000 -> 0x4000; 0x6000 -> 0x8000 */ + if (up && (n % MEM_GRANULARITY_SIZE)) + temp_n += MEM_GRANULARITY_SIZE; + + return temp_n; +} + + + +static uint8_t * +rom_reset(uint32_t addr, int sz) +{ + biosaddr = bios_normalize(addr, 0); + biosmask = bios_normalize(sz, 1) - 1; + if ((biosaddr + biosmask) > 0x000fffff) + biosaddr = 0x000fffff - biosmask; + + rom_log("Load BIOS: %i bytes at %08X-%08X\n", biosmask + 1, biosaddr, biosaddr + biosmask); + + /* If not done yet, allocate a 128KB buffer for the BIOS ROM. */ + if (rom != NULL) { + rom_log("ROM allocated, freeing...\n"); + free(rom); + rom = NULL; + } + rom_log("Allocating ROM...\n"); + rom = (uint8_t *)malloc(biosmask + 1); + rom_log("Filling ROM with FF's...\n"); + memset(rom, 0xff, biosmask + 1); + + return rom; +} + + +/* These four are for loading the BIOS. */ +int +bios_load(wchar_t *fn1, wchar_t *fn2, uint32_t addr, int sz, int off, int flags) +{ + uint8_t ret = 0; + uint8_t *ptr = NULL; + int i, old_sz = sz; + + /* + f0000, 65536 = prepare 64k rom starting at f0000, load 64k bios at 0000 + fe000, 65536 = prepare 64k rom starting at f0000, load 8k bios at e000 + fe000, 49152 = prepare 48k rom starting at f4000, load 8k bios at a000 + fe000, 8192 = prepare 16k rom starting at fc000, load 8k bios at 2000 + */ + if (!bios_only) + ptr = (flags & FLAG_AUX) ? rom : rom_reset(addr, sz); + + if (!(flags & FLAG_AUX) && ((addr + sz) > 0x00100000)) + sz = 0x00100000 - addr; + +#ifdef ENABLE_ROM_LOG + if (!bios_only) + rom_log("%sing %i bytes of %sBIOS starting with ptr[%08X] (ptr = %08X)\n", (bios_only) ? "Check" : "Load", sz, (flags & FLAG_AUX) ? "auxiliary " : "", addr - biosaddr, ptr); +#endif + + if (flags & FLAG_INT) + ret = rom_load_interleaved(fn1, fn2, addr - biosaddr, sz, off, ptr); + else { + if (flags & FLAG_INV) + ret = rom_load_linear_inverted(fn1, addr - biosaddr, sz, off, ptr); + else + ret = rom_load_linear(fn1, addr - biosaddr, sz, off, ptr); + } + + if (!bios_only && (flags & FLAG_REP) && (old_sz >= 65536) && (sz < old_sz)) { + old_sz /= sz; + for (i = 0; i < (old_sz - 1); i++) { + rom_log("Copying ptr[%08X] to ptr[%08X]\n", addr - biosaddr, i * sz); + memcpy(&(ptr[i * sz]), &(ptr[addr - biosaddr]), sz); + } + } + + if (!bios_only && ret && !(flags & FLAG_AUX)) + mem_add_bios(); + + return ret; +} + + +int +bios_load_linear_combined(wchar_t *fn1, wchar_t *fn2, int sz, int off) +{ + uint8_t ret = 0; + + ret = bios_load_linear(fn1, 0x000f0000, 131072, 128); + ret &= bios_load_aux_linear(fn2, 0x000e0000, sz - 65536, 128); + + return ret; +} + + +#if defined(DEV_BRANCH) && defined(USE_TC430HX) +int +bios_load_linear_combined2(wchar_t *fn1, wchar_t *fn2, wchar_t *fn3, wchar_t *fn4, wchar_t *fn5, int sz, int off) +{ + uint8_t ret = 0; + + ret = bios_load_linear(fn3, 0x000f0000, 262144, 128); + ret &= bios_load_aux_linear(fn1, 0x000d0000, 65536, 128); + ret &= bios_load_aux_linear(fn2, 0x000c0000, 65536, 128); + ret &= bios_load_aux_linear(fn4, 0x000e0000, sz - 196608, 128); + ret &= bios_load_aux_linear(fn5, 0x000ec000, 16384, 128); + + return ret; +} +#endif + + int rom_init(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint32_t flags) { + rom_log("rom_init(%08X, %08X, %08X, %08X, %08X, %08X, %08X)\n", rom, fn, addr, sz, mask, off, flags); + /* Allocate a buffer for the image. */ rom->rom = malloc(sz); memset(rom->rom, 0xff, sz); @@ -270,6 +407,7 @@ rom_init(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint return(-1); } + rom->sz = sz; rom->mask = mask; mem_mapping_add(&rom->mapping, @@ -297,6 +435,7 @@ rom_init_interleaved(rom_t *rom, wchar_t *fnl, wchar_t *fnh, uint32_t addr, int return(-1); } + rom->sz = sz; rom->mask = mask; mem_mapping_add(&rom->mapping, @@ -307,718 +446,3 @@ rom_init_interleaved(rom_t *rom, wchar_t *fnl, wchar_t *fnh, uint32_t addr, int return(0); } - - -/* Load the ROM BIOS image(s) for the selected machine into memory. */ -int -rom_load_bios(int rom_id) -{ - FILE *f; - - loadfont(L"roms/video/mda/mda.rom", 0); - - /* If not done yet, allocate a 128KB buffer for the BIOS ROM. */ - if (rom == NULL) - rom = (uint8_t *)malloc(131072); - memset(rom, 0xff, 131072); - - /* Default to a 64K ROM BIOS image. */ - biosmask = 0xffff; - - /* Zap the BIOS ROM EXTENSION area. */ - memset(romext, 0xff, 0x8000); - mem_mapping_disable(&romext_mapping); - - switch (rom_id) { - case ROM_IBMPC: /* IBM PC (1981) */ - if (! rom_load_linear( - L"roms/machines/ibmpc/BIOS_5150_24APR81_U33.BIN", - 0x00e000, 8192, 0, rom)) break; - - /* Try to load the (full) BASIC ROM. */ - if (rom_load_linear( - L"roms/machines/ibmpc/ibm-basic-1.10.rom", - 0x006000, 32768, 0, rom)) return(1); - - /* Nope. Try to load the first BASIC ROM image. */ - if (! rom_load_linear( - L"roms/machines/ibmpc/basicc11.f6", - 0x006000, 8192, 0, rom)) return(1); /* nope */ - if (! rom_load_linear( - L"roms/machines/ibmpc/basicc11.f8", - 0x008000, 8192, 0, rom)) break; /* nope */ - if (! rom_load_linear( - L"roms/machines/ibmpc/basicc11.fa", - 0x00a000, 8192, 0, rom)) break; /* nope */ - if (! rom_load_linear( - L"roms/machines/ibmpc/basicc11.fc", - 0x00c000, 8192, 0, rom)) break; /* nope */ - return(1); - - case ROM_IBMPC82: /* IBM PC (1982) */ - if (! rom_load_linear( - L"roms/machines/ibmpc82/pc102782.bin", - 0x00e000, 8192, 0, rom)) break; - - /* Try to load the (full) BASIC ROM. */ - if (rom_load_linear( - L"roms/machines/ibmpc82/ibm-basic-1.10.rom", - 0x006000, 32768, 0, rom)) return(1); - - /* Nope. Try to load the first BASIC ROM image. */ - if (! rom_load_linear( - L"roms/machines/ibmpc82/basicc11.f6", - 0x006000, 8192, 0, rom)) return(1); /* nope */ - if (! rom_load_linear( - L"roms/machines/ibmpc82/basicc11.f8", - 0x008000, 8192, 0, rom)) break; /* nope */ - if (! rom_load_linear( - L"roms/machines/ibmpc82/basicc11.fa", - 0x00a000, 8192, 0, rom)) break; /* nope */ - if (! rom_load_linear( - L"roms/machines/ibmpc82/basicc11.fc", - 0x00c000, 8192, 0, rom)) break; /* nope */ - return(1); - - case ROM_IBMXT: /* IBM PX-XT (1982) */ - if (rom_load_linear( - L"roms/machines/ibmxt/xt.rom", - 0x000000, 65536, 0, rom)) return(1); - - if (! rom_load_linear( - L"roms/machines/ibmxt/5000027.u19", - 0x000000, 32768, 0, rom)) break; - if (rom_load_linear( - L"roms/machines/ibmxt/1501512.u18", - 0x008000, 32768, 0, rom)) return(1); - break; - - case ROM_IBMXT86: /* IBM PX-XT (1986) */ - if (! rom_load_linear( - L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U19_62X0819_68X4370_27256_F000.BIN", - 0x000000, 32768, 0, rom)) break; - if (rom_load_linear( - L"roms/machines/ibmxt86/BIOS_5160_09MAY86_U18_59X7268_62X0890_27256_F800.BIN", - 0x008000, 32768, 0, rom)) return(1); - break; - - case ROM_XI8088: - if (rom_load_linear_inverted( - L"roms/machines/xi8088/bios-xi8088.bin", - 0x000000, 131072, 0, rom)) { - biosmask = 0x1ffff; - xi8088_bios_128kb_set(1); - return(1); - } else { - if (rom_load_linear( - L"roms/machines/xi8088/bios-xi8088.bin", - 0x000000, 65536, 0, rom)) { - xi8088_bios_128kb_set(0); - return(1); - } - } - break; - - case ROM_IBMXT286: /* IBM PX-XT 286 */ - if (rom_load_interleaved( - L"roms/machines/ibmxt286/bios_5162_21apr86_u34_78x7460_27256.bin", - L"roms/machines/ibmxt286/bios_5162_21apr86_u35_78x7461_27256.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_IBMPCJR: /* IBM PCjr */ - if (rom_load_linear( - L"roms/machines/ibmpcjr/bios.rom", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_IBMAT: /* IBM PC-AT */ - if (rom_load_interleaved( - L"roms/machines/ibmat/62x0820.u27", - L"roms/machines/ibmat/62x0821.u47", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_GENXT: /* Generic PC-XT clone */ - if (rom_load_linear( - L"roms/machines/genxt/pcxt.rom", - 0x00e000, 8192, 0, rom)) return(1); - break; - - case ROM_PC1512: /* Amstrad PC-1512 */ - if (! rom_load_interleaved( - L"roms/machines/pc1512/40044", - L"roms/machines/pc1512/40043", - 0x00c000, 16384, 0, rom)) break; - f = rom_fopen(L"roms/machines/pc1512/40078", L"rb"); - if (f == NULL) break; - (void)fclose(f); - return(1); - - case ROM_PC1640: /* Amstrad PC-1640 */ - if (! rom_load_interleaved( - L"roms/machines/pc1640/40044.v3", - L"roms/machines/pc1640/40043.v3", - 0x00c000, 16384, 0, rom)) break; - f = rom_fopen(L"roms/machines/pc1640/40100", L"rb"); - if (f == NULL) break; - (void)fclose(f); - return(1); - - case ROM_PC200: - if (! rom_load_interleaved( - L"roms/machines/pc200/pc20v2.1", - L"roms/machines/pc200/pc20v2.0", - 0x00c000, 16384, 0, rom)) break; - f = rom_fopen(L"roms/machines/pc200/40109", L"rb"); - if (f == NULL) break; - (void)fclose(f); - return(1); - - case ROM_TANDY: - if (rom_load_linear( - L"roms/machines/tandy/tandy1t1.020", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_TANDY1000HX: - if (! rom_load_linear( - L"roms/machines/tandy1000hx/v020000.u12", - 0x000000, 0x20000, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_TANDY1000SL2: - if (rom_load_interleaved( - L"roms/machines/tandy1000sl2/8079047.hu1", - L"roms/machines/tandy1000sl2/8079048.hu2", - 0x000000, 65536, 0x30000/2, rom)) return(1); - break; - - case ROM_PORTABLE: - if (rom_load_linear( - L"roms/machines/portable/compaq portable plus 100666-001 rev c u47.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; - - case ROM_PORTABLEII: - if (! rom_load_interleaved( - L"roms/machines/portableii/109740-001.rom", - L"roms/machines/portableii/109739-001.rom", - 0x000000, 32768, 0, rom)) break; - biosmask = 0x7fff; - return(1); - -#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - case ROM_PORTABLEIII: - case ROM_PORTABLEIII386: - if (rom_load_interleaved( - L"roms/machines/portableiii/109738-002.bin", - L"roms/machines/portableiii/109737-002.bin", - 0x000000, 65536, 0, rom)) return(1); - break; -#endif - - case ROM_DTKXT: - if (rom_load_linear( - L"roms/machines/dtk/dtk_erso_2.42_2764.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; - - case ROM_OLIM24: - if (rom_load_interleaved( - L"roms/machines/olivetti_m24/olivetti_m24_version_1.43_low.bin", - L"roms/machines/olivetti_m24/olivetti_m24_version_1.43_high.bin", - 0x00c000, 16384, 0, rom)) return(1); - break; - - case ROM_PC2086: - if (! rom_load_interleaved( - L"roms/machines/pc2086/40179.ic129", - L"roms/machines/pc2086/40180.ic132", - 0x000000, 16384, 0, rom)) break; - f = rom_fopen(L"roms/machines/pc2086/40186.ic171", L"rb"); - if (f == NULL) break; - (void)fclose(f); - biosmask = 0x3fff; - return(1); - - case ROM_PC3086: - if (! rom_load_linear( - L"roms/machines/pc3086/fc00.bin", - 0x000000, 16384, 0, rom)) break; - f = rom_fopen(L"roms/machines/pc3086/c000.bin", L"rb"); - if (f == NULL) break; - (void)fclose(f); - biosmask = 0x3fff; - return(1); - - case ROM_ZD_SUPERS: /* [8088] Zenith Data Systems SupersPort */ - if (!rom_load_linear( - L"roms/machines/zdsupers/z184m v3.1d.10d", - 0x000000, 32768, 0, rom)) break; - biosmask = 0x7fff; - return(1); - - case ROM_CMDPC30: - if (! rom_load_interleaved( - L"roms/machines/cmdpc30/commodore pc 30 iii even.bin", - L"roms/machines/cmdpc30/commodore pc 30 iii odd.bin", - 0x000000, 32768, 0, rom)) break; - biosmask = 0x7fff; - return(1); - - case ROM_TG286M: - if (rom_load_linear( - L"roms/machines/tg286m/ami.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_AMA932J: - if (rom_load_linear( - L"roms/machines/ama932j/ami.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_AMI386SX: - if (rom_load_linear( - L"roms/machines/ami386/ami386.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_AMI386SX_OPTI495: /* uses the OPTi 82C495 chipset */ - case ROM_AMI386DX_OPTI495: /* uses the OPTi 82C495 chipset */ - case ROM_AMI486_OPTI495: /* uses the OPTi 82C495 chipset */ - if (rom_load_linear( - L"roms/machines/ami495/opt495sx.ami", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_MR386SX_OPTI495: /* uses the OPTi 82C495 chipset */ - case ROM_MR386DX_OPTI495: /* uses the OPTi 82C495 chipset */ - case ROM_MR486_OPTI495: /* uses the OPTi 82C495 chipset */ - if (rom_load_linear( - L"roms/machines/mr495/opt495sx.mr", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_AWARD386SX_OPTI495: /* uses the OPTi 82C495 chipset */ - case ROM_AWARD386DX_OPTI495: /* uses the OPTi 82C495 chipset */ - case ROM_AWARD486_OPTI495: /* uses the OPTi 82C495 chipset */ - if (rom_load_linear( - L"roms/machines/award495/opt495s.awa", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_AMI286: - if (rom_load_linear( - L"roms/machines/ami286/amic206.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_AWARD286: - if (rom_load_linear( - L"roms/machines/award286/award.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_EUROPC: - if (rom_load_linear( - L"roms/machines/europc/50145", - 0x008000, 32768, 0, rom)) return(1); - break; - - case ROM_MEGAPC: - case ROM_MEGAPCDX: - if (rom_load_interleaved( - L"roms/machines/megapc/41651-bios lo.u18", - L"roms/machines/megapc/211253-bios hi.u19", - 0x000000, 65536, 0x08000, rom)) return(1); - break; - - case ROM_AMI486: - if (rom_load_linear( - L"roms/machines/ami486/ami486.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_WIN486: - if (rom_load_linear( - L"roms/machines/win486/ali1429g.amw", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_430VX: - if (! rom_load_linear( - L"roms/machines/430vx/55xwuq0e.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_REVENGE: - if (! rom_load_linear( - L"roms/machines/revenge/1009af2_.bio", - 0x010000, 65536, 128, rom)) break; - if (! rom_load_linear( - L"roms/machines/revenge/1009af2_.bi1", - 0x000000, 0x00c000, 128, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_ENDEAVOR: - if (! rom_load_linear( - L"roms/machines/endeavor/1006cb0_.bio", - 0x010000, 65536, 128, rom)) break; - if (! rom_load_linear( - L"roms/machines/endeavor/1006cb0_.bi1", - 0x000000, 0x00d000, 128, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS1_2011: - if (! rom_load_linear( - L"roms/machines/ibmps1es/f80000.bin", - 0x000000, 131072, 0x60000, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS1_2121: - case ROM_IBMPS1_2121_ISA: - if (! rom_load_linear( - L"roms/machines/ibmps1_2121/fc0000.bin", - 0x000000, 131072, 0x20000, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS1_2133: - if (! rom_load_linear( - L"roms/machines/ibmps1_2133/ps1_2133_52g2974_rom.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - -#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - case ROM_DESKPRO_386: - if (! rom_load_interleaved( - L"roms/machines/deskpro386/109592-005.u11.bin", - L"roms/machines/deskpro386/109591-005.u13.bin", - 0x000000, 32768, 0, rom)) break; - biosmask = 0x7fff; - return(1); -#endif - - case ROM_AMIXT: - if (rom_load_linear( - L"roms/machines/amixt/ami_8088_bios_31jan89.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; - -#if defined(DEV_BRANCH) && defined(USE_LASERXT) - case ROM_LTXT: - if (rom_load_linear( - L"roms/machines/ltxt/27c64.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; - - case ROM_LXT3: - if (rom_load_linear( - L"roms/machines/lxt3/27c64d.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; -#endif - - case ROM_GW286CT: - if (rom_load_linear( - L"roms/machines/gw286ct/2ctc001.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_SPC4200P: /* Samsung SPC-4200P */ - if (rom_load_linear( - L"roms/machines/spc4200p/u8.01", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_SPC4216P: - if (! rom_load_interleaved( - L"roms/machines/spc4216p/7101.u8", - L"roms/machines/spc4216p/ac64.u10", - 0x000000, 65536, 0, rom)) break; - return(1); - - case ROM_KMXC02: - if (rom_load_linear( - L"roms/machines/kmxc02/3ctm005.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_SUPER286TR: /* Hyundai Super-286TR */ - if (rom_load_linear( - L"roms/machines/super286tr/hyundai_award286.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_DTK386: /* uses NEAT chipset */ - if (rom_load_linear( - L"roms/machines/dtk386/3cto001.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_PXXT: - if (rom_load_linear( - L"roms/machines/pxxt/000p001.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; - - case ROM_JUKOPC: - if (rom_load_linear( - L"roms/machines/jukopc/000o001.bin", - 0x00e000, 8192, 0, rom)) return(1); - break; - - case ROM_IBMPS2_M30_286: - if (! rom_load_linear( - L"roms/machines/ibmps2_m30_286/33f5381a.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS2_M70_TYPE3: - if (! rom_load_interleaved( - L"roms/machines/ibmps2_m70_type3/70-a_even.bin", - L"roms/machines/ibmps2_m70_type3/70-a_odd.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - -#if defined(DEV_BRANCH) && defined(USE_PS2M70T4) - case ROM_IBMPS2_M70_TYPE4: - if (! rom_load_interleaved( - L"roms/machines/ibmps2_m70_type4/70-b_even.bin", - L"roms/machines/ibmps2_m70_type4/70-b_odd.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); -#endif - - case ROM_DTK486: - if (rom_load_linear( - L"roms/machines/dtk486/4siw005.bin", - 0x000000, 65536, 0, rom)) return(1); - break; - - case ROM_R418: - if (! rom_load_linear( - L"roms/machines/r418/r418i.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - -#if 0 - case ROM_586MC1: - if (! rom_load_linear( - L"roms/machines/586mc1/is.34", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); -#endif - - case ROM_PLATO: - if (! rom_load_linear( - L"roms/machines/plato/1016ax1_.bio", - 0x010000, 65536, 128, rom)) break; - if (! rom_load_linear( - L"roms/machines/plato/1016ax1_.bi1", - 0x000000, 0x00d000, 128, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_MB500N: - if (! rom_load_linear( - L"roms/machines/mb500n/031396s.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_AP53: - if (! rom_load_linear( - L"roms/machines/ap53/ap53r2c0.rom", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_P55T2S: - if (! rom_load_linear( - L"roms/machines/p55t2s/s6y08t.rom", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_PRESIDENT: - if (! rom_load_linear( - L"roms/machines/president/bios.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_P54TP4XE: - if (! rom_load_linear( - L"roms/machines/p54tp4xe/t15i0302.awd", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_ACERM3A: - if (! rom_load_linear( - L"roms/machines/acerm3a/r01-b3.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_ACERV35N: - if (! rom_load_linear( - L"roms/machines/acerv35n/v35nd1s1.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_P55VA: - if (! rom_load_linear( - L"roms/machines/p55va/va021297.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_P55T2P4: - if (! rom_load_linear( - L"roms/machines/p55t2p4/0207_j2.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_P55TVP4: - if (! rom_load_linear( - L"roms/machines/p55tvp4/tv5i0204.awd", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_J656VXD: - if (! rom_load_linear( - L"roms/machines/j656vxd/J656VXD.BIN", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - -#if defined(DEV_BRANCH) && defined(USE_I686) - case ROM_440FX: /* working Tyan BIOS */ - if (! rom_load_linear( - L"roms/machines/440fx/ntmaw501.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_S1668: /* working Tyan BIOS */ - if (! rom_load_linear( - L"roms/machines/tpatx/s1668p.rom", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); -#endif - - case ROM_THOR: - if (! rom_load_linear( - L"roms/machines/thor/1006cn0_.bio", - 0x010000, 65536, 128, rom)) break; - if (! rom_load_linear( - L"roms/machines/thor/1006cn0_.bi1", - 0x000000, 65536, 128, rom)) break; - biosmask = 0x1ffff; - return(1); - -#if defined(DEV_BRANCH) && defined(USE_MRTHOR) - case ROM_MRTHOR: - if (! rom_load_linear( - L"roms/machines/mrthor/mr_atx.bio", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); -#endif - - case ROM_PB640: - if (! rom_load_linear( - L"roms/machines/pb640/1007CP0R.BIO", - 0x010000, 65536, 128, rom)) break; - if (! rom_load_linear( - L"roms/machines/pb640/1007CP0R.BI1", - 0x000000, 0x00d000, 128, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_ZAPPA: - if (! rom_load_linear( - L"roms/machines/zappa/1006bs0_.bio", - 0x010000, 65536, 128, rom)) break; - if (! rom_load_linear( - L"roms/machines/zappa/1006bs0_.bi1", - 0x000000, 65536, 128, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS2_M50: - if (! rom_load_interleaved( - L"roms/machines/ibmps2_m50/90x7423.zm14", - L"roms/machines/ibmps2_m50/90x7426.zm16", - 0x000000, 65536, 0, rom)) break; - if (! rom_load_interleaved( - L"roms/machines/ibmps2_m50/90x7420.zm13", - L"roms/machines/ibmps2_m50/90x7429.zm18", - 0x010000, 65536, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS2_M55SX: - if (! rom_load_interleaved( - L"roms/machines/ibmps2_m55sx/33f8146.zm41", - L"roms/machines/ibmps2_m55sx/33f8145.zm40", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_IBMPS2_M80: - if (! rom_load_interleaved( - L"roms/machines/ibmps2_m80/15f6637.bin", - L"roms/machines/ibmps2_m80/15f6639.bin", - 0x000000, 131072, 0, rom)) break; - biosmask = 0x1ffff; - return(1); - - case ROM_T1000: - loadfont(L"roms/machines/t1000/t1000font.bin", 2); - if (!rom_load_linear( - L"roms/machines/t1000/t1000.rom", - 0x000000, 32768, 0, rom)) break; - biosmask = 0x7fff; - return(1); - - case ROM_T1200: - loadfont(L"roms/machines/t1200/t1000font.bin", 2); - if (!rom_load_linear( - L"roms/machines/t1200/t1200_019e.ic15.bin", - 0x000000, 32768, 0, rom)) break; - biosmask = 0x7fff; - return(1); - - case ROM_T3100E: - loadfont(L"roms/machines/t3100e/t3100e_font.bin", 5); - if (rom_load_linear( - L"roms/machines/t3100e/t3100e.rom", - 0x000000, 65536, 0, rom)) return(1); - break; - - default: - rom_log("ROM: don't know how to handle ROM set %d !\n", rom_id); - } - - return(0); -} diff --git a/src/rom.h b/src/rom.h index 6e50467e7..38cd033b0 100644 --- a/src/rom.h +++ b/src/rom.h @@ -8,166 +8,39 @@ * * Definitions for the ROM image handler. * - * Version: @(#)rom.h 1.0.22 2019/02/08 + * Version: @(#)rom.h 1.0.23 2019/03/03 * * Author: Fred N. van Kempen, - * Copyright 2018 Fred N. van Kempen. + * Copyright 2018,2019 Fred N. van Kempen. */ #ifndef EMU_ROM_H # define EMU_ROM_H -#define PCJR (romset==ROM_IBMPCJR) +#define FLAG_INT 1 +#define FLAG_INV 2 +#define FLAG_AUX 4 +#define FLAG_REP 8 + + +#define bios_load_linear(a, b, c, d) bios_load(a, NULL, b, c, d, 0) +#define bios_load_linearr(a, b, c, d) bios_load(a, NULL, b, c, d, FLAG_REP) +#define bios_load_aux_linear(a, b, c, d) bios_load(a, NULL, b, c, d, FLAG_AUX) +#define bios_load_linear_inverted(a, b, c, d) bios_load(a, NULL, b, c, d, FLAG_INV) +#define bios_load_aux_linear_inverted(a, b, c, d) bios_load(a, NULL, b, c, d, FLAG_INV | FLAG_AUX) +#define bios_load_interleaved(a, b, c, d, e) bios_load(a, b, c, d, e, FLAG_INT) +#define bios_load_interleavedr(a, b, c, d, e) bios_load(a, b, c, d, e, FLAG_INT | FLAG_REP) +#define bios_load_aux_interleaved(a, b, c, d, e) bios_load(a, b, c, d, e, FLAG_INT | FLAG_AUX) typedef struct { uint8_t *rom; + int sz; uint32_t mask; mem_mapping_t mapping; } rom_t; -enum { - ROM_IBMPC = 0, /* 1981 - 16-64 variant */ - ROM_IBMPC82, /* 1982 - 64-256 variant */ - ROM_AMIXT, /* XT Clone with AMI BIOS */ - ROM_DTKXT, - ROM_IBMXT, - ROM_IBMXT86, - ROM_GENXT, /* 'Generic XT BIOS' */ - ROM_JUKOPC, - ROM_PORTABLE, - ROM_PXXT, -#if defined(DEV_BRANCH) && defined(USE_LASERXT) - ROM_LTXT, - - ROM_LXT3, -#endif - - ROM_T1000, - ROM_T1200, - - ROM_XI8088, - - ROM_IBMPCJR, - ROM_TANDY, - ROM_TANDY1000HX, - ROM_EUROPC, - ROM_PC1512, - ROM_PC1640, - ROM_PC200, - ROM_PC2086, - ROM_PC3086, - ROM_OLIM24, - ROM_TANDY1000SL2, - ROM_ZD_SUPERS, - - ROM_T3100E, - - ROM_AMI286, - ROM_AWARD286, - ROM_CMDPC30, - ROM_TG286M, - ROM_PORTABLEII, -#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - ROM_PORTABLEIII, -#endif - ROM_GW286CT, - ROM_SUPER286TR, /* Hyundai Super-286TR/SCAT/Award */ - ROM_IBMAT, - ROM_IBMPS1_2011, - ROM_IBMPS2_M30_286, - ROM_IBMXT286, - ROM_SPC4200P, /* Samsung SPC-4200P/SCAT/Phoenix */ - ROM_SPC4216P, /* Samsung SPC-4216P/SCAT */ - - ROM_IBMPS2_M50, - - ROM_AMA932J, - ROM_AMI386SX_OPTI495, - ROM_AMI386SX, - ROM_KMXC02, - ROM_MEGAPC, - ROM_MR386SX_OPTI495, - ROM_AWARD386SX_OPTI495, -#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - ROM_DESKPRO_386, -#endif - ROM_DTK386, - ROM_IBMPS1_2121, - ROM_IBMPS1_2121_ISA,/* IBM PS/1 Model 2121 with ISA expansion bus */ -#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - ROM_PORTABLEIII386, -#endif - - ROM_IBMPS2_M55SX, - - ROM_AMI386DX_OPTI495, - ROM_MEGAPCDX, /* 386DX mdl - Note: documentation (in German) clearly says such a model exists */ - ROM_AWARD386DX_OPTI495, - ROM_MR386DX_OPTI495, - - ROM_IBMPS2_M80, - - ROM_AMI486_OPTI495, - ROM_AMI486, - ROM_WIN486, -#ifdef UNIMPLEMENTED_MACHINES - ROM_VLI486SV2G, /* ASUS VL/I-486SV2G/SiS 471/Award/SiS 85C471 */ /* 51 */ -#endif - ROM_AWARD486_OPTI495, - ROM_DTK486, /* DTK PKM-0038S E-2/SiS 471/Award/SiS 85C471 */ - ROM_IBMPS1_2133, - ROM_MR486_OPTI495, - - ROM_IBMPS2_M70_TYPE3, -#if defined(DEV_BRANCH) && defined(USE_PS2M70T4) - ROM_IBMPS2_M70_TYPE4, -#endif - - ROM_R418, /* Rise Computer R418/SiS 496/497/Award/SMC FDC37C665 */ - - ROM_REVENGE, /* Intel Premiere/PCI I/430LX/AMI/SMC FDC37C665 */ - - ROM_PLATO, /* Intel Premiere/PCI II/430NX/AMI/SMC FDC37C665 */ - - ROM_P54TP4XE, /* ASUS P/I-P55TP4XE/430FX/Award/SMC FDC37C665 */ - ROM_ENDEAVOR, /* Intel Advanced_EV/430FX/AMI/NS PC87306 */ - ROM_ZAPPA, /* Intel Advanced_ZP/430FX/AMI/NS PC87306 */ -#ifdef UNIMPLEMENTED_MACHINES - ROM_POWERMATE_V, /* NEC PowerMate V/430FX/Phoenix/SMC FDC37C66 5*/ -#endif - ROM_MB500N, /* PC Partner MB500N/430FX/Award/SMC FDC37C665 */ - ROM_PRESIDENT, /* President Award 430FX PCI/430FX/Award/Unknown SIO */ - - ROM_THOR, /* Intel Advanced_ATX/430FX/AMI/NS PC87306 */ -#if defined(DEV_BRANCH) && defined(USE_MRTHOR) - ROM_MRTHOR, /* Intel Advanced_ATX/430FX/MR.BIOS/NS PC87306 */ -#endif - ROM_PB640, /* Packard Bell PB640/430FX/AMI/NS PC87306 */ - - ROM_ACERM3A, /* Acer M3A/430HX/Acer/SMC FDC37C932FR */ - ROM_ACERV35N, /* Acer V35N/430HX/Acer/SMC FDC37C932FR */ - ROM_AP53, /* AOpen AP53/430HX/AMI/SMC FDC37C665/669 */ - ROM_P55T2P4, /* ASUS P/I-P55T2P4/430HX/Award/Winbond W8387F*/ - ROM_P55T2S, /* ASUS P/I-P55T2S/430HX/AMI/NS PC87306 */ - - ROM_P55TVP4, /* ASUS P/I-P55TVP4/430VX/Award/Winbond W8387F*/ - ROM_430VX, /* Award 430VX PCI/430VX/Award/UMC UM8669F*/ - ROM_P55VA, /* Epox P55-VA/430VX/Award/SMC FDC37C932FR*/ - ROM_J656VXD, /* Jetway J656VXD/430VX/Award/SMC FDC37C669*/ - -#if defined(DEV_BRANCH) && defined(USE_I686) - ROM_440FX, /* Tyan Titan-Pro AT/440FX/Award BIOS/SMC FDC37C665 */ - ROM_S1668, /* Tyan Titan-Pro ATX/440FX/AMI/SMC FDC37C669 */ -#endif - - ROM_MAX -}; - - -extern int romspresent[ROM_MAX]; - extern uint8_t rom_read(uint32_t addr, void *p); extern uint16_t rom_readw(uint32_t addr, void *p); extern uint32_t rom_readl(uint32_t addr, void *p); @@ -181,6 +54,16 @@ extern int rom_load_linear(wchar_t *fn, uint32_t addr, int sz, extern int rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int off, uint8_t *ptr); +extern int bios_load(wchar_t *fn1, wchar_t *fn2, uint32_t addr, int sz, + int off, int flags); +extern int bios_load_linear_combined(wchar_t *fn1, wchar_t *fn2, + int sz, int off); +#if defined(DEV_BRANCH) && defined(USE_TC430HX) +extern int bios_load_linear_combined2(wchar_t *fn1, wchar_t *fn2, + wchar_t *fn3, wchar_t *fn4, wchar_t *fn5, + int sz, int off); +#endif + extern int rom_init(rom_t *rom, wchar_t *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags); extern int rom_init_interleaved(rom_t *rom, wchar_t *fn_low, @@ -188,7 +71,5 @@ extern int rom_init_interleaved(rom_t *rom, wchar_t *fn_low, int size, int mask, int file_offset, uint32_t flags); -extern int rom_load_bios(int rom_id); - #endif /*EMU_ROM_H*/ diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index f0a5bed9c..c23e7f83d 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -56,23 +56,25 @@ typedef const struct { static SCSI_CARD scsi_cards[] = { { "None", "none", NULL, }, - { "[ISA] Adaptec AHA-1540B", "aha1540b", &aha1540b_device, }, - { "[ISA] Adaptec AHA-1542C", "aha1542c", &aha1542c_device, }, - { "[ISA] Adaptec AHA-1542CF", "aha1542cf", &aha1542cf_device, }, + { "[ISA] Adaptec AHA-154xA", "aha154xa", &aha154xa_device, }, + { "[ISA] Adaptec AHA-154xB", "aha154xb", &aha154xb_device, }, + { "[ISA] Adaptec AHA-154xC", "aha154xc", &aha154xc_device, }, + { "[ISA] Adaptec AHA-154xCF", "aha154xcf", &aha154xcf_device, }, + { "[ISA] BusLogic BT-542B", "bt542b", &buslogic_542b_1991_device, }, { "[ISA] BusLogic BT-542BH", "bt542bh", &buslogic_device, }, { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device, }, { "[ISA] Longshine LCS-6821N", "lcs6821n", &scsi_lcs6821n_device, }, - { "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, }, + { "[ISA] Rancho RT1000B", "rt1000b", &scsi_rt1000b_device, }, { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, }, - { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, #ifdef WALTJE + { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, }, #endif { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, }, { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device, }, { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, }, { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device, }, - { "[PCI] NCR 53C825A", "ncr53c825a", &ncr53c825a_pci_device, }, + //{ "[PCI] NCR 53C825A", "ncr53c825a", &ncr53c825a_pci_device, }, { "[PCI] NCR 53C875", "ncr53c875", &ncr53c875_pci_device, }, { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device, }, { "", "", NULL, }, diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 41f9540df..a33d35f07 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -26,6 +26,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mca.h" #include "../mem.h" #include "../mca.h" @@ -34,7 +35,6 @@ #include "../nvr.h" #include "../dma.h" #include "../pic.h" -#include "../timer.h" #include "../plat.h" // #include "../cpu/cpu.h" #include "scsi.h" @@ -43,6 +43,7 @@ enum { + AHA_154xA, AHA_154xB, AHA_154xC, AHA_154xCF, @@ -51,6 +52,7 @@ enum { }; + #define CMD_WRITE_EEPROM 0x22 /* UNDOC: Write EEPROM */ #define CMD_READ_EEPROM 0x23 /* UNDOC: Read EEPROM */ #define CMD_SHADOW_RAM 0x24 /* UNDOC: BIOS shadow ram */ @@ -290,7 +292,7 @@ aha_param_len(void *p) break; case CMD_WRITE_EEPROM: - return 3+32; + return 35; break; case CMD_READ_EEPROM: @@ -358,7 +360,7 @@ aha_cmds(void *p) case CMD_BIOS_MBINIT: /* BIOS Mailbox Initialization */ /* Sent by CF BIOS. */ - dev->Mbx24bit = 1; + dev->flags |= X54X_MBX_24BIT; mbi = (MailboxInit_t *)dev->CmdBuf; @@ -578,6 +580,15 @@ aha_mca_write(int port, uint8_t val, void *priv) } +static uint8_t +aha_mca_feedb(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + return (dev->pos_regs[2] & 0x01); +} + + /* Initialize the board's ROM BIOS. */ static void aha_setbios(x54x_t *dev) @@ -717,16 +728,12 @@ aha_setnvr(x54x_t *dev) memset(dev->nvr, 0x00, NVR_SIZE); f = nvr_fopen(dev->nvr_path, L"rb"); - if (f) - { + if (f) { fread(dev->nvr, 1, NVR_SIZE, f); fclose(f); f = NULL; - } - else - { + } else aha_initnvr(dev); - } } @@ -753,10 +760,7 @@ aha_init(const device_t *info) dev->HostID = 7; /* default HA ID */ dev->setup_info_len = sizeof(aha_setup_t); dev->max_id = 7; - dev->int_geom_writable = 0; - dev->cdrom_boot = 0; - dev->bit32 = 0; - dev->lba_bios = 0; + dev->flags = 0; dev->ven_callback = aha_callback; dev->ven_cmd_is_fast = aha_cmd_is_fast; @@ -769,6 +773,17 @@ aha_init(const device_t *info) /* Perform per-board initialization. */ switch(dev->type) { + case AHA_154xA: + strcpy(dev->name, "AHA-154xA"); + dev->fw_rev = "A003"; /* The 3.07 microcode says A006. */ + dev->bios_path = L"roms/scsi/adaptec/aha1540a307.bin"; /*Only for port 0x330*/ + /* This is configurable from the configuration for the 154xB, the rest of the controllers read it from the EEPROM. */ + dev->HostID = device_get_config_int("hostid"); + dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shramsz = 128; /* size of shadow RAM */ + dev->ha_bps = 5000000.0; /* normal SCSI */ + break; + case AHA_154xB: strcpy(dev->name, "AHA-154xB"); switch(dev->Base) { @@ -814,7 +829,7 @@ aha_init(const device_t *info) dev->rom_shramsz = 128; /* size of shadow RAM */ dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ dev->rom_fwhigh = 0x0022; /* firmware version (hi/lo) */ - dev->cdrom_boot = 1; + dev->flags |= X54X_CDROM_BOOT; dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ @@ -841,12 +856,12 @@ aha_init(const device_t *info) dev->bios_path = L"roms/scsi/adaptec/aha1640.bin"; dev->fw_rev = "BB01"; - dev->lba_bios = 1; + dev->flags |= X54X_LBA_BIOS; /* Enable MCA. */ dev->pos_regs[0] = 0x1F; /* MCA board ID */ dev->pos_regs[1] = 0x0F; - mca_add(aha_mca_read, aha_mca_write, dev); + mca_add(aha_mca_read, aha_mca_write, aha_mca_feedb, dev); dev->ha_bps = 5000000.0; /* normal SCSI */ break; } @@ -1107,8 +1122,17 @@ static const device_config_t aha_154x_config[] = { }; -const device_t aha1540b_device = { - "Adaptec AHA-1540B", +const device_t aha154xa_device = { + "Adaptec AHA-154xA", + DEVICE_ISA | DEVICE_AT, + AHA_154xA, + aha_init, x54x_close, NULL, + NULL, NULL, NULL, + aha_154xb_config +}; + +const device_t aha154xb_device = { + "Adaptec AHA-154xB", DEVICE_ISA | DEVICE_AT, AHA_154xB, aha_init, x54x_close, NULL, @@ -1116,8 +1140,8 @@ const device_t aha1540b_device = { aha_154xb_config }; -const device_t aha1542c_device = { - "Adaptec AHA-1542C", +const device_t aha154xc_device = { + "Adaptec AHA-154xC", DEVICE_ISA | DEVICE_AT, AHA_154xC, aha_init, x54x_close, NULL, @@ -1125,8 +1149,8 @@ const device_t aha1542c_device = { aha_154x_config }; -const device_t aha1542cf_device = { - "Adaptec AHA-1542CF", +const device_t aha154xcf_device = { + "Adaptec AHA-154xCF", DEVICE_ISA | DEVICE_AT, AHA_154xCF, aha_init, x54x_close, NULL, diff --git a/src/scsi/scsi_aha154x.h b/src/scsi/scsi_aha154x.h index 73eb10b89..e7b3d62c0 100644 --- a/src/scsi/scsi_aha154x.h +++ b/src/scsi/scsi_aha154x.h @@ -1,10 +1,10 @@ #ifndef SCSI_AHA154X_H # define SCSI_AHA154X_H - -extern const device_t aha1540b_device; -extern const device_t aha1542c_device; -extern const device_t aha1542cf_device; +extern const device_t aha154xa_device; +extern const device_t aha154xb_device; +extern const device_t aha154xc_device; +extern const device_t aha154xcf_device; extern const device_t aha1640_device; extern void aha_device_reset(void *p); diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index 8ac6e3e4a..15a4dc7d4 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -11,7 +11,7 @@ * 1 - BT-545S ISA; * 2 - BT-958D PCI * - * Version: @(#)scsi_buslogic.c 1.0.44 2018/11/11 + * Version: @(#)scsi_buslogic.c 1.0.45 2019/02/11 * * Authors: TheCollector1995, * Miran Grca, @@ -29,6 +29,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mca.h" #include "../mem.h" #include "../mca.h" @@ -38,7 +39,6 @@ #include "../dma.h" #include "../pic.h" #include "../pci.h" -#include "../timer.h" #include "../plat.h" #include "scsi.h" #include "scsi_buslogic.h" @@ -229,6 +229,7 @@ typedef struct { enum { + CHIP_BUSLOGIC_ISA_542_1991, CHIP_BUSLOGIC_ISA_542, CHIP_BUSLOGIC_ISA, CHIP_BUSLOGIC_MCA, @@ -263,6 +264,8 @@ BuslogicGetNVRFileName(buslogic_data_t *bl) { switch(bl->chip) { + case CHIP_BUSLOGIC_ISA_542_1991: + return L"bt542b.nvr"; case CHIP_BUSLOGIC_ISA_542: return L"bt542bh.nvr"; case CHIP_BUSLOGIC_ISA: @@ -298,6 +301,9 @@ BuslogicAutoSCSIRamSetDefaults(x54x_t *dev, uint8_t safe) HALR->structured.autoSCSIData.aHostAdaptertype[0] = ' '; HALR->structured.autoSCSIData.aHostAdaptertype[5] = ' '; switch (bl->chip) { + case CHIP_BUSLOGIC_ISA_542_1991: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "542B", 4); + break; case CHIP_BUSLOGIC_ISA_542: memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "542BH", 5); break; @@ -463,7 +469,7 @@ buslogic_get_host_id(void *p) HALocalRAM *HALR = &bl->LocalRAM; - if (bl->chip == CHIP_BUSLOGIC_ISA_542) + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991)) return dev->HostID; else return HALR->structured.autoSCSIData.uSCSIId; @@ -480,7 +486,7 @@ buslogic_get_irq(void *p) HALocalRAM *HALR = &bl->LocalRAM; - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_PCI)) + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991) || (bl->chip == CHIP_BUSLOGIC_PCI)) return dev->Irq; else return bl_irq[HALR->structured.autoSCSIData.uIrqChannel]; @@ -499,7 +505,7 @@ buslogic_get_dma(void *p) if (bl->chip == CHIP_BUSLOGIC_PCI) return (dev->Base ? 7 : 0); - else if (bl->chip == CHIP_BUSLOGIC_ISA_542) + else if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991)) return dev->DmaChannel; else return bl_dma[HALR->structured.autoSCSIData.uDMAChannel]; @@ -718,7 +724,7 @@ buslogic_cmds(void *p) dev->IrqEnabled = 1; return 1; case 0x81: - dev->Mbx24bit = 0; + dev->flags &= ~X54X_MBX_24BIT; MailboxInitE = (MailboxInitExtended_t *)dev->CmdBuf; @@ -812,6 +818,7 @@ buslogic_cmds(void *p) memset(ReplyIESI, 0, sizeof(ReplyInquireExtendedSetupInformation)); switch (bl->chip) { + case CHIP_BUSLOGIC_ISA_542_1991: case CHIP_BUSLOGIC_ISA_542: case CHIP_BUSLOGIC_ISA: case CHIP_BUSLOGIC_VLB: @@ -829,7 +836,7 @@ buslogic_cmds(void *p) ReplyIESI->cMailbox = dev->MailboxCount; ReplyIESI->uMailboxAddressBase = dev->MailboxOutAddr; ReplyIESI->fHostWideSCSI = 1; /* This should be set for the BT-542B as well. */ - if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_MCA)) + if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_ISA_542_1991) && (bl->chip != CHIP_BUSLOGIC_MCA)) ReplyIESI->fLevelSensitiveInterrupt = bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; if (bl->chip == CHIP_BUSLOGIC_PCI) ReplyIESI->fHostUltraSCSI = 1; @@ -864,7 +871,7 @@ buslogic_cmds(void *p) break; } case 0x92: - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) { + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991) || (bl->chip == CHIP_BUSLOGIC_MCA)) { dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; break; @@ -910,7 +917,7 @@ buslogic_cmds(void *p) } break; case 0x94: - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) { + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991) || (bl->chip == CHIP_BUSLOGIC_MCA)) { dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; break; @@ -1030,6 +1037,7 @@ buslogic_setup_data(void *p) bl_setup->uCharacterD = 'D'; /* BusLogic model. */ switch(bl->chip) { + case CHIP_BUSLOGIC_ISA_542_1991: case CHIP_BUSLOGIC_ISA_542: case CHIP_BUSLOGIC_ISA: bl_setup->uHostBusType = 'A'; @@ -1063,7 +1071,7 @@ buslogic_interrupt_type(void *p) x54x_t *dev = (x54x_t *)p; buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA_542_1991) || (bl->chip == CHIP_BUSLOGIC_MCA)) return 0; else return !!bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; @@ -1152,7 +1160,7 @@ BuslogicPCIRead(int func, int addr, void *p) // return (buslogic_pci_bar[1].addr_regs[0] & 0xe0); /*Memory space*/ return 0x00; case 0x15: - return buslogic_pci_bar[1].addr_regs[1]; + return buslogic_pci_bar[1].addr_regs[1] & 0xc0; case 0x16: return buslogic_pci_bar[1].addr_regs[2]; case 0x17: @@ -1480,6 +1488,15 @@ buslogic_mca_write(int port, uint8_t val, void *priv) } +static uint8_t +buslogic_mca_feedb(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + return (dev->pos_regs[2] & 0x01); +} + + void BuslogicDeviceReset(void *p) { @@ -1530,10 +1547,7 @@ buslogic_init(const device_t *info) dev->HostID = 7; /* default HA ID */ dev->setup_info_len = sizeof(buslogic_setup_t); dev->max_id = 7; - dev->int_geom_writable = 1; - dev->cdrom_boot = 0; - dev->bit32 = 0; - dev->lba_bios = 0; + dev->flags = X54X_INT_GEOM_WRITABLE; bl->chip = info->local; bl->PCIBase = 0; @@ -1566,6 +1580,17 @@ buslogic_init(const device_t *info) switch(bl->chip) { + case CHIP_BUSLOGIC_ISA_542_1991: + strcpy(dev->name, "BT-542B"); + bios_rom_name = L"roms/scsi/buslogic/BT-542B_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 0; + has_scam_rom = 0; + dev->fw_rev = "AA221"; + dev->ha_bps = 5000000.0; /* normal SCSI */ + dev->max_id = 7; /* narrow SCSI */ + break; case CHIP_BUSLOGIC_ISA_542: strcpy(dev->name, "BT-542BH"); bios_rom_name = L"roms/scsi/buslogic/BT-542BH_BIOS.rom"; @@ -1575,7 +1600,7 @@ buslogic_init(const device_t *info) has_scam_rom = 0; dev->fw_rev = "AA335"; dev->ha_bps = 5000000.0; /* normal SCSI */ - dev->max_id = 15; /* wide SCSI */ + dev->max_id = 7; /* narrow SCSI */ break; case CHIP_BUSLOGIC_ISA: default: @@ -1589,7 +1614,7 @@ buslogic_init(const device_t *info) has_scam_rom = 0; dev->fw_rev = "AA421E"; dev->ha_bps = 10000000.0; /* fast SCSI */ - dev->max_id = 15; /* wide SCSI */ + dev->max_id = 7; /* narrow SCSI */ break; case CHIP_BUSLOGIC_MCA: strcpy(dev->name, "BT-640A"); @@ -1599,12 +1624,12 @@ buslogic_init(const device_t *info) has_autoscsi_rom = 0; has_scam_rom = 0; dev->fw_rev = "BA150"; - dev->bit32 = 1; + dev->flags |= X54X_32BIT; dev->pos_regs[0] = 0x08; /* MCA board ID */ dev->pos_regs[1] = 0x07; - mca_add(buslogic_mca_read, buslogic_mca_write, dev); + mca_add(buslogic_mca_read, buslogic_mca_write, buslogic_mca_feedb, dev); dev->ha_bps = 5000000.0; /* normal SCSI */ - dev->max_id = 15; /* wide SCSI */ + dev->max_id = 7; /* narrow SCSI */ break; case CHIP_BUSLOGIC_VLB: strcpy(dev->name, "BT-445S"); @@ -1618,9 +1643,9 @@ buslogic_init(const device_t *info) scam_rom_name = L"roms/scsi/buslogic/BT-445S_SCAM.rom"; scam_rom_size = 0x0200; dev->fw_rev = "AA507B"; - dev->bit32 = 1; + dev->flags |= X54X_32BIT; dev->ha_bps = 10000000.0; /* fast SCSI */ - dev->max_id = 15; /* wide SCSI */ + dev->max_id = 7; /* narrow SCSI */ break; case CHIP_BUSLOGIC_PCI: strcpy(dev->name, "BT-958D"); @@ -1634,8 +1659,7 @@ buslogic_init(const device_t *info) scam_rom_name = L"roms/scsi/buslogic/BT-958D_SCAM.rom"; scam_rom_size = 0x0200; dev->fw_rev = "AA507B"; - dev->cdrom_boot = 1; - dev->bit32 = 1; + dev->flags |= (X54X_CDROM_BOOT | X54X_32BIT); dev->ha_bps = 20000000.0; /* ultra SCSI */ dev->max_id = 15; /* wide SCSI */ break; @@ -1706,7 +1730,7 @@ buslogic_init(const device_t *info) x54x_device_reset(dev); - if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_MCA)) { + if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_ISA_542_1991) && (bl->chip != CHIP_BUSLOGIC_MCA)) { BuslogicInitializeLocalRAM(bl); BuslogicInitializeAutoSCSIRam(dev); } @@ -1820,6 +1844,14 @@ static const device_config_t BT958D_Config[] = { } }; +const device_t buslogic_542b_1991_device = { + "Buslogic BT-542B ISA", + DEVICE_ISA | DEVICE_AT, + CHIP_BUSLOGIC_ISA_542_1991, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, + BT_ISA_Config +}; const device_t buslogic_device = { "Buslogic BT-542BH ISA", diff --git a/src/scsi/scsi_buslogic.h b/src/scsi/scsi_buslogic.h index 83ce417d9..87f79d522 100644 --- a/src/scsi/scsi_buslogic.h +++ b/src/scsi/scsi_buslogic.h @@ -20,6 +20,7 @@ # define SCSI_BUSLOGIC_H +extern const device_t buslogic_542b_1991_device; extern const device_t buslogic_device; extern const device_t buslogic_545s_device; extern const device_t buslogic_640a_device; diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 782f41d5c..d6690bb74 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.69 2018/11/11 + * Version: @(#)scsi_cdrom.c 1.0.70 2019/03/11 * * Author: Miran Grca, * - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -83,7 +83,8 @@ const uint8_t scsi_cdrom_command_flags[0x100] = IMPLEMENTED | CHECK_READY, /* 0x1E */ 0, 0, 0, 0, 0, 0, /* 0x1F-0x24 */ IMPLEMENTED | CHECK_READY, /* 0x25 */ - 0, 0, /* 0x26-0x27 */ + 0 /*IMPLEMENTED | CHECK_READY | SCSI_ONLY*/, + 0, /* 0x26-0x27 */ IMPLEMENTED | CHECK_READY, /* 0x28 */ 0, 0, /* 0x29-0x2A */ IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ @@ -139,9 +140,12 @@ const uint8_t scsi_cdrom_command_flags[0x100] = IMPLEMENTED, /* 0xBD */ IMPLEMENTED | CHECK_READY, /* 0xBE */ IMPLEMENTED | CHECK_READY, /* 0xBF */ - 0, 0, /* 0xC0-0xC1 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC2 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC3-0xCC */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC0 */ + 0, /* 0xC1 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC2 */ + 0, 0, 0, /* 0xC3-0xC5 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC6 */ + 0, 0, 0, 0, 0, 0, /* 0xC7-0xCC */ IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCD */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xCE-0xD9 */ IMPLEMENTED | SCSI_ONLY, /* 0xDA */ @@ -331,7 +335,7 @@ scsi_cdrom_log(const char *format, ...) static void scsi_cdrom_set_callback(scsi_cdrom_t *dev) { - if (dev && dev->drv && (dev->drv->bus_type != CDROM_BUS_SCSI)) + if (dev && dev->drv && (dev->drv->bus_type != CDROM_BUS_SCSI && dev->drv->bus_type != CDROM_BUS_SCSI_CHINON)) ide_set_callback(dev->drv->ide_channel >> 1, dev->callback); } @@ -370,7 +374,7 @@ scsi_cdrom_init(scsi_cdrom_t *dev) static int scsi_cdrom_current_mode(scsi_cdrom_t *dev) { - if (dev->drv->bus_type == CDROM_BUS_SCSI) + if (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) return 2; else if (dev->drv->bus_type == CDROM_BUS_ATAPI) { scsi_cdrom_log("CD-ROM %i: ATAPI drive, setting to %s\n", dev->id, @@ -444,7 +448,7 @@ scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default, sizeof(mode_sense_pages_t)); memset(file_name, 0, 512 * sizeof(wchar_t)); - if (dev->drv->bus_type == CDROM_BUS_SCSI) + if (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); else swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); @@ -604,8 +608,8 @@ scsi_cdrom_update_request_length(scsi_cdrom_t *dev, int len, int block_len) static double scsi_cdrom_bus_speed(scsi_cdrom_t *dev) { - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - dev->callback = -1LL; /* Speed depends on SCSI controller */ + if (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) { + dev->callback = -1.0; /* Speed depends on SCSI controller */ return 0.0; } else { /* TODO: Get the actual selected speed from IDE. */ @@ -621,17 +625,16 @@ static void scsi_cdrom_command_common(scsi_cdrom_t *dev) { double bytes_per_second, period; - double dusec; dev->status = BUSY_STAT; dev->phase = 1; dev->pos = 0; - dev->callback = 0LL; + dev->callback = 0; scsi_cdrom_log("CD-ROM %i: Current speed: %ix\n", dev->id, dev->drv->cur_speed); if (dev->packet_status == PHASE_COMPLETE) - dev->callback = 0LL; + dev->callback = 0; else { switch(dev->current_cdb[0]) { case GPCMD_REZERO_UNIT: @@ -640,9 +643,8 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) /* Seek time is in us. */ period = cdrom_seek_time(dev->drv); scsi_cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", - dev->id, (int64_t) period); - period = period * ((double) TIMER_USEC); - dev->callback += ((int64_t) period); + dev->id, (uint64_t) period); + dev->callback += period; scsi_cdrom_set_callback(dev); return; case 0x08: @@ -651,9 +653,8 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) /* Seek time is in us. */ period = cdrom_seek_time(dev->drv); scsi_cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", - dev->id, (int64_t) period); - period = period * ((double) TIMER_USEC); - dev->callback += ((int64_t) period); + dev->id, (uint64_t) period); + dev->callback += period; /*FALLTHROUGH*/ case 0x25: case 0x42: @@ -666,7 +667,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) case 0xb9: case 0xbe: if (dev->current_cdb[0] == 0x42) - dev->callback += 200LL * CDROM_TIME; + dev->callback += 200.0 * CDROM_TIME; /* Account for seek time. */ bytes_per_second = 176.0 * 1024.0; bytes_per_second *= (double) dev->drv->cur_speed; @@ -674,18 +675,17 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) default: bytes_per_second = scsi_cdrom_bus_speed(dev); if (bytes_per_second == 0.0) { - dev->callback = -1LL; /* Speed depends on SCSI controller */ + dev->callback = -1; /* Speed depends on SCSI controller */ return; } break; } period = 1000000.0 / bytes_per_second; - scsi_cdrom_log("CD-ROM %i: Byte transfer period: %" PRIu64 " us\n", dev->id, (int64_t) period); + scsi_cdrom_log("CD-ROM %i: Byte transfer period: %" PRIu64 " us\n", dev->id, (uint64_t) period); period = period * (double) (dev->packet_len); - scsi_cdrom_log("CD-ROM %i: Sector transfer period: %" PRIu64 " us\n", dev->id, (int64_t) period); - dusec = period * ((double) TIMER_USEC); - dev->callback += ((int64_t) dusec); + scsi_cdrom_log("CD-ROM %i: Sector transfer period: %" PRIu64 " us\n", dev->id, (uint64_t) period); + dev->callback += period; } scsi_cdrom_set_callback(dev); } @@ -745,13 +745,13 @@ static void scsi_cdrom_data_command_finish(scsi_cdrom_t *dev, int len, int block len = alloc_len; } if ((len == 0) || (scsi_cdrom_current_mode(dev) == 0)) { - if (dev->drv->bus_type != CDROM_BUS_SCSI) + if (dev->drv->bus_type != CDROM_BUS_SCSI && dev->drv->bus_type != CDROM_BUS_SCSI_CHINON) dev->packet_len = 0; scsi_cdrom_command_complete(dev); } else { if (scsi_cdrom_current_mode(dev) == 2) { - if (dev->drv->bus_type != CDROM_BUS_SCSI) + if (dev->drv->bus_type != CDROM_BUS_SCSI && dev->drv->bus_type != CDROM_BUS_SCSI_CHINON) dev->packet_len = alloc_len; if (direction == 0) @@ -784,7 +784,7 @@ scsi_cdrom_set_phase(scsi_cdrom_t *dev, uint8_t phase) { uint8_t scsi_id = dev->drv->scsi_device_id; - if (dev->drv->bus_type != CDROM_BUS_SCSI) + if (dev->drv->bus_type != CDROM_BUS_SCSI && dev->drv->bus_type != CDROM_BUS_SCSI_CHINON) return; scsi_devices[scsi_id].phase = phase; @@ -802,7 +802,7 @@ scsi_cdrom_cmd_error(scsi_cdrom_t *dev) dev->phase = 3; dev->pos = 0; dev->packet_status = PHASE_ERROR; - dev->callback = 50LL * CDROM_TIME; + dev->callback = 50.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); scsi_cdrom_log("CD-ROM %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_cdrom_sense_key, scsi_cdrom_asc, scsi_cdrom_ascq); } @@ -819,7 +819,7 @@ scsi_cdrom_unit_attention(scsi_cdrom_t *dev) dev->phase = 3; dev->pos = 0; dev->packet_status = PHASE_ERROR; - dev->callback = 50LL * CDROM_TIME; + dev->callback = 50.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); scsi_cdrom_log("CD-ROM %i: UNIT ATTENTION\n", dev->id); } @@ -948,63 +948,6 @@ scsi_cdrom_data_phase_error(scsi_cdrom_t *dev) } -void -scsi_cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks) -{ - int temp = 0; - - switch(cdb[0]) { - case GPCMD_READ_6: - cdb[1] = (lba_pos >> 16) & 0xff; - cdb[2] = (lba_pos >> 8) & 0xff; - cdb[3] = lba_pos & 0xff; - break; - - case GPCMD_READ_10: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[7] = (number_of_blocks >> 8) & 0xff; - cdb[8] = number_of_blocks & 0xff; - break; - - case GPCMD_READ_12: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[6] = (number_of_blocks >> 24) & 0xff; - cdb[7] = (number_of_blocks >> 16) & 0xff; - cdb[8] = (number_of_blocks >> 8) & 0xff; - cdb[9] = number_of_blocks & 0xff; - break; - - case GPCMD_READ_CD_MSF: - temp = cdrom_lba_to_msf_accurate(lba_pos); - cdb[3] = (temp >> 16) & 0xff; - cdb[4] = (temp >> 8) & 0xff; - cdb[5] = temp & 0xff; - - temp = cdrom_lba_to_msf_accurate(lba_pos + number_of_blocks - 1); - cdb[6] = (temp >> 16) & 0xff; - cdb[7] = (temp >> 8) & 0xff; - cdb[8] = temp & 0xff; - break; - - case GPCMD_READ_CD: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[6] = (number_of_blocks >> 16) & 0xff; - cdb[7] = (number_of_blocks >> 8) & 0xff; - cdb[8] = number_of_blocks & 0xff; - break; - } -} - - static int scsi_cdrom_read_data(scsi_cdrom_t *dev, int msf, int type, int flags, int32_t *len) { @@ -1023,15 +966,20 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, int msf, int type, int flags, int32_t *l scsi_cdrom_log("CD-ROM %i: Trying to read from beyond the end of disc (%i >= %i)\n", dev->id, dev->sector_pos, cdsize); scsi_cdrom_lba_out_of_range(dev); - return 0; + return -1; } +/* FIXME: Temporarily disabled this because the Triones ATAPI DMA driver seems to + always request a 4-sector read but sets the DMA bus master to transfer less + data than that. */ +#if 0 if ((dev->sector_pos + dev->sector_len - 1) >= cdsize) { scsi_cdrom_log("CD-ROM %i: Trying to read to beyond the end of disc (%i >= %i)\n", dev->id, (dev->sector_pos + dev->sector_len - 1), cdsize); scsi_cdrom_lba_out_of_range(dev); - return 0; + return -1; } +#endif dev->old_len = 0; *len = 0; @@ -1079,13 +1027,13 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, int first_batch) scsi_cdrom_log("Reading %i blocks starting from %i...\n", dev->requested_blocks, dev->sector_pos); - scsi_cdrom_update_cdb(dev->current_cdb, dev->sector_pos, dev->requested_blocks); - ret = scsi_cdrom_read_data(dev, msf, type, flags, len); scsi_cdrom_log("Read %i bytes of blocks...\n", *len); - if (!ret || ((dev->old_len != *len) && !first_batch)) { + if (ret == -1) + return 0; + else if (!ret || ((dev->old_len != *len) && !first_batch)) { if ((dev->old_len != *len) && !first_batch) scsi_cdrom_illegal_mode(dev); @@ -1234,7 +1182,7 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) { int ready = 0; - if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) { if ((cdb[0] != GPCMD_REQUEST_SENSE) && (cdb[1] & 0xe0)) { scsi_cdrom_log("CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, ((dev->request_length >> 5) & 7)); @@ -1245,7 +1193,7 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) if (!(scsi_cdrom_command_flags[cdb[0]] & IMPLEMENTED)) { scsi_cdrom_log("CD-ROM %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], - (dev->drv->bus_type == CDROM_BUS_SCSI) ? "SCSI" : "ATAPI"); + (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) ? "SCSI" : "ATAPI"); scsi_cdrom_illegal_opcode(dev); return 0; @@ -1257,7 +1205,7 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) return 0; } - if ((dev->drv->bus_type == CDROM_BUS_SCSI) && (scsi_cdrom_command_flags[cdb[0]] & ATAPI_ONLY)) { + if ((dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) && (scsi_cdrom_command_flags[cdb[0]] & ATAPI_ONLY)) { scsi_cdrom_log("CD-ROM %i: Attempting to execute ATAPI-only command %02X over SCSI\n", dev->id, cdb[0]); scsi_cdrom_illegal_opcode(dev); return 0; @@ -1340,7 +1288,7 @@ scsi_cdrom_reset(scsi_common_t *sc) scsi_cdrom_rezero(dev); dev->status = 0; - dev->callback = 0LL; + dev->callback = 0.0; scsi_cdrom_set_callback(dev); dev->phase = 1; dev->request_length = 0xEB14; @@ -1365,16 +1313,14 @@ scsi_cdrom_request_sense(scsi_cdrom_t *dev, uint8_t *buffer, uint8_t alloc_lengt buffer[12]=ASC_AUDIO_PLAY_OPERATION; buffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; } else if ((scsi_cdrom_sense_key == 0) && ((dev->drv->cd_status == CD_STATUS_PAUSED) || - (dev->drv->cd_status >= CD_STATUS_PLAYING))) { + ((dev->drv->cd_status >= CD_STATUS_PLAYING) && (dev->drv->cd_status != CD_STATUS_STOPPED)))) { buffer[2]=SENSE_ILLEGAL_REQUEST; buffer[12]=ASC_AUDIO_PLAY_OPERATION; buffer[13]=(dev->drv->cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; - } else { - if (dev->unit_attention && (scsi_cdrom_sense_key == 0)) { - buffer[2]=SENSE_UNIT_ATTENTION; - buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; - buffer[13]=0; - } + } else if (dev->unit_attention && (scsi_cdrom_sense_key == 0)) { + buffer[2]=SENSE_UNIT_ATTENTION; + buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[13]=0; } scsi_cdrom_log("CD-ROM %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); @@ -1413,7 +1359,7 @@ scsi_cdrom_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t al static void scsi_cdrom_set_buf_len(scsi_cdrom_t *dev, int32_t *BufLen, int32_t *src_len) { - if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) { if (*BufLen == -1) *BufLen = *src_len; else { @@ -1447,11 +1393,13 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) int real_pos, track = 0; char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; - int32_t blen = 0, *BufLen; + char device_identify_chinon[9] = { 'C', 'D', 'S', '-', '4', '3', '1', ' ', 0 }; + char device_identify_ex_chinon[15] = { 'C', 'D', 'S', '-', '4', '3', '1', ' ', ' ', 'H', '4', '2', ' ', ' ', 0 }; + int32_t blen = 0, *BufLen; uint8_t *b; uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; - if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) { BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; dev->status &= ~ERR_STAT; } else { @@ -1468,6 +1416,9 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) device_identify_ex[10] = EMU_VERSION[0]; device_identify_ex[12] = EMU_VERSION[2]; device_identify_ex[13] = EMU_VERSION[3]; + + device_identify_chinon[7] = dev->id + 0x30; + device_identify_ex_chinon[7] = dev->id + 0x30; memcpy(dev->current_cdb, cdb, 12); @@ -1513,7 +1464,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (!max_len) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->packet_status = PHASE_COMPLETE; - dev->callback = 20LL * CDROM_TIME; + dev->callback = 20.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); break; } @@ -1598,6 +1549,8 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) switch(cdb[0]) { case GPCMD_READ_6: dev->sector_len = cdb[4]; + if (dev->sector_len == 0) + dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); msf = 0; break; @@ -1638,7 +1591,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); /* scsi_cdrom_log("CD-ROM %i: All done - callback set\n", dev->id); */ dev->packet_status = PHASE_COMPLETE; - dev->callback = 20LL * CDROM_TIME; + dev->callback = 20.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); break; } @@ -1657,7 +1610,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (ret <= 0) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->packet_status = PHASE_COMPLETE; - dev->callback = 20LL * CDROM_TIME; + dev->callback = 20.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); scsi_cdrom_buf_free(dev); return; @@ -1708,7 +1661,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_MODE_SENSE_10: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - if (dev->drv->bus_type == CDROM_BUS_SCSI) + if (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; else block_desc = 0; @@ -1855,7 +1808,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ b[3] = 8; - if (dev->drv->bus_type == CDROM_BUS_SCSI) + if (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) b[7] = 1; else b[7] = 2; @@ -1997,16 +1950,16 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) memset(dev->buffer, 0, 36); dev->buffer[0] = 0; dev->buffer[1] = 34; - dev->buffer[2] = 1; /* track number (LSB) */ - dev->buffer[3] = 1; /* session number (LSB) */ - dev->buffer[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ - dev->buffer[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ - dev->buffer[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ + dev->buffer[2] = 1; /* track number (LSB) */ + dev->buffer[3] = 1; /* session number (LSB) */ + dev->buffer[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ + dev->buffer[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ + dev->buffer[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ - dev->buffer[24] = (dev->drv->cdrom_capacity >> 24) & 0xff; /* track size */ - dev->buffer[25] = (dev->drv->cdrom_capacity >> 16) & 0xff; /* track size */ - dev->buffer[26] = (dev->drv->cdrom_capacity >> 8) & 0xff; /* track size */ - dev->buffer[27] = dev->drv->cdrom_capacity & 0xff; /* track size */ + dev->buffer[24] = ((dev->drv->cdrom_capacity - 1) >> 24) & 0xff; /* track size */ + dev->buffer[25] = ((dev->drv->cdrom_capacity - 1) >> 16) & 0xff; /* track size */ + dev->buffer[26] = ((dev->drv->cdrom_capacity - 1) >> 8) & 0xff; /* track size */ + dev->buffer[27] = (dev->drv->cdrom_capacity - 1) & 0xff; /* track size */ if (len > max_len) { len = max_len; @@ -2101,9 +2054,13 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) return; } - switch(cdb[3]) { + if (!(cdb[2] & 0x40)) + alloc_length = 4; + else switch(cdb[3]) { case 0: - alloc_length = 4; + /* SCSI-2: Q-type subchannel, ATAPI: reserved */ + alloc_length = (dev->drv->bus_type == CDROM_BUS_SCSI || + dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) ? 48 : 4; break; case 1: alloc_length = 16; @@ -2113,36 +2070,38 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) break; } + len = alloc_length; + memset(dev->buffer, 0, 24); pos = 0; dev->buffer[pos++] = 0; dev->buffer[pos++] = 0; /*Audio status*/ dev->buffer[pos++] = 0; dev->buffer[pos++] = 0; /*Subchannel length*/ - dev->buffer[pos++] = cdb[3] & 3; /*Format code*/ - if (cdb[3] == 1) { - dev->buffer[1] = cdrom_get_current_subchannel(dev->drv, &dev->buffer[5], msf); + /* 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)) { + 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; switch(dev->drv->cd_status) { case CD_STATUS_PLAYING: dev->buffer[1] = 0x11; break; case CD_STATUS_PAUSED: - dev->buffer[1] = 0x12; + dev->buffer[1] = dev->drv->bus_type == CDROM_BUS_SCSI_CHINON ? 0x15 : 0x12; break; case CD_STATUS_DATA_ONLY: - dev->buffer[1] = 0x15; + dev->buffer[1] = dev->drv->bus_type == CDROM_BUS_SCSI_CHINON ? 0x00 : 0x15; break; default: - dev->buffer[1] = 0x13; + dev->buffer[1] = dev->drv->bus_type == CDROM_BUS_SCSI_CHINON ? 0x00 : 0x13; break; } + + scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[1]); } - if (!(cdb[2] & 0x40) || (cdb[3] == 0)) - len = 4; - else - len = alloc_length; - len = MIN(len, max_len); scsi_cdrom_set_buf_len(dev, BufLen, &len); @@ -2182,6 +2141,13 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) } break; + case GPCMD_CHINON_STOP: + case 0x26: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_stop(sc); + scsi_cdrom_command_complete(dev); + break; + case GPCMD_START_STOP_UNIT: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); @@ -2205,6 +2171,13 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_command_complete(dev); break; + case GPCMD_CHINON_EJECT: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_stop(sc); + cdrom_eject(dev->id); + scsi_cdrom_command_complete(dev); + break; + case GPCMD_INQUIRY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); @@ -2249,9 +2222,16 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->buffer[idx++] = 0x01; dev->buffer[idx++] = 0x00; dev->buffer[idx++] = 68; - ide_padstr8(dev->buffer + idx, 8, EMU_NAME); /* Vendor */ + if (dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) + ide_padstr8(dev->buffer + idx, 8, "CHINON"); /* Vendor */ + else + ide_padstr8(dev->buffer + idx, 8, EMU_NAME); /* Vendor */ idx += 8; - ide_padstr8(dev->buffer + idx, 40, device_identify_ex); /* Product */ + if (dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) + ide_padstr8(dev->buffer + idx, 40, device_identify_ex_chinon); /* Product */ + else + ide_padstr8(dev->buffer + idx, 40, device_identify_ex); /* Product */ + idx += 40; ide_padstr8(dev->buffer + idx, 20, "53R141"); /* Product */ idx += 20; @@ -2269,17 +2249,33 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) memset(dev->buffer, 0, 8); dev->buffer[0] = 5; /*CD-ROM*/ dev->buffer[1] = 0x80; /*Removable*/ - dev->buffer[2] = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - dev->buffer[3] = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 0x02 : 0x21; + + if (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) { + dev->buffer[2] = 0x02; + dev->buffer[3] = 0x02; + } + else { + dev->buffer[2] = 0x00; + dev->buffer[3] = 0x21; + } + dev->buffer[4] = 31; - if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) { dev->buffer[6] = 1; /* 16-bit transfers supported */ dev->buffer[7] = 0x20; /* Wide bus supported */ } - ide_padstr8(dev->buffer + 8, 8, EMU_NAME); /* Vendor */ - ide_padstr8(dev->buffer + 16, 16, device_identify); /* Product */ - ide_padstr8(dev->buffer + 32, 4, EMU_VERSION); /* Revision */ + if (dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) { + ide_padstr8(dev->buffer + 8, 8, "CHINON"); /* Vendor */ + ide_padstr8(dev->buffer + 16, 16, device_identify_chinon); /* Product */ + ide_padstr8(dev->buffer + 32, 4, "H42 "); /* Revision */ + } + else { + ide_padstr8(dev->buffer + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(dev->buffer + 16, 16, device_identify); /* Product */ + ide_padstr8(dev->buffer + 32, 4, EMU_VERSION); /* Revision */ + } + idx = 36; if (max_len == 96) { @@ -2334,10 +2330,10 @@ atapi_out: /* IMPORTANT: What's returned is the last LBA block. */ memset(dev->buffer, 0, 8); - dev->buffer[0] = (dev->drv->cdrom_capacity >> 24) & 0xff; - dev->buffer[1] = (dev->drv->cdrom_capacity >> 16) & 0xff; - dev->buffer[2] = (dev->drv->cdrom_capacity >> 8) & 0xff; - dev->buffer[3] = dev->drv->cdrom_capacity & 0xff; + dev->buffer[0] = ((dev->drv->cdrom_capacity - 1) >> 24) & 0xff; + dev->buffer[1] = ((dev->drv->cdrom_capacity - 1) >> 16) & 0xff; + dev->buffer[2] = ((dev->drv->cdrom_capacity - 1) >> 8) & 0xff; + dev->buffer[3] = (dev->drv->cdrom_capacity - 1) & 0xff; dev->buffer[6] = 8; len = 8; @@ -2399,7 +2395,7 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) else hdr_len = 4; - if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) { if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { block_desc_len = dev->buffer[2]; block_desc_len <<= 8; @@ -2446,7 +2442,7 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) pos += page_len; - if (dev->drv->bus_type == CDROM_BUS_SCSI) + if (dev->drv->bus_type == CDROM_BUS_SCSI || dev->drv->bus_type == CDROM_BUS_SCSI_CHINON) val = scsi_cdrom_mode_sense_pages_default_scsi.pages[page][0] & 0x80; else val = scsi_cdrom_mode_sense_pages_default.pages[page][0] & 0x80; @@ -2576,7 +2572,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->bus_type == CDROM_BUS_SCSI_CHINON) && (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. */ @@ -2599,7 +2595,7 @@ scsi_cdrom_drive_reset(int c) scsi_cdrom_init(dev); - if (drv->bus_type == CDROM_BUS_SCSI) { + if (drv->bus_type == CDROM_BUS_SCSI || drv->bus_type == CDROM_BUS_SCSI_CHINON) { /* SCSI CD-ROM, attach to the SCSI bus. */ sd = &scsi_devices[drv->scsi_device_id]; @@ -2614,7 +2610,7 @@ scsi_cdrom_drive_reset(int c) scsi_cdrom_log("SCSI CD-ROM drive %i attached to SCSI ID %i\n", c, cdrom[c].scsi_device_id); } else if (drv->bus_type == CDROM_BUS_ATAPI) { /* ATAPI CD-ROM, attach to the IDE bus. */ - id = ide_drives[drv->ide_channel]; + id = ide_get_drive(drv->ide_channel); /* If the IDE channel is initialized, we attach to it, otherwise, we do nothing - it's going to be a drive that's not attached to anything. */ diff --git a/src/scsi/scsi_cdrom.h b/src/scsi/scsi_cdrom.h index 7b47db55d..f83c6457c 100644 --- a/src/scsi/scsi_cdrom.h +++ b/src/scsi/scsi_cdrom.h @@ -19,7 +19,7 @@ #define EMU_SCSI_CDROM_H -#define CDROM_TIME (5LL * 100LL * (1LL << TIMER_SHIFT)) +#define CDROM_TIME 500.0 #ifdef SCSI_DEVICE_H @@ -49,7 +49,7 @@ typedef struct { uint32_t sector_pos, sector_len, packet_len, pos; - int64_t callback; + double callback; } scsi_cdrom_t; #endif diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index fb1a9db89..c0fe14694 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -47,13 +47,13 @@ scsi_device_target_command(scsi_device_t *dev, uint8_t *cdb) } -int64_t +double scsi_device_get_callback(scsi_device_t *dev) { if (dev->sc) return dev->sc->callback; else - return -1LL; + return -1.0; } diff --git a/src/scsi/scsi_device.h b/src/scsi/scsi_device.h index 4c8d982ad..883d9efc2 100644 --- a/src/scsi/scsi_device.h +++ b/src/scsi/scsi_device.h @@ -22,9 +22,9 @@ #define SCSI_LUN_MAX 8 /* always 8 */ #ifdef WALTJE -#define SCSI_TIME (50 * (1 << TIMER_SHIFT)) +#define SCSI_TIME 50.0 #else -#define SCSI_TIME (5 * 100 * (1 << TIMER_SHIFT)) +#define SCSI_TIME 500.0 #endif @@ -100,7 +100,9 @@ #define GPCMD_MECHANISM_STATUS 0xbd #define GPCMD_READ_CD 0xbe #define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ -#define GPCMD_PAUSE_RESUME_ALT 0xc2 +#define GPCMD_CHINON_EJECT 0xc0 /*Vendor Unique*/ +#define GPCMD_PAUSE_RESUME_ALT 0xc2 +#define GPCMD_CHINON_STOP 0xc6 /*Vendor Unique*/ #define GPCMD_SCAN_ALT 0xcd /* Should be equivalent to 0xba */ #define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */ @@ -289,23 +291,6 @@ #define MODE_SELECT_PHASE_PAGE_HEADER 3 #define MODE_SELECT_PHASE_PAGE 4 - -/* This is probably no longer needed. */ -#if 0 -typedef struct -{ - uint8_t command[20]; - - int state, new_state, - clear_req, dev_id, - command_pos, data_pos, - change_state_delay, - new_req_delay; - - uint32_t bus_in, bus_out; -} scsi_bus_t; -#endif - typedef struct { uint8_t pages[0x40][0x40]; } mode_sense_pages_t; @@ -338,7 +323,7 @@ typedef struct scsi_common_s { uint32_t sector_pos, sector_len, packet_len, pos; - int64_t callback; + double callback; } scsi_common_t; typedef struct { @@ -373,7 +358,7 @@ extern int mode_select_terminate(int force); extern int mode_select_write(uint8_t val); extern uint8_t *scsi_device_sense(scsi_device_t *dev); -extern int64_t scsi_device_get_callback(scsi_device_t *dev); +extern double scsi_device_get_callback(scsi_device_t *dev); extern void scsi_device_request_sense(scsi_device_t *dev, uint8_t *buffer, uint8_t alloc_length); extern void scsi_device_reset(scsi_device_t *dev); diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index b15fc72fd..a154685b4 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -111,13 +111,13 @@ uint64_t scsi_disk_mode_sense_page_flags = (GPMODEP_FORMAT_DEVICE_PAGE | /* This should be done in a better way but for time being, it's been done this way so it's not as huge and more readable. */ static const mode_sense_pages_t scsi_disk_mode_sense_pages_default = { { [GPMODE_FORMAT_DEVICE_PAGE] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - [GPMODE_RIGID_DISK_PAGE ] = { GPMODE_RIGID_DISK_PAGE, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [GPMODE_RIGID_DISK_PAGE ] = { GPMODE_RIGID_DISK_PAGE, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 200, 0xff, 0xff, 0xff, 0, 0, 0, 0x15, 0x18, 0, 0 }, [GPMODE_UNK_VENDOR_PAGE ] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } } }; static const mode_sense_pages_t scsi_disk_mode_sense_pages_changeable = -{ { [GPMODE_FORMAT_DEVICE_PAGE] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0 }, - [GPMODE_RIGID_DISK_PAGE ] = { GPMODE_RIGID_DISK_PAGE, 0x16, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0 }, +{ { [GPMODE_FORMAT_DEVICE_PAGE] = { GPMODE_FORMAT_DEVICE_PAGE, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [GPMODE_RIGID_DISK_PAGE ] = { GPMODE_RIGID_DISK_PAGE, 0x16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, [GPMODE_UNK_VENDOR_PAGE ] = { 0xB0, 0x16, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } } }; @@ -151,8 +151,8 @@ scsi_disk_mode_sense_load(scsi_disk_t *dev) memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); memcpy(&dev->ms_pages_saved, &scsi_disk_mode_sense_pages_default, sizeof(mode_sense_pages_t)); - swprintf(file_name, 512, L"scsi_disk_%02i_mode_sense.bin", dev->id); memset(file_name, 0, 512 * sizeof(wchar_t)); + swprintf(file_name, 512, L"scsi_disk_%02i_mode_sense.bin", dev->id); f = plat_fopen(nvr_path(file_name), L"rb"); if (f) { fread(dev->ms_pages_saved.pages[0x30], 1, 0x18, f); @@ -166,6 +166,7 @@ scsi_disk_mode_sense_save(scsi_disk_t *dev) { FILE *f; wchar_t file_name[512]; + memset(file_name, 0, 512 * sizeof(wchar_t)); swprintf(file_name, 512, L"scsi_disk_%02i_mode_sense.bin", dev->id); f = plat_fopen(nvr_path(file_name), L"wb"); @@ -180,17 +181,58 @@ scsi_disk_mode_sense_save(scsi_disk_t *dev) uint8_t scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) { - switch (page_control) { + if (page_control == 1) + return scsi_disk_mode_sense_pages_changeable.pages[page][pos]; + + if (page == GPMODE_RIGID_DISK_PAGE) switch (page_control) { + /* Rigid disk geometry page. */ + case 0: + case 2: + case 3: + switch(pos) { + case 0: + case 1: + default: + return scsi_disk_mode_sense_pages_default.pages[page][pos]; + case 2: + case 6: + case 9: + return (dev->drv->tracks >> 16) & 0xff; + case 3: + case 7: + case 10: + return (dev->drv->tracks >> 8) & 0xff; + case 4: + case 8: + case 11: + return dev->drv->tracks & 0xff; + case 5: + return dev->drv->hpc & 0xff; + } + break; + } else if (page == GPMODE_FORMAT_DEVICE_PAGE) switch (page_control) { + /* Format device page. */ + case 0: + case 2: + case 3: + switch(pos) { + case 0: + case 1: + default: + return scsi_disk_mode_sense_pages_default.pages[page][pos]; + /* Actual sectors + the 1 "alternate sector" we report. */ + case 10: + return ((dev->drv->spt + 1) >> 8) & 0xff; + case 11: + return (dev->drv->spt + 1) & 0xff; + } + break; + } else switch (page_control) { case 0: case 3: return dev->ms_pages_saved.pages[page][pos]; - break; - case 1: - return scsi_disk_mode_sense_pages_changeable.pages[page][pos]; - break; case 2: return scsi_disk_mode_sense_pages_default.pages[page][pos]; - break; } return 0; @@ -243,9 +285,9 @@ scsi_disk_command_common(scsi_disk_t *dev) dev->status = BUSY_STAT; dev->phase = 1; if (dev->packet_status == PHASE_COMPLETE) - dev->callback = 0LL; + dev->callback = 0.0; else - dev->callback = -1LL; /* Speed depends on SCSI controller */ + dev->callback = -1.0; /* Speed depends on SCSI controller */ } @@ -320,7 +362,7 @@ scsi_disk_cmd_error(scsi_disk_t *dev) dev->status = READY_STAT | ERR_STAT; dev->phase = 3; dev->packet_status = PHASE_ERROR; - dev->callback = 50 * SCSI_TIME; + dev->callback = 50.0 * SCSI_TIME; scsi_disk_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); } @@ -441,7 +483,7 @@ scsi_disk_reset(scsi_common_t *sc) scsi_disk_rezero(dev); dev->status = 0; - dev->callback = 0; + dev->callback = 0.0; dev->packet_status = PHASE_NONE; } @@ -517,9 +559,6 @@ static void scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) { scsi_disk_t *dev = (scsi_disk_t *) sc; -#ifdef ENABLE_SCSI_DISK_LOG - uint8_t *hdbufferb; -#endif int32_t *BufLen; int32_t len, max_len, alloc_length; int pos = 0; @@ -530,9 +569,6 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; int block_desc = 0; -#ifdef ENABLE_SCSI_DISK_LOG - hdbufferb = scsi_devices[dev->drv->scsi_id].cmd_buffer; -#endif BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length; last_sector = hdd_image_get_last_sector(dev->id); @@ -597,7 +633,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) if (!len) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); dev->packet_status = PHASE_COMPLETE; - dev->callback = 20 * SCSI_TIME; + dev->callback = 20.0 * SCSI_TIME; break; } @@ -633,6 +669,8 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) switch(cdb[0]) { case GPCMD_READ_6: dev->sector_len = cdb[4]; + if (dev->sector_len == 0) + dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); break; case GPCMD_READ_10: @@ -645,7 +683,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) break; } - if ((dev->sector_pos > last_sector) || ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + if ((dev->sector_pos > last_sector)/* || ((dev->sector_pos + dev->sector_len - 1) > last_sector)*/) { scsi_disk_lba_out_of_range(dev); return; } @@ -654,7 +692,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); scsi_disk_log("SCSI HD %i: All done - callback set\n", dev); dev->packet_status = PHASE_COMPLETE; - dev->callback = 20 * SCSI_TIME; + dev->callback = 20.0 * SCSI_TIME; break; } @@ -697,6 +735,8 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_VERIFY_6: case GPCMD_WRITE_6: dev->sector_len = cdb[4]; + if (dev->sector_len == 0) + dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); break; @@ -715,8 +755,8 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) break; } - if ((dev->sector_pos > last_sector) || - ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + if ((dev->sector_pos > last_sector)/* || + ((dev->sector_pos + dev->sector_len - 1) > last_sector)*/) { scsi_disk_lba_out_of_range(dev); return; } @@ -725,7 +765,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); dev->packet_status = PHASE_COMPLETE; - dev->callback = 20 * SCSI_TIME; + dev->callback = 20.0 * SCSI_TIME; break; } @@ -756,8 +796,8 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - if ((dev->sector_pos > last_sector) || - ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + if ((dev->sector_pos > last_sector)/* || + ((dev->sector_pos + dev->sector_len - 1) > last_sector)*/) { scsi_disk_lba_out_of_range(dev); return; } @@ -766,7 +806,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); dev->packet_status = PHASE_COMPLETE; - dev->callback = 20 * SCSI_TIME; + dev->callback = 20.0 * SCSI_TIME; break; } @@ -857,7 +897,7 @@ scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); /* scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); */ dev->packet_status = PHASE_COMPLETE; - dev->callback = 20 * SCSI_TIME; + dev->callback = 20.0 * SCSI_TIME; break; } @@ -939,8 +979,6 @@ atapi_out: dev->temp_buffer[size_idx] = idx - preamble_len; len=idx; - scsi_disk_log("scsi_disk_command(): Inquiry (%08X, %08X)\n", hdbufferb, dev->temp_buffer); - if (len > max_len) len = max_len; diff --git a/src/scsi/scsi_disk.h b/src/scsi/scsi_disk.h index 220183c3f..54c872e2b 100644 --- a/src/scsi/scsi_disk.h +++ b/src/scsi/scsi_disk.h @@ -39,7 +39,7 @@ typedef struct { uint32_t sector_pos, sector_len, packet_len, pos; - int64_t callback; + double callback; } scsi_disk_t; diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 262725726..3851a52ec 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -29,6 +29,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../dma.h" #include "../pic.h" #include "../mca.h" @@ -36,7 +37,6 @@ #include "../rom.h" #include "../device.h" #include "../nvr.h" -#include "../timer.h" #include "../plat.h" #include "scsi.h" #include "scsi_device.h" @@ -46,7 +46,9 @@ #define LCS6821N_ROM L"roms/scsi/ncr5380/Longshine LCS-6821N - BIOS version 1.04.bin" #define RT1000B_ROM L"roms/scsi/ncr5380/Rancho_RT1000_RTBios_version_8.10R.bin" #define T130B_ROM L"roms/scsi/ncr5380/trantor_t130b_bios_v2.14.bin" +#if defined(DEV_BRANCH) && defined(USE_SUMO) #define SCSIAT_ROM L"roms/scsi/ncr5380/sumo_scsiat_bios_v6.3.bin" +#endif #define NCR_CURDATA 0 /* current SCSI data (read only) */ @@ -146,10 +148,9 @@ typedef struct { int dma_enabled; - int64_t timer_period; - int64_t timer_enabled; - + pc_timer_t timer; double period; + int timer_enabled; int ncr_busy; } ncr5380_t; @@ -168,6 +169,7 @@ typedef struct { static int cmd_len[8] = {6, 10, 10, 6, 16, 12, 6, 6}; + #ifdef ENABLE_NCR5380_LOG int ncr5380_do_log = ENABLE_NCR5380_LOG; @@ -210,8 +212,8 @@ get_dev_id(uint8_t data) static void ncr_reset(ncr_t *ncr) { - memset(ncr, 0x00, sizeof(ncr_t)); - ncr_log("NCR reset\n"); + memset(ncr, 0x00, sizeof(ncr_t)); + ncr_log("NCR reset\n"); } @@ -770,6 +772,8 @@ t130b_out(uint16_t port, uint8_t val, void *priv) } } + +#if defined(DEV_BRANCH) && defined(USE_SUMO) static uint8_t scsiat_in(uint16_t port, void *priv) { @@ -869,6 +873,7 @@ scsiat_out(uint16_t port, uint8_t val, void *priv) break; } } +#endif static void @@ -878,7 +883,7 @@ ncr_callback(void *priv) ncr_t *ncr = &ncr_dev->ncr; scsi_device_t *dev = &scsi_devices[ncr->target_id]; int req_len, c = 0; - int64_t p; + double p; uint8_t temp, data; ncr_log("DMA mode=%d\n", ncr->dma_mode); @@ -886,9 +891,9 @@ ncr_callback(void *priv) ncr_dev->timer_enabled = 0; if (((ncr->state == STATE_DATAIN) || (ncr->state == STATE_DATAOUT)) && (ncr->dma_mode != DMA_IDLE)) - ncr_dev->timer_period = (int64_t) ncr_dev->period; + timer_on(&ncr_dev->timer, ncr_dev->period, 0); else - ncr_dev->timer_period += 40LL * TIMER_USEC; + timer_on(&ncr_dev->timer, 40.0, 0); if (ncr->dma_mode == DMA_IDLE) { ncr->bus_host = get_bus_host(ncr); @@ -965,8 +970,8 @@ ncr_callback(void *priv) if (dev->buffer_length && (dev->phase == SCSI_PHASE_DATA_IN || dev->phase == SCSI_PHASE_DATA_OUT)) { p = scsi_device_get_callback(dev); req_len = MIN(64, dev->buffer_length); - if (p <= 0LL) - ncr_dev->period = 0.2 * ((double) TIMER_USEC) * ((double) req_len); + if (p <= 0.0) + ncr_dev->period = 0.2 * ((double) req_len); else ncr_dev->period = (p / ((double) dev->buffer_length)) * ((double) req_len); } @@ -1282,7 +1287,7 @@ ncr_init(const device_t *info) switch(ncr_dev->type) { case 0: /* Longshine LCS6821N */ - ncr_dev->rom_addr = 0xDC000; + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); rom_init(&ncr_dev->bios_rom, LCS6821N_ROM, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); @@ -1295,7 +1300,7 @@ ncr_init(const device_t *info) break; case 1: /* Rancho RT1000B */ - ncr_dev->rom_addr = 0xDC000; + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); rom_init(&ncr_dev->bios_rom, RT1000B_ROM, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); @@ -1308,12 +1313,14 @@ ncr_init(const device_t *info) break; case 2: /* Trantor T130B */ - ncr_dev->rom_addr = 0xDC000; + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); ncr_dev->base = device_get_config_hex16("base"); ncr_dev->irq = device_get_config_int("irq"); rom_init(&ncr_dev->bios_rom, T130B_ROM, ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&ncr_dev->bios_rom.mapping); + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, t130b_read, NULL, NULL, t130b_write, NULL, NULL, @@ -1323,6 +1330,7 @@ ncr_init(const device_t *info) t130b_in,NULL,NULL, t130b_out,NULL,NULL, ncr_dev); break; +#if defined(DEV_BRANCH) && defined(USE_SUMO) case 3: /* Sumo SCSI-AT */ ncr_dev->base = device_get_config_hex16("base"); ncr_dev->irq = device_get_config_int("irq"); @@ -1340,6 +1348,7 @@ ncr_init(const device_t *info) io_sethandler(ncr_dev->base, 16, scsiat_in,NULL,NULL, scsiat_out,NULL,NULL, ncr_dev); break; +#endif } sprintf(temp, "%s: BIOS=%05X", ncr_dev->name, ncr_dev->rom_addr); @@ -1349,13 +1358,14 @@ ncr_init(const device_t *info) sprintf(&temp[strlen(temp)], " IRQ=%d", ncr_dev->irq); ncr_log("%s\n", temp); - ncr_reset(&ncr_dev->ncr); + ncr_reset(&ncr_dev->ncr); ncr_dev->status_ctrl = STATUS_BUFFER_NOT_READY; - ncr_dev->buffer_host_pos = 128; - - ncr_dev->timer_period = 10LL * TIMER_USEC; - timer_add(ncr_callback, &ncr_dev->timer_period, TIMER_ALWAYS_ENABLED, ncr_dev); - + ncr_dev->buffer_host_pos = 128; + + timer_add(&ncr_dev->timer, ncr_callback, ncr_dev, 1); + ncr_dev->timer.period = 10.0; + timer_set_delay_u64(&ncr_dev->timer, (uint64_t) (ncr_dev->timer.period * ((double) TIMER_USEC))); + return(ncr_dev); } @@ -1365,15 +1375,14 @@ ncr_close(void *priv) { ncr5380_t *ncr_dev = (ncr5380_t *)priv; - if (ncr_dev) - { - /* Tell the timer to terminate. */ - ncr_dev->timer_period = 0LL; - ncr_dev->timer_enabled = 0LL; - - free(ncr_dev); - ncr_dev = NULL; - } + if (ncr_dev) { + /* Tell the timer to terminate. */ + timer_stop(&ncr_dev->timer); + ncr_dev->timer_enabled = 0; + + free(ncr_dev); + ncr_dev = NULL; + } } @@ -1398,13 +1407,68 @@ t130b_available(void) } +#if defined(DEV_BRANCH) && defined(USE_SUMO) static int scsiat_available(void) { return(rom_present(SCSIAT_ROM)); } +#endif + + +static const device_config_t ncr5380_mmio_config[] = { + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "CC00H", 0xcc000 + }, + { + "D800H", 0xd8000 + }, + { + "DC00H", 0xdc000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; static const device_config_t t130b_config[] = { + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "CC00H", 0xcc000 + }, + { + "D800H", 0xd8000 + }, + { + "DC00H", 0xdc000 + }, + { + "" + } + }, + }, { "base", "Address", CONFIG_HEX16, "", 0x0350, { @@ -1447,6 +1511,7 @@ static const device_config_t t130b_config[] = { } }; +#if defined(DEV_BRANCH) && defined(USE_SUMO) static const device_config_t scsiat_config[] = { { "base", "Address", CONFIG_HEX16, "", 0x0310, @@ -1542,6 +1607,7 @@ static const device_config_t scsiat_config[] = { "", "", -1 } }; +#endif const device_t scsi_lcs6821n_device = @@ -1552,7 +1618,7 @@ const device_t scsi_lcs6821n_device = ncr_init, ncr_close, NULL, lcs6821n_available, NULL, NULL, - NULL + ncr5380_mmio_config }; const device_t scsi_rt1000b_device = @@ -1563,7 +1629,7 @@ const device_t scsi_rt1000b_device = ncr_init, ncr_close, NULL, rt1000b_available, NULL, NULL, - NULL + ncr5380_mmio_config }; const device_t scsi_t130b_device = @@ -1577,6 +1643,7 @@ const device_t scsi_t130b_device = t130b_config }; +#if defined(DEV_BRANCH) && defined(USE_SUMO) const device_t scsi_scsiat_device = { "Sumo SCSI-AT", @@ -1587,3 +1654,4 @@ const device_t scsi_scsiat_device = NULL, NULL, scsiat_config }; +#endif diff --git a/src/scsi/scsi_ncr5380.h b/src/scsi/scsi_ncr5380.h index 55b16f654..5e14f77a2 100644 --- a/src/scsi/scsi_ncr5380.h +++ b/src/scsi/scsi_ncr5380.h @@ -27,7 +27,9 @@ extern const device_t scsi_lcs6821n_device; extern const device_t scsi_rt1000b_device; extern const device_t scsi_t130b_device; +#if defined(DEV_BRANCH) && defined(USE_SUMO) extern const device_t scsi_scsiat_device; +#endif #endif /*SCSI_NCR5380_H*/ diff --git a/src/scsi/scsi_ncr53c8xx - Cópia.c b/src/scsi/scsi_ncr53c8xx - Cópia.c new file mode 100644 index 000000000..dff69c291 --- /dev/null +++ b/src/scsi/scsi_ncr53c8xx - Cópia.c @@ -0,0 +1,2736 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the NCR 53C810 and 53C875 SCSI Host + * Adapters made by NCR and later Symbios and LSI. These + * controllers were designed for the PCI bus. + * + * To do: Identify the type of serial EEPROM used and its + * interface. + * + * Version: @(#)scsi_ncr53c8xx.c 1.0.17 2018/10/30 + * + * Authors: Paul Brook (QEMU) + * Artyom Tarasenko (QEMU) + * TheCollector1995, + * Miran Grca, + * + * Copyright 2006-2018 Paul Brook. + * Copyright 2009-2018 Artyom Tarasenko. + * Copyright 2017,2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include "../86box.h" +#include "../io.h" +#include "../timer.h" +#include "../dma.h" +#include "../pic.h" +#include "../mem.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../nvr.h" +#include "../plat.h" +#include "scsi.h" +#include "scsi_device.h" +#include "scsi_ncr53c8xx.h" + +#define NCR53C8XX_ROM L"roms/scsi/ncr53c8xx/NCR307.BIN" + +#define CHIP_810 0x01 +#define CHIP_825 0x03 +#define CHIP_875 0x0f + +#define NCR_SCNTL0_TRG 0x01 +#define NCR_SCNTL0_AAP 0x02 +#define NCR_SCNTL0_EPC 0x08 +#define NCR_SCNTL0_WATN 0x10 +#define NCR_SCNTL0_START 0x20 + +#define NCR_SCNTL1_SST 0x01 +#define NCR_SCNTL1_IARB 0x02 +#define NCR_SCNTL1_AESP 0x04 +#define NCR_SCNTL1_RST 0x08 +#define NCR_SCNTL1_CON 0x10 +#define NCR_SCNTL1_DHP 0x20 +#define NCR_SCNTL1_ADB 0x40 +#define NCR_SCNTL1_EXC 0x80 + +#define NCR_SCNTL2_WSR 0x01 +#define NCR_SCNTL2_VUE0 0x02 +#define NCR_SCNTL2_VUE1 0x04 +#define NCR_SCNTL2_WSS 0x08 +#define NCR_SCNTL2_SLPHBEN 0x10 +#define NCR_SCNTL2_SLPMD 0x20 +#define NCR_SCNTL2_CHM 0x40 +#define NCR_SCNTL2_SDU 0x80 + +#define NCR_ISTAT_DIP 0x01 +#define NCR_ISTAT_SIP 0x02 +#define NCR_ISTAT_INTF 0x04 +#define NCR_ISTAT_CON 0x08 +#define NCR_ISTAT_SEM 0x10 +#define NCR_ISTAT_SIGP 0x20 +#define NCR_ISTAT_SRST 0x40 +#define NCR_ISTAT_ABRT 0x80 + +#define NCR_SSTAT0_SDP0 0x01 +#define NCR_SSTAT0_RST 0x02 +#define NCR_SSTAT0_WOA 0x04 +#define NCR_SSTAT0_LOA 0x08 +#define NCR_SSTAT0_AIP 0x10 +#define NCR_SSTAT0_OLF 0x20 +#define NCR_SSTAT0_ORF 0x40 +#define NCR_SSTAT0_ILF 0x80 + +#define NCR_SIST0_PAR 0x01 +#define NCR_SIST0_RST 0x02 +#define NCR_SIST0_UDC 0x04 +#define NCR_SIST0_SGE 0x08 +#define NCR_SIST0_RSL 0x10 +#define NCR_SIST0_SEL 0x20 +#define NCR_SIST0_CMP 0x40 +#define NCR_SIST0_MA 0x80 + +#define NCR_SIST1_HTH 0x01 +#define NCR_SIST1_GEN 0x02 +#define NCR_SIST1_STO 0x04 +#define NCR_SIST1_SBMC 0x10 + +#define NCR_SOCL_IO 0x01 +#define NCR_SOCL_CD 0x02 +#define NCR_SOCL_MSG 0x04 +#define NCR_SOCL_ATN 0x08 +#define NCR_SOCL_SEL 0x10 +#define NCR_SOCL_BSY 0x20 +#define NCR_SOCL_ACK 0x40 +#define NCR_SOCL_REQ 0x80 + +#define NCR_DSTAT_IID 0x01 +#define NCR_DSTAT_SIR 0x04 +#define NCR_DSTAT_SSI 0x08 +#define NCR_DSTAT_ABRT 0x10 +#define NCR_DSTAT_BF 0x20 +#define NCR_DSTAT_MDPE 0x40 +#define NCR_DSTAT_DFE 0x80 + +#define NCR_DCNTL_COM 0x01 +#define NCR_DCNTL_IRQD 0x02 +#define NCR_DCNTL_STD 0x04 +#define NCR_DCNTL_IRQM 0x08 +#define NCR_DCNTL_SSM 0x10 +#define NCR_DCNTL_PFEN 0x20 +#define NCR_DCNTL_PFF 0x40 +#define NCR_DCNTL_CLSE 0x80 + +#define NCR_DMODE_MAN 0x01 +#define NCR_DMODE_BOF 0x02 +#define NCR_DMODE_ERMP 0x04 +#define NCR_DMODE_ERL 0x08 +#define NCR_DMODE_DIOM 0x10 +#define NCR_DMODE_SIOM 0x20 + +#define NCR_CTEST2_DACK 0x01 +#define NCR_CTEST2_DREQ 0x02 +#define NCR_CTEST2_TEOP 0x04 +#define NCR_CTEST2_PCICIE 0x08 +#define NCR_CTEST2_CM 0x10 +#define NCR_CTEST2_CIO 0x20 +#define NCR_CTEST2_SIGP 0x40 +#define NCR_CTEST2_DDIR 0x80 + +#define NCR_CTEST5_BL2 0x04 +#define NCR_CTEST5_DDIR 0x08 +#define NCR_CTEST5_MASR 0x10 +#define NCR_CTEST5_DFSN 0x20 +#define NCR_CTEST5_BBCK 0x40 +#define NCR_CTEST5_ADCK 0x80 + +/* Enable Response to Reselection */ +#define NCR_SCID_RRE 0x60 + +#define PHASE_DO 0 +#define PHASE_DI 1 +#define PHASE_CMD 2 +#define PHASE_ST 3 +#define PHASE_MO 6 +#define PHASE_MI 7 +#define PHASE_MASK 7 + +/* Maximum length of MSG IN data. */ +#define NCR_MAX_MSGIN_LEN 8 + +/* Flag set if this is a tagged command. */ +#define NCR_TAG_VALID (1 << 16) + +#define NCR_BUF_SIZE 4096 + +typedef struct ncr53c8xx_request { + uint32_t tag; + uint32_t dma_len; + uint8_t *dma_buf; + uint32_t pending; + int out; +} ncr53c8xx_request; + +typedef enum +{ + SCSI_STATE_SEND_COMMAND, + SCSI_STATE_READ_DATA, + SCSI_STATE_WRITE_DATA, + SCSI_STATE_READ_STATUS, + SCSI_STATE_READ_MESSAGE, + SCSI_STATE_WRITE_MESSAGE +} scsi_state_t; + +typedef struct { + wchar_t *nvr_path; + uint8_t pci_slot; + uint8_t chip; + int has_bios; + int BIOSBase; + rom_t bios; + int PCIBase; + int MMIOBase; + mem_mapping_t mmio_mapping; + int RAMBase; + mem_mapping_t ram_mapping; + + int carry; /* ??? Should this be an a visible register somewhere? */ + int status; + /* Action to take at the end of a MSG IN phase. + 0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN. */ + int msg_action; + int msg_len; + uint8_t msg[NCR_MAX_MSGIN_LEN]; +#ifdef USE_NVRAM + uint16_t nvram; + uint8_t nvram_t; + uint8_t nvram_op; + uint8_t nvram_param; + uint8_t nvram_start; + uint8_t nvram_index; +#endif + uint8_t ram[NCR_BUF_SIZE]; /* NCR 53c875 RAM (4 kB). */ + /* 0 if SCRIPTS are running or stopped. + * 1 if a Wait Reselect instruction has been issued. + * 2 if processing DMA from ncr53c8xx_execute_script. + * 3 if a DMA operation is in progress. */ + int waiting; + + uint8_t current_lun; + + uint8_t istat; + uint8_t dcmd; + uint8_t dstat; + uint8_t dien; + uint8_t sist0; + uint8_t sist1; + uint8_t sien0; + uint8_t sien1; + uint8_t mbox0; + uint8_t mbox1; + uint8_t dfifo; + uint8_t ctest2; + uint8_t ctest3; + uint8_t ctest4; + uint8_t ctest5; + uint8_t dmode; + uint8_t dcntl; + uint8_t scntl0; + uint8_t scntl1; + uint8_t scntl2; + uint8_t scntl3; + uint8_t sstat0; + uint8_t sstat1; + uint8_t scid; + uint8_t sxfer; + uint8_t socl; + uint8_t sdid; + uint8_t ssid; + uint8_t sfbr; + uint8_t stest1; + uint8_t stest2; + uint8_t stest3; + uint8_t sidl0; + uint8_t sidl1; + uint8_t stime0; + uint8_t respid0; + uint8_t respid1; + uint8_t sbr; + uint8_t chip_rev; + uint8_t gpreg; + uint8_t slpar; + uint8_t swide; + uint8_t gpcntl; + uint8_t last_command; + + int command_complete; + ncr53c8xx_request *current; + + int irq; + + uint32_t dsa; + uint32_t temp; + uint32_t dnad; + uint32_t dbc; + uint32_t dsp; + uint32_t dsps; + uint32_t scratcha, scratchb, scratchc, scratchd; + uint32_t scratche, scratchf, scratchg, scratchh; + uint32_t scratchi, scratchj; + int last_level; + void *hba_private; + uint32_t buffer_pos; + int32_t temp_buf_len; + + uint8_t sstop; + + uint8_t regop; + uint32_t adder; + + pc_timer_t timer; +} ncr53c8xx_t; + + +#ifdef ENABLE_NCR53C8XX_LOG +int ncr53c8xx_do_log = ENABLE_NCR53C8XX_LOG; + + +static void +ncr53c8xx_log(const char *fmt, ...) +{ + va_list ap; + + if (ncr53c8xx_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ncr53c8xx_log(fmt, ...) +#endif + + +static uint8_t ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset); +static void ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val); + + +static __inline__ int32_t +sextract32(uint32_t value, int start, int length) +{ + /* Note that this implementation relies on right shift of signed + * integers being an arithmetic shift. + */ + return ((int32_t)(value << (32 - length - start))) >> (32 - length); +} + + +static __inline__ uint32_t +deposit32(uint32_t value, int start, int length, + uint32_t fieldval) +{ + uint32_t mask; + mask = (~0U >> (32 - length)) << start; + return (value & ~mask) | ((fieldval << start) & mask); +} + + +static __inline__ int +ncr53c8xx_irq_on_rsl(ncr53c8xx_t *dev) +{ + return (dev->sien0 & NCR_SIST0_RSL) && (dev->scid & NCR_SCID_RRE); +} + + +static void +ncr53c8xx_soft_reset(ncr53c8xx_t *dev) +{ + int i; + + ncr53c8xx_log("LSI Reset\n"); + timer_stop(&dev->timer); + + dev->carry = 0; + + dev->msg_action = 0; + dev->msg_len = 0; + dev->waiting = 0; + dev->dsa = 0; + dev->dnad = 0; + dev->dbc = 0; + dev->temp = 0; + dev->scratcha = 0; + dev->scratchb = 0; + dev->scratchc = 0; + dev->scratchd = 0; + dev->scratche = 0; + dev->scratchf = 0; + dev->scratchg = 0; + dev->scratchh = 0; + dev->scratchi = 0; + dev->scratchj = 0; + dev->istat = 0; + dev->dcmd = 0x40; + dev->dstat = NCR_DSTAT_DFE; + dev->dien = 0; + dev->sist0 = 0; + dev->sist1 = 0; + dev->sien0 = 0; + dev->sien1 = 0; + dev->mbox0 = 0; + dev->mbox1 = 0; + dev->dfifo = 0; + dev->ctest2 = NCR_CTEST2_DACK; + dev->ctest3 = 0; + dev->ctest4 = 0; + dev->ctest5 = 0; + dev->dsp = 0; + dev->dsps = 0; + dev->dmode = 0; + dev->dcntl = 0; + dev->scntl0 = 0xc0; + dev->scntl1 = 0; + dev->scntl2 = 0; + if (dev->chip >= CHIP_825) + dev->scntl3 = 8; + else + dev->scntl3 = 0; + dev->sstat0 = 0; + dev->sstat1 = 0; + dev->scid = 7; + dev->sxfer = 0; + dev->socl = 0; + dev->sdid = 0; + dev->ssid = 0; + dev->stest1 = 0; + dev->stest2 = 0; + dev->stest3 = 0; + dev->sidl0 = 0; + dev->sidl1 = 0; + dev->stime0 = 0; + dev->stime0 = 1; + dev->respid0 = 0x80; + dev->respid1 = 0x00; + dev->sbr = 0; + dev->last_level = 0; + dev->gpreg = 0; + dev->slpar = 0; + dev->sstop = 1; + dev->gpcntl = 0x0f; +#ifdef USE_NVRAM + dev->nvram_t = dev->nvram_index = 0; +#endif + + if (dev->chip >= CHIP_825) { + /* This *IS* a wide SCSI controller, so reset all SCSI + devices. */ + for (i = 0; i < 16; i++) + scsi_device_reset(&scsi_devices[i]); + } else { + /* This is *NOT* a wide SCSI controller, so do not touch + SCSI devices with ID's >= 8. */ + for (i = 0; i < 8; i++) + scsi_device_reset(&scsi_devices[i]); + } +} + + +static void +ncr53c8xx_read(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) +{ + uint32_t i = 0; + + ncr53c8xx_log("ncr53c8xx_read(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); + + if (dev->dmode & NCR_DMODE_SIOM) { + ncr53c8xx_log("NCR 810: Reading from I/O address %04X\n", (uint16_t) addr); + for (i = 0; i < len; i++) + buf[i] = inb((uint16_t) (addr + i)); + } else { + ncr53c8xx_log("NCR 810: Reading from memory address %08X\n", addr); + DMAPageRead(addr, buf, len); + } +} + + +static void +ncr53c8xx_write(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) +{ + uint32_t i = 0; + + ncr53c8xx_log("ncr53c8xx_write(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); + + if (dev->dmode & NCR_DMODE_DIOM) { + ncr53c8xx_log("NCR 810: Writing to I/O address %04X\n", (uint16_t) addr); + for (i = 0; i < len; i++) + outb((uint16_t) (addr + i), buf[i]); + } else { + ncr53c8xx_log("NCR 810: Writing to memory address %08X\n", addr); + DMAPageWrite(addr, buf, len); + } +} + + +static __inline__ uint32_t +read_dword(ncr53c8xx_t *dev, uint32_t addr) +{ + uint32_t buf; + ncr53c8xx_log("Reading the next DWORD from memory (%08X)...\n", addr); + DMAPageRead(addr, (uint8_t *)&buf, 4); + return buf; +} + + +static +void do_irq(ncr53c8xx_t *dev, int level) +{ + if (level) { + pci_set_irq(dev->pci_slot, PCI_INTA); + ncr53c8xx_log("Raising IRQ...\n"); + } else { + pci_clear_irq(dev->pci_slot, PCI_INTA); + ncr53c8xx_log("Lowering IRQ...\n"); + } +} + + +static void +ncr53c8xx_update_irq(ncr53c8xx_t *dev) +{ + int level; + + /* It's unclear whether the DIP/SIP bits should be cleared when the + Interrupt Status Registers are cleared or when istat is read. + We currently do the formwer, which seems to work. */ + level = 0; + if (dev->dstat & 0x7f) { + if ((dev->dstat & dev->dien) & 0x7f) + level = 1; + dev->istat |= NCR_ISTAT_DIP; + } else { + dev->istat &= ~NCR_ISTAT_DIP; + } + + if (dev->sist0 || dev->sist1) { + if ((dev->sist0 & dev->sien0) || (dev->sist1 & dev->sien1)) + level = 1; + dev->istat |= NCR_ISTAT_SIP; + } else { + dev->istat &= ~NCR_ISTAT_SIP; + } + if (dev->istat & NCR_ISTAT_INTF) { + level = 1; + } + + if (level != dev->last_level) { + ncr53c8xx_log("Update IRQ level %d dstat %02x sist %02x%02x\n", + level, dev->dstat, dev->sist1, dev->sist0); + dev->last_level = level; + do_irq(dev, level); /* Only do something with the IRQ if the new level differs from the previous one. */ + } +} + + +/* Stop SCRIPTS execution and raise a SCSI interrupt. */ +static void +ncr53c8xx_script_scsi_interrupt(ncr53c8xx_t *dev, int stat0, int stat1) +{ + uint32_t mask0; + uint32_t mask1; + + ncr53c8xx_log("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n", + stat1, stat0, dev->sist1, dev->sist0); + dev->sist0 |= stat0; + dev->sist1 |= stat1; + /* Stop processor on fatal or unmasked interrupt. As a special hack + we don't stop processing when raising STO. Instead continue + execution and stop at the next insn that accesses the SCSI bus. */ + mask0 = dev->sien0 | ~(NCR_SIST0_CMP | NCR_SIST0_SEL | NCR_SIST0_RSL); + mask1 = dev->sien1 | ~(NCR_SIST1_GEN | NCR_SIST1_HTH); + mask1 &= ~NCR_SIST1_STO; + if ((dev->sist0 & mask0) || (dev->sist1 & mask1)) { + ncr53c8xx_log("NCR 810: IRQ-mandated stop\n"); + dev->sstop = 1; + timer_stop(&dev->timer); + } + ncr53c8xx_update_irq(dev); +} + + +/* Stop SCRIPTS execution and raise a DMA interrupt. */ +static void +ncr53c8xx_script_dma_interrupt(ncr53c8xx_t *dev, int stat) +{ + ncr53c8xx_log("DMA Interrupt 0x%x prev 0x%x\n", stat, dev->dstat); + dev->dstat |= stat; + ncr53c8xx_update_irq(dev); + dev->sstop = 1; + timer_stop(&dev->timer); +} + + +static __inline__ void +ncr53c8xx_set_phase(ncr53c8xx_t *dev, int phase) +{ + dev->sstat1 = (dev->sstat1 & ~PHASE_MASK) | phase; +} + + +static void +ncr53c8xx_bad_phase(ncr53c8xx_t *dev, int out, int new_phase) +{ + /* Trigger a phase mismatch. */ + ncr53c8xx_log("Phase mismatch interrupt\n"); + ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); + dev->sstop = 1; + timer_stop(&dev->timer); + ncr53c8xx_set_phase(dev, new_phase); +} + + +static void +ncr53c8xx_disconnect(ncr53c8xx_t *dev) +{ + dev->scntl1 &= ~NCR_SCNTL1_CON; + dev->sstat1 &= ~PHASE_MASK; + if (dev->dcmd & 0x01) /* Select with ATN */ + dev->sstat1 |= 0x07; +} + + +static void +ncr53c8xx_bad_selection(ncr53c8xx_t *dev, uint32_t id) +{ + ncr53c8xx_log("Selected absent target %d\n", id); + ncr53c8xx_script_scsi_interrupt(dev, 0, NCR_SIST1_STO); + ncr53c8xx_disconnect(dev); +} + + +/* Callback to indicate that the SCSI layer has completed a command. */ +static void +ncr53c8xx_command_complete(void *priv, uint32_t status) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; + int out; + + out = (dev->sstat1 & PHASE_MASK) == PHASE_DO; + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Command complete status=%d\n", dev->current->tag, dev->current_lun, dev->last_command, (int)status); + dev->status = status; + dev->command_complete = 2; + if (dev->waiting && dev->dbc != 0) { + /* Raise phase mismatch for short transfers. */ + ncr53c8xx_bad_phase(dev, out, PHASE_ST); + } else + ncr53c8xx_set_phase(dev, PHASE_ST); + + dev->sstop = 0; +} + + +static void +ncr53c8xx_do_dma(ncr53c8xx_t *dev, int out, uint8_t id) +{ + uint32_t addr, tdbc; + int count; + + scsi_device_t *sd = &scsi_devices[id]; + + if ((!scsi_device_present(sd))) { + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Device not present when attempting to do DMA\n", id, dev->current_lun, dev->last_command); + return; + } + + if (!dev->current->dma_len) { + /* Wait until data is available. */ + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA no data available\n", id, dev->current_lun, dev->last_command); + return; + } + + /* Make sure count is never bigger than buffer_length. */ + count = tdbc = dev->dbc; + if (count > dev->temp_buf_len) + count = dev->temp_buf_len; + + addr = dev->dnad; + + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA addr=0x%08x len=%d cur_len=%d dev->dbc=%d\n", id, dev->current_lun, dev->last_command, dev->dnad, dev->temp_buf_len, count, tdbc); + dev->dnad += count; + dev->dbc -= count; + + if (out) + ncr53c8xx_read(dev, addr, sd->sc->temp_buffer + dev->buffer_pos, count); + else { +#ifdef ENABLE_NCR53C8XX_LOG + if (!dev->buffer_pos) + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DI\n", id, dev->current_lun, dev->last_command); +#endif + ncr53c8xx_write(dev, addr, sd->sc->temp_buffer + dev->buffer_pos, count); + } + + dev->temp_buf_len -= count; + dev->buffer_pos += count; + + if (dev->temp_buf_len <= 0) { + scsi_device_command_phase1(&scsi_devices[id]); +#ifdef ENABLE_NCR53C8XX_LOG + if (out) + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DO\n", id, dev->current_lun, dev->last_command); +#endif + ncr53c8xx_command_complete(dev, sd->status); + } else { + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Resume SCRIPTS\n", id, dev->current_lun, dev->last_command); + dev->sstop = 0; + } +} + + +/* Queue a byte for a MSG IN phase. */ +static void +ncr53c8xx_add_msg_byte(ncr53c8xx_t *dev, uint8_t data) +{ + if (dev->msg_len >= NCR_MAX_MSGIN_LEN) + ncr53c8xx_log("MSG IN data too long\n"); + else { + ncr53c8xx_log("MSG IN 0x%02x\n", data); + dev->msg[dev->msg_len++] = data; + } +} + + +static void +ncr53c8xx_timer_on(ncr53c8xx_t *dev, scsi_device_t *sd, double p) +{ + if (p <= 0) + timer_on_auto(&dev->timer, ((double) sd->buffer_length) * 0.1); /* Fast SCSI: 10000000 bytes per second */ + else + timer_on_auto(&dev->timer, p); +} + + +static int +ncr53c8xx_do_command(ncr53c8xx_t *dev, uint8_t id) +{ + scsi_device_t *sd; + uint8_t buf[12]; + + memset(buf, 0, 12); + DMAPageRead(dev->dnad, buf, MIN(12, dev->dbc)); + if (dev->dbc > 12) { + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: CDB length %i too big\n", id, dev->current_lun, buf[0], dev->dbc); + dev->dbc = 12; + } + dev->sfbr = buf[0]; + dev->command_complete = 0; + + sd = &scsi_devices[id]; + if (!scsi_device_present(sd)) { + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Bad Selection\n", id, dev->current_lun, buf[0]); + ncr53c8xx_bad_selection(dev, id); + return 0; + } + + dev->current = (ncr53c8xx_request*)malloc(sizeof(ncr53c8xx_request)); + dev->current->tag = id; + + sd->buffer_length = -1; + + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DBC=%i\n", id, dev->current_lun, buf[0], dev->dbc); + dev->last_command = buf[0]; + + /* Make sure bits 5-7 of the CDB have the correct LUN. */ + if ((buf[1] & 0xe0) != (dev->current_lun << 5)) + buf[1] = (buf[1] & 0x1f) | (dev->current_lun << 5); + + scsi_device_command_phase0(&scsi_devices[dev->current->tag], buf); + dev->hba_private = (void *)dev->current; + + dev->waiting = 0; + dev->buffer_pos = 0; + + dev->temp_buf_len = sd->buffer_length; + + if (sd->buffer_length > 0) { + /* This should be set to the underlying device's buffer by command phase 0. */ + dev->current->dma_len = sd->buffer_length; + } + + if ((sd->phase == SCSI_PHASE_DATA_IN) && (sd->buffer_length > 0)) { + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]); + ncr53c8xx_set_phase(dev, PHASE_DI); + ncr53c8xx_timer_on(dev, sd, scsi_device_get_callback(&scsi_devices[dev->current->tag])); + return 1; + } else if ((sd->phase == SCSI_PHASE_DATA_OUT) && (sd->buffer_length > 0)) { + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, buf[0]); + ncr53c8xx_set_phase(dev, PHASE_DO); + ncr53c8xx_timer_on(dev, sd, scsi_device_get_callback(&scsi_devices[dev->current->tag])); + return 1; + } else { + ncr53c8xx_command_complete(dev, sd->status); + return 0; + } +} + + +static void +ncr53c8xx_do_status(ncr53c8xx_t *dev) +{ + uint8_t status; + ncr53c8xx_log("Get status len=%d status=%d\n", dev->dbc, dev->status); + if (dev->dbc != 1) + ncr53c8xx_log("Bad Status move\n"); + dev->dbc = 1; + status = dev->status; + dev->sfbr = status; + ncr53c8xx_write(dev, dev->dnad, &status, 1); + ncr53c8xx_set_phase(dev, PHASE_MI); + dev->msg_action = 1; + ncr53c8xx_add_msg_byte(dev, 0); /* COMMAND COMPLETE */ +} + + +#ifdef USE_WDTR +static void +ncr53c8xx_do_wdtr(ncr53c8xx_t *dev, int exponent) +{ + ncr53c8xx_log("Target-initiated WDTR (%08X)\n", dev); + ncr53c8xx_set_phase(dev, PHASE_MI); + dev->msg_action = 4; + ncr53c8xx_add_msg_byte(dev, 0x01); /* EXTENDED MESSAGE */ + ncr53c8xx_add_msg_byte(dev, 0x02); /* EXTENDED MESSAGE LENGTH */ + ncr53c8xx_add_msg_byte(dev, 0x03); /* WIDE DATA TRANSFER REQUEST */ + ncr53c8xx_add_msg_byte(dev, exponent); /* TRANSFER WIDTH EXPONENT (16-bit) */ +} +#endif + + +static void +ncr53c8xx_do_msgin(ncr53c8xx_t *dev) +{ + uint32_t len; + ncr53c8xx_log("Message in len=%d/%d\n", dev->dbc, dev->msg_len); + dev->sfbr = dev->msg[0]; + len = dev->msg_len; + if (len > dev->dbc) + len = dev->dbc; + ncr53c8xx_write(dev, dev->dnad, dev->msg, len); + /* Linux drivers rely on the last byte being in the SIDL. */ + dev->sidl0 = dev->msg[len - 1]; + dev->msg_len -= len; + if (dev->msg_len) + memmove(dev->msg, dev->msg + len, dev->msg_len); + else { + /* ??? Check if ATN (not yet implemented) is asserted and maybe + switch to PHASE_MO. */ + switch (dev->msg_action) { + case 0: + ncr53c8xx_set_phase(dev, PHASE_CMD); + break; + case 1: + ncr53c8xx_disconnect(dev); + break; + case 2: + ncr53c8xx_set_phase(dev, PHASE_DO); + break; + case 3: + ncr53c8xx_set_phase(dev, PHASE_DI); + break; + case 4: + ncr53c8xx_set_phase(dev, PHASE_MO); + break; + default: + abort(); + } + } +} + + +/* Read the next byte during a MSGOUT phase. */ +static uint8_t +ncr53c8xx_get_msgbyte(ncr53c8xx_t *dev) +{ + uint8_t data; + DMAPageRead(dev->dnad, &data, 1); + dev->dnad++; + dev->dbc--; + return data; +} + + +/* Skip the next n bytes during a MSGOUT phase. */ +static void +ncr53c8xx_skip_msgbytes(ncr53c8xx_t *dev, unsigned int n) +{ + dev->dnad += n; + dev->dbc -= n; +} + + +static void +ncr53c8xx_bad_message(ncr53c8xx_t *dev, uint8_t msg) +{ + ncr53c8xx_log("Unimplemented message 0x%02x\n", msg); + ncr53c8xx_set_phase(dev, PHASE_MI); + ncr53c8xx_add_msg_byte(dev, 7); /* MESSAGE REJECT */ + dev->msg_action = 0; +} + + +static void +ncr53c8xx_do_msgout(ncr53c8xx_t *dev, uint8_t id) +{ + uint8_t msg; + int len, arg; +#ifdef ENABLE_NCR53C8XX_LOG + uint32_t current_tag; +#endif + scsi_device_t *sd; + + sd = &scsi_devices[id]; + +#ifdef ENABLE_NCR53C8XX_LOG + current_tag = id; +#endif + + ncr53c8xx_log("MSG out len=%d\n", dev->dbc); + while (dev->dbc) { + msg = ncr53c8xx_get_msgbyte(dev); + dev->sfbr = msg; + + switch (msg) { + case 0x04: + ncr53c8xx_log("MSG: Disconnect\n"); + ncr53c8xx_disconnect(dev); + break; + case 0x08: + ncr53c8xx_log("MSG: No Operation\n"); + ncr53c8xx_set_phase(dev, PHASE_CMD); + break; + case 0x01: + len = ncr53c8xx_get_msgbyte(dev); + msg = ncr53c8xx_get_msgbyte(dev); + arg = ncr53c8xx_get_msgbyte(dev); + (void) len; /* avoid a warning about unused variable*/ + ncr53c8xx_log("Extended message 0x%x (len %d)\n", msg, len); + switch (msg) { + case 1: + ncr53c8xx_log("SDTR (ignored)\n"); + ncr53c8xx_skip_msgbytes(dev, 1); + break; + case 3: + ncr53c8xx_log("WDTR (ignored)\n"); + if (arg > 0x01) { + ncr53c8xx_bad_message(dev, msg); + return; + } +#ifdef USE_WDTR + ncr53c8xx_set_phase(dev, PHASE_CMD); +#endif + break; + case 5: + ncr53c8xx_log("PPR (ignored)\n"); + ncr53c8xx_skip_msgbytes(dev, 4); + break; + default: + ncr53c8xx_bad_message(dev, msg); + return; + } + break; + case 0x20: /* SIMPLE queue */ + id |= ncr53c8xx_get_msgbyte(dev) | NCR_TAG_VALID; + ncr53c8xx_log("SIMPLE queue tag=0x%x\n", id & 0xff); + break; + case 0x21: /* HEAD of queue */ + ncr53c8xx_log("HEAD queue not implemented\n"); + id |= ncr53c8xx_get_msgbyte(dev) | NCR_TAG_VALID; + break; + case 0x22: /* ORDERED queue */ + ncr53c8xx_log("ORDERED queue not implemented\n"); + id |= ncr53c8xx_get_msgbyte(dev) | NCR_TAG_VALID; + break; + case 0x0d: + /* The ABORT TAG message clears the current I/O process only. */ + ncr53c8xx_log("MSG: Abort Tag\n"); + scsi_device_command_stop(sd); + ncr53c8xx_disconnect(dev); + break; + case 0x06: + case 0x0e: + case 0x0c: + /* clear the current I/O process */ + scsi_device_command_stop(sd); + ncr53c8xx_disconnect(dev); + break; + default: + if ((msg & 0x80) == 0) { + ncr53c8xx_bad_message(dev, msg); + return; + } else { + /* 0x80 to 0xff are IDENTIFY messages. */ + ncr53c8xx_log("MSG: Identify\n"); + dev->current_lun = msg & 7; + ncr53c8xx_log("Select LUN %d\n", dev->current_lun); +#ifdef USE_WDTR + ncr53c8xx_do_wdtr(dev, 0x01); +#else + ncr53c8xx_set_phase(dev, PHASE_CMD); +#endif + } + break; + } + } +} + + +static void +ncr53c8xx_memcpy(ncr53c8xx_t *dev, uint32_t dest, uint32_t src, int count) +{ + int n; + uint8_t buf[NCR_BUF_SIZE]; + + ncr53c8xx_log("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); + while (count) { + n = (count > NCR_BUF_SIZE) ? NCR_BUF_SIZE : count; + ncr53c8xx_read(dev, src, buf, n); + ncr53c8xx_write(dev, dest, buf, n); + src += n; + dest += n; + count -= n; + } +} + + +static void +ncr53c8xx_process_script(ncr53c8xx_t *dev) +{ + uint32_t insn, addr, id, buf[2], dest; + int opcode, insn_processed = 0, reg, operator, cond, jmp, n, i, c; + int32_t offset; + uint8_t op0, op1, data8, mask, data[7]; +#ifdef ENABLE_NCR53C8XX_LOG + uint8_t *pp; +#endif + + dev->sstop = 0; +again: + insn_processed++; + insn = read_dword(dev, dev->dsp); + if (!insn) { + /* If we receive an empty opcode increment the DSP by 4 bytes + instead of 8 and execute the next opcode at that location */ + dev->dsp += 4; + timer_on_auto(&dev->timer, 10.0); + if (insn_processed < 100) + goto again; + else + return; + } + addr = read_dword(dev, dev->dsp + 4); + ncr53c8xx_log("SCRIPTS dsp=%08x opcode %08x arg %08x\n", dev->dsp, insn, addr); + dev->dsps = addr; + dev->dcmd = insn >> 24; + dev->dsp += 8; + + switch (insn >> 30) { + case 0: /* Block move. */ + ncr53c8xx_log("00: Block move\n"); + if (dev->sist1 & NCR_SIST1_STO) { + ncr53c8xx_log("Delayed select timeout\n"); + dev->sstop = 1; + break; + } + ncr53c8xx_log("Block Move DBC=%d\n", dev->dbc); + dev->dbc = insn & 0xffffff; + ncr53c8xx_log("Block Move DBC=%d now\n", dev->dbc); + /* ??? Set ESA. */ + if (insn & (1 << 29)) { + /* Indirect addressing. */ + /* Should this respect SIOM? */ + addr = read_dword(dev, addr); + ncr53c8xx_log("Indirect Block Move address: %08X\n", addr); + } else if (insn & (1 << 28)) { + /* Table indirect addressing. */ + + /* 32-bit Table indirect */ + offset = sextract32(addr, 0, 24); + DMAPageRead(dev->dsa + offset, (uint8_t *)buf, 8); + /* byte count is stored in bits 0:23 only */ + dev->dbc = buf[0] & 0xffffff; + addr = buf[1]; + + /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of + * table, bits [31:24] */ + } + if ((dev->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) { + ncr53c8xx_log("Wrong phase got %d expected %d\n", + dev->sstat1 & PHASE_MASK, (insn >> 24) & 7); + ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); + break; + } + dev->dnad = addr; + switch (dev->sstat1 & 0x7) { + case PHASE_DO: + ncr53c8xx_log("Data Out Phase\n"); + dev->waiting = 0; + ncr53c8xx_do_dma(dev, 1, dev->sdid); + break; + case PHASE_DI: + ncr53c8xx_log("Data In Phase\n"); + dev->waiting = 0; + ncr53c8xx_do_dma(dev, 0, dev->sdid); + break; + case PHASE_CMD: + ncr53c8xx_log("Command Phase\n"); + c = ncr53c8xx_do_command(dev, dev->sdid); + + if (!c || dev->sstop || dev->waiting || ((dev->sstat1 & 0x7) == PHASE_ST)) + break; + + dev->dfifo = dev->dbc & 0xff; + dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); + + timer_on_auto(&dev->timer, 40.0); + + if (dev->dcntl & NCR_DCNTL_SSM) + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SSI); + return; + case PHASE_ST: + ncr53c8xx_log("Status Phase\n"); + ncr53c8xx_do_status(dev); + break; + case PHASE_MO: + ncr53c8xx_log("MSG Out Phase\n"); + ncr53c8xx_do_msgout(dev, dev->sdid); + break; + case PHASE_MI: + ncr53c8xx_log("MSG In Phase\n"); + ncr53c8xx_do_msgin(dev); + break; + default: + ncr53c8xx_log("Unimplemented phase %d\n", dev->sstat1 & PHASE_MASK); + } + dev->dfifo = dev->dbc & 0xff; + dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); + break; + + case 1: /* IO or Read/Write instruction. */ + ncr53c8xx_log("01: I/O or Read/Write instruction\n"); + opcode = (insn >> 27) & 7; + if (opcode < 5) { + if (insn & (1 << 25)) + id = read_dword(dev, dev->dsa + sextract32(insn, 0, 24)); + else + id = insn; + id = (id >> 16) & 0xf; + if (insn & (1 << 26)) + addr = dev->dsp + sextract32(addr, 0, 24); + dev->dnad = addr; + switch (opcode) { + case 0: /* Select */ + dev->sdid = id; + if (dev->scntl1 & NCR_SCNTL1_CON) { + ncr53c8xx_log("Already reselected, jumping to alternative address\n"); + dev->dsp = dev->dnad; + break; + } + dev->sstat0 |= NCR_SSTAT0_WOA; + dev->scntl1 &= ~NCR_SCNTL1_IARB; + if (!scsi_device_present(&scsi_devices[id])) { + ncr53c8xx_bad_selection(dev, id); + break; + } + ncr53c8xx_log("Selected target %d%s\n", + id, insn & (1 << 24) ? " ATN" : ""); + dev->scntl1 |= NCR_SCNTL1_CON; + if (insn & (1 << 24)) + dev->socl |= NCR_SOCL_ATN; + ncr53c8xx_set_phase(dev, PHASE_MO); + dev->waiting = 0; + break; + case 1: /* Disconnect */ + ncr53c8xx_log("Wait Disconnect\n"); + dev->scntl1 &= ~NCR_SCNTL1_CON; + break; + case 2: /* Wait Reselect */ + ncr53c8xx_log("Wait Reselect\n"); + if (dev->istat & NCR_ISTAT_SIGP) + dev->dsp = dev->dnad; /* If SIGP is set, this command causes an immediate jump to DNAD. */ + else { + if (!ncr53c8xx_irq_on_rsl(dev)) + dev->waiting = 1; + } + break; + case 3: /* Set */ + ncr53c8xx_log("Set%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", + insn & (1 << 6) ? " ACK" : "", + insn & (1 << 9) ? " TM" : "", + insn & (1 << 10) ? " CC" : ""); + if (insn & (1 << 3)) { + dev->socl |= NCR_SOCL_ATN; + ncr53c8xx_set_phase(dev, PHASE_MO); + } + if (insn & (1 << 9)) + ncr53c8xx_log("Target mode not implemented\n"); + if (insn & (1 << 10)) + dev->carry = 1; + break; + case 4: /* Clear */ + ncr53c8xx_log("Clear%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", + insn & (1 << 6) ? " ACK" : "", + insn & (1 << 9) ? " TM" : "", + insn & (1 << 10) ? " CC" : ""); + if (insn & (1 << 3)) + dev->socl &= ~NCR_SOCL_ATN; + if (insn & (1 << 10)) + dev->carry = 0; + break; + } + } else { + reg = ((insn >> 16) & 0x7f) | (insn & 0x80); + data8 = (insn >> 8) & 0xff; + opcode = (insn >> 27) & 7; + operator = (insn >> 24) & 7; + op0 = op1 = 0; + switch (opcode) { + case 5: /* From SFBR */ + op0 = dev->sfbr; + op1 = data8; + break; + case 6: /* To SFBR */ + if (operator) + op0 = ncr53c8xx_reg_readb(dev, reg); + op1 = data8; + break; + case 7: /* Read-modify-write */ + if (operator) + op0 = ncr53c8xx_reg_readb(dev, reg); + if (insn & (1 << 23)) + op1 = dev->sfbr; + else + op1 = data8; + break; + } + + switch (operator) { + case 0: /* move */ + op0 = op1; + break; + case 1: /* Shift left */ + op1 = op0 >> 7; + op0 = (op0 << 1) | dev->carry; + dev->carry = op1; + break; + case 2: /* OR */ + op0 |= op1; + break; + case 3: /* XOR */ + op0 ^= op1; + break; + case 4: /* AND */ + op0 &= op1; + break; + case 5: /* SHR */ + op1 = op0 & 1; + op0 = (op0 >> 1) | (dev->carry << 7); + dev->carry = op1; + break; + case 6: /* ADD */ + op0 += op1; + dev->carry = op0 < op1; + break; + case 7: /* ADC */ + op0 += op1 + dev->carry; + if (dev->carry) + dev->carry = op0 <= op1; + else + dev->carry = op0 < op1; + break; + } + + switch (opcode) { + case 5: /* From SFBR */ + case 7: /* Read-modify-write */ + ncr53c8xx_reg_writeb(dev, reg, op0); + break; + case 6: /* To SFBR */ + dev->sfbr = op0; + break; + } + } + break; + + case 2: /* Transfer Control. */ + ncr53c8xx_log("02: Transfer Control\n"); + if ((insn & 0x002e0000) == 0) { + ncr53c8xx_log("NOP\n"); + break; + } + if (dev->sist1 & NCR_SIST1_STO) { + ncr53c8xx_log("Delayed select timeout\n"); + dev->sstop = 1; + break; + } + cond = jmp = (insn & (1 << 19)) != 0; + if (cond == jmp && (insn & (1 << 21))) { + ncr53c8xx_log("Compare carry %d\n", dev->carry == jmp); + cond = dev->carry != 0; + } + if (cond == jmp && (insn & (1 << 17))) { + ncr53c8xx_log("Compare phase %d %c= %d\n", (dev->sstat1 & PHASE_MASK), + jmp ? '=' : '!', ((insn >> 24) & 7)); + cond = (dev->sstat1 & PHASE_MASK) == ((insn >> 24) & 7); + } + if (cond == jmp && (insn & (1 << 18))) { + mask = (~insn >> 8) & 0xff; + ncr53c8xx_log("Compare data 0x%x & 0x%x %c= 0x%x\n", dev->sfbr, mask, + jmp ? '=' : '!', insn & mask); + cond = (dev->sfbr & mask) == (insn & mask); + } + if (cond == jmp) { + if (insn & (1 << 23)) { + /* Relative address. */ + addr = dev->dsp + sextract32(addr, 0, 24); + } + switch ((insn >> 27) & 7) { + case 0: /* Jump */ + ncr53c8xx_log("Jump to 0x%08x\n", addr); + dev->adder = addr; + dev->dsp = addr; + break; + case 1: /* Call */ + ncr53c8xx_log("Call 0x%08x\n", addr); + dev->temp = dev->dsp; + dev->dsp = addr; + break; + case 2: /* Return */ + ncr53c8xx_log("Return to 0x%08x\n", dev->temp); + dev->dsp = dev->temp; + break; + case 3: /* Interrupt */ + ncr53c8xx_log("Interrupt 0x%08x\n", dev->dsps); + if ((insn & (1 << 20)) != 0) { + dev->istat |= NCR_ISTAT_INTF; + ncr53c8xx_update_irq(dev); + } else + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SIR); + break; + default: + ncr53c8xx_log("Illegal transfer control\n"); + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_IID); + break; + } + } else + ncr53c8xx_log("Control condition failed\n"); + break; + + case 3: + ncr53c8xx_log("00: Memory move\n"); + if ((insn & (1 << 29)) == 0) { + /* Memory move. */ + /* ??? The docs imply the destination address is loaded into + the TEMP register. However the Linux drivers rely on + the value being presrved. */ + dest = read_dword(dev, dev->dsp); + dev->dsp += 4; + ncr53c8xx_memcpy(dev, dest, addr, insn & 0xffffff); + } else { +#ifdef ENABLE_NCR53C8XX_LOG + pp = data; +#endif + + if (insn & (1 << 28)) + addr = dev->dsa + sextract32(addr, 0, 24); + n = (insn & 7); + reg = (insn >> 16) & 0xff; + if (insn & (1 << 24)) { + DMAPageRead(addr, data, n); + for (i = 0; i < n; i++) + ncr53c8xx_reg_writeb(dev, reg + i, data[i]); + } else { + ncr53c8xx_log("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); + for (i = 0; i < n; i++) + data[i] = ncr53c8xx_reg_readb(dev, reg + i); + DMAPageWrite(addr, data, n); + } + } + break; + + default: + ncr53c8xx_log("%02X: Unknown command\n", (uint8_t) (insn >> 30)); + } + + timer_on_auto(&dev->timer, 40.0); + + ncr53c8xx_log("instructions processed %i\n", insn_processed); + if (insn_processed > 10000 && !dev->waiting) { + /* Some windows drivers make the device spin waiting for a memory + location to change. If we have been executed a lot of code then + assume this is the case and force an unexpected device disconnect. + This is apparently sufficient to beat the drivers into submission. + */ + ncr53c8xx_log("Some windows drivers make the device spin...\n"); + if (!(dev->sien0 & NCR_SIST0_UDC)) + ncr53c8xx_log("inf. loop with UDC masked\n"); + ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_UDC, 0); + ncr53c8xx_disconnect(dev); + } else if (!dev->sstop && !dev->waiting) { + if (dev->dcntl & NCR_DCNTL_SSM) { + ncr53c8xx_log("NCR 810: SCRIPTS: Single-step mode\n"); + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SSI); + } else { + ncr53c8xx_log("NCR 810: SCRIPTS: Normal mode\n"); + if (insn_processed < 100) + goto again; + } + } else { + if (dev->sstop) + ncr53c8xx_log("NCR 810: SCRIPTS: Stopped\n"); + if (dev->waiting) + ncr53c8xx_log("NCR 810: SCRIPTS: Waiting\n"); + } + + ncr53c8xx_log("SCRIPTS execution stopped\n"); +} + + +static void +ncr53c8xx_execute_script(ncr53c8xx_t *dev) +{ + dev->sstop = 0; + timer_on_auto(&dev->timer, 40.0); +} + + +static void +ncr53c8xx_callback(void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *) p; + + if (!dev->sstop) { + if (dev->waiting) + timer_on_auto(&dev->timer, 40.0); + else + ncr53c8xx_process_script(dev); + } + + if (dev->sstop) + timer_stop(&dev->timer); + else + timer_on_auto(&dev->timer, 10.0); +} + + +#ifdef USE_NVRAM +static void +ncr53c8xx_eeprom(ncr53c8xx_t *dev, int save) +{ + FILE *f; + + if (save) + f = nvr_fopen(dev->nvr_path, L"wb"); + else + f = nvr_fopen(dev->nvr_path, L"rb"); + if (f) + { + if (save) { + fwrite((uint8_t *) &dev->nvram, 1, 1, f); + fwrite(((uint8_t *) &dev->nvram) + 1, 1, 1, f); + } else { + fread((uint8_t *) &dev->nvram, 1, 1, f); + fread(((uint8_t *) &dev->nvram) + 1, 1, 1, f); + } + fclose(f); + f = NULL; + } +} + + +#define ADDRESS_LENGTH 9 +#define ADDRESS_END (ADDRESS_LENGTH + 2) +#define ADDRESS_SHIFT (ADDRESS_LENGTH - 2) +#define ADDRESS_MASK 0x3f +#define DATA_LENGTH 8 +#define DATA_START (ADDRESS_END + 1) +#define DATA_END (ADDRESS_END + DATA_LENGTH) + + +static void +ncr53c8xx_serial_eeprom_write(ncr53c8xx_t *dev, uint8_t val) +{ + uint8_t temp, old = dev->nvram_t; + dev->nvram_t = val & 0x03; + + if (val & 0x02) { + if (!dev->nvram_index) { + /* First signal clocked in after clock is high, start bit. */ + dev->nvram_start = 1; + ncr53c8xx_log("[W] Serial EEPROM: Start bit\n"); + dev->nvram_op = 0; + } else if ((dev->nvram_index == 1) || (dev->nvram_index == 2)) { + if (!dev->nvram_start) + return; + + dev->nvram_op = (val & 0x01) << (dev->nvram_index - 1); + if (dev->nvram_index == 2) { + // ncr53c8xx_log("[W] Serial EEPROM: Opcode: %01X\n", dev->nvram_op); + dev->nvram_param = 0; + } + } else if ((dev->nvram_index >= 3) && (dev->nvram_index <= ADDRESS_END)) { + if (!dev->nvram_start) + return; + + dev->nvram_param = (val & 0x01) << (dev->nvram_index - 3); + if (dev->nvram_index < ADDRESS_END) { + dev->nvram_index++; + return; + } + + switch (dev->nvram_op) { + case 0x00: + temp = dev->nvram_param >> ADDRESS_SHIFT; + switch(temp) { + case 0x00: + ncr53c8xx_log("[W] Serial EEPROM: EWDS\n"); + break; + case 0x01: + ncr53c8xx_log("[W] Serial EEPROM: WRAL\n"); + break; + case 0x02: + ncr53c8xx_log("[W] Serial EEPROM: ERAL\n"); + break; + case 0x03: + ncr53c8xx_log("[W] Serial EEPROM: EWEN\n"); + break; + default: + ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN 00\n"); + break; + } + dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; + return; + case 0x01: + ncr53c8xx_log("[W] Serial EEPROM: WRITE\n"); + break; + case 0x02: + ncr53c8xx_log("[W] Serial EEPROM: READ\n"); + break; + case 0x03: + ncr53c8xx_log("[W] Serial EEPROM: ERASE\n"); + break; + default: + ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN\n"); + break; + } + } else if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) { + if (!dev->nvram_start) + return; + + if (dev->nvram_index == DATA_END) { + ncr53c8xx_log("[W] Serial EEPROM: Data end\n"); + dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; + return; + } + } + dev->nvram_index++; + } +} + + +static uint8_t +ncr53c8xx_serial_eeprom_read(ncr53c8xx_t *dev) +{ + uint8_t temp = 0; + + if (dev->gpreg & 0x02) { + if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) { + if (!dev->nvram_start) + return temp; + + dev->nvram_index++; + + if (dev->nvram_index == DATA_END) { + ncr53c8xx_log("[R] Serial EEPROM: Data end\n"); + dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; + return temp; + } + } + } + + return temp; +} +#endif + + +static void +ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val) +{ + uint8_t tmp = 0; + +#define CASE_SET_REG24(name, addr) \ + case addr : dev->name &= 0xffffff00; dev->name |= val; break; \ + case addr + 1: dev->name &= 0xffff00ff; dev->name |= val << 8; break; \ + case addr + 2: dev->name &= 0xff00ffff; dev->name |= val << 16; break; + +#define CASE_SET_REG32(name, addr) \ + case addr : dev->name &= 0xffffff00; dev->name |= val; break; \ + case addr + 1: dev->name &= 0xffff00ff; dev->name |= val << 8; break; \ + case addr + 2: dev->name &= 0xff00ffff; dev->name |= val << 16; break; \ + case addr + 3: dev->name &= 0x00ffffff; dev->name |= val << 24; break; + +#ifdef DEBUG_NCR_REG + ncr53c8xx_log("Write reg %02x = %02x\n", offset, val); +#endif + + dev->regop = 1; + + switch (offset) { + case 0x00: /* SCNTL0 */ + dev->scntl0 = val; + if (val & NCR_SCNTL0_START) { + /* Looks like this (turn on bit 4 of SSTAT0 to mark arbitration in progress) + is enough to make BIOS v4.x happy. */ + ncr53c8xx_log("NCR 810: Selecting SCSI ID %i\n", dev->sdid); + dev->sstat0 |= 0x10; + } + break; + case 0x01: /* SCNTL1 */ + dev->scntl1 = val & ~NCR_SCNTL1_SST; + if (val & NCR_SCNTL1_IARB) { + ncr53c8xx_log("Arbitration lost\n"); + dev->sstat0 |= 0x08; + dev->waiting = 0; + } + if (val & NCR_SCNTL1_RST) { + if (!(dev->sstat0 & NCR_SSTAT0_RST)) { + dev->sstat0 |= NCR_SSTAT0_RST; + ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_RST, 0); + } + } else + dev->sstat0 &= ~NCR_SSTAT0_RST; + break; + case 0x02: /* SCNTL2 */ + val &= ~(NCR_SCNTL2_WSR | NCR_SCNTL2_WSS); + dev->scntl2 = val; + break; + case 0x03: /* SCNTL3 */ + dev->scntl3 = val; + break; + case 0x04: /* SCID */ + dev->scid = val; + break; + case 0x05: /* SXFER */ + dev->sxfer = val; + break; + case 0x06: /* SDID */ + if ((dev->ssid & 0x80) && (val & 0xf) != (dev->ssid & 0xf)) + ncr53c8xx_log("Destination ID does not match SSID\n"); + dev->sdid = val & 0xf; + break; + case 0x07: /* GPREG */ + ncr53c8xx_log("NCR 810: GPREG write %02X\n", val); + tmp = dev->gpreg; + dev->gpreg = val & 0xfe; +#ifdef USE_NVRAM + if ((dev->gpcntl & 0xc3) == 0x00) + ncr53c8xx_serial_eeprom_write(dev, val & 0x03); +#endif + break; + case 0x08: /* SFBR */ + /* The CPU is not allowed to write to this register. However the + SCRIPTS register move instructions are. */ + dev->sfbr = val; + break; + case 0x09: /* SOCL */ + ncr53c8xx_log("NCR 810: SOCL write %02X\n", val); + dev->socl = val; + break; + case 0x0a: case 0x0b: + /* Openserver writes to these readonly registers on startup */ + return; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + /* Linux writes to these readonly registers on startup. */ + return; + CASE_SET_REG32(dsa, 0x10) + case 0x14: /* ISTAT */ + ncr53c8xx_log("ISTAT write: %02X\n", val); + tmp = dev->istat; + dev->istat = (dev->istat & 0x0f) | (val & 0xf0); + if ((val & NCR_ISTAT_ABRT) && !(val & NCR_ISTAT_SRST)) + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_ABRT); + if (val & NCR_ISTAT_INTF) { + dev->istat &= ~NCR_ISTAT_INTF; + ncr53c8xx_update_irq(dev); + } + + if ((dev->waiting == 1) && (val & NCR_ISTAT_SIGP)) { + ncr53c8xx_log("Woken by SIGP\n"); + dev->waiting = 0; + dev->dsp = dev->dnad; + /* ncr53c8xx_execute_script(dev); */ + } + if ((val & NCR_ISTAT_SRST) && !(tmp & NCR_ISTAT_SRST)) { + ncr53c8xx_soft_reset(dev); + ncr53c8xx_update_irq(dev); + dev->istat = 0; + } + break; + case 0x16: /* MBOX0 */ + dev->mbox0 = val; + break; + case 0x17: /* MBOX1 */ + dev->mbox1 = val; + break; + case 0x18: /* CTEST0 */ + /* nothing to do */ + break; + case 0x19: /* CTEST1 */ + /* nothing to do */ + break; + case 0x1a: /* CTEST2 */ + dev->ctest2 = val & NCR_CTEST2_PCICIE; + break; + case 0x1b: /* CTEST3 */ + dev->ctest3 = val & 0x0f; + break; + CASE_SET_REG32(temp, 0x1c) + case 0x21: /* CTEST4 */ + if (val & 7) + ncr53c8xx_log("Unimplemented CTEST4-FBL 0x%x\n", val); + dev->ctest4 = val; + break; + case 0x22: /* CTEST5 */ + if (val & (NCR_CTEST5_ADCK | NCR_CTEST5_BBCK)) + ncr53c8xx_log("CTEST5 DMA increment not implemented\n"); + dev->ctest5 = val; + break; + CASE_SET_REG24(dbc, 0x24) + CASE_SET_REG32(dnad, 0x28) + case 0x2c: /* DSP[0:7] */ + dev->dsp &= 0xffffff00; + dev->dsp |= val; + break; + case 0x2d: /* DSP[8:15] */ + dev->dsp &= 0xffff00ff; + dev->dsp |= val << 8; + break; + case 0x2e: /* DSP[16:23] */ + dev->dsp &= 0xff00ffff; + dev->dsp |= val << 16; + break; + case 0x2f: /* DSP[24:31] */ + dev->dsp &= 0x00ffffff; + dev->dsp |= val << 24; + if (!(dev->dmode & NCR_DMODE_MAN) && dev->sstop) + ncr53c8xx_execute_script(dev); + break; + CASE_SET_REG32(dsps, 0x30) + CASE_SET_REG32(scratcha, 0x34) + case 0x38: /* DMODE */ + dev->dmode = val; + break; + case 0x39: /* DIEN */ + ncr53c8xx_log("DIEN write: %02X\n", val); + dev->dien = val; + ncr53c8xx_update_irq(dev); + break; + case 0x3a: /* SBR */ + dev->sbr = val; + break; + case 0x3b: /* DCNTL */ + dev->dcntl = val & ~(NCR_DCNTL_PFF | NCR_DCNTL_STD); + if ((val & NCR_DCNTL_STD) && dev->sstop) + ncr53c8xx_execute_script(dev); + break; + case 0x40: /* SIEN0 */ + dev->sien0 = val; + ncr53c8xx_update_irq(dev); + break; + case 0x41: /* SIEN1 */ + dev->sien1 = val; + ncr53c8xx_update_irq(dev); + break; + case 0x47: /* GPCNTL */ + ncr53c8xx_log("GPCNTL write: %02X\n", val); + dev->gpcntl = val; + break; + case 0x48: /* STIME0 */ + dev->stime0 = val; + break; + case 0x49: /* STIME1 */ + if (val & 0xf) { + ncr53c8xx_log("General purpose timer not implemented\n"); + /* ??? Raising the interrupt immediately seems to be sufficient + to keep the FreeBSD driver happy. */ + ncr53c8xx_script_scsi_interrupt(dev, 0, NCR_SIST1_GEN); + } + break; + case 0x4a: /* RESPID0 */ + dev->respid0 = val; + break; + case 0x4b: /* RESPID1 */ + if (dev->chip >= CHIP_825) + dev->respid1 = val; + break; + case 0x4d: /* STEST1 */ + dev->stest1 = val; + break; + case 0x4e: /* STEST2 */ + if (val & 1) + ncr53c8xx_log("Low level mode not implemented\n"); + dev->stest2 = val; + break; + case 0x4f: /* STEST3 */ + if (val & 0x41) + ncr53c8xx_log("SCSI FIFO test mode not implemented\n"); + dev->stest3 = val; + break; + case 0x54: + case 0x55: + break; + CASE_SET_REG32(scratchb, 0x5c) + CASE_SET_REG32(scratchc, 0x60) + CASE_SET_REG32(scratchd, 0x64) + CASE_SET_REG32(scratche, 0x68) + CASE_SET_REG32(scratchf, 0x6c) + CASE_SET_REG32(scratchg, 0x70) + CASE_SET_REG32(scratchh, 0x74) + CASE_SET_REG32(scratchi, 0x78) + CASE_SET_REG32(scratchj, 0x7c) + default: + ncr53c8xx_log("Unhandled writeb 0x%x = 0x%x\n", offset, val); + } +#undef CASE_SET_REG24 +#undef CASE_SET_REG32 +} + + +static uint8_t +ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset) +{ + uint8_t tmp; +#define CASE_GET_REG24(name, addr) \ + case addr: return dev->name & 0xff; \ + case addr + 1: return (dev->name >> 8) & 0xff; \ + case addr + 2: return (dev->name >> 16) & 0xff; + +#define CASE_GET_REG32(name, addr) \ + case addr: return dev->name & 0xff; \ + case addr + 1: return (dev->name >> 8) & 0xff; \ + case addr + 2: return (dev->name >> 16) & 0xff; \ + case addr + 3: return (dev->name >> 24) & 0xff; + +#define CASE_GET_REG32_COND(name, addr) \ + case addr: if (dev->chip >= CHIP_825) \ + return dev->name & 0xff; \ + else \ + return 0x00; \ + case addr + 1: if (dev->chip >= CHIP_825) \ + return (dev->name >> 8) & 0xff; \ + else \ + return 0x00; \ + case addr + 2: if (dev->chip >= CHIP_825) \ + return (dev->name >> 16) & 0xff; \ + else \ + return 0x00; \ + case addr + 3: if (dev->chip >= CHIP_825) \ + return (dev->name >> 24) & 0xff; \ + else \ + return 0x00; + + dev->regop = 1; + + switch (offset) { + case 0x00: /* SCNTL0 */ + ncr53c8xx_log("NCR 810: Read SCNTL0 %02X\n", dev->scntl0); + return dev->scntl0; + case 0x01: /* SCNTL1 */ + ncr53c8xx_log("NCR 810: Read SCNTL1 %02X\n", dev->scntl1); + return dev->scntl1; + case 0x02: /* SCNTL2 */ + ncr53c8xx_log("NCR 810: Read SCNTL2 %02X\n", dev->scntl2); + return dev->scntl2; + case 0x03: /* SCNTL3 */ + ncr53c8xx_log("NCR 810: Read SCNTL3 %02X\n", dev->scntl3); + return dev->scntl3; + case 0x04: /* SCID */ + ncr53c8xx_log("NCR 810: Read SCID %02X\n", dev->scid); + return dev->scid & ~0x40; + case 0x05: /* SXFER */ + ncr53c8xx_log("NCR 810: Read SXFER %02X\n", dev->sxfer); + return dev->sxfer; + case 0x06: /* SDID */ + ncr53c8xx_log("NCR 810: Read SDID %02X\n", dev->sdid); + return dev->sdid; + case 0x07: /* GPREG */ +#ifdef USE_NVRAM + tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e; + if ((dev->gpcntl & 0xc3) == 0x01) + tmp |= ncr53c8xx_serial_eeprom_read(dev); +#else + tmp = ((dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e) | 0x01; +#endif + ncr53c8xx_log("NCR 810: Read GPREG %02X\n", tmp); + return tmp; + case 0x08: /* Revision ID */ + ncr53c8xx_log("NCR 810: Read REVID 00\n"); + return 0x00; + case 0xa: /* SSID */ + ncr53c8xx_log("NCR 810: Read SSID %02X\n", dev->ssid); + return dev->ssid; + case 0xb: /* SBCL */ + /* Bit 7 = REQ (SREQ/ status) + Bit 6 = ACK (SACK/ status) + Bit 5 = BSY (SBSY/ status) + Bit 4 = SEL (SSEL/ status) + Bit 3 = ATN (SATN/ status) + Bit 2 = MSG (SMSG/ status) + Bit 1 = C/D (SC_D/ status) + Bit 0 = I/O (SI_O/ status) */ + tmp = (dev->sstat1 & 7); + ncr53c8xx_log("NCR 810: Read SBCL %02X\n", tmp); + return tmp; /* For now, return the MSG, C/D, and I/O bits from SSTAT1. */ + case 0xc: /* DSTAT */ + tmp = dev->dstat | NCR_DSTAT_DFE; + if ((dev->istat & NCR_ISTAT_INTF) == 0) + dev->dstat = 0; + ncr53c8xx_update_irq(dev); + ncr53c8xx_log("NCR 810: Read DSTAT %02X\n", tmp); + return tmp; + case 0x0d: /* SSTAT0 */ + ncr53c8xx_log("NCR 810: Read SSTAT0 %02X\n", dev->sstat0); + return dev->sstat0; + case 0x0e: /* SSTAT1 */ + ncr53c8xx_log("NCR 810: Read SSTAT1 %02X\n", dev->sstat1); + return dev->sstat1; + case 0x0f: /* SSTAT2 */ + ncr53c8xx_log("NCR 810: Read SSTAT2 %02X\n", dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2); + return dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2; + CASE_GET_REG32(dsa, 0x10) + case 0x14: /* ISTAT */ + ncr53c8xx_log("NCR 810: Read ISTAT %02X\n", dev->istat); + tmp = dev->istat; + return tmp; + case 0x16: /* MBOX0 */ + if (dev->chip >= CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read MBOX0 %02X\n", dev->mbox0); + return dev->mbox0; + case 0x17: /* MBOX1 */ + if (dev->chip >= CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read MBOX1 %02X\n", dev->mbox1); + return dev->mbox1; + case 0x18: /* CTEST0 */ + ncr53c8xx_log("NCR 810: Read CTEST0 FF\n"); + return 0xff; + case 0x19: /* CTEST1 */ + ncr53c8xx_log("NCR 810: Read CTEST1 F0\n"); + return 0xf0; /* dma fifo empty */ + case 0x1a: /* CTEST2 */ + tmp = dev->ctest2 | NCR_CTEST2_DACK | NCR_CTEST2_CM; + if (dev->istat & NCR_ISTAT_SIGP) { + dev->istat &= ~NCR_ISTAT_SIGP; + tmp |= NCR_CTEST2_SIGP; + } + ncr53c8xx_log("NCR 810: Read CTEST2 %02X\n", tmp); + return tmp; + case 0x1b: /* CTEST3 */ + ncr53c8xx_log("NCR 810: Read CTEST3 %02X\n", + (dev->ctest3 & (0x08 | 0x02 | 0x01)) | ((dev->chip_rev & 0x0f) << 4)); + return (dev->ctest3 & (0x08 | 0x02 | 0x01)) | ((dev->chip_rev & 0x0f) << 4); + CASE_GET_REG32(temp, 0x1c) + case 0x20: /* DFIFO */ + ncr53c8xx_log("NCR 810: Read DFIFO 00\n"); + return 0; + case 0x21: /* CTEST4 */ + ncr53c8xx_log("NCR 810: Read CTEST4 %02X\n", dev->ctest4); + return dev->ctest4; + case 0x22: /* CTEST5 */ + ncr53c8xx_log("NCR 810: Read CTEST5 %02X\n", dev->ctest5); + return dev->ctest5; + case 0x23: /* CTEST6 */ + ncr53c8xx_log("NCR 810: Read CTEST6 00\n"); + return 0; + CASE_GET_REG24(dbc, 0x24) + case 0x27: /* DCMD */ + ncr53c8xx_log("NCR 810: Read DCMD %02X\n", dev->dcmd); + return dev->dcmd; + CASE_GET_REG32(dnad, 0x28) + CASE_GET_REG32(dsp, 0x2c) + CASE_GET_REG32(dsps, 0x30) + CASE_GET_REG32(scratcha, 0x34) + case 0x38: /* DMODE */ + ncr53c8xx_log("NCR 810: Read DMODE %02X\n", dev->dmode); + return dev->dmode; + case 0x39: /* DIEN */ + ncr53c8xx_log("NCR 810: Read DIEN %02X\n", dev->dien); + return dev->dien; + case 0x3a: /* SBR */ + ncr53c8xx_log("NCR 810: Read SBR %02X\n", dev->sbr); + return dev->sbr; + case 0x3b: /* DCNTL */ + ncr53c8xx_log("NCR 810: Read DCNTL %02X\n", dev->dcntl); + return dev->dcntl; + CASE_GET_REG32(adder, 0x3c) /* ADDER Output (Debug of relative jump address) */ + case 0x40: /* SIEN0 */ + ncr53c8xx_log("NCR 810: Read SIEN0 %02X\n", dev->sien0); + return dev->sien0; + case 0x41: /* SIEN1 */ + ncr53c8xx_log("NCR 810: Read SIEN1 %02X\n", dev->sien1); + return dev->sien1; + case 0x42: /* SIST0 */ + tmp = dev->sist0; + dev->sist0 = 0x00; + ncr53c8xx_update_irq(dev); + ncr53c8xx_log("NCR 810: Read SIST0 %02X\n", tmp); + return tmp; + case 0x43: /* SIST1 */ + tmp = dev->sist1; + dev->sist1 = 0x00; + ncr53c8xx_update_irq(dev); + ncr53c8xx_log("NCR 810: Read SIST1 %02X\n", tmp); + return tmp; + case 0x44: /* SLPAR */ + if (dev->chip < CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read SLPAR %02X\n", dev->stime0); + return dev->slpar; + case 0x45: /* SWIDE */ + if (dev->chip < CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read SWIDE %02X\n", dev->stime0); + return dev->swide; + case 0x46: /* MACNTL */ + ncr53c8xx_log("NCR 810: Read MACNTL 4F\n"); + return 0x4f; + case 0x47: /* GPCNTL */ + ncr53c8xx_log("NCR 810: Read GPCNTL %02X\n", dev->gpcntl); + return dev->gpcntl; + case 0x48: /* STIME0 */ + ncr53c8xx_log("NCR 810: Read STIME0 %02X\n", dev->stime0); + return dev->stime0; + case 0x4a: /* RESPID0 */ + if (dev->chip >= CHIP_825) + ncr53c8xx_log("NCR 810: Read RESPID0 %02X\n", dev->respid0); + else + ncr53c8xx_log("NCR 810: Read RESPID %02X\n", dev->respid0); + return dev->respid0; + case 0x4b: /* RESPID1 */ + if (dev->chip < CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read RESPID1 %02X\n", dev->respid1); + return dev->respid1; + case 0x4c: /* STEST0 */ + ncr53c8xx_log("NCR 810: Read STEST0 %02X\n", dev->stest1); + return 0x00; + case 0x4d: /* STEST1 */ + ncr53c8xx_log("NCR 810: Read STEST1 %02X\n", dev->stest1); + return dev->stest1; + case 0x4e: /* STEST2 */ + ncr53c8xx_log("NCR 810: Read STEST2 %02X\n", dev->stest2); + return dev->stest2; + case 0x4f: /* STEST3 */ + ncr53c8xx_log("NCR 810: Read STEST3 %02X\n", dev->stest3); + return dev->stest3; + case 0x50: /* SIDL0 */ + /* This is needed by the linux drivers. We currently only update it + during the MSG IN phase. */ + if (dev->chip >= CHIP_825) + ncr53c8xx_log("NCR 810: Read SIDL0 %02X\n", dev->sidl0); + else + ncr53c8xx_log("NCR 810: Read SIDL %02X\n", dev->sidl0); + return dev->sidl0; + case 0x51: /* SIDL1 */ + if (dev->chip < CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read SIDL1 %02X\n", dev->sidl1); + return dev->sidl1; + case 0x52: /* STEST4 */ + ncr53c8xx_log("NCR 810: Read STEST4 E0\n"); + return 0xe0; + case 0x58: /* SBDL */ + /* Some drivers peek at the data bus during the MSG IN phase. */ + if ((dev->sstat1 & PHASE_MASK) == PHASE_MI) { + ncr53c8xx_log("NCR 810: Read SBDL %02X\n", dev->msg[0]); + return dev->msg[0]; + } + ncr53c8xx_log("NCR 810: Read SBDL 00\n"); + return 0; + case 0x59: /* SBDL high */ + ncr53c8xx_log("NCR 810: Read SBDLH 00\n"); + return 0; + CASE_GET_REG32(scratchb, 0x5c) + CASE_GET_REG32_COND(scratchc, 0x60) + CASE_GET_REG32_COND(scratchd, 0x64) + CASE_GET_REG32_COND(scratche, 0x68) + CASE_GET_REG32_COND(scratchf, 0x6c) + CASE_GET_REG32_COND(scratchg, 0x70) + CASE_GET_REG32_COND(scratchh, 0x74) + CASE_GET_REG32_COND(scratchi, 0x78) + CASE_GET_REG32_COND(scratchj, 0x7c) + } + ncr53c8xx_log("readb 0x%x\n", offset); + return 0; + +#undef CASE_GET_REG24 +#undef CASE_GET_REG32 +} + + +static uint8_t +ncr53c8xx_io_readb(uint16_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + return ncr53c8xx_reg_readb(dev, addr & 0xff); +} + + +static uint16_t +ncr53c8xx_io_readw(uint16_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + uint16_t val; + + addr &= 0xff; + val = ncr53c8xx_reg_readb(dev, addr); + val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; + return val; +} + + +static uint32_t +ncr53c8xx_io_readl(uint16_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + uint32_t val; + + addr &= 0xff; + val = ncr53c8xx_reg_readb(dev, addr); + val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; + val |= ncr53c8xx_reg_readb(dev, addr + 2) << 16; + val |= ncr53c8xx_reg_readb(dev, addr + 3) << 24; + return val; +} + + +static void +ncr53c8xx_io_writeb(uint16_t addr, uint8_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + ncr53c8xx_reg_writeb(dev, addr & 0xff, val); +} + + +static void +ncr53c8xx_io_writew(uint16_t addr, uint16_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + addr &= 0xff; + ncr53c8xx_reg_writeb(dev, addr, val & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); +} + + +static void +ncr53c8xx_io_writel(uint16_t addr, uint32_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + addr &= 0xff; + ncr53c8xx_reg_writeb(dev, addr, val & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); +} + + +static void +ncr53c8xx_mmio_writeb(uint32_t addr, uint8_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + ncr53c8xx_reg_writeb(dev, addr & 0xff, val); +} + + +static void +ncr53c8xx_mmio_writew(uint32_t addr, uint16_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + addr &= 0xff; + ncr53c8xx_reg_writeb(dev, addr, val & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); +} + + +static void +ncr53c8xx_mmio_writel(uint32_t addr, uint32_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + addr &= 0xff; + ncr53c8xx_reg_writeb(dev, addr, val & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); +} + + +static uint8_t +ncr53c8xx_mmio_readb(uint32_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + return ncr53c8xx_reg_readb(dev, addr & 0xff); +} + + +static uint16_t +ncr53c8xx_mmio_readw(uint32_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + uint16_t val; + + addr &= 0xff; + val = ncr53c8xx_reg_readb(dev, addr); + val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; + return val; +} + + +static uint32_t +ncr53c8xx_mmio_readl(uint32_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + uint32_t val; + + addr &= 0xff; + val = ncr53c8xx_reg_readb(dev, addr); + val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; + val |= ncr53c8xx_reg_readb(dev, addr + 2) << 16; + val |= ncr53c8xx_reg_readb(dev, addr + 3) << 24; + + return val; +} + + +static void +ncr53c8xx_ram_writeb(uint32_t addr, uint8_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + dev->ram[addr & 0x0fff] = val; +} + + +static void +ncr53c8xx_ram_writew(uint32_t addr, uint16_t val, void *p) +{ + ncr53c8xx_ram_writeb(addr, val & 0xff, p); + ncr53c8xx_ram_writeb(addr + 1, (val >> 8) & 0xff, p); +} + + +static void +ncr53c8xx_ram_writel(uint32_t addr, uint32_t val, void *p) +{ + ncr53c8xx_ram_writeb(addr, val & 0xff, p); + ncr53c8xx_ram_writeb(addr + 1, (val >> 8) & 0xff, p); + ncr53c8xx_ram_writeb(addr + 2, (val >> 16) & 0xff, p); + ncr53c8xx_ram_writeb(addr + 3, (val >> 24) & 0xff, p); +} + + +static uint8_t +ncr53c8xx_ram_readb(uint32_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + return dev->ram[addr & 0x0fff]; +} + + +static uint16_t +ncr53c8xx_ram_readw(uint32_t addr, void *p) +{ + uint16_t val; + + val = ncr53c8xx_ram_readb(addr, p); + val |= ncr53c8xx_ram_readb(addr + 1, p) << 8; + + return val; +} + + +static uint32_t +ncr53c8xx_ram_readl(uint32_t addr, void *p) +{ + uint32_t val; + + val = ncr53c8xx_ram_readb(addr, p); + val |= ncr53c8xx_ram_readb(addr + 1, p) << 8; + val |= ncr53c8xx_ram_readb(addr + 2, p) << 16; + val |= ncr53c8xx_ram_readb(addr + 3, p) << 24; + + return val; +} + + +static void +ncr53c8xx_io_set(ncr53c8xx_t *dev, uint32_t base, uint16_t len) +{ + ncr53c8xx_log("NCR53c8xx: [PCI] Setting I/O handler at %04X\n", base); + io_sethandler(base, len, + ncr53c8xx_io_readb, ncr53c8xx_io_readw, ncr53c8xx_io_readl, + ncr53c8xx_io_writeb, ncr53c8xx_io_writew, ncr53c8xx_io_writel, dev); +} + + +static void +ncr53c8xx_io_remove(ncr53c8xx_t *dev, uint32_t base, uint16_t len) +{ + ncr53c8xx_log("NCR53c8xx: Removing I/O handler at %04X\n", base); + io_removehandler(base, len, + ncr53c8xx_io_readb, ncr53c8xx_io_readw, ncr53c8xx_io_readl, + ncr53c8xx_io_writeb, ncr53c8xx_io_writew, ncr53c8xx_io_writel, dev); +} + + +static void +ncr53c8xx_mem_init(ncr53c8xx_t *dev, uint32_t addr) +{ + mem_mapping_add(&dev->mmio_mapping, addr, 0x100, + ncr53c8xx_mmio_readb, ncr53c8xx_mmio_readw, ncr53c8xx_mmio_readl, + ncr53c8xx_mmio_writeb, ncr53c8xx_mmio_writew, ncr53c8xx_mmio_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); +} + + +static void +ncr53c8xx_ram_init(ncr53c8xx_t *dev, uint32_t addr) +{ + mem_mapping_add(&dev->ram_mapping, addr, 0x1000, + ncr53c8xx_ram_readb, ncr53c8xx_ram_readw, ncr53c8xx_ram_readl, + ncr53c8xx_ram_writeb, ncr53c8xx_ram_writew, ncr53c8xx_ram_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); +} + + +static void +ncr53c8xx_mem_set_addr(ncr53c8xx_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->mmio_mapping, base, 0x100); +} + + +static void +ncr53c8xx_ram_set_addr(ncr53c8xx_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->ram_mapping, base, 0x1000); +} + + +#ifdef USE_BIOS_BAR +static void +ncr53c8xx_bios_set_addr(ncr53c8xx_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->bios.mapping, base, 0x10000); +} +#endif + + +static void +ncr53c8xx_mem_disable(ncr53c8xx_t *dev) +{ + mem_mapping_disable(&dev->mmio_mapping); +} + + +static void +ncr53c8xx_ram_disable(ncr53c8xx_t *dev) +{ + mem_mapping_disable(&dev->ram_mapping); +} + + +#ifdef USE_BIOS_BAR +static void +ncr53c8xx_bios_disable(ncr53c8xx_t *dev) +{ + mem_mapping_disable(&dev->bios.mapping); +} +#endif + + +uint8_t ncr53c8xx_pci_regs[256]; +bar_t ncr53c8xx_pci_bar[4]; + + +static uint8_t +ncr53c8xx_pci_read(int func, int addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + ncr53c8xx_log("NCR53c8xx: Reading register %02X\n", addr & 0xff); + + if ((addr >= 0x80) && (addr <= 0xFF)) + return ncr53c8xx_reg_readb(dev, addr & 0x7F); + + switch (addr) { + case 0x00: + return 0x00; + case 0x01: + return 0x10; + case 0x02: + return dev->chip; + case 0x03: + return 0x00; + case 0x04: + return ncr53c8xx_pci_regs[0x04] & 0x57; /*Respond to IO and memory accesses*/ + case 0x05: + return ncr53c8xx_pci_regs[0x05] & 0x01; + case 0x07: + return 2; + case 0x08: + return dev->chip_rev; /*Revision ID*/ + case 0x09: + return 0; /*Programming interface*/ + case 0x0A: + return 0; /*devubclass*/ + case 0x0B: + return 1; /*Class code*/ + case 0x0C: + case 0x0D: + return ncr53c8xx_pci_regs[addr]; + case 0x0E: + return 0; /*Header type */ + case 0x10: + return 1; /*I/O space*/ + case 0x11: + return ncr53c8xx_pci_bar[0].addr_regs[1]; + case 0x12: + return ncr53c8xx_pci_bar[0].addr_regs[2]; + case 0x13: + return ncr53c8xx_pci_bar[0].addr_regs[3]; + case 0x14: + return 0; /*Memory space*/ + case 0x15: + return ncr53c8xx_pci_bar[1].addr_regs[1]; + case 0x16: + return ncr53c8xx_pci_bar[1].addr_regs[2]; + case 0x17: + return ncr53c8xx_pci_bar[1].addr_regs[3]; + case 0x18: + return 0; /*Memory space*/ + case 0x19: + if (dev->chip < CHIP_825) + return 0; + return ncr53c8xx_pci_bar[2].addr_regs[1]; + case 0x1A: + if (dev->chip < CHIP_825) + return 0; + return ncr53c8xx_pci_bar[2].addr_regs[2]; + case 0x1B: + if (dev->chip < CHIP_825) + return 0; + return ncr53c8xx_pci_bar[2].addr_regs[3]; + case 0x2C: + return 0x00; + case 0x2D: + if (dev->chip >= CHIP_825) + return 0; + return 0x10; + case 0x2E: + if (dev->chip >= CHIP_825) + return 0; + return 0x01; + case 0x2F: + return 0x00; +#ifdef USE_BIOS_BAR + case 0x30: + if ((dev->chip < CHIP_825) || !dev->has_bios) + return 0; + return ncr53c8xx_pci_bar[3].addr_regs[0]; + case 0x31: + if ((dev->chip < CHIP_825) || !dev->has_bios) + return 0; + return ncr53c8xx_pci_bar[3].addr_regs[1]; + case 0x32: + if ((dev->chip < CHIP_825) || !dev->has_bios) + return 0; + return ncr53c8xx_pci_bar[3].addr_regs[2]; + case 0x33: + if ((dev->chip < CHIP_825) || !dev->has_bios) + return 0; + return ncr53c8xx_pci_bar[3].addr_regs[3]; +#endif + case 0x3C: + return dev->irq; + case 0x3D: + return PCI_INTA; + case 0x3E: + return 0x11; + case 0x3F: + return 0x40; + } + + return(0); +} + + +static void +ncr53c8xx_pci_write(int func, int addr, uint8_t val, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + uint8_t valxor; + + ncr53c8xx_log("NCR53c8xx: Write value %02X to register %02X\n", val, addr & 0xff); + + if ((addr >= 0x80) && (addr <= 0xFF)) { + ncr53c8xx_reg_writeb(dev, addr & 0x7F, val); + return; + } + + switch (addr) + { + case 0x04: + valxor = (val & 0x57) ^ ncr53c8xx_pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) { + ncr53c8xx_io_remove(dev, dev->PCIBase, 0x0100); + if ((dev->PCIBase != 0) && (val & PCI_COMMAND_IO)) + ncr53c8xx_io_set(dev, dev->PCIBase, 0x0100); + } + if (valxor & PCI_COMMAND_MEM) { + ncr53c8xx_mem_disable(dev); + if ((dev->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) + ncr53c8xx_mem_set_addr(dev, dev->MMIOBase); + if (dev->chip >= CHIP_825) { + ncr53c8xx_ram_disable(dev); + if ((dev->RAMBase != 0) && (val & PCI_COMMAND_MEM)) + ncr53c8xx_ram_set_addr(dev, dev->RAMBase); + } + } + ncr53c8xx_pci_regs[addr] = val & 0x57; + break; + + case 0x05: + ncr53c8xx_pci_regs[addr] = val & 0x01; + break; + + case 0x0C: + case 0x0D: + ncr53c8xx_pci_regs[addr] = val; + break; + + case 0x10: case 0x11: case 0x12: case 0x13: + /* I/O Base set. */ + /* First, remove the old I/O. */ + ncr53c8xx_io_remove(dev, dev->PCIBase, 0x0100); + /* Then let's set the PCI regs. */ + ncr53c8xx_pci_bar[0].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + ncr53c8xx_pci_bar[0].addr &= 0xff00; + dev->PCIBase = ncr53c8xx_pci_bar[0].addr; + /* Log the new base. */ + ncr53c8xx_log("NCR53c8xx: New I/O base is %04X\n" , dev->PCIBase); + /* We're done, so get out of the here. */ + if (ncr53c8xx_pci_regs[4] & PCI_COMMAND_IO) { + if (dev->PCIBase != 0) { + ncr53c8xx_io_set(dev, dev->PCIBase, 0x0100); + } + } + return; + + case 0x15: case 0x16: case 0x17: + /* MMIO Base set. */ + /* First, remove the old I/O. */ + ncr53c8xx_mem_disable(dev); + /* Then let's set the PCI regs. */ + ncr53c8xx_pci_bar[1].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + ncr53c8xx_pci_bar[1].addr &= 0xffffc000; + dev->MMIOBase = ncr53c8xx_pci_bar[1].addr & 0xffffc000; + /* Log the new base. */ + ncr53c8xx_log("NCR53c8xx: New MMIO base is %08X\n" , dev->MMIOBase); + /* We're done, so get out of the here. */ + if (ncr53c8xx_pci_regs[4] & PCI_COMMAND_MEM) { + if (dev->MMIOBase != 0) + ncr53c8xx_mem_set_addr(dev, dev->MMIOBase); + } + return; + + case 0x19: case 0x1A: case 0x1B: + if (dev->chip < CHIP_825) + return; + /* RAM Base set. */ + /* First, remove the old I/O. */ + ncr53c8xx_ram_disable(dev); + /* Then let's set the PCI regs. */ + ncr53c8xx_pci_bar[2].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + ncr53c8xx_pci_bar[2].addr &= 0xffffc000; + dev->RAMBase = ncr53c8xx_pci_bar[2].addr & 0xffffc000; + /* Log the new base. */ + ncr53c8xx_log("NCR53c8xx: New RAM base is %08X\n" , dev->RAMBase); + /* We're done, so get out of the here. */ + if (ncr53c8xx_pci_regs[4] & PCI_COMMAND_MEM) { + if (dev->RAMBase != 0) + ncr53c8xx_ram_set_addr(dev, dev->RAMBase); + } + return; + +#ifdef USE_BIOS_BAR + case 0x30: case 0x31: case 0x32: case 0x33: + return; + if ((dev->chip < CHIP_825) || !dev->has_bios) + return; + /* BIOS Base set. */ + /* First, remove the old I/O. */ + ncr53c8xx_bios_disable(dev); + /* Then let's set the PCI regs. */ + ncr53c8xx_pci_bar[3].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + ncr53c8xx_pci_bar[3].addr &= 0xffff0001; + dev->BIOSBase = ncr53c8xx_pci_bar[3].addr & 0xffff0000; + /* Log the new base. */ + ncr53c8xx_log("NCR53c8xx: New BIOS base is %08X\n" , dev->BIOSBase); + /* We're done, so get out of the here. */ + if (ncr53c8xx_pci_bar[3].addr & 0x00000001) + ncr53c8xx_bios_set_addr(dev, dev->BIOSBase); + return; +#endif + + case 0x3C: + ncr53c8xx_pci_regs[addr] = val; + dev->irq = val; + return; + } +} + + +static void * +ncr53c8xx_init(const device_t *info) +{ + ncr53c8xx_t *dev; + + dev = malloc(sizeof(ncr53c8xx_t)); + memset(dev, 0x00, sizeof(ncr53c8xx_t)); + + dev->chip_rev = 0; + dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, ncr53c8xx_pci_read, ncr53c8xx_pci_write, dev); + + ncr53c8xx_pci_bar[0].addr_regs[0] = 1; + ncr53c8xx_pci_bar[1].addr_regs[0] = 0; + dev->chip = info->local; + ncr53c8xx_pci_regs[0x04] = 3; + + ncr53c8xx_mem_init(dev, 0x0fffff00); + ncr53c8xx_mem_disable(dev); + + dev->has_bios = device_get_config_int("bios"); + if (dev->has_bios) + rom_init(&dev->bios, NCR53C8XX_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + if (dev->chip >= CHIP_825) { + + if (dev->chip == CHIP_875) { + dev->chip_rev = 0x04; + dev->nvr_path = L"ncr53c875.nvr"; + } else { + dev->chip_rev = 0x26; + dev->nvr_path = L"ncr53c825a.nvr"; + } + ncr53c8xx_pci_bar[2].addr_regs[0] = 0; + ncr53c8xx_pci_bar[3].addr = 0xffff0000; + /* Need to make it align on a 16k boundary as that's this emulator's + memory mapping granularity. */ + ncr53c8xx_ram_init(dev, 0x0fffc000); + ncr53c8xx_ram_disable(dev); + +#ifdef USE_BIOS_BAR + if (dev->has_bios) + ncr53c8xx_bios_disable(dev); +#endif + } else { + if (dev->has_bios) + rom_init(&dev->bios, NCR53C8XX_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + dev->nvr_path = L"ncr53c810.nvr"; + } + +#ifdef USE_NVRAM + /* Load the serial EEPROM. */ + ncr53c8xx_eeprom(dev, 0); +#endif + + ncr53c8xx_soft_reset(dev); + + timer_add(&dev->timer, ncr53c8xx_callback, dev, 0); + + return(dev); +} + + +static void +ncr53c8xx_close(void *priv) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; + + if (dev) { + free(dev); + dev = NULL; + } +} + + +static const device_config_t ncr53c8xx_pci_config[] = { + { + "bios", "Enable BIOS", CONFIG_BINARY, "", 0 + }, + { + "", "", -1 + } +}; + + +const device_t ncr53c810_pci_device = +{ + "NCR 53c810 (SCSI)", + DEVICE_PCI, + 0x01, + ncr53c8xx_init, ncr53c8xx_close, NULL, + NULL, NULL, NULL, + ncr53c8xx_pci_config +}; + +const device_t ncr53c825a_pci_device = +{ + "NCR 53c825A (SCSI)", + DEVICE_PCI, + CHIP_825, + ncr53c8xx_init, ncr53c8xx_close, NULL, + NULL, NULL, NULL, + ncr53c8xx_pci_config +}; + +const device_t ncr53c875_pci_device = +{ + "NCR 53c875 (SCSI)", + DEVICE_PCI, + CHIP_875, + ncr53c8xx_init, ncr53c8xx_close, NULL, + NULL, NULL, NULL, + ncr53c8xx_pci_config +}; diff --git a/src/scsi/scsi_ncr53c8xx.c b/src/scsi/scsi_ncr53c8xx.c index def2cb6bc..72786a031 100644 --- a/src/scsi/scsi_ncr53c8xx.c +++ b/src/scsi/scsi_ncr53c8xx.c @@ -34,6 +34,7 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../dma.h" #include "../pic.h" #include "../mem.h" @@ -41,7 +42,6 @@ #include "../pci.h" #include "../device.h" #include "../nvr.h" -#include "../timer.h" #include "../plat.h" #include "scsi.h" #include "scsi_device.h" @@ -301,8 +301,7 @@ typedef struct { uint8_t regop; uint32_t adder; - int64_t timer_period; - int64_t timer_enabled; + pc_timer_t timer; } ncr53c8xx_t; @@ -363,7 +362,7 @@ ncr53c8xx_soft_reset(ncr53c8xx_t *dev) int i; ncr53c8xx_log("LSI Reset\n"); - dev->timer_period = dev->timer_enabled = 0; + timer_stop(&dev->timer); dev->carry = 0; @@ -566,7 +565,7 @@ ncr53c8xx_script_scsi_interrupt(ncr53c8xx_t *dev, int stat0, int stat1) if ((dev->sist0 & mask0) || (dev->sist1 & mask1)) { ncr53c8xx_log("NCR 810: IRQ-mandated stop\n"); dev->sstop = 1; - dev->timer_period = dev->timer_enabled = 0; + timer_stop(&dev->timer); } ncr53c8xx_update_irq(dev); } @@ -580,7 +579,7 @@ ncr53c8xx_script_dma_interrupt(ncr53c8xx_t *dev, int stat) dev->dstat |= stat; ncr53c8xx_update_irq(dev); dev->sstop = 1; - dev->timer_period = dev->timer_enabled = 0; + timer_stop(&dev->timer); } @@ -598,7 +597,7 @@ ncr53c8xx_bad_phase(ncr53c8xx_t *dev, int out, int new_phase) ncr53c8xx_log("Phase mismatch interrupt\n"); ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); dev->sstop = 1; - dev->timer_period = dev->timer_enabled = 0; + timer_stop(&dev->timer); ncr53c8xx_set_phase(dev, new_phase); } @@ -713,16 +712,22 @@ ncr53c8xx_add_msg_byte(ncr53c8xx_t *dev, uint8_t data) } +static void +ncr53c8xx_timer_on(ncr53c8xx_t *dev, scsi_device_t *sd, double p) +{ + if (p <= 0) + timer_on_auto(&dev->timer, ((double) sd->buffer_length) * 0.1); /* Fast SCSI: 10000000 bytes per second */ + else + timer_on_auto(&dev->timer, p); +} + + static int ncr53c8xx_do_command(ncr53c8xx_t *dev, uint8_t id) { scsi_device_t *sd; uint8_t buf[12]; - int64_t p; - - double period; - memset(buf, 0, 12); DMAPageRead(dev->dnad, buf, MIN(12, dev->dbc)); if (dev->dbc > 12) { @@ -767,22 +772,12 @@ ncr53c8xx_do_command(ncr53c8xx_t *dev, uint8_t id) if ((sd->phase == SCSI_PHASE_DATA_IN) && (sd->buffer_length > 0)) { ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]); ncr53c8xx_set_phase(dev, PHASE_DI); - p = scsi_device_get_callback(&scsi_devices[dev->current->tag]); - if (p <= 0LL) { - period = ((double) sd->buffer_length) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ - dev->timer_period += (int64_t) period; - } else - dev->timer_period += p; + ncr53c8xx_timer_on(dev, sd, scsi_device_get_callback(&scsi_devices[dev->current->tag])); return 1; } else if ((sd->phase == SCSI_PHASE_DATA_OUT) && (sd->buffer_length > 0)) { ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, buf[0]); ncr53c8xx_set_phase(dev, PHASE_DO); - p = scsi_device_get_callback(&scsi_devices[dev->current->tag]); - if (p <= 0LL) { - period = ((double) sd->buffer_length) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ - dev->timer_period += (int64_t) period; - } else - dev->timer_period += p; + ncr53c8xx_timer_on(dev, sd, scsi_device_get_callback(&scsi_devices[dev->current->tag])); return 1; } else { ncr53c8xx_command_complete(dev, sd->status); @@ -1038,7 +1033,7 @@ again: /* If we receive an empty opcode increment the DSP by 4 bytes instead of 8 and execute the next opcode at that location */ dev->dsp += 4; - dev->timer_period += (10LL * TIMER_USEC); + timer_on_auto(&dev->timer, 10.0); if (insn_processed < 100) goto again; else @@ -1108,7 +1103,7 @@ again: dev->dfifo = dev->dbc & 0xff; dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); - dev->timer_period += (40LL * TIMER_USEC); + timer_on_auto(&dev->timer, 40.0); if (dev->dcntl & NCR_DCNTL_SSM) ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SSI); @@ -1378,7 +1373,7 @@ again: ncr53c8xx_log("%02X: Unknown command\n", (uint8_t) (insn >> 30)); } - dev->timer_period += (40LL * TIMER_USEC); + timer_on_auto(&dev->timer, 40.0); ncr53c8xx_log("instructions processed %i\n", insn_processed); if (insn_processed > 10000 && !dev->waiting) { @@ -1416,8 +1411,7 @@ static void ncr53c8xx_execute_script(ncr53c8xx_t *dev) { dev->sstop = 0; - dev->timer_period = 40LL * TIMER_USEC; - dev->timer_enabled = 1; + timer_on_auto(&dev->timer, 40.0); } @@ -1426,19 +1420,17 @@ ncr53c8xx_callback(void *p) { ncr53c8xx_t *dev = (ncr53c8xx_t *) p; - dev->timer_period = 0; if (!dev->sstop) { if (dev->waiting) - dev->timer_period = 40LL * TIMER_USEC; + timer_on_auto(&dev->timer, 40.0); else ncr53c8xx_process_script(dev); } - if (dev->sstop) { - dev->timer_enabled = 0; - dev->timer_period = 0; - } else - dev->timer_enabled = 1; + if (dev->sstop) + timer_stop(&dev->timer); + else + timer_on_auto(&dev->timer, 10.0); } @@ -2638,6 +2630,7 @@ ncr53c8xx_init(const device_t *info) memset(dev, 0x00, sizeof(ncr53c8xx_t)); dev->chip_rev = 0; + // dev->pci_slot = pci_add_card(PCI_ADD_SCSI, ncr53c8xx_pci_read, ncr53c8xx_pci_write, dev); dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, ncr53c8xx_pci_read, ncr53c8xx_pci_write, dev); ncr53c8xx_pci_bar[0].addr_regs[0] = 1; @@ -2685,7 +2678,7 @@ ncr53c8xx_init(const device_t *info) ncr53c8xx_soft_reset(dev); - timer_add(ncr53c8xx_callback, &dev->timer_period, &dev->timer_enabled, dev); + timer_add(&dev->timer, ncr53c8xx_callback, dev, 0); return(dev); } diff --git a/src/scsi/scsi_x54x.c b/src/scsi/scsi_x54x.c index 2e45e5f45..027067aaa 100644 --- a/src/scsi/scsi_x54x.c +++ b/src/scsi/scsi_x54x.c @@ -11,7 +11,7 @@ * series of SCSI Host Adapters made by Mylex. * These controllers were designed for various buses. * - * Version: @(#)scsi_x54x.c 1.0.28 2018/11/02 + * Version: @(#)scsi_x54x.c 1.0.29 2019/05/16 * * Authors: TheCollector1995, * Miran Grca, @@ -30,6 +30,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../dma.h" #include "../pic.h" #include "../pci.h" @@ -38,7 +39,6 @@ #include "../rom.h" #include "../device.h" #include "../nvr.h" -#include "../timer.h" #include "../plat.h" #include "scsi.h" #include "scsi_device.h" @@ -51,9 +51,6 @@ static void x54x_cmd_callback(void *priv); -static volatile -x54x_t *x54x_dev; - #ifdef ENABLE_X54X_LOG int x54x_do_log = ENABLE_X54X_LOG; @@ -111,6 +108,8 @@ static void raise_irq(x54x_t *dev, int suppress, uint8_t Interrupt) { if (Interrupt & (INTR_MBIF | INTR_MBOA)) { + x54x_log("%s: RaiseInterrupt(): Interrupt=%02X %s\n", + dev->name, Interrupt, (! (dev->Interrupt & INTR_HACC)) ? "Immediate" : "Pending"); if (! (dev->Interrupt & INTR_HACC)) { dev->Interrupt |= Interrupt; /* Report now. */ } else { @@ -431,7 +430,7 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) x54x_log("BIOS Target ID %i has no device attached\n", cmd->id); ret = 0x80; } else { - if ((dev->type == SCSI_REMOVABLE_CDROM) && !x54x->cdrom_boot) { + if ((dev->type == SCSI_REMOVABLE_CDROM) && !(x54x->flags & X54X_CDROM_BOOT)) { x54x_log("BIOS Target ID %i is CD-ROM on unsupported BIOS\n", cmd->id); return(0x80); } else { @@ -566,9 +565,9 @@ x54x_cmd_done(x54x_t *dev, int suppress) static void -x54x_add_to_period(int TransferLength) +x54x_add_to_period(x54x_t *dev, int TransferLength) { - x54x_dev->temp_period += (int64_t) TransferLength; + dev->temp_period += (uint64_t) TransferLength; } @@ -580,7 +579,7 @@ x54x_mbi_setup(x54x_t *dev, uint32_t CCBPointer, CCBU *CmdBlock, req->CCBPointer = CCBPointer; memcpy(&(req->CmdBlock), CmdBlock, sizeof(CCB32)); - req->Is24bit = dev->Mbx24bit; + req->Is24bit = !!(dev->flags & X54X_MBX_24BIT); req->HostStatus = HostStatus; req->TargetStatus = TargetStatus; req->MailboxCompletionCode = mbcc; @@ -599,7 +598,7 @@ x54x_ccb(x54x_t *dev) DMAPageWrite(req->CCBPointer + 0x000D, &(req->MailboxCompletionCode), 1); DMAPageWrite(req->CCBPointer + 0x000E, &(req->HostStatus), 1); DMAPageWrite(req->CCBPointer + 0x000F, &(req->TargetStatus), 1); - x54x_add_to_period(3); + x54x_add_to_period(dev, 3); if (dev->MailboxOutInterrupts) dev->ToRaise = INTR_MBOA | INTR_ANY; @@ -620,7 +619,7 @@ x54x_mbi(x54x_t *dev) uint32_t MailboxCompletionCode = req->MailboxCompletionCode; uint32_t Incoming; - Incoming = dev->MailboxInAddr + (dev->MailboxInPosCur * (dev->Mbx24bit ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); + Incoming = dev->MailboxInAddr + (dev->MailboxInPosCur * ((dev->flags & X54X_MBX_24BIT) ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); if (MailboxCompletionCode != MBI_NOT_FOUND) { CmdBlock->common.HostStatus = HostStatus; @@ -630,19 +629,19 @@ x54x_mbi(x54x_t *dev) x54x_log("CCB statuses rewritten (pointer %08X)\n", req->CCBPointer); DMAPageWrite(req->CCBPointer + 0x000E, &(req->HostStatus), 1); DMAPageWrite(req->CCBPointer + 0x000F, &(req->TargetStatus), 1); - x54x_add_to_period(2); + x54x_add_to_period(dev, 2); } else { x54x_log("Mailbox not found!\n"); } x54x_log("Host Status 0x%02X, Target Status 0x%02X\n",HostStatus,TargetStatus); - if (dev->Mbx24bit) { + if (dev->flags & X54X_MBX_24BIT) { U32_TO_ADDR(CCBPointer, req->CCBPointer); x54x_log("Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", req->MailboxCompletionCode, CCBPointer); DMAPageWrite(Incoming, &(req->MailboxCompletionCode), 1); DMAPageWrite(Incoming + 1, (uint8_t *)&CCBPointer, 3); - x54x_add_to_period(4); + x54x_add_to_period(dev, 4); x54x_log("%i bytes of 24-bit mailbox written to: %08X\n", sizeof(Mailbox_t), Incoming); } else { x54x_log("Mailbox 32-bit: Status=0x%02X, CCB at 0x%04X\n", req->MailboxCompletionCode, CCBPointer); @@ -650,7 +649,7 @@ x54x_mbi(x54x_t *dev) DMAPageWrite(Incoming + 4, &(req->HostStatus), 1); DMAPageWrite(Incoming + 5, &(req->TargetStatus), 1); DMAPageWrite(Incoming + 7, &(req->MailboxCompletionCode), 1); - x54x_add_to_period(7); + x54x_add_to_period(dev, 7); x54x_log("%i bytes of 32-bit mailbox written to: %08X\n", sizeof(Mailbox32_t), Incoming); } @@ -665,13 +664,13 @@ x54x_mbi(x54x_t *dev) static void -x54x_rd_sge(int Is24bit, uint32_t Address, SGE32 *SG) +x54x_rd_sge(x54x_t *dev, int Is24bit, uint32_t Address, SGE32 *SG) { SGE SGE24; if (Is24bit) { DMAPageRead(Address, (uint8_t *)&SGE24, sizeof(SGE)); - x54x_add_to_period(sizeof(SGE)); + x54x_add_to_period(dev, sizeof(SGE)); /* Convert the 24-bit entries into 32-bit entries. */ x54x_log("Read S/G block: %06X, %06X\n", SGE24.Segment, SGE24.SegmentPointer); @@ -679,13 +678,13 @@ x54x_rd_sge(int Is24bit, uint32_t Address, SGE32 *SG) SG->SegmentPointer = ADDR_TO_U32(SGE24.SegmentPointer); } else { DMAPageRead(Address, (uint8_t *)SG, sizeof(SGE32)); - x54x_add_to_period(sizeof(SGE32)); + x54x_add_to_period(dev, sizeof(SGE32)); } } static int -x54x_get_length(Req_t *req, int Is24bit) +x54x_get_length(x54x_t *dev, Req_t *req, int Is24bit) { uint32_t DataPointer, DataLength; uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); @@ -710,7 +709,7 @@ x54x_get_length(Req_t *req, int Is24bit) if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { for (i = 0; i < DataLength; i += SGEntryLength) { - x54x_rd_sge(Is24bit, DataPointer + i, &SGBuffer); + x54x_rd_sge(dev, Is24bit, DataPointer + i, &SGBuffer); DataToTransfer += SGBuffer.Segment; } @@ -728,7 +727,7 @@ x54x_get_length(Req_t *req, int Is24bit) static void -x54x_set_residue(Req_t *req, int32_t TransferLength) +x54x_set_residue(x54x_t *dev, Req_t *req, int32_t TransferLength) { uint32_t Residue = 0; addr24 Residue24; @@ -746,11 +745,11 @@ x54x_set_residue(Req_t *req, int32_t TransferLength) if (req->Is24bit) { U32_TO_ADDR(Residue24, Residue); DMAPageWrite(req->CCBPointer + 0x0004, (uint8_t *)&Residue24, 3); - x54x_add_to_period(3); + x54x_add_to_period(dev, 3); x54x_log("24-bit Residual data length for reading: %d\n", Residue); } else { DMAPageWrite(req->CCBPointer + 0x0004, (uint8_t *)&Residue, 4); - x54x_add_to_period(4); + x54x_add_to_period(dev, 4); x54x_log("32-bit Residual data length for reading: %d\n", Residue); } } @@ -758,7 +757,7 @@ x54x_set_residue(Req_t *req, int32_t TransferLength) static void -x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) +x54x_buf_dma_transfer(x54x_t *dev, Req_t *req, int Is24bit, int TransferLength, int dir) { uint32_t DataPointer, DataLength; uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); @@ -788,7 +787,7 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) checking its length, so do this procedure for both no read/write commands. */ if ((DataLength > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { for (i = 0; i < DataLength; i += SGEntryLength) { - x54x_rd_sge(Is24bit, DataPointer + i, &SGBuffer); + x54x_rd_sge(dev, Is24bit, DataPointer + i, &SGBuffer); Address = SGBuffer.SegmentPointer; DataToTransfer = MIN((int) SGBuffer.Segment, BufLen); @@ -860,7 +859,7 @@ SenseBufferPointer(Req_t *req) static void -SenseBufferFree(Req_t *req, int Copy) +SenseBufferFree(x54x_t *dev, Req_t *req, int Copy) { uint8_t SenseLength = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); uint32_t SenseBufferAddress; @@ -881,7 +880,7 @@ SenseBufferFree(Req_t *req, int Copy) x54x_log("SenseBufferFree(): Writing %i bytes at %08X\n", SenseLength, SenseBufferAddress); DMAPageWrite(SenseBufferAddress, temp_sense, SenseLength); - x54x_add_to_period(SenseLength); + x54x_add_to_period(dev, SenseLength); x54x_log("Sense data written to buffer: %02X %02X %02X\n", temp_sense[2], temp_sense[12], temp_sense[13]); } @@ -899,7 +898,7 @@ x54x_scsi_cmd(x54x_t *dev) uint8_t temp_cdb[12]; uint32_t i, SenseBufferAddress; int target_data_len, target_cdb_len = 12; - int64_t p; + double p; scsi_device_t *sd; id = req->TargetID; @@ -909,7 +908,7 @@ x54x_scsi_cmd(x54x_t *dev) #endif target_cdb_len = 12; - target_data_len = x54x_get_length(req, bit24); + target_data_len = x54x_get_length(dev, req, bit24); if (!scsi_device_valid(sd)) fatal("SCSI target on %02i has disappeared\n", id); @@ -926,10 +925,10 @@ x54x_scsi_cmd(x54x_t *dev) if (req->CmdBlock.common.CdbLength <= target_cdb_len) { memcpy(temp_cdb, req->CmdBlock.common.Cdb, req->CmdBlock.common.CdbLength); - x54x_add_to_period(req->CmdBlock.common.CdbLength); + x54x_add_to_period(dev, req->CmdBlock.common.CdbLength); } else { memcpy(temp_cdb, req->CmdBlock.common.Cdb, target_cdb_len); - x54x_add_to_period(target_cdb_len); + x54x_add_to_period(dev, target_cdb_len); } dev->Residue = 0; @@ -949,24 +948,24 @@ x54x_scsi_cmd(x54x_t *dev) if ((sd->status != SCSI_STATUS_OK) && (sd->buffer_length > 0)) { SenseBufferAddress = SenseBufferPointer(req); DMAPageWrite(SenseBufferAddress, scsi_devices[id].sc->temp_buffer, sd->buffer_length); - x54x_add_to_period(sd->buffer_length); + x54x_add_to_period(dev, sd->buffer_length); } scsi_device_command_phase1(sd); } else { p = scsi_device_get_callback(sd); - if (p <= 0LL) - x54x_add_to_period(sd->buffer_length); + if (p <= 0.0) + x54x_add_to_period(dev, sd->buffer_length); else dev->media_period += p; - x54x_buf_dma_transfer(req, bit24, target_data_len, (phase == SCSI_PHASE_DATA_OUT)); + x54x_buf_dma_transfer(dev, req, bit24, target_data_len, (phase == SCSI_PHASE_DATA_OUT)); scsi_device_command_phase1(sd); - SenseBufferFree(req, (sd->status != SCSI_STATUS_OK)); + SenseBufferFree(dev, req, (sd->status != SCSI_STATUS_OK)); } } else - SenseBufferFree(req, (sd->status != SCSI_STATUS_OK)); + SenseBufferFree(dev, req, (sd->status != SCSI_STATUS_OK)); - x54x_set_residue(req, target_data_len); + x54x_set_residue(dev, req, target_data_len); x54x_log("Request complete\n"); @@ -982,12 +981,27 @@ x54x_scsi_cmd(x54x_t *dev) } +static void +x54x_mbo_free(x54x_t *dev) +{ + uint8_t CmdStatus = MBO_FREE; + uint32_t CodeOffset = 0; + + CodeOffset = (dev->flags & X54X_MBX_24BIT) ? 0 : 7; + + x54x_log("x54x_mbo_free(): Writing %i bytes at %08X\n", sizeof(CmdStatus), dev->Outgoing + CodeOffset); + DMAPageWrite(dev->Outgoing + CodeOffset, &CmdStatus, 1); +} + + static void x54x_notify(x54x_t *dev) { + x54x_mbo_free(dev); + if (dev->MailboxIsBIOS) x54x_ccb(dev); - else + else x54x_mbi(dev); } @@ -1001,12 +1015,12 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) /* Fetch data from the Command Control Block. */ DMAPageRead(CCBPointer, (uint8_t *)&req->CmdBlock, sizeof(CCB32)); - x54x_add_to_period(sizeof(CCB32)); + x54x_add_to_period(dev, sizeof(CCB32)); - req->Is24bit = dev->Mbx24bit; + req->Is24bit = !!(dev->flags & X54X_MBX_24BIT); req->CCBPointer = CCBPointer; - req->TargetID = dev->Mbx24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; - req->LUN = dev->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; + req->TargetID = req->Is24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; + req->LUN = req->Is24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; id = req->TargetID; sd = &scsi_devices[id]; @@ -1080,7 +1094,7 @@ x54x_req_abort(x54x_t *dev, uint32_t CCBPointer) /* Fetch data from the Command Control Block. */ DMAPageRead(CCBPointer, (uint8_t *)&CmdBlock, sizeof(CCB32)); - x54x_add_to_period(sizeof(CCB32)); + x54x_add_to_period(dev, sizeof(CCB32)); x54x_mbi_setup(dev, CCBPointer, &CmdBlock, 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); @@ -1106,10 +1120,10 @@ x54x_mbo(x54x_t *dev, Mailbox32_t *Mailbox32) Cur = dev->MailboxOutPosCur; } - if (dev->Mbx24bit) { + if (dev->flags & X54X_MBX_24BIT) { Outgoing = Addr + (Cur * sizeof(Mailbox_t)); DMAPageRead(Outgoing, (uint8_t *)&MailboxOut, sizeof(Mailbox_t)); - x54x_add_to_period(sizeof(Mailbox_t)); + x54x_add_to_period(dev, sizeof(Mailbox_t)); ccbp = *(uint32_t *) &MailboxOut; Mailbox32->CCBPointer = (ccbp >> 24) | ((ccbp >> 8) & 0xff00) | ((ccbp << 8) & 0xff0000); @@ -1118,7 +1132,7 @@ x54x_mbo(x54x_t *dev, Mailbox32_t *Mailbox32) Outgoing = Addr + (Cur * sizeof(Mailbox32_t)); DMAPageRead(Outgoing, (uint8_t *)Mailbox32, sizeof(Mailbox32_t)); - x54x_add_to_period(sizeof(Mailbox32_t)); + x54x_add_to_period(dev, sizeof(Mailbox32_t)); } return(Outgoing); @@ -1129,13 +1143,9 @@ uint8_t x54x_mbo_process(x54x_t *dev) { Mailbox32_t mb32; - uint32_t Outgoing; - uint8_t CmdStatus = MBO_FREE; - uint32_t CodeOffset = 0; - CodeOffset = dev->Mbx24bit ? 0 : 7; - - Outgoing = x54x_mbo(dev, &mb32); + dev->ToRaise = 0; + dev->Outgoing = x54x_mbo(dev, &mb32); if (mb32.u.out.ActionCode == MBO_START) { x54x_log("Start Mailbox Command\n"); @@ -1149,9 +1159,7 @@ x54x_mbo_process(x54x_t *dev) if ((mb32.u.out.ActionCode == MBO_START) || (!dev->MailboxIsBIOS && (mb32.u.out.ActionCode == MBO_ABORT))) { /* We got the mailbox, mark it as free in the guest. */ - x54x_log("x54x_do_mail(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); - DMAPageWrite(Outgoing + CodeOffset, &CmdStatus, 1); - x54x_add_to_period(1); + x54x_add_to_period(dev, 1); if (dev->ToRaise) raise_irq(dev, 0, dev->ToRaise); @@ -1213,7 +1221,7 @@ static void x54x_cmd_callback(void *priv) { double period; - x54x_t *dev = (x54x_t *) x54x_dev; + x54x_t *dev = (x54x_t *) priv; int mailboxes_present, bios_mailboxes_present; @@ -1222,11 +1230,12 @@ x54x_cmd_callback(void *priv) if (!mailboxes_present && !bios_mailboxes_present) { /* If we did not get anything, do nothing and wait 10 us. */ - dev->timer_period = 10LL * TIMER_USEC; + timer_on(&dev->timer, 10.0, 0); return; } - dev->temp_period = dev->media_period = 0LL; + dev->temp_period = 0; + dev->media_period = 0.0; if (!mailboxes_present) { /* Do only BIOS mailboxes. */ @@ -1244,9 +1253,9 @@ x54x_cmd_callback(void *priv) dev->callback_phase = (dev->callback_phase + 1) & 0x01; } - period = (1000000.0 / x54x_dev->ha_bps) * ((double) TIMER_USEC) * ((double) dev->temp_period); - dev->timer_period = dev->media_period + ((int64_t) period) + (40LL * TIMER_USEC); - x54x_log("Temporary period: %" PRId64 " us (%" PRIi64 " periods)\n", dev->timer_period, dev->temp_period); + period = (1000000.0 / dev->ha_bps) * ((double) dev->temp_period); + timer_on(&dev->timer, dev->media_period + period + 40.0, 0); + x54x_log("Temporary period: %lf us (%" PRIi64 " periods)\n", dev->timer.period, dev->temp_period); } @@ -1273,7 +1282,7 @@ x54x_in(uint16_t port, void *priv) break; case 2: - if (dev->int_geom_writable) + if (dev->flags & X54X_INT_GEOM_WRITABLE) ret = dev->Interrupt; else ret = dev->Interrupt & ~0x70; @@ -1290,7 +1299,7 @@ x54x_in(uint16_t port, void *priv) 6 Not checked 7 Not checked */ - if (dev->int_geom_writable) + if (dev->flags & X54X_INT_GEOM_WRITABLE) ret = dev->Geometry; else { switch(dev->Geometry) { @@ -1326,7 +1335,7 @@ x54x_inl(uint16_t port, void *priv) static uint8_t -x54x_read(uint32_t port, void *priv) +x54x_readb(uint32_t port, void *priv) { return(x54x_in(port & 3, priv)); } @@ -1352,8 +1361,6 @@ x54x_reset_poll(void *priv) x54x_t *dev = (x54x_t *)priv; dev->Status = STAT_INIT | STAT_IDLE; - - dev->ResetCB = 0LL; } @@ -1363,15 +1370,17 @@ x54x_reset(x54x_t *dev) int i; clear_irq(dev); - if (dev->int_geom_writable) + if (dev->flags & X54X_INT_GEOM_WRITABLE) dev->Geometry = 0x80; else dev->Geometry = 0x00; dev->callback_phase = 0; + timer_stop(&dev->timer); + timer_set_delay_u64(&dev->timer, (uint64_t) (dev->timer.period * ((double) TIMER_USEC))); dev->Command = 0xFF; dev->CmdParam = 0; dev->CmdParamLeft = 0; - dev->Mbx24bit = 1; + dev->flags |= X54X_MBX_24BIT; dev->MailboxInPosCur = 0; dev->MailboxOutInterrupts = 0; dev->PendingInterrupt = 0; @@ -1400,10 +1409,9 @@ x54x_reset_ctrl(x54x_t *dev, uint8_t Reset) if (Reset) { dev->Status = STAT_STST; - dev->ResetCB = X54X_RESET_DURATION_US * TIMER_USEC; - } else { + timer_set_delay_u64(&dev->ResetCB, X54X_RESET_DURATION_US * TIMER_USEC); + } else dev->Status = STAT_INIT | STAT_IDLE; - } } @@ -1431,7 +1439,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) reset = (val & CTRL_HRST); x54x_log("Reset completed = %x\n", reset); x54x_reset_ctrl(dev, reset); - x54x_log("Controller reset: "); + x54x_log("Controller reset\n"); break; } @@ -1443,7 +1451,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) if (val & CTRL_IRST) { clear_irq(dev); - x54x_log("Interrupt reset: "); + x54x_log("Interrupt reset\n"); } break; @@ -1451,7 +1459,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) /* Fast path for the mailbox execution command. */ if ((val == CMD_START_SCSI) && (dev->Command == 0xff)) { dev->MailboxReq++; - x54x_log("Start SCSI command: "); + x54x_log("Start SCSI command\n"); return; } if (dev->ven_fast_cmds) { @@ -1518,7 +1526,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) break; case CMD_MBINIT: /* mailbox initialization */ - dev->Mbx24bit = 1; + dev->flags |= X54X_MBX_24BIT; mbi = (MailboxInit_t *)dev->CmdBuf; @@ -1540,12 +1548,12 @@ x54x_out(uint16_t port, uint8_t val, void *priv) case CMD_BIOSCMD: /* execute BIOS */ cmd = (BIOSCMD *)dev->CmdBuf; - if (!dev->lba_bios) { + if (!(dev->flags & X54X_LBA_BIOS)) { /* 1640 uses LBA. */ cyl = ((cmd->u.chs.cyl & 0xff) << 8) | ((cmd->u.chs.cyl >> 8) & 0xff); cmd->u.chs.cyl = cyl; } - if (dev->lba_bios) { + if (dev->flags & X54X_LBA_BIOS) { /* 1640 uses LBA. */ x54x_log("BIOS LBA=%06lx (%lu)\n", lba32_blk(cmd), @@ -1558,7 +1566,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) cmd->u.chs.head, cmd->u.chs.sec); } - dev->DataBuf[0] = x54x_bios_command(dev, dev->max_id, cmd, (dev->lba_bios)?1:0); + dev->DataBuf[0] = x54x_bios_command(dev, dev->max_id, cmd, !!(dev->flags & X54X_LBA_BIOS)); x54x_log("BIOS Completion/Status Code %x\n", dev->DataBuf[0]); dev->DataReplyLeft = 1; break; @@ -1645,7 +1653,6 @@ x54x_out(uint16_t port, uint8_t val, void *priv) break; case CMD_RETSETUP: /* return Setup */ - { ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; memset(ReplyISI, 0x00, sizeof(ReplyInquireSetupInformation)); @@ -1655,14 +1662,12 @@ x54x_out(uint16_t port, uint8_t val, void *priv) ReplyISI->cMailbox = dev->MailboxCount; U32_TO_ADDR(ReplyISI->MailboxAddress, dev->MailboxOutAddr); - if (dev->get_ven_data) { + if (dev->get_ven_data) dev->get_ven_data(dev); - } dev->DataReplyLeft = dev->CmdBuf[0]; x54x_log("Return Setup Information: %d (length: %i)\n", dev->CmdBuf[0], sizeof(ReplyInquireSetupInformation)); - } - break; + break; case CMD_ECHO: /* ECHO data */ dev->DataBuf[0] = dev->CmdBuf[0]; @@ -1713,12 +1718,12 @@ x54x_out(uint16_t port, uint8_t val, void *priv) break; case 2: - if (dev->int_geom_writable) + if (dev->flags & X54X_INT_GEOM_WRITABLE) dev->Interrupt = val; break; case 3: - if (dev->int_geom_writable) + if (dev->flags & X54X_INT_GEOM_WRITABLE) dev->Geometry = val; break; } @@ -1740,7 +1745,7 @@ x54x_outl(uint16_t port, uint32_t val, void *priv) static void -x54x_write(uint32_t port, uint8_t val, void *priv) +x54x_writeb(uint32_t port, uint8_t val, void *priv) { x54x_out(port & 3, val, priv); } @@ -1760,17 +1765,24 @@ x54x_writel(uint32_t port, uint32_t val, void *priv) } -void -x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len) +static int +x54x_is_32bit(x54x_t *dev) { int bit32 = 0; if (dev->bus & DEVICE_PCI) bit32 = 1; - else if ((dev->bus & DEVICE_MCA) && dev->bit32) + else if ((dev->bus & DEVICE_MCA) && (dev->flags & X54X_32BIT)) bit32 = 1; - if (bit32) { + return bit32; +} + + +void +x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len) +{ + if (x54x_is_32bit(dev)) { x54x_log("x54x: [PCI] Setting I/O handler at %04X\n", base); io_sethandler(base, len, x54x_in, x54x_inw, x54x_inl, @@ -1787,16 +1799,9 @@ x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len) void x54x_io_remove(x54x_t *dev, uint32_t base, uint8_t len) { - int bit32 = 0; - - if (dev->bus & DEVICE_PCI) - bit32 = 1; - else if ((dev->bus & DEVICE_MCA) && dev->bit32) - bit32 = 1; - x54x_log("x54x: Removing I/O handler at %04X\n", base); - if (bit32) { + if (x54x_is_32bit(dev)) { io_removehandler(base, len, x54x_in, x54x_inw, x54x_inl, x54x_out, x54x_outw, x54x_outl, dev); @@ -1811,22 +1816,15 @@ x54x_io_remove(x54x_t *dev, uint32_t base, uint8_t len) void x54x_mem_init(x54x_t *dev, uint32_t addr) { - int bit32 = 0; - - if (dev->bus & DEVICE_PCI) - bit32 = 1; - else if ((dev->bus & DEVICE_MCA) && dev->bit32) - bit32 = 1; - - if (bit32) { + if (x54x_is_32bit(dev)) { mem_mapping_add(&dev->mmio_mapping, addr, 0x20, - x54x_read, x54x_readw, x54x_readl, - x54x_write, x54x_writew, x54x_writel, + x54x_readb, x54x_readw, x54x_readl, + x54x_writeb, x54x_writew, x54x_writel, NULL, MEM_MAPPING_EXTERNAL, dev); } else { mem_mapping_add(&dev->mmio_mapping, addr, 0x20, - x54x_read, x54x_readw, NULL, - x54x_write, x54x_writew, NULL, + x54x_readb, x54x_readw, NULL, + x54x_writeb, x54x_writew, NULL, NULL, MEM_MAPPING_EXTERNAL, dev); } } @@ -1867,12 +1865,11 @@ x54x_init(const device_t *info) dev->bus = info->flags; dev->callback_phase = 0; - - timer_add(x54x_reset_poll, &dev->ResetCB, &dev->ResetCB, dev); - dev->timer_period = 10LL * TIMER_USEC; - timer_add(x54x_cmd_callback, &dev->timer_period, TIMER_ALWAYS_ENABLED, dev); - - x54x_dev = dev; + + timer_add(&dev->ResetCB, x54x_reset_poll, dev, 0); + timer_add(&dev->timer, x54x_cmd_callback, dev, 1); + dev->timer.period = 10.0; + timer_set_delay_u64(&dev->timer, (uint64_t) (dev->timer.period * ((double) TIMER_USEC))); return(dev); } @@ -1884,10 +1881,11 @@ x54x_close(void *priv) x54x_t *dev = (x54x_t *)priv; if (dev) { - x54x_dev = NULL; - /* Tell the timer to terminate. */ - dev->timer_period = 0LL; + timer_stop(&dev->timer); + + /* Also terminate the reset callback timer. */ + timer_disable(&dev->ResetCB); dev->MailboxInit = dev->BIOSMailboxInit = 0; dev->MailboxCount = dev->BIOSMailboxCount = 0; @@ -1912,6 +1910,6 @@ x54x_device_reset(void *priv) x54x_reset_ctrl(dev, 1); - dev->ResetCB = 0LL; + timer_disable(&dev->ResetCB); dev->Status = STAT_IDLE | STAT_INIT; } diff --git a/src/scsi/scsi_x54x.h b/src/scsi/scsi_x54x.h index 267181ba3..840cfa0ff 100644 --- a/src/scsi/scsi_x54x.h +++ b/src/scsi/scsi_x54x.h @@ -362,111 +362,87 @@ typedef struct { } SGE; #pragma pack(pop) +#define X54X_CDROM_BOOT 1 +#define X54X_32BIT 2 +#define X54X_LBA_BIOS 4 +#define X54X_INT_GEOM_WRITABLE 8 +#define X54X_MBX_24BIT 16 + typedef struct { - int8_t type; /* type of device */ + /* 32 bytes */ + char vendor[16], /* name of device vendor */ + name[16]; /* name of device */ - char vendor[16]; /* name of device vendor */ - char name[16]; /* name of device */ + /* 24 bytes */ + int8_t type, /* type of device */ + IrqEnabled, Irq, + DmaChannel, + HostID; - int64_t timer_period, temp_period; - uint8_t callback_phase; - int64_t media_period; - double ha_bps; /* bytes per second */ - - int8_t Irq; - uint8_t IrqEnabled; - - int8_t DmaChannel; - int8_t HostID; - uint32_t Base; - uint8_t pos_regs[8]; /* MCA */ - - wchar_t *bios_path; /* path to BIOS image file */ - uint32_t rom_addr; /* address of BIOS ROM */ - uint16_t rom_ioaddr; /* offset in BIOS of I/O addr */ - uint16_t rom_shram; /* index to shared RAM */ - uint16_t rom_shramsz; /* size of shared RAM */ - uint16_t rom_fwhigh; /* offset in BIOS of ver ID */ - rom_t bios; /* BIOS memory descriptor */ - rom_t uppersck; /* BIOS memory descriptor */ - uint8_t *rom1; /* main BIOS image */ - uint8_t *rom2; /* SCSI-Select image */ - - wchar_t *nvr_path; /* path to NVR image file */ - uint8_t *nvr; /* EEPROM buffer */ - - int64_t ResetCB; + uint8_t callback_phase, sync, + parity, shram_mode, + Geometry, Control, + Command, CmdParam, + BusOnTime, BusOffTime, + ATBusSpeed, setup_info_len, + max_id, pci_slot; volatile uint8_t /* for multi-threading, keep */ - Status, /* these volatile */ - Interrupt; + Status, Interrupt, /* these volatile */ + MailboxIsBIOS, ToRaise, + flags; - Req_t Req; - uint8_t Geometry; - uint8_t Control; - uint8_t Command; - uint8_t CmdBuf[128]; - uint8_t CmdParam; - uint32_t CmdParamLeft; - uint8_t DataBuf[65536]; - uint16_t DataReply; - uint16_t DataReplyLeft; + /* 65928 bytes */ + uint8_t pos_regs[8], /* MCA */ + CmdBuf[128], + DataBuf[65536], + shadow_ram[128], + dma_buffer[128]; + + /* 16 bytes */ + char *fw_rev; /* The 4 bytes of the revision command information + 2 extra bytes for BusLogic */ + + uint8_t *rom1, /* main BIOS image */ + *rom2, /* SCSI-Select image */ + *nvr; /* EEPROM buffer */ + + /* 6 words = 12 bytes */ + uint16_t DataReply, DataReplyLeft, + rom_ioaddr, /* offset in BIOS of I/O addr */ + rom_shram, /* index to shared RAM */ + rom_shramsz, /* size of shared RAM */ + rom_fwhigh; /* offset in BIOS of ver ID */ + + /* 16 + 20 + 52 = 88 bytes */ + volatile int + MailboxOutInterrupts, + PendingInterrupt, Lock; + + uint32_t Base, rom_addr, /* address of BIOS ROM */ + CmdParamLeft, Outgoing, + pad32; volatile uint32_t - MailboxInit, - MailboxCount, - MailboxOutAddr, - MailboxOutPosCur, - MailboxInAddr, - MailboxInPosCur, - MailboxReq; - - volatile int - Mbx24bit, - MailboxOutInterrupts; - - volatile int - PendingInterrupt, - Lock; - - uint8_t shadow_ram[128]; - - volatile uint8_t - MailboxIsBIOS, - ToRaise; - - uint8_t shram_mode; - - uint8_t sync; - uint8_t parity; - - uint8_t dma_buffer[128]; - - volatile - uint32_t BIOSMailboxInit, - BIOSMailboxCount, - BIOSMailboxOutAddr, - BIOSMailboxOutPosCur, + MailboxInit, MailboxCount, + MailboxOutAddr, MailboxOutPosCur, + MailboxInAddr, MailboxInPosCur, + MailboxReq, + BIOSMailboxInit, BIOSMailboxCount, + BIOSMailboxOutAddr, BIOSMailboxOutPosCur, BIOSMailboxReq, - Residue; + Residue, bus; /* Basically a copy of device flags */ - uint8_t BusOnTime, - BusOffTime, - ATBusSpeed; + /* 8 bytes */ + uint64_t temp_period; - char *fw_rev; /* The 4 bytes of the revision command information + 2 extra bytes for BusLogic */ - uint16_t bus; /* Basically a copy of device flags */ - uint8_t setup_info_len; - uint8_t max_id; - uint8_t pci_slot; - uint8_t bit32; - uint8_t lba_bios; + /* 16 bytes */ + double media_period, ha_bps; /* bytes per second */ - mem_mapping_t mmio_mapping; - - uint8_t int_geom_writable; - uint8_t cdrom_boot; + /* 8 bytes */ + wchar_t *bios_path, /* path to BIOS image file */ + *nvr_path; /* path to NVR image file */ + /* 56 bytes */ /* Pointer to a structure of vendor-specific data that only the vendor-specific code can understand */ void *ven_data; @@ -496,6 +472,15 @@ typedef struct { uint8_t (*interrupt_type)(void *p); /* Pointer to a function that resets vendor-specific data */ void (*ven_reset)(void *p); + + rom_t bios, /* BIOS memory descriptor */ + uppersck; /* BIOS memory descriptor */ + + mem_mapping_t mmio_mapping; + + pc_timer_t timer, ResetCB; + + Req_t Req; } x54x_t; diff --git a/src/serial.c b/src/serial.c index 5756c6d97..76192141c 100644 --- a/src/serial.c +++ b/src/serial.c @@ -7,13 +7,13 @@ #define HAVE_STDARG_H #include "86box.h" #include "device.h" +#include "timer.h" #include "machine/machine.h" #include "io.h" #include "pic.h" #include "mem.h" #include "rom.h" #include "serial.h" -#include "timer.h" #include "mouse.h" @@ -64,11 +64,12 @@ serial_reset_port(serial_t *dev) void serial_transmit_period(serial_t *dev) { - double ddlab, byte_period, bits, dusec; + double ddlab, byte_period, bits; ddlab = (double) dev->dlab; /* Bit period based on DLAB. */ - byte_period = (16000000.0 * ddlab) / 1846200.0; + /* correct: 833.333333... */ + byte_period = (16000000.0 * ddlab) / 1843200.0; /* Data bits according to LCR 1,0. */ bits = (double) ((dev->lcr & 0x03) + 5); /* Stop bits. */ @@ -80,10 +81,8 @@ serial_transmit_period(serial_t *dev) if (dev->lcr & 0x08) bits += 1.0; byte_period *= bits; - dusec = (double) TIMER_USEC; - byte_period *= dusec; - dev->transmit_period = (int64_t) byte_period; + dev->transmit_period = byte_period; } @@ -112,8 +111,8 @@ serial_update_ints(serial_t *dev) dev->iir = 0; } - if (stat && ((dev->mctrl & 8) || PCJR)) { - if (dev->type >= SERIAL_NS16540) + if (stat && ((dev->mctrl & 8) || (dev->type == SERIAL_8250_PCJR))) { + if (dev->type >= SERIAL_NS16450) picintlevel(1 << dev->irq); else picint(1 << dev->irq); @@ -133,7 +132,7 @@ serial_write_fifo(serial_t *dev, uint8_t dat) dev->rcvr_fifo_pos %= dev->rcvr_fifo_len; dev->lsr &= 0xfe; dev->lsr |= (!dev->rcvr_fifo_pos); - dev->int_status &= SERIAL_INT_RECEIVE; + dev->int_status &= ~SERIAL_INT_RECEIVE; if (!dev->rcvr_fifo_pos) { dev->int_status |= SERIAL_INT_RECEIVE; serial_update_ints(dev); @@ -166,17 +165,27 @@ serial_transmit_timer(void *priv) if (dev->fifo_enabled) { serial_transmit(dev, dev->xmit_fifo[dev->xmit_fifo_pos++]); if (dev->xmit_fifo_pos == 16) { - dev->transmit_delay = 0LL; dev->xmit_fifo_pos = 0; /* Mark both FIFO and shift register as empty. */ dev->lsr |= 0x40; + dev->transmit_enabled = 0; } else - dev->transmit_delay += dev->transmit_period; + timer_advance_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC)); } else { serial_transmit(dev, dev->thr); - dev->transmit_delay = 0LL; /* Mark both THR and shift register as empty. */ dev->lsr |= 0x40; + dev->transmit_enabled = 0; + } +} + + +static void +serial_update_speed(serial_t *dev) +{ + if (dev->transmit_enabled) { + timer_disable(&dev->transmit_timer); + timer_set_delay_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC)); } } @@ -189,11 +198,14 @@ serial_write(uint16_t addr, uint8_t val, void *p) serial_log("UART: Write %02X to port %02X\n", val, addr); + sub_cycles(ISA_CYCLES(8)); + switch (addr & 7) { case 0: if (dev->lcr & 0x80) { dev->dlab = (dev->dlab & 0xff00) | val; serial_transmit_period(dev); + serial_update_speed(dev); return; } @@ -211,7 +223,9 @@ serial_write(uint16_t addr, uint8_t val, void *p) serial_update_ints(dev); } else { /* FIFO full, begin transmitting. */ - dev->transmit_delay = dev->transmit_period; + timer_disable(&dev->transmit_timer); + timer_set_delay_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC)); + dev->transmit_enabled = 1; dev->lsr &= 0xbf; /* Update interrupts. */ dev->lsr |= 0x20; @@ -221,7 +235,9 @@ serial_write(uint16_t addr, uint8_t val, void *p) } else { /* Non-FIFO mode. */ /* Begin transmitting. */ - dev->transmit_delay = dev->transmit_period; + timer_disable(&dev->transmit_timer); + timer_set_delay_u64(&dev->transmit_timer, (uint64_t) (dev->transmit_period * (double)TIMER_USEC)); + dev->transmit_enabled = 1; dev->thr = val; /* Clear bit 6 because shift register is full. */ dev->lsr &= 0xbf; @@ -236,6 +252,7 @@ serial_write(uint16_t addr, uint8_t val, void *p) if (dev->lcr & 0x80) { dev->dlab = (dev->dlab & 0x00ff) | (val << 8); serial_transmit_period(dev); + serial_update_speed(dev); return; } dev->ier = val & 0xf; @@ -247,7 +264,7 @@ serial_write(uint16_t addr, uint8_t val, void *p) dev->fifo_enabled = val & 0x01; if (!dev->fifo_enabled) { memset(dev->rcvr_fifo, 0, 14); - memset(dev->xmit_fifo, 0, 14); + memset(dev->xmit_fifo, 0, 16); dev->rcvr_fifo_pos = dev->xmit_fifo_pos = 0; dev->rcvr_fifo_len = 1; break; @@ -257,7 +274,7 @@ serial_write(uint16_t addr, uint8_t val, void *p) dev->rcvr_fifo_pos = 0; } if (val & 0x04) { - memset(dev->xmit_fifo, 0, 14); + memset(dev->xmit_fifo, 0, 16); dev->xmit_fifo_pos = 0; } switch ((val >> 6) & 0x03) { @@ -279,8 +296,10 @@ serial_write(uint16_t addr, uint8_t val, void *p) case 3: old = dev->lcr; dev->lcr = val; - if ((old ^ val) & 0x0f) + if ((old ^ val) & 0x0f) { serial_transmit_period(dev); + serial_update_speed(dev); + } break; case 4: if ((val & 2) && !(dev->mctrl & 2)) { @@ -303,6 +322,8 @@ serial_write(uint16_t addr, uint8_t val, void *p) new_msr |= 0x04; dev->msr = new_msr; + + dev->xmit_fifo_pos = dev->rcvr_fifo_pos = 0; } break; case 5: @@ -322,7 +343,8 @@ serial_write(uint16_t addr, uint8_t val, void *p) serial_update_ints(dev); break; case 7: - dev->scratch = val; + if (dev->type >= SERIAL_NS16450) + dev->scratch = val; break; } } @@ -334,6 +356,8 @@ serial_read(uint16_t addr, void *p) serial_t *dev = (serial_t *)p; uint8_t ret = 0; + sub_cycles(ISA_CYCLES(8)); + switch (addr & 7) { case 0: if (dev->lcr & 0x80) { @@ -343,12 +367,22 @@ serial_read(uint16_t addr, void *p) if ((dev->type >= SERIAL_NS16550) && dev->fifo_enabled) { /* FIFO mode. */ - ret = dev->rcvr_fifo[dev->rcvr_fifo_pos++]; - dev->rcvr_fifo_pos %= dev->rcvr_fifo_len; - if (!dev->rcvr_fifo_pos) { - dev->lsr &= 0xfe; - dev->int_status &= ~SERIAL_INT_RECEIVE; - serial_update_ints(dev); + if (dev->mctrl & 0x10) { + ret = dev->xmit_fifo[dev->xmit_fifo_pos++]; + dev->xmit_fifo_pos %= 16; + if (!dev->xmit_fifo_pos) { + dev->lsr &= 0xfe; + dev->int_status &= ~SERIAL_INT_RECEIVE; + serial_update_ints(dev); + } + } else { + ret = dev->rcvr_fifo[dev->rcvr_fifo_pos++]; + dev->rcvr_fifo_pos %= dev->rcvr_fifo_len; + if (!dev->rcvr_fifo_pos) { + dev->lsr &= 0xfe; + dev->int_status &= ~SERIAL_INT_RECEIVE; + serial_update_ints(dev); + } } } else { ret = dev->dat; @@ -454,6 +488,15 @@ serial_attach(int port, } +static void +serial_speed_changed(void *priv) +{ + serial_t *dev = (serial_t *) priv; + + serial_update_speed(dev); +} + + static void serial_close(void *priv) { @@ -489,8 +532,7 @@ serial_init(const device_t *info) dev->dlab = 96; dev->fcr = 0x06; serial_transmit_period(dev); - dev->transmit_delay = 0LL; - timer_add(serial_transmit_timer, &dev->transmit_delay, &dev->transmit_delay, dev); + timer_add(&dev->transmit_timer, serial_transmit_timer, dev, 0); } next_inst++; @@ -499,15 +541,18 @@ serial_init(const device_t *info) } +void +serial_set_next_inst(int ni) +{ + next_inst = ni; +} + + void serial_standalone_init(void) { if (next_inst == 0) { - if (PCJR) - device_add(&i8250_pcjr_device); - else { - device_add_inst(&i8250_device, 1); - device_add_inst(&i8250_device, 2); - } + device_add_inst(&i8250_device, 1); + device_add_inst(&i8250_device, 2); } else if (next_inst == 1) device_add_inst(&i8250_device, 2); }; @@ -518,25 +563,25 @@ const device_t i8250_device = { 0, SERIAL_8250, serial_init, serial_close, NULL, - NULL, NULL, NULL, + NULL, serial_speed_changed, NULL, NULL }; const device_t i8250_pcjr_device = { "Intel 8250(-compatible) UART for PCjr", DEVICE_PCJR, - SERIAL_8250, + SERIAL_8250_PCJR, serial_init, serial_close, NULL, - NULL, NULL, NULL, + NULL, serial_speed_changed, NULL, NULL }; -const device_t ns16540_device = { - "National Semiconductor NS16540(-compatible) UART", +const device_t ns16450_device = { + "National Semiconductor NS16450(-compatible) UART", 0, - SERIAL_NS16540, + SERIAL_NS16450, serial_init, serial_close, NULL, - NULL, NULL, NULL, + NULL, serial_speed_changed, NULL, NULL }; @@ -545,6 +590,6 @@ const device_t ns16550_device = { 0, SERIAL_NS16550, serial_init, serial_close, NULL, - NULL, NULL, NULL, + NULL, serial_speed_changed, NULL, NULL }; diff --git a/src/serial.h b/src/serial.h index 6293af003..d5e29db07 100644 --- a/src/serial.h +++ b/src/serial.h @@ -8,18 +8,19 @@ * * Definitions for the SERIAL card. * - * Version: @(#)serial.h 1.0.9 2018/11/12 + * Version: @(#)serial.h 1.0.10 2019/03/24 * * Author: Fred N. van Kempen, - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. */ #ifndef EMU_SERIAL_H # define EMU_SERIAL_H -#define SERIAL_8250 0 -#define SERIAL_NS16540 1 -#define SERIAL_NS16550 2 +#define SERIAL_8250 0 +#define SERIAL_8250_PCJR 1 +#define SERIAL_NS16450 2 +#define SERIAL_NS16550 3 /* Default settings for the standard ports. */ #define SERIAL1_ADDR 0x03f8 @@ -34,22 +35,18 @@ struct serial_s; typedef struct serial_s { uint8_t lsr, thr, mctrl, rcr, - iir, ier, lcr, msr; - uint16_t dlab; - uint8_t dat; - uint8_t int_status; - uint8_t scratch; - uint8_t fcr; + iir, ier, lcr, msr, + dat, int_status, scratch, fcr, + irq, type, inst, transmit_enabled, + fifo_enabled, rcvr_fifo_len, pad, pad0; - uint8_t irq, type, - inst; - uint16_t base_address; + uint16_t dlab, base_address; - uint8_t fifo_enabled, rcvr_fifo_len; uint8_t rcvr_fifo_pos, rcvr_fifo[14]; uint8_t xmit_fifo_pos, xmit_fifo[16]; - int64_t transmit_delay, transmit_period; + pc_timer_t transmit_timer; + double transmit_period; struct serial_device_s *sd; } serial_t; @@ -72,11 +69,12 @@ extern void serial_set_type(serial_t *dev, int type); extern void serial_setup(serial_t *dev, uint16_t addr, int irq); extern void serial_clear_fifo(serial_t *dev); extern void serial_write_fifo(serial_t *dev, uint8_t dat); +extern void serial_set_next_inst(int ni); extern void serial_standalone_init(void); extern const device_t i8250_device; extern const device_t i8250_pcjr_device; -extern const device_t ns16540_device; +extern const device_t ns16450_device; extern const device_t ns16550_device; diff --git a/src/sio.h b/src/sio.h index 4b8e84f01..76f3a08f1 100644 --- a/src/sio.h +++ b/src/sio.h @@ -8,7 +8,7 @@ * * Definitions for the Super I/O chips. * - * Version: @(#)sio.h 1.0.4 2018/11/05 + * Version: @(#)sio.h 1.0.6 2019/05/17 * * Author: Fred N. van Kempen, * Copyright 2017 Fred N. van Kempen. @@ -17,17 +17,20 @@ # define EMU_SIO_H +extern const device_t acc3221_device; extern const device_t fdc37c663_device; extern const device_t fdc37c665_device; extern const device_t fdc37c666_device; extern const device_t fdc37c669_device; extern const device_t fdc37c932fr_device; +extern const device_t fdc37c932qf_device; extern const device_t fdc37c935_device; extern const device_t pc87306_device; extern const device_t sio_detect_device; extern const device_t um8669f_device; extern const device_t w83877f_device; extern const device_t w83877f_president_device; +extern const device_t w83877tf_device; #endif /*EMU_SIO_H*/ diff --git a/src/sio_acc3221.c b/src/sio_acc3221.c new file mode 100644 index 000000000..18f759f17 --- /dev/null +++ b/src/sio_acc3221.c @@ -0,0 +1,485 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the ACC 3221-SP Super I/O Chip. + * + * Version: @(#)sio_acc3221.c 1.0.0 2019/04/05 + * + * Authors: Sarah Walker, + * + * Copyright 2019 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "io.h" +#include "timer.h" +#include "device.h" +#include "pci.h" +#include "lpt.h" +#include "serial.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sio.h" + +typedef struct acc3221_t +{ + int reg_idx; + uint8_t regs[256]; + fdc_t * fdc; + serial_t * uart[2]; +} acc3221_t; + + +/* Configuration Register Index, BE (R/W): + Bit Function + 7 PIRQ 5 polarity. + 1 = active high, default + 0 = active low + 6 PIRQ 7 polarity. + 1 = active high, default + 0 = active low + 5 Primary Parallel Port Extended Mode + 0 = Compatible mode, default + 1 = Extended/Bidirectional mode. + 4 Primary Parallel Port Disable + 1 = Disable, 0 = Enable + Power Up Default is set by pin 120 + (3221-DP)/pin 96 (3221-SP) + 3 Primary Parallel Port Power Down + 1 = Power Down, default = 0 + 2** Secondary Parallel Port Extended + Mode + 0 = Compatible mode, default + 1 = Extended/Bidirectional mode. + 1** Secondary Parallel Port Disable + 1 = Disable, 0 = Enable + Power Up Default is set by pin 77 + (3221-DP) + 0** Secondary Parallel Port Power Down + 1 = Power Down + 0 = Enable, default + Note: Power Up not applicable to 3221-EP. */ +#define REG_BE_LPT1_DISABLE (3 << 3) +#define REG_BE_LPT2_DISABLE (3 << 0) /* 3221-DP/EP only */ + +/* Configuration Register Index, BF (R/W): + Bit Function + 7-0 The 8 most significant address bits of + the primary parallel port (A9-2) + Default 9E (LPT2, at 278-27B) */ + +/* Configuration Register Index, DA (R/W)**: + Bit Function + 7-0 The 8 most significant address bits of + the secondary parallel port (A9-2) + Default DE (LPT1, at 378-37B) */ + +/* Configuration Register Index, DB (R/W): + Bit Function + 7 SIRQ4 polarity. + 1 = active high; default + 0 = active low + 6 SIRQ3 polarity. + 1 = active high; default + 0 = active low + 5 SXTAL clock off. 1 = SCLK off, + 0 = SCKL on, default + 4 Primary serial port disable + 1 = Disable, 0 = Enable + Power Up default is set by pin 116 + (3221-DP)/pin 93 (3221-SP) + 3 Primary serial port power down + 1 = Power down, 0 = Enable + Power Up default is set by pin 116 + (3221-DP)/pin 93 (3221-SP) + 2 Reserved + 1 Secondary serial port disable + 1 = Disable, 0 = Enable + Power Up default is set by pin 121 + (3221-DP)/pin 97 (3221-SP) + 0 Secondary serial port power down + 1 = Power down, 0 = Enable + Power Up default is set by pin 121 + (3221-DP)/pin 97 (3221-SP) + Note: Power Up not applicable to 3221-EP. */ +#define REG_DB_SERIAL1_DISABLE (3 << 3) +#define REG_DB_SERIAL2_DISABLE (3 << 0) + +/* Configuration Register Index, DC (R/W): + Bit Function + 7-1 The MSB of the Primary Serial Port + Address (bits A9-3). + Default = 7F (COM1, at 3F8-3FF). + 0 When this bit is set to 1, bit A2 of + primary parallel port is decoded. + Default is 0. */ + +/* Configuration Register Index, DD (R/W): + Bit Function + 7-1 The MSB of the Secondary Serial Port + Address (bits A9-3). + Default = 5F (COM2, at 2F8-2FF). + 0** When this bit is set to 1, bit A2 of + secondary parallel port is decoded. + Default is 0. */ + +/* Configuration Register Index, DE (R/W): + Bit Function + 7-6 SIRQ3 source + b7 b6 + 0 0 Disabled, tri-stated + 0 1 Disabled, tri-stated** + 1 0 Primary serial port + 1 1 Secondary serial port, + default + 5-4 SIRQ4 source + b5 b4 + 0 0 Disabled, tri-stated + 0 1 Disabled, tri-stated** + 1 0 Primary serial port, + default + 1 1 Secondary serial port + + 3-2** PIRQ7 source + b3 b2 + 0 0 Diabled, tri-stated, + default + 0 1 Primary serial port + 1 0 Primary parallel port + 1 1 Secondary parallel + port + Note: Bits 3-2 are reserved in 3221-SP. + + 1-0 PIRQ5 source + b1 b0 + 0 0 Disabled, tri-stated + 0 1 Secondary serial port + 1 0 Primary parallel port, + default + 1 1 Secondary parallel + port** */ +#define REG_DE_SIRQ3_SOURCE (3 << 6) +#define REG_DE_SIRQ3_SERIAL1 (1 << 6) +#define REG_DE_SIRQ3_SERIAL2 (3 << 6) +#define REG_DE_SIRQ4_SOURCE (3 << 4) +#define REG_DE_SIRQ4_SERIAL1 (1 << 4) +#define REG_DE_SIRQ4_SERIAL2 (3 << 4) +#define REG_DE_PIRQ7_SOURCE (3 << 2) +#define REG_DE_PIRQ7_SERIAL1 (1 << 2) +#define REG_DE_PIRQ7_LPT1 (2 << 2) +#define REG_DE_PIRQ7_LPT2 (3 << 2) +#define REG_DE_PIRQ5_SOURCE (3 << 0) +#define REG_DE_PIRQ5_SERIAL2 (1 << 0) +#define REG_DE_PIRQ5_LPT1 (2 << 0) +#define REG_DE_PIRQ5_LPT2 (3 << 0) + +/* Configuration Register Index, DF (R/W)**: + Bit Function + 7-6 Reserved + 5 RTC interface disable + 1 = /RTCCS disabled + 0 = /RTCCS enabled, default + 4 Disable Modem Select + 1 = Moden CS disabled, default + 0 = Modem CS enabled + + 3-2 + b3 b2 + 1 1 Reserved + 1 0 Modem port address + = 3E8-3EF (default) + 0 1 Modem port address: + 2F8-2FF + 0 0 Modem port address: + 3F8-3FF + + 1-0 + b1 b0 + 1 1 Reserved + 1 0 Mode 2, EISA Mode + 0 1 Mode 1, AT BUS, + 0 0 Mode 0, Two parallel + ports, default */ + +/* Configuration Register Index, FA (R/W)**: + Bit Function + 7 General purpose I/O register, Bit 7 + 6 General purpose I/O register, Bit 6 + 5 General purpose I/O register, Bit 5 + 4 General purpose I/O register, Bit 4 + 3 General purpose I/O register, Bit 3 + 2 General purpose I/O register, Bit 2 + 1 General purpose I/O register, Bit 1 + 0 General purpose I/O register, Bit 0 */ + +/* Configuration Register Index, FB (R/W)**: + Bit Function + 7 Reserved + 6** 0/2 EXG (Read Only) + In mode 1 and mode 2 + operation, when the third + floppy drive is installed, pin + EXTFDD should be pulled + high to enable the third floppy + drive or be pulled low to + disable the third floppy drive. + 1 = Third floppy drive enabled + 0 = Third floppy drive disabled + 5** EXTFDD (Read Only) + In mode 1 and mode 2 + operation, when the third + floppy drive is installed and + pin 0/2 EXG is pulled high, + the third floppy drive becomes + the bootable drive (drive 0). + When pi 0/2 EXG is pulled low, + the third floppy drive acts as + drive 2. + 1 = Third floppy drive as drive 0 (bootable) + 0 = Third floppy drive as drive 2 + 4** MS + In mode 1 and mode 2, t his bit is to + control the output pin MS to support a + special 3 1/2", 1.2M drive. When this + bit is set to high (1), the MS pin sends + a low signal. When this bit is set to + low (0), the MS pin sends a high + signal to support a 3 1/2", 1.2M drive. + 3 FDC, Clock disable + 0 = enable, default + 1 = disable + 2 Reserved + 1 FDC disable + 0 = enable, 1= disable + Power Upd efault set by pin 117 (3221- + DP)/pin 94 (3221-SP) + 0 FDC address + 0 = Primary, default + 1 = Secondary + Note: Bits 6-4 are reserved in 3221-SP. */ +#define REG_FB_FDC_DISABLE (1 << 1) + +/* Configuration Register Index, FB (R/W)**: + Bit Function + 7** Disable general chip select 1 + 1 = disable, default + 0 = enable + 6** Disable general chip select 2 + 1 = disable, default + 0 = enable + 5** Enable SA2 decoding for general chip + select 1 + 1 = enable + 0 = disable, default + 4** Enable SA2 decoding for general chip + select 2 + 1 = enable + 0 = disable, default + 3 Reserved + 2 IDE XT selected + 0 = IDE AT interface, default + 1 = IDE XT interface + 1 IDE disable, 1 = IDE disable + 0 = IDE enable + Power Up default set by pin 13 (3221- + DP)/pin 13 (3221-SP) + 0 Secondary IDE + 1 = secondary + 0 = primary, default + Note: Bits 6-4 are reserved in 3221-SP. */ +#define REG_FE_IDE_DISABLE (1 << 1) + + +static void +acc3221_lpt_handle(acc3221_t *dev) +{ + lpt1_remove(); + + if (!(dev->regs[0xbe] & REG_BE_LPT1_DISABLE)) + lpt1_init(dev->regs[0xbf] << 2); +} + + +static void +acc3221_serial1_handler(acc3221_t *dev) +{ + uint16_t com_addr = 0; + + serial_remove(dev->uart[0]); + + if (!(dev->regs[0xdb] & REG_DB_SERIAL1_DISABLE)) { + com_addr = ((dev->regs[0xdc] & 0xfe) << 2); + + if ((dev->regs[0xde] & REG_DE_SIRQ3_SOURCE) == REG_DE_SIRQ3_SERIAL1) + serial_setup(dev->uart[0], com_addr, 3); + else if ((dev->regs[0xde] & REG_DE_SIRQ4_SOURCE) == REG_DE_SIRQ4_SERIAL1) + serial_setup(dev->uart[0], com_addr, 4); + } +} + + +static void +acc3221_serial2_handler(acc3221_t *dev) +{ + uint16_t com_addr = 0; + + serial_remove(dev->uart[1]); + + if (!(dev->regs[0xdb] & REG_DB_SERIAL2_DISABLE)) { + com_addr = ((dev->regs[0xdd] & 0xfe) << 2); + + if ((dev->regs[0xde] & REG_DE_SIRQ3_SOURCE) == REG_DE_SIRQ3_SERIAL2) + serial_setup(dev->uart[1], com_addr, 3); + else if ((dev->regs[0xde] & REG_DE_SIRQ4_SOURCE) == REG_DE_SIRQ4_SERIAL2) + serial_setup(dev->uart[1], com_addr, 4); + else if ((dev->regs[0xde] & REG_DE_PIRQ5_SOURCE) == REG_DE_PIRQ5_SERIAL2) + serial_setup(dev->uart[1], com_addr, 5); + } +} + + +static void +acc3221_write(uint16_t addr, uint8_t val, void *p) +{ + acc3221_t *dev = (acc3221_t *)p; + uint8_t old; + + if (!(addr & 1)) + dev->reg_idx = val; + else { + old = dev->regs[dev->reg_idx]; + dev->regs[dev->reg_idx] = val; + + switch (dev->reg_idx) { + case 0xbe: + if ((old ^ val) & REG_BE_LPT1_DISABLE) + acc3221_lpt_handle(dev); + break; + + case 0xbf: + if (old != val) + acc3221_lpt_handle(dev); + break; + + case 0xdb: + if ((old ^ val) & REG_DB_SERIAL2_DISABLE) + acc3221_serial2_handler(dev); + if ((old ^ val) & REG_DB_SERIAL1_DISABLE) + acc3221_serial1_handler(dev); + break; + + case 0xdc: + if (old != val) + acc3221_serial1_handler(dev); + break; + + case 0xdd: + if (old != val) + acc3221_serial2_handler(dev); + break; + + case 0xde: + if ((old ^ val) & (REG_DE_SIRQ3_SOURCE | REG_DE_SIRQ4_SOURCE)) { + acc3221_serial2_handler(dev); + acc3221_serial1_handler(dev); + } + break; + + case 0xfb: + if ((old ^ val) & REG_FB_FDC_DISABLE) { + fdc_remove(dev->fdc); + if (!(dev->regs[0xfb] & REG_FB_FDC_DISABLE)) + fdc_set_base(dev->fdc, 0x03f0); + } + break; + + case 0xfe: + if ((old ^ val) & REG_FE_IDE_DISABLE) { + ide_pri_disable(); + if (!(dev->regs[0xfe] & REG_FE_IDE_DISABLE)) + ide_pri_enable(); + } + break; + } + } +} + + +static uint8_t +acc3221_read(uint16_t addr, void *p) +{ + acc3221_t *dev = (acc3221_t *)p; + + if (!(addr & 1)) + return dev->reg_idx; + + if (dev->reg_idx < 0xbc) + return 0xff; + + return dev->regs[dev->reg_idx]; +} + + +static void +acc3221_reset(acc3221_t *dev) +{ + serial_remove(dev->uart[0]); + serial_setup(dev->uart[0], SERIAL1_ADDR, SERIAL1_IRQ); + + serial_remove(dev->uart[1]); + serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); + + lpt1_remove(); + lpt1_init(0x378); + lpt1_irq(7); + + fdc_reset(dev->fdc); +} + +static void +acc3221_close(void *priv) +{ + acc3221_t *dev = (acc3221_t *) priv; + + free(dev); +} + + +static void * +acc3221_init(const device_t *info) +{ + acc3221_t *dev = (acc3221_t *) malloc(sizeof(acc3221_t)); + memset(dev, 0, sizeof(acc3221_t)); + + dev->fdc = device_add(&fdc_at_device); + + dev->uart[0] = device_add_inst(&ns16450_device, 1); + dev->uart[1] = device_add_inst(&ns16450_device, 2); + + io_sethandler(0x00f2, 0x0002, acc3221_read, NULL, NULL, acc3221_write, NULL, NULL, dev); + + acc3221_reset(dev); + + return dev; +} + + +const device_t acc3221_device = { + "ACC 3221-SP Super I/O", + 0, + 0, + acc3221_init, acc3221_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_detect.c b/src/sio_detect.c index 980f17a2d..bc0a3e377 100644 --- a/src/sio_detect.c +++ b/src/sio_detect.c @@ -22,6 +22,7 @@ #include "86box.h" #include "device.h" #include "io.h" +#include "timer.h" #include "floppy/fdd.h" #include "floppy/fdc.h" #include "sio.h" diff --git a/src/sio_fdc37c669.c b/src/sio_fdc37c669.c index 3e5a0b669..1f484af41 100644 --- a/src/sio_fdc37c669.c +++ b/src/sio_fdc37c669.c @@ -20,6 +20,7 @@ #include #include "86box.h" #include "io.h" +#include "timer.h" #include "device.h" #include "pci.h" #include "lpt.h" @@ -184,6 +185,10 @@ fdc37c669_write(uint16_t port, uint8_t val, void *priv) serial_setup(dev->uart[1], make_port(dev, 0x25), dev->regs[0x28] & 0x0f); } break; + case 0x27: + if (valxor & 0xf) + lpt1_irq(val & 0xf); + break; case 0x28: if (valxor & 0xf) { serial_remove(dev->uart[1]); @@ -229,8 +234,6 @@ fdc37c669_reset(fdc37c669_t *dev) serial_remove(dev->uart[1]); serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); - lpt2_remove(); - lpt1_remove(); lpt1_init(0x378); diff --git a/src/sio_fdc37c66x.c b/src/sio_fdc37c66x.c index 4f6ce8719..21003e648 100644 --- a/src/sio_fdc37c66x.c +++ b/src/sio_fdc37c66x.c @@ -24,6 +24,7 @@ #include #include "86box.h" #include "io.h" +#include "timer.h" #include "device.h" #include "pci.h" #include "lpt.h" @@ -114,12 +115,15 @@ lpt1_handler(fdc37c66x_t *dev) switch (dev->regs[1] & 3) { case 1: lpt1_init(0x3bc); + lpt1_irq(7); break; case 2: lpt1_init(0x378); + lpt1_irq(5); break; case 3: lpt1_init(0x278); + lpt1_irq(5); break; } } @@ -211,8 +215,6 @@ fdc37c66x_reset(fdc37c66x_t *dev) serial_remove(dev->uart[1]); serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); - lpt2_remove(); - lpt1_remove(); lpt1_init(0x378); diff --git a/src/sio_fdc37c93x.c b/src/sio_fdc37c93x.c index ab9cfabfb..e93ffea54 100644 --- a/src/sio_fdc37c93x.c +++ b/src/sio_fdc37c93x.c @@ -21,6 +21,7 @@ #include #include "86box.h" #include "io.h" +#include "timer.h" #include "device.h" #include "pci.h" #include "lpt.h" @@ -129,6 +130,10 @@ fdc37c93x_lpt_handler(fdc37c93x_t *dev) uint16_t ld_port = 0; uint8_t global_enable = !!(dev->regs[0x22] & (1 << 3)); uint8_t local_enable = !!dev->ld_regs[3][0x30]; + uint8_t lpt_irq = dev->ld_regs[3][0x70]; + + if (lpt_irq > 15) + lpt_irq = 0xff; lpt1_remove(); if (global_enable && local_enable) { @@ -136,6 +141,7 @@ fdc37c93x_lpt_handler(fdc37c93x_t *dev) if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) lpt1_init(ld_port); } + lpt1_irq(lpt_irq); } @@ -407,6 +413,7 @@ fdc37c93x_write(uint16_t port, uint8_t val, void *priv) case 0x30: case 0x60: case 0x61: + case 0x70: if (valxor) fdc37c93x_lpt_handler(dev); break; @@ -470,23 +477,22 @@ static uint8_t fdc37c93x_read(uint16_t port, void *priv) uint8_t index = (port & 1) ? 0 : 1; uint8_t ret = 0xff; - if (!dev->locked) - return ret; - - if (index) - ret = dev->cur_reg; - else { - if (dev->cur_reg < 0x30) { - if (dev->cur_reg == 0x20) - ret = dev->chip_id; - else - ret = dev->regs[dev->cur_reg]; - } else { - if ((dev->regs[7] == 0) && (dev->cur_reg == 0xF2)) { - ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | - (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6)); - } else - ret = dev->ld_regs[dev->regs[7]][dev->cur_reg]; + if (dev->locked) { + if (index) + ret = dev->cur_reg; + else { + if (dev->cur_reg < 0x30) { + if (dev->cur_reg == 0x20) + ret = dev->chip_id; + else + ret = dev->regs[dev->cur_reg]; + } else { + if ((dev->regs[7] == 0) && (dev->cur_reg == 0xF2)) { + ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | + (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6)); + } else + ret = dev->ld_regs[dev->regs[7]][dev->cur_reg]; + } } } @@ -499,8 +505,6 @@ fdc37c93x_reset(fdc37c93x_t *dev) { int i = 0; - lpt2_remove(); - memset(dev->regs, 0, 48); dev->regs[0x03] = 0x03; @@ -576,8 +580,6 @@ fdc37c93x_reset(fdc37c93x_t *dev) dev->ld_regs[7][0x70] = 1; /* Logical device 8: Auxiliary I/O */ - io_removehandler(dev->access_bus->base, 0x0004, - fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, dev->access_bus); /* Logical device 9: ACCESS.bus */ @@ -590,6 +592,7 @@ fdc37c93x_reset(fdc37c93x_t *dev) fdc37c932fr_access_bus_handler(dev); fdc_reset(dev->fdc); + fdc37c93x_fdc_handler(dev); dev->locked = 0; } @@ -670,6 +673,15 @@ const device_t fdc37c932fr_device = { NULL }; +const device_t fdc37c932qf_device = { + "SMC FDC37C932QF Super I/O", + 0, + 0x02, /* Share the same ID with the 935. */ + fdc37c93x_init, fdc37c93x_close, NULL, + NULL, NULL, NULL, + NULL +}; + const device_t fdc37c935_device = { "SMC FDC37C935 Super I/O", 0, diff --git a/src/sio_pc87306.c b/src/sio_pc87306.c index f0f3e48b0..c2d3ceaf8 100644 --- a/src/sio_pc87306.c +++ b/src/sio_pc87306.c @@ -20,6 +20,7 @@ #include #include "86box.h" #include "io.h" +#include "timer.h" #include "device.h" #include "lpt.h" #include "mem.h" @@ -88,34 +89,44 @@ lpt1_handler(pc87306_t *dev) { int temp; uint16_t lptba, lpt_port = 0x378; + uint8_t lpt_irq = 5; temp = dev->regs[0x01] & 3; lptba = ((uint16_t) dev->regs[0x19]) << 2; if (dev->regs[0x1b] & 0x10) { - if (dev->regs[0x1b] & 0x20) + if (dev->regs[0x1b] & 0x20) { lpt_port = 0x278; - else + lpt_irq = 7; + } else { lpt_port = 0x378; + lpt_irq = 5; + } } else { switch (temp) { case 0: lpt_port = 0x378; + lpt_irq = (dev->regs[0x02] & 0x08) ? 7 : 5; break; case 1: lpt_port = lptba; + lpt_irq = 7; break; case 2: lpt_port = 0x278; + lpt_irq = 5; break; case 3: lpt_port = 0x000; + lpt_irq = 0xff; break; } } if (lpt_port) lpt1_init(lpt_port); + + lpt1_irq(lpt_irq); } @@ -365,7 +376,6 @@ pc87306_reset(pc87306_t *dev) 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" */ lpt1_remove(); - lpt2_remove(); lpt1_handler(dev); serial_remove(dev->uart[0]); serial_remove(dev->uart[1]); diff --git a/src/sio_pc87307.c b/src/sio_pc87307.c new file mode 100644 index 000000000..e93ffea54 --- /dev/null +++ b/src/sio_pc87307.c @@ -0,0 +1,692 @@ +/* + * 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 SMC FDC37C932FR and FDC37C935 Super + * I/O Chips. + * + * Version: @(#)sio_fdc37c93x.c 1.0.15 2018/11/12 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "io.h" +#include "timer.h" +#include "device.h" +#include "pci.h" +#include "lpt.h" +#include "serial.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sio.h" + + +#define AB_RST 0x80 + + +typedef struct { + uint8_t control; + uint8_t status; + uint8_t own_addr; + uint8_t data; + uint8_t clock; + uint16_t base; +} access_bus_t; + +typedef struct { + uint8_t chip_id, tries, + gpio_regs[2], auxio_reg, + regs[48], + ld_regs[10][256]; + uint16_t gpio_base, /* Set to EA */ + auxio_base; + int locked, + cur_reg; + fdc_t *fdc; + serial_t *uart[2]; + access_bus_t *access_bus; +} fdc37c93x_t; + + +static uint16_t +make_port(fdc37c93x_t *dev, uint8_t ld) +{ + uint16_t r0 = dev->ld_regs[ld][0x60]; + uint16_t r1 = dev->ld_regs[ld][0x61]; + + uint16_t p = (r0 << 8) + r1; + + return p; +} + + +static uint8_t +fdc37c93x_auxio_read(uint16_t port, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + return dev->auxio_reg; +} + + +static void +fdc37c93x_auxio_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + dev->auxio_reg = val; +} + + +static uint8_t +fdc37c93x_gpio_read(uint16_t port, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + return dev->gpio_regs[port & 1]; +} + + +static void +fdc37c93x_gpio_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + dev->gpio_regs[port & 1] = val; +} + + +static void +fdc37c93x_fdc_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 0)); + uint8_t local_enable = !!dev->ld_regs[0][0x30]; + + fdc_remove(dev->fdc); + if (global_enable && local_enable) { + ld_port = make_port(dev, 0); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + fdc_set_base(dev->fdc, ld_port); + } +} + + +static void +fdc37c93x_lpt_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 3)); + uint8_t local_enable = !!dev->ld_regs[3][0x30]; + uint8_t lpt_irq = dev->ld_regs[3][0x70]; + + if (lpt_irq > 15) + lpt_irq = 0xff; + + lpt1_remove(); + if (global_enable && local_enable) { + ld_port = make_port(dev, 3); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) + lpt1_init(ld_port); + } + lpt1_irq(lpt_irq); +} + + +static void +fdc37c93x_serial_handler(fdc37c93x_t *dev, int uart) +{ + uint16_t ld_port = 0; + uint8_t uart_no = 4 + uart; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << uart_no)); + uint8_t local_enable = !!dev->ld_regs[uart_no][0x30]; + + serial_remove(dev->uart[uart]); + if (global_enable && local_enable) { + ld_port = make_port(dev, uart_no); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + serial_setup(dev->uart[uart], ld_port, dev->ld_regs[uart_no][0x70]); + } +} + + +static void fdc37c93x_auxio_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t local_enable = !!dev->ld_regs[8][0x30]; + + io_removehandler(dev->auxio_base, 0x0001, + fdc37c93x_auxio_read, NULL, NULL, fdc37c93x_auxio_write, NULL, NULL, dev); + if (local_enable) { + dev->auxio_base = ld_port = make_port(dev, 8); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFF)) + io_sethandler(dev->auxio_base, 0x0001, + fdc37c93x_auxio_read, NULL, NULL, fdc37c93x_auxio_write, NULL, NULL, dev); + } +} + + +static void fdc37c93x_gpio_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t local_enable; + + local_enable = !!(dev->regs[0x03] & 0x80); + + io_removehandler(dev->gpio_base, 0x0002, + fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, dev); + if (local_enable) { + switch (dev->regs[0x03] & 0x03) { + case 0: + ld_port = 0xe0; + break; + case 1: + ld_port = 0xe2; + break; + case 2: + ld_port = 0xe4; + break; + case 3: + ld_port = 0xea; /* Default */ + break; + } + dev->gpio_base = ld_port; + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFE)) + io_sethandler(dev->gpio_base, 0x0002, + fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, dev); + } +} + + +static uint8_t +fdc37c932fr_access_bus_read(uint16_t port, void *priv) +{ + access_bus_t *dev = (access_bus_t *) priv; + uint8_t ret = 0xff; + + switch(port & 3) { + case 0: + ret = (dev->status & 0xBF); + break; + case 1: + ret = (dev->own_addr & 0x7F); + break; + case 2: + ret = dev->data; + break; + case 3: + ret = (dev->clock & 0x87); + break; + } + + return ret; +} + + +static void +fdc37c932fr_access_bus_write(uint16_t port, uint8_t val, void *priv) +{ + access_bus_t *dev = (access_bus_t *) priv; + + switch(port & 3) { + case 0: + dev->control = (val & 0xCF); + break; + case 1: + dev->own_addr = (val & 0x7F); + break; + case 2: + dev->data = val; + break; + case 3: + dev->clock &= 0x80; + dev->clock |= (val & 0x07); + break; + } +} + + +static void fdc37c932fr_access_bus_handler(fdc37c93x_t *dev) +{ + uint16_t ld_port = 0; + uint8_t global_enable = !!(dev->regs[0x22] & (1 << 6)); + uint8_t local_enable = !!dev->ld_regs[9][0x30]; + + io_removehandler(dev->access_bus->base, 0x0004, + fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, dev->access_bus); + if (global_enable && local_enable) { + dev->access_bus->base = ld_port = make_port(dev, 9); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) + io_sethandler(dev->access_bus->base, 0x0004, + fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, dev->access_bus); + } +} + + +static void +fdc37c93x_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + + if (index) { + if ((val == 0x55) && !dev->locked) { + if (dev->tries) { + dev->locked = 1; + fdc_3f1_enable(dev->fdc, 0); + dev->tries = 0; + } else + dev->tries++; + } else { + if (dev->locked) { + if (val == 0xaa) { + dev->locked = 0; + fdc_3f1_enable(dev->fdc, 1); + return; + } + dev->cur_reg = val; + } else { + if (dev->tries) + dev->tries = 0; + } + } + return; + } else { + if (dev->locked) { + if (dev->cur_reg < 48) { + valxor = val ^ dev->regs[dev->cur_reg]; + if ((val == 0x20) || (val == 0x21)) + return; + dev->regs[dev->cur_reg] = val; + } else { + valxor = val ^ dev->ld_regs[dev->regs[7]][dev->cur_reg]; + if (((dev->cur_reg & 0xF0) == 0x70) && (dev->regs[7] < 4)) + return; + /* Block writes to some logical devices. */ + if (dev->regs[7] > 9) + return; + else switch (dev->regs[7]) { + case 1: + case 2: + case 6: + case 7: + return; + case 9: + /* If we're on the FDC37C935, return as this is not a valid + logical device there. */ + if (dev->chip_id == 0x02) + return; + break; + } + dev->ld_regs[dev->regs[7]][dev->cur_reg] = val; + } + } else + return; + } + + if (dev->cur_reg < 48) { + switch(dev->cur_reg) { + case 0x03: + if (valxor & 0x83) + fdc37c93x_gpio_handler(dev); + dev->regs[0x03] &= 0x83; + break; + case 0x22: + if (valxor & 0x01) + fdc37c93x_fdc_handler(dev); + if (valxor & 0x08) + fdc37c93x_lpt_handler(dev); + if (valxor & 0x10) + fdc37c93x_serial_handler(dev, 0); + if (valxor & 0x20) + fdc37c93x_serial_handler(dev, 1); + break; + } + + return; + } + + switch(dev->regs[7]) { + case 0: + /* FDD */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + if (valxor) + fdc37c93x_fdc_handler(dev); + break; + case 0xF0: + if (valxor & 0x01) + fdc_update_enh_mode(dev->fdc, val & 0x01); + if (valxor & 0x10) + fdc_set_swap(dev->fdc, (val & 0x10) >> 4); + break; + case 0xF1: + if (valxor & 0xC) + fdc_update_densel_force(dev->fdc, (val & 0xC) >> 2); + break; + case 0xF2: + if (valxor & 0xC0) + fdc_update_rwc(dev->fdc, 3, (valxor & 0xC0) >> 6); + if (valxor & 0x30) + fdc_update_rwc(dev->fdc, 2, (valxor & 0x30) >> 4); + if (valxor & 0x0C) + fdc_update_rwc(dev->fdc, 1, (valxor & 0x0C) >> 2); + if (valxor & 0x03) + fdc_update_rwc(dev->fdc, 0, (valxor & 0x03)); + break; + case 0xF4: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 0, (val & 0x18) >> 3); + break; + case 0xF5: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 1, (val & 0x18) >> 3); + break; + case 0xF6: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 2, (val & 0x18) >> 3); + break; + case 0xF7: + if (valxor & 0x18) + fdc_update_drvrate(dev->fdc, 3, (val & 0x18) >> 3); + break; + } + break; + case 3: + /* Parallel port */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c93x_lpt_handler(dev); + break; + } + break; + case 4: + /* Serial port 1 */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c93x_serial_handler(dev, 0); + break; + } + break; + case 5: + /* Serial port 2 */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c93x_serial_handler(dev, 1); + break; + } + break; + case 8: + /* Auxiliary I/O */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c93x_auxio_handler(dev); + break; + } + break; + case 9: + /* Access bus (FDC37C932FR only) */ + switch(dev->cur_reg) { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + fdc37c932fr_access_bus_handler(dev); + break; + } + break; + } +} + + +static uint8_t fdc37c93x_read(uint16_t port, void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t ret = 0xff; + + if (dev->locked) { + if (index) + ret = dev->cur_reg; + else { + if (dev->cur_reg < 0x30) { + if (dev->cur_reg == 0x20) + ret = dev->chip_id; + else + ret = dev->regs[dev->cur_reg]; + } else { + if ((dev->regs[7] == 0) && (dev->cur_reg == 0xF2)) { + ret = (fdc_get_rwc(dev->fdc, 0) | (fdc_get_rwc(dev->fdc, 1) << 2) | + (fdc_get_rwc(dev->fdc, 2) << 4) | (fdc_get_rwc(dev->fdc, 3) << 6)); + } else + ret = dev->ld_regs[dev->regs[7]][dev->cur_reg]; + } + } + } + + return ret; +} + + +static void +fdc37c93x_reset(fdc37c93x_t *dev) +{ + int i = 0; + + memset(dev->regs, 0, 48); + + dev->regs[0x03] = 0x03; + dev->regs[0x21] = 0x01; + dev->regs[0x20] = dev->chip_id; + dev->regs[0x22] = 0x39; + dev->regs[0x24] = 0x04; + dev->regs[0x26] = 0xF0; + dev->regs[0x27] = 0x03; + + for (i = 0; i < 10; i++) + memset(dev->ld_regs[i], 0, 256); + + /* Logical device 0: FDD */ + dev->ld_regs[0][0x30] = 1; + dev->ld_regs[0][0x60] = 3; + dev->ld_regs[0][0x61] = 0xF0; + dev->ld_regs[0][0x70] = 6; + dev->ld_regs[0][0x74] = 2; + dev->ld_regs[0][0xF0] = 0xE; + dev->ld_regs[0][0xF2] = 0xFF; + + /* Logical device 1: IDE1 */ + dev->ld_regs[1][0x30] = 0; + dev->ld_regs[1][0x60] = 1; + dev->ld_regs[1][0x61] = 0xF0; + dev->ld_regs[1][0x62] = 3; + dev->ld_regs[1][0x63] = 0xF6; + dev->ld_regs[1][0x70] = 0xE; + dev->ld_regs[1][0xF0] = 0xC; + + /* Logical device 2: IDE2 */ + dev->ld_regs[2][0x30] = 0; + dev->ld_regs[2][0x60] = 1; + dev->ld_regs[2][0x61] = 0x70; + dev->ld_regs[2][0x62] = 3; + dev->ld_regs[2][0x63] = 0x76; + dev->ld_regs[2][0x70] = 0xF; + + /* Logical device 3: Parallel Port */ + dev->ld_regs[3][0x30] = 1; + dev->ld_regs[3][0x60] = 3; + dev->ld_regs[3][0x61] = 0x78; + dev->ld_regs[3][0x70] = 7; + dev->ld_regs[3][0x74] = 4; + dev->ld_regs[3][0xF0] = 0x3C; + + /* Logical device 4: Serial Port 1 */ + dev->ld_regs[4][0x30] = 1; + dev->ld_regs[4][0x60] = 3; + dev->ld_regs[4][0x61] = 0xf8; + dev->ld_regs[4][0x70] = 4; + dev->ld_regs[4][0xF0] = 3; + serial_setup(dev->uart[0], 0x3f8, dev->ld_regs[4][0x70]); + + /* Logical device 5: Serial Port 2 */ + dev->ld_regs[5][0x30] = 1; + dev->ld_regs[5][0x60] = 2; + dev->ld_regs[5][0x61] = 0xf8; + dev->ld_regs[5][0x70] = 3; + dev->ld_regs[5][0x74] = 4; + dev->ld_regs[5][0xF1] = 2; + dev->ld_regs[5][0xF2] = 3; + serial_setup(dev->uart[1], 0x2f8, dev->ld_regs[5][0x70]); + + /* Logical device 6: RTC */ + dev->ld_regs[6][0x63] = 0x70; + dev->ld_regs[6][0xF4] = 3; + + /* Logical device 7: Keyboard */ + dev->ld_regs[7][0x30] = 1; + dev->ld_regs[7][0x61] = 0x60; + dev->ld_regs[7][0x70] = 1; + + /* Logical device 8: Auxiliary I/O */ + + /* Logical device 9: ACCESS.bus */ + + fdc37c93x_gpio_handler(dev); + fdc37c93x_lpt_handler(dev); + fdc37c93x_serial_handler(dev, 0); + fdc37c93x_serial_handler(dev, 1); + fdc37c93x_auxio_handler(dev); + if (dev->chip_id == 0x03) + fdc37c932fr_access_bus_handler(dev); + + fdc_reset(dev->fdc); + fdc37c93x_fdc_handler(dev); + + dev->locked = 0; +} + + +static void +access_bus_close(void *priv) +{ + access_bus_t *dev = (access_bus_t *) priv; + + free(dev); +} + + +static void * +access_bus_init(const device_t *info) +{ + access_bus_t *dev = (access_bus_t *) malloc(sizeof(access_bus_t)); + memset(dev, 0, sizeof(access_bus_t)); + + return dev; +} + + +static const device_t access_bus_device = { + "SMC FDC37C932FR ACCESS.bus", + 0, + 0x03, + access_bus_init, access_bus_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +static void +fdc37c93x_close(void *priv) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) priv; + + free(dev); +} + + +static void * +fdc37c93x_init(const device_t *info) +{ + fdc37c93x_t *dev = (fdc37c93x_t *) malloc(sizeof(fdc37c93x_t)); + memset(dev, 0, sizeof(fdc37c93x_t)); + + dev->fdc = device_add(&fdc_at_smc_device); + + dev->uart[0] = device_add_inst(&ns16550_device, 1); + dev->uart[1] = device_add_inst(&ns16550_device, 2); + + dev->chip_id = info->local; + + dev->gpio_regs[0] = 0xFD; + dev->gpio_regs[1] = 0xFF; + + if (dev->chip_id == 0x03) + dev->access_bus = device_add(&access_bus_device); + + io_sethandler(0x3f0, 0x0002, + fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, dev); + + fdc37c93x_reset(dev); + + return dev; +} + + +const device_t fdc37c932fr_device = { + "SMC FDC37C932FR Super I/O", + 0, + 0x03, + fdc37c93x_init, fdc37c93x_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t fdc37c932qf_device = { + "SMC FDC37C932QF Super I/O", + 0, + 0x02, /* Share the same ID with the 935. */ + fdc37c93x_init, fdc37c93x_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t fdc37c935_device = { + "SMC FDC37C935 Super I/O", + 0, + 0x02, + fdc37c93x_init, fdc37c93x_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/sio_um8669f.c b/src/sio_um8669f.c index 42652c2fc..d946c251c 100644 --- a/src/sio_um8669f.c +++ b/src/sio_um8669f.c @@ -29,6 +29,7 @@ PnP registers : #include "86box.h" #include "device.h" #include "io.h" +#include "timer.h" #include "pci.h" #include "lpt.h" #include "serial.h" @@ -77,6 +78,7 @@ um8669f_pnp_write(uint16_t port, uint8_t val, void *priv) um8669f_t *dev = (um8669f_t *) priv; uint8_t valxor = 0; + uint8_t lpt_irq = 0xff; if (port == 0x279) dev->cur_reg = val; @@ -138,6 +140,9 @@ um8669f_pnp_write(uint16_t port, uint8_t val, void *priv) if (dev->dev[DEV_LPT1].enable & 1) lpt1_init(dev->dev[DEV_LPT1].addr); } + if (dev->dev[DEV_LPT1].irq <= 15) + lpt_irq = dev->dev[DEV_LPT1].irq; + lpt1_irq(lpt_irq); break; } } @@ -246,8 +251,6 @@ um8669f_reset(um8669f_t *dev) serial_remove(dev->uart[1]); serial_setup(dev->uart[1], SERIAL2_ADDR, SERIAL2_IRQ); - lpt2_remove(); - lpt1_remove(); lpt1_init(0x378); diff --git a/src/sio_w83877f.c b/src/sio_w83877f.c index d14cef614..98d514c32 100644 --- a/src/sio_w83877f.c +++ b/src/sio_w83877f.c @@ -11,7 +11,7 @@ * Winbond W83877F Super I/O Chip * Used by the Award 430HX * - * Version: @(#)sio_w83877f.c 1.0.14 2018/11/05 + * Version: @(#)sio_w83877f.c 1.0.15 2019/05/17 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -24,6 +24,7 @@ #include "86box.h" #include "device.h" #include "io.h" +#include "timer.h" #include "pci.h" #include "mem.h" #include "rom.h" @@ -53,10 +54,13 @@ #define HEFRAS (dev->regs[0x16] & 1) +#define PRTIQS (dev->regs[0x27] & 0x0f) +#define ECPIRQ ((dev->regs[0x27] >> 5) & 0x07) + typedef struct { - uint8_t tries, reg16_init, - regs[42]; + uint8_t tries, regs[42]; + uint16_t reg_init; int locked, rw_locked, cur_reg, base_address, key, @@ -166,6 +170,7 @@ w83877f_write(uint16_t port, uint8_t val, void *priv) uint8_t index = (port & 1) ? 0 : 1; uint8_t valxor = 0; uint8_t max = 0x2A; + uint8_t lpt_irq; if (index) { if ((val == dev->key) && !dev->locked) { @@ -302,6 +307,16 @@ w83877f_write(uint16_t port, uint8_t val, void *priv) if (valxor & 0xfe) w83877f_serial_handler(dev, 1); break; + case 0x27: + if (valxor & 0xef) { + lpt_irq = 0xff; + + if (PRTIQS != 0x00) + lpt_irq = ECPIRQ; + + lpt1_irq(lpt_irq); + } + break; case 0x28: if (valxor & 0xf) { if ((dev->regs[0x28] & 0x0f) == 0) @@ -345,8 +360,6 @@ w83877f_read(uint16_t port, void *priv) static void w83877f_reset(w83877f_t *dev) { - lpt2_remove(); - lpt1_remove(); lpt1_init(0x378); @@ -355,11 +368,11 @@ w83877f_reset(w83877f_t *dev) memset(dev->regs, 0, 0x2A); dev->regs[0x03] = 0x30; dev->regs[0x07] = 0xF5; - dev->regs[0x09] = 0x0A; + dev->regs[0x09] = (dev->reg_init >> 8) & 0xff; dev->regs[0x0a] = 0x1F; dev->regs[0x0c] = 0x28; dev->regs[0x0d] = 0xA3; - dev->regs[0x16] = dev->reg16_init; + dev->regs[0x16] = dev->reg_init & 0xff; dev->regs[0x1e] = 0x81; dev->regs[0x20] = (0x3f0 >> 2) & 0xfc; dev->regs[0x21] = (0x1f0 >> 2) & 0xfc; @@ -406,7 +419,7 @@ w83877f_init(const device_t *info) dev->uart[0] = device_add_inst(&ns16550_device, 1); dev->uart[1] = device_add_inst(&ns16550_device, 2); - dev->reg16_init = info->local; + dev->reg_init = info->local; w83877f_reset(dev); @@ -417,7 +430,7 @@ w83877f_init(const device_t *info) const device_t w83877f_device = { "Winbond W83877F Super I/O", 0, - 5, + 0x0a05, w83877f_init, w83877f_close, NULL, NULL, NULL, NULL, NULL @@ -427,7 +440,17 @@ const device_t w83877f_device = { const device_t w83877f_president_device = { "Winbond W83877F Super I/O (President)", 0, - 4, + 0x0a04, + w83877f_init, w83877f_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +const device_t w83877tf_device = { + "Winbond W83877TF Super I/O", + 0, + 0x0c04, w83877f_init, w83877f_close, NULL, NULL, NULL, NULL, NULL diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index a35646dc9..fd5631b12 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -75,13 +75,21 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) case 7: freq /= 2560; break; } ad1848->freq = freq; - ad1848->timer_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); break; case 9: + if (!ad1848->enable && (val & 0x41) == 0x01) { + if (ad1848->timer_latch) + timer_set_delay_u64(&ad1848->timer_count, ad1848->timer_latch); + else + timer_set_delay_u64(&ad1848->timer_count, TIMER_USEC); + } ad1848->enable = ((val & 0x41) == 0x01); - if (!ad1848->enable) + if (!ad1848->enable) { + timer_disable(&ad1848->timer_count); ad1848->out_l = ad1848->out_r = 0; + } break; case 12: @@ -101,7 +109,7 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) void ad1848_speed_changed(ad1848_t *ad1848) { - ad1848->timer_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); } void ad1848_update(ad1848_t *ad1848) @@ -118,10 +126,10 @@ static void ad1848_poll(void *p) ad1848_t *ad1848 = (ad1848_t *)p; if (ad1848->timer_latch) - ad1848->timer_count += ad1848->timer_latch; + timer_advance_u64(&ad1848->timer_count, ad1848->timer_latch); else - ad1848->timer_count = TIMER_USEC; - + timer_advance_u64(&ad1848->timer_count, TIMER_USEC * 1000); + ad1848_update(ad1848); if (ad1848->enable) @@ -183,8 +191,6 @@ void ad1848_init(ad1848_t *ad1848) { int c; double attenuation; - - ad1848->enable = 0; ad1848->status = 0xcc; ad1848->index = ad1848->trd = 0; @@ -219,5 +225,5 @@ void ad1848_init(ad1848_t *ad1848) ad1848_vols[c] = (int)(attenuation * 65536); } - timer_add(ad1848_poll, &ad1848->timer_count, &ad1848->enable, ad1848); + timer_add(&ad1848->timer_count, ad1848_poll, ad1848, 0); } diff --git a/src/sound/snd_ad1848.h b/src/sound/snd_ad1848.h index 39dc60a5e..6ec719475 100644 --- a/src/sound/snd_ad1848.h +++ b/src/sound/snd_ad1848.h @@ -11,13 +11,14 @@ typedef struct ad1848_t int16_t out_l, out_r; - int64_t enable; + int enable; int irq, dma; - int64_t freq; + int freq; - int64_t timer_count, timer_latch; + pc_timer_t timer_count; + uint64_t timer_latch; int16_t buffer[SOUNDBUFLEN * 2]; int pos; diff --git a/src/sound/snd_adlib.c b/src/sound/snd_adlib.c index 998c14dab..c0417f69d 100644 --- a/src/sound/snd_adlib.c +++ b/src/sound/snd_adlib.c @@ -7,6 +7,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mca.h" #include "../device.h" #include "sound.h" @@ -85,6 +86,14 @@ void adlib_mca_write(int port, uint8_t val, void *p) adlib->pos_regs[port & 7] = val; } +uint8_t adlib_mca_feedb(void *p) +{ + adlib_t *adlib = (adlib_t *)p; + + return (adlib->pos_regs[2] & 1); +} + + void *adlib_init(const device_t *info) { adlib_t *adlib = malloc(sizeof(adlib_t)); @@ -102,7 +111,7 @@ void *adlib_mca_init(const device_t *info) adlib_t *adlib = adlib_init(info); io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); - mca_add(adlib_mca_read, adlib_mca_write, adlib); + mca_add(adlib_mca_read, adlib_mca_write, adlib_mca_feedb, adlib); adlib->pos_regs[0] = 0xd7; adlib->pos_regs[1] = 0x70; diff --git a/src/sound/snd_adlibgold.c b/src/sound/snd_adlibgold.c index 4606eec06..06a4fcee5 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -5,11 +5,11 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../dma.h" #include "../pic.h" #include "../device.h" #include "../nvr.h" -#include "../timer.h" #include "sound.h" #include "filters.h" #include "snd_opl.h" @@ -37,7 +37,7 @@ typedef struct adgold_t int16_t adgold_mma_out[2]; int adgold_mma_intpos[2]; - int64_t adgold_mma_timer_count; + pc_timer_t adgold_mma_timer_count; struct { @@ -576,67 +576,64 @@ void adgold_timer_poll(void *p) { adgold_t *adgold = (adgold_t *)p; - while (adgold->adgold_mma_timer_count <= 0LL) - { - adgold->adgold_mma_timer_count += (int64_t)((double)TIMER_USEC * 1.88964); - if (adgold->adgold_mma_regs[0][8] & 0x01) /*Timer 0*/ - { - adgold->adgold_mma.timer0_count--; - if (!adgold->adgold_mma.timer0_count) - { - adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; - adgold->adgold_mma_status |= 0x10; - adgold_update_irq_status(adgold); - } - } - if (adgold->adgold_mma_regs[0][8] & 0x08) /*Base timer*/ - { - adgold->adgold_mma.timerbase_count--; - if (!adgold->adgold_mma.timerbase_count) - { - adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; - if (adgold->adgold_mma_regs[0][8] & 0x02) /*Timer 1*/ - { - adgold->adgold_mma.timer1_count--; - if (!adgold->adgold_mma.timer1_count) - { - adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; - adgold->adgold_mma_status |= 0x20; - adgold_update_irq_status(adgold); - } - } - if (adgold->adgold_mma_regs[0][8] & 0x04) /*Timer 2*/ - { - adgold->adgold_mma.timer2_count--; - if (!adgold->adgold_mma.timer2_count) - { - adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; - adgold->adgold_mma_status |= 0x40; - adgold_update_irq_status(adgold); - } - } - } - } + timer_advance_u64(&adgold->adgold_mma_timer_count, (uint64_t)((double)TIMER_USEC * 1.88964)); + if (adgold->adgold_mma_regs[0][8] & 0x01) /*Timer 0*/ + { + adgold->adgold_mma.timer0_count--; + if (!adgold->adgold_mma.timer0_count) + { + adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; + adgold->adgold_mma_status |= 0x10; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x08) /*Base timer*/ + { + adgold->adgold_mma.timerbase_count--; + if (!adgold->adgold_mma.timerbase_count) + { + adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + if (adgold->adgold_mma_regs[0][8] & 0x02) /*Timer 1*/ + { + adgold->adgold_mma.timer1_count--; + if (!adgold->adgold_mma.timer1_count) + { + adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; + adgold->adgold_mma_status |= 0x20; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x04) /*Timer 2*/ + { + adgold->adgold_mma.timer2_count--; + if (!adgold->adgold_mma.timer2_count) + { + adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; + adgold->adgold_mma_status |= 0x40; + adgold_update_irq_status(adgold); + } + } + } + } - if (adgold->adgold_mma_enable[0]) - { - adgold->adgold_mma.voice_count[0]--; - if (!adgold->adgold_mma.voice_count[0]) - { - adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; - adgold_mma_poll(adgold, 0); - } - } - if (adgold->adgold_mma_enable[1]) - { - adgold->adgold_mma.voice_count[1]--; - if (!adgold->adgold_mma.voice_count[1]) - { - adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; - adgold_mma_poll(adgold, 1); - } - } - } + if (adgold->adgold_mma_enable[0]) + { + adgold->adgold_mma.voice_count[0]--; + if (!adgold->adgold_mma.voice_count[0]) + { + adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; + adgold_mma_poll(adgold, 0); + } + } + if (adgold->adgold_mma_enable[1]) + { + adgold->adgold_mma.voice_count[1]--; + if (!adgold->adgold_mma.voice_count[1]) + { + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + adgold_mma_poll(adgold, 1); + } + } } static void adgold_get_buffer(int32_t *buffer, int len, void *p) @@ -802,7 +799,7 @@ void *adgold_init(const device_t *info) /*388/389 are handled by adlib_init*/ io_sethandler(0x0388, 0x0008, adgold_read, NULL, NULL, adgold_write, NULL, NULL, adgold); - timer_add(adgold_timer_poll, &adgold->adgold_mma_timer_count, TIMER_ALWAYS_ENABLED, adgold); + timer_add(&adgold->adgold_mma_timer_count, adgold_timer_poll, adgold, 1); sound_add_handler(adgold_get_buffer, adgold); diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index c43fb3a1e..c6bbefc6b 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -53,9 +53,11 @@ typedef struct { uint32_t addr, addr_latch; uint16_t count, size; - uint16_t samp_ct, curr_samp_ct; + uint16_t samp_ct; + int curr_samp_ct; - int64_t time, latch; + pc_timer_t timer; + uint64_t latch; uint32_t vf, ac; @@ -606,8 +608,6 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) case 0xc: es1371->dac[0].size = val & 0xffff; es1371->dac[0].count = val >> 16; - if (es1371->dac[0].count) - es1371->dac[0].count -= 4; break; case 0xd: @@ -1105,8 +1105,8 @@ static void es1371_poll(void *p) { es1371_t *es1371 = (es1371_t *)p; - es1371->dac[1].time += es1371->dac[1].latch; - + timer_advance_u64(&es1371->dac[1].timer, es1371->dac[1].latch); + es1371_update(es1371); if (es1371->int_ctrl & INT_DAC1_EN) @@ -1120,7 +1120,6 @@ static void es1371_poll(void *p) es1371->dac[0].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15; es1371->dac[0].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15; -// audiopci_log("1Samp %i %i %08x\n", es1371->dac[0].curr_samp_ct, es1371->dac[0].samp_ct, es1371->dac[0].ac); es1371->dac[0].ac += es1371->dac[0].vf; es1371->dac[0].ac &= ((32 << 15) - 1); if ((es1371->dac[0].ac >> (15+4)) != es1371->dac[0].f_pos) @@ -1128,16 +1127,12 @@ static void es1371_poll(void *p) es1371_next_sample_filtered(es1371, 0, es1371->dac[0].f_pos ? 16 : 0); es1371->dac[0].f_pos = (es1371->dac[0].f_pos + 1) & 1; - es1371->dac[0].curr_samp_ct++; - if (es1371->dac[0].curr_samp_ct == es1371->dac[0].samp_ct) + es1371->dac[0].curr_samp_ct--; + if (es1371->dac[0].curr_samp_ct < 0) { -// audiopci_log("DAC1 IRQ\n"); es1371->int_status |= INT_STATUS_DAC1; es1371_update_irqs(es1371); - } - if (es1371->dac[0].curr_samp_ct > es1371->dac[0].samp_ct) - { - es1371->dac[0].curr_samp_ct = 0; + es1371->dac[0].curr_samp_ct = es1371->dac[0].samp_ct; } } } @@ -1153,7 +1148,6 @@ static void es1371_poll(void *p) es1371->dac[1].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15; es1371->dac[1].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15; -// audiopci_log("2Samp %i %i %08x\n", es1371->dac[1].curr_samp_ct, es1371->dac[1].samp_ct, es1371->dac[1].ac); es1371->dac[1].ac += es1371->dac[1].vf; es1371->dac[1].ac &= ((32 << 15) - 1); if ((es1371->dac[1].ac >> (15+4)) != es1371->dac[1].f_pos) @@ -1161,16 +1155,13 @@ static void es1371_poll(void *p) es1371_next_sample_filtered(es1371, 1, es1371->dac[1].f_pos ? 16 : 0); es1371->dac[1].f_pos = (es1371->dac[1].f_pos + 1) & 1; - es1371->dac[1].curr_samp_ct++; - if (es1371->dac[1].curr_samp_ct > es1371->dac[1].samp_ct) + es1371->dac[1].curr_samp_ct--; + if (es1371->dac[1].curr_samp_ct < 0) { -// es1371->dac[1].curr_samp_ct = 0; -// audiopci_log("DAC2 IRQ\n"); es1371->int_status |= INT_STATUS_DAC2; es1371_update_irqs(es1371); + es1371->dac[1].curr_samp_ct = es1371->dac[1].samp_ct; } - if (es1371->dac[1].curr_samp_ct > es1371->dac[1].samp_ct) - es1371->dac[1].curr_samp_ct = 0; } } } @@ -1232,8 +1223,8 @@ static void *es1371_init() sound_add_handler(es1371_get_buffer, es1371); es1371->card = pci_add_card(PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, es1371); - - timer_add(es1371_poll, &es1371->dac[1].time, TIMER_ALWAYS_ENABLED, es1371); + + timer_add(&es1371->dac[1].timer, es1371_poll, es1371, 1); generate_es1371_filter(); @@ -1251,7 +1242,7 @@ static void es1371_speed_changed(void *p) { es1371_t *es1371 = (es1371_t *)p; - es1371->dac[1].latch = (int)((double)TIMER_USEC * (1000000.0 / 48000.0)); + es1371->dac[1].latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / 48000.0)); } void es1371_add_status_info_dac(es1371_t *es1371, char *s, int max_len, int dac_nr) diff --git a/src/sound/snd_dbopl.cc b/src/sound/snd_dbopl.cc index 78840f4a6..e2a0e079b 100644 --- a/src/sound/snd_dbopl.cc +++ b/src/sound/snd_dbopl.cc @@ -21,7 +21,7 @@ static struct uint8_t status; int is_opl3; - void (*timer_callback)(void *param, int timer, int64_t period); + void (*timer_callback)(void *param, int timer, uint64_t period); void *timer_param; } opl[2]; @@ -41,7 +41,7 @@ enum CTRL_TIMER1_CTRL = 0x01 }; -void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3) +void opl_init(void (*timer_callback)(void *param, int timer, uint64_t period), void *timer_param, int nr, int is_opl3) { opl[nr].timer_callback = timer_callback; opl[nr].timer_param = timer_param; diff --git a/src/sound/snd_dbopl.h b/src/sound/snd_dbopl.h index ca6299724..e95a2becd 100644 --- a/src/sound/snd_dbopl.h +++ b/src/sound/snd_dbopl.h @@ -4,7 +4,7 @@ #ifdef __cplusplus extern "C" { #endif - void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3); + void opl_init(void (*timer_callback)(void *param, int timer, uint64_t period), void *timer_param, int nr, int is_opl3); void opl_write(int nr, uint16_t addr, uint8_t val); uint8_t opl_read(int nr, uint16_t addr); void opl_timer_over(int nr, int timer); diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index 3bd367e63..84c338a93 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -47,13 +47,14 @@ typedef struct gus_t int16_t buffer[2][SOUNDBUFLEN]; int pos; - int64_t samp_timer, samp_latch; + pc_timer_t samp_timer; + uint64_t samp_latch; uint8_t *ram; int irqnext; - int64_t timer_1, timer_2; + pc_timer_t timer_1, timer_2; int irq, dma, irq_midi; int latch_enable; @@ -745,7 +746,7 @@ void gus_poll_timer_1(void *p) { gus_t *gus = (gus_t *)p; - gus->timer_1 += (TIMER_USEC * 80LL); + timer_advance_u64(&gus->timer_1, TIMER_USEC * 80); if (gus->t1on) { gus->t1++; @@ -776,7 +777,7 @@ void gus_poll_timer_2(void *p) { gus_t *gus = (gus_t *)p; - gus->timer_2 += (TIMER_USEC * 320LL); + timer_advance_u64(&gus->timer_2, TIMER_USEC * 320); if (gus->t2on) { gus->t2++; @@ -832,7 +833,7 @@ void gus_poll_wave(void *p) gus_update(gus); - gus->samp_timer += gus->samp_latch; + timer_advance_u64(&gus->samp_timer, gus->samp_latch); gus->out_l = gus->out_r = 0; @@ -1021,8 +1022,8 @@ void *gus_init(const device_t *info) } gus->voices=14; - - gus->samp_timer = gus->samp_latch = (int64_t)(TIMER_USEC * (1000000.0 / 44100.0)); + + gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / 44100.0)); gus->t1l = gus->t2l = 0xff; @@ -1030,9 +1031,9 @@ void *gus_init(const device_t *info) io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); io_sethandler(0x0746, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); io_sethandler(0x0388, 0x0002, readgus, NULL, NULL, writegus, NULL, NULL, gus); - timer_add(gus_poll_wave, &gus->samp_timer, TIMER_ALWAYS_ENABLED, gus); - timer_add(gus_poll_timer_1, &gus->timer_1, TIMER_ALWAYS_ENABLED, gus); - timer_add(gus_poll_timer_2, &gus->timer_2, TIMER_ALWAYS_ENABLED, gus); + timer_add(&gus->samp_timer, gus_poll_wave, gus, 1); + timer_add(&gus->timer_1, gus_poll_timer_1, gus, 1); + timer_add(&gus->timer_2, gus_poll_timer_2, gus, 1); sound_add_handler(gus_get_buffer, gus); @@ -1052,9 +1053,9 @@ void gus_speed_changed(void *p) gus_t *gus = (gus_t *)p; if (gus->voices < 14) - gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / 44100.0)); else - gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); + gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); } const device_t gus_device = diff --git a/src/sound/snd_lpt_dac.c b/src/sound/snd_lpt_dac.c index c92201d57..f368e3a21 100644 --- a/src/sound/snd_lpt_dac.c +++ b/src/sound/snd_lpt_dac.c @@ -14,6 +14,8 @@ typedef struct lpt_dac_t { + void *lpt; + uint8_t dac_val_l, dac_val_r; int is_stereo; @@ -36,8 +38,6 @@ static void dac_update(lpt_dac_t *lpt_dac) static void dac_write_data(uint8_t val, void *p) { lpt_dac_t *lpt_dac = (lpt_dac_t *)p; - - timer_clock(); if (lpt_dac->is_stereo) { @@ -80,18 +80,20 @@ static void dac_get_buffer(int32_t *buffer, int len, void *p) lpt_dac->pos = 0; } -static void *dac_init() +static void *dac_init(void *lpt) { lpt_dac_t *lpt_dac = malloc(sizeof(lpt_dac_t)); memset(lpt_dac, 0, sizeof(lpt_dac_t)); + lpt_dac->lpt = lpt; + sound_add_handler(dac_get_buffer, lpt_dac); return lpt_dac; } -static void *dac_stereo_init() +static void *dac_stereo_init(void *lpt) { - lpt_dac_t *lpt_dac = dac_init(); + lpt_dac_t *lpt_dac = dac_init(lpt); lpt_dac->is_stereo = 1; diff --git a/src/sound/snd_lpt_dss.c b/src/sound/snd_lpt_dss.c index 48ed68949..72b5574af 100644 --- a/src/sound/snd_lpt_dss.c +++ b/src/sound/snd_lpt_dss.c @@ -14,12 +14,15 @@ typedef struct dss_t { + void *lpt; + uint8_t fifo[16]; int read_idx, write_idx; - uint8_t dac_val; + uint8_t dac_val, + status; - int64_t time; + pc_timer_t timer; int16_t buffer[SOUNDBUFLEN]; int pos; @@ -32,16 +35,29 @@ static void dss_update(dss_t *dss) } +static void dss_update_status(dss_t *dss) +{ + uint8_t old = dss->status; + + dss->status &= ~0x40; + + if ((dss->write_idx - dss->read_idx) >= 16) + dss->status |= 0x40; + + if ((old & 0x40) && !(dss->status & 0x40)) + lpt_irq(dss->lpt, 1); +} + + static void dss_write_data(uint8_t val, void *p) { dss_t *dss = (dss_t *)p; - timer_clock(); - if ((dss->write_idx - dss->read_idx) < 16) { dss->fifo[dss->write_idx & 15] = val; dss->write_idx++; + dss_update_status(dss); } } @@ -53,9 +69,7 @@ static uint8_t dss_read_status(void *p) { dss_t *dss = (dss_t *)p; - if ((dss->write_idx - dss->read_idx) >= 16) - return 0x40; - return 0; + return dss->status; } @@ -63,12 +77,15 @@ static void dss_get_buffer(int32_t *buffer, int len, void *p) { dss_t *dss = (dss_t *)p; int c; + int16_t val; + float fval; dss_update(dss); for (c = 0; c < len*2; c += 2) { - int16_t val = (int16_t)dss_iir((float)dss->buffer[c >> 1]); + fval = dss_iir((float)dss->buffer[c >> 1]); + val = (float) fval; buffer[c] += val; buffer[c+1] += val; @@ -87,19 +104,22 @@ static void dss_callback(void *p) { dss->dac_val = dss->fifo[dss->read_idx & 15]; dss->read_idx++; + dss_update_status(dss); } - - dss->time += (int64_t) (TIMER_USEC * (1000000.0 / 7000.0)); + + timer_advance_u64(&dss->timer, (TIMER_USEC * (1000000.0 / 7000.0))); } -static void *dss_init() +static void *dss_init(void *lpt) { dss_t *dss = malloc(sizeof(dss_t)); memset(dss, 0, sizeof(dss_t)); + dss->lpt = lpt; + sound_add_handler(dss_get_buffer, dss); - timer_add(dss_callback, &dss->time, TIMER_ALWAYS_ENABLED, dss); - + timer_add(&dss->timer, dss_callback, dss, 1); + return dss; } static void dss_close(void *p) diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index 5944cb57b..15105268f 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -47,11 +47,6 @@ enum { int mpu401_standalone_enable = 0; -static int64_t mpu401_event_callback = 0LL; -static int64_t mpu401_eoi_callback = 0LL; -static int64_t mpu401_reset_callback = 0LL; - - static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val); static void MPU401_EOIHandlerDispatch(void *p); @@ -165,7 +160,7 @@ MPU401_ResetDone(void *priv) mpu401_log("MPU-401 reset callback\n"); - mpu401_reset_callback = 0LL; + timer_disable(&mpu->mpu401_reset_callback); mpu->state.reset = 0; if (mpu->state.cmd_pending) { @@ -204,7 +199,7 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) switch (val & 0xc) { case 0x4: /* Stop */ mpu->state.playing = 0; - mpu401_event_callback = 0LL; + timer_disable(&mpu->mpu401_event_callback); for (i = 0xb0; i < 0xbf; i++) { /* All notes off */ @@ -216,7 +211,7 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) case 0x8: /* Play */ mpu->state.playing = 1; - mpu401_event_callback = (MPU401_TIMECONSTANT / (mpu->clock.tempo*mpu->clock.timebase)) * 1000LL * TIMER_USEC; + timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / (mpu->clock.tempo*mpu->clock.timebase)) * 1000 * TIMER_USEC); ClrQueue(mpu); break; } @@ -334,7 +329,7 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) case 0xff: /* Reset MPU-401 */ mpu401_log("MPU-401:Reset %X\n",val); - mpu401_reset_callback = MPU401_RESETBUSY * 33LL * TIMER_USEC; + timer_set_delay_u64(&mpu->mpu401_reset_callback, MPU401_RESETBUSY * 33LL * TIMER_USEC); mpu->state.reset = 1; was_uart = (mpu->mode == M_UART); MPU401_Reset(mpu); @@ -675,7 +670,7 @@ MPU401_EOIHandler(void *priv) mpu401_log("MPU-401 end of input callback\n"); - mpu401_eoi_callback = 0LL; + timer_disable(&mpu->mpu401_eoi_callback); mpu->state.eoi_scheduled = 0; if (mpu->state.send_now) { mpu->state.send_now = 0; @@ -707,7 +702,7 @@ MPU401_EOIHandlerDispatch(void *priv) mpu401_log("EOI handler dispatch\n"); if (mpu->state.send_now) { mpu->state.eoi_scheduled = 1; - mpu401_eoi_callback = 60LL * TIMER_USEC; /* Possible a bit longer */ + timer_advance_u64(&mpu->mpu401_eoi_callback, 60 * TIMER_USEC); /* Possibly a bit longer */ } else if (!mpu->state.eoi_scheduled) MPU401_EOIHandler(mpu); } @@ -833,7 +828,7 @@ MPU401_Event(void *priv) mpu401_log("MPU-401 event callback\n"); if (mpu->mode == M_UART) { - mpu401_event_callback = 0LL; + timer_disable(&mpu->mpu401_event_callback); return; } @@ -865,11 +860,11 @@ MPU401_Event(void *priv) next_event: new_time = ((mpu->clock.tempo * mpu->clock.timebase * mpu->clock.tempo_rel) / 0x40); if (new_time == 0) { - mpu401_event_callback = 0LL; + timer_disable(&mpu->mpu401_event_callback); return; } else { - mpu401_event_callback += (MPU401_TIMECONSTANT / new_time) * 1000LL * TIMER_USEC; - mpu401_log("Next event after %i us (time constant: %i)\n", (int) ((MPU401_TIMECONSTANT/new_time) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); + 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); } } @@ -890,18 +885,14 @@ mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode) mpu->intelligent = (mode == M_INTELLIGENT) ? 1 : 0; mpu401_log("Starting as %s (mode is %s)\n", mpu->intelligent ? "INTELLIGENT" : "UART", (mode == M_INTELLIGENT) ? "INTELLIGENT" : "UART"); - mpu401_event_callback = 0LL; - mpu401_eoi_callback = 0LL; - mpu401_reset_callback = 0LL; - if (addr) io_sethandler(addr, 2, mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); io_sethandler(0x2A20, 16, NULL, NULL, NULL, imf_write, NULL, NULL, mpu); - timer_add(MPU401_Event, &mpu401_event_callback, &mpu401_event_callback, mpu); - timer_add(MPU401_EOIHandler, &mpu401_eoi_callback, &mpu401_eoi_callback, mpu); - timer_add(MPU401_ResetDone, &mpu401_reset_callback, &mpu401_reset_callback, mpu); + timer_add(&mpu->mpu401_event_callback, MPU401_Event, mpu, 0); + timer_add(&mpu->mpu401_eoi_callback, MPU401_EOIHandler, mpu, 0); + timer_add(&mpu->mpu401_reset_callback, MPU401_ResetDone, mpu, 0); MPU401_Reset(mpu); } @@ -955,6 +946,13 @@ mpu401_mca_write(int port, uint8_t val, void *p) } +static uint8_t +mpu401_mca_feedb(void *p) +{ + return 1; +} + + static void * mpu401_standalone_init(const device_t *info) { @@ -968,7 +966,7 @@ mpu401_standalone_init(const device_t *info) mpu401_log("mpu_init\n"); if (info->flags & DEVICE_MCA) { - mca_add(mpu401_mca_read, mpu401_mca_write, mpu); + mca_add(mpu401_mca_read, mpu401_mca_write, mpu401_mca_feedb, mpu); mpu->pos_regs[0] = 0x0F; mpu->pos_regs[1] = 0x6C; base = 0; /* Tell mpu401_init() that this is the MCA variant. */ diff --git a/src/sound/snd_mpu401.h b/src/sound/snd_mpu401.h index c95ff2dc4..0aa3f12ad 100644 --- a/src/sound/snd_mpu401.h +++ b/src/sound/snd_mpu401.h @@ -93,6 +93,9 @@ typedef struct mpu_t cth_rate, cth_counter; int clock_to_host,cth_active; } clock; + + pc_timer_t mpu401_event_callback, mpu401_eoi_callback, + mpu401_reset_callback; } mpu_t; extern int mpu401_standalone_enable; diff --git a/src/sound/snd_opl.c b/src/sound/snd_opl.c index b18509d8e..f89a81a04 100644 --- a/src/sound/snd_opl.c +++ b/src/sound/snd_opl.c @@ -22,7 +22,7 @@ uint8_t opl2_read(uint16_t a, void *priv) { opl_t *opl = (opl_t *)priv; - cycles -= ISA_CYCLES(8); + sub_cycles((int)(isa_timing * 8)); opl2_update2(opl); return opl_read(0, a); } @@ -39,7 +39,7 @@ uint8_t opl2_l_read(uint16_t a, void *priv) { opl_t *opl = (opl_t *)priv; - cycles -= ISA_CYCLES(8); + sub_cycles((int)(isa_timing * 8)); opl2_update2(opl); return opl_read(0, a); } @@ -55,7 +55,7 @@ uint8_t opl2_r_read(uint16_t a, void *priv) { opl_t *opl = (opl_t *)priv; - cycles -= ISA_CYCLES(8); + sub_cycles((int)(isa_timing * 8)); opl2_update2(opl); return opl_read(1, a); } @@ -71,7 +71,7 @@ uint8_t opl3_read(uint16_t a, void *priv) { opl_t *opl = (opl_t *)priv; - cycles -= ISA_CYCLES(8); + sub_cycles((int)(isa_timing * 8)); opl3_update2(opl); return opl_read(0, a); } @@ -111,58 +111,49 @@ void opl3_update2(opl_t *opl) } } -void ym3812_timer_set_0(void *param, int timer, int64_t period) +void ym3812_timer_set_0(void *param, int timer, uint64_t period) { opl_t *opl = (opl_t *)param; - opl->timers[0][timer] = period * TIMER_USEC * 20LL; - if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; - opl->timers_enable[0][timer] = period ? 1 : 0; + if (period) + timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); + else + timer_disable(&opl->timers[0][timer]); } -void ym3812_timer_set_1(void *param, int timer, int64_t period) +void ym3812_timer_set_1(void *param, int timer, uint64_t period) { opl_t *opl = (opl_t *)param; - opl->timers[1][timer] = period * TIMER_USEC * 20LL; - if (!opl->timers[1][timer]) opl->timers[1][timer] = 1; - opl->timers_enable[1][timer] = period ? 1 : 0; + if (period) + timer_set_delay_u64(&opl->timers[1][timer], period * TIMER_USEC * 20); + else + timer_disable(&opl->timers[1][timer]); } -void ymf262_timer_set(void *param, int timer, int64_t period) +void ymf262_timer_set(void *param, int timer, uint64_t period) { opl_t *opl = (opl_t *)param; - opl->timers[0][timer] = period * TIMER_USEC * 20LL; - if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; - opl->timers_enable[0][timer] = period ? 1 : 0; + if (period) + timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); + else + timer_disable(&opl->timers[0][timer]); } static void opl_timer_callback00(void *p) { - opl_t *opl = (opl_t *)p; - - opl->timers_enable[0][0] = 0; opl_timer_over(0, 0); } static void opl_timer_callback01(void *p) { - opl_t *opl = (opl_t *)p; - - opl->timers_enable[0][1] = 0; opl_timer_over(0, 1); } static void opl_timer_callback10(void *p) { - opl_t *opl = (opl_t *)p; - - opl->timers_enable[1][0] = 0; opl_timer_over(1, 0); } static void opl_timer_callback11(void *p) { - opl_t *opl = (opl_t *)p; - - opl->timers_enable[1][1] = 0; opl_timer_over(1, 1); } @@ -170,16 +161,16 @@ void opl2_init(opl_t *opl) { opl_init(ym3812_timer_set_0, opl, 0, 0); opl_init(ym3812_timer_set_1, opl, 1, 0); - timer_add(opl_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl); - timer_add(opl_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl); - timer_add(opl_timer_callback10, &opl->timers[1][0], &opl->timers_enable[1][0], (void *)opl); - timer_add(opl_timer_callback11, &opl->timers[1][1], &opl->timers_enable[1][1], (void *)opl); + 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_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl); - timer_add(opl_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl); + timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0); + timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0); } diff --git a/src/sound/snd_opl.h b/src/sound/snd_opl.h index e99f716f9..628d8b55f 100644 --- a/src/sound/snd_opl.h +++ b/src/sound/snd_opl.h @@ -5,8 +5,7 @@ typedef struct opl_t { int chip_nr[2]; - int64_t timers[2][2]; - int64_t timers_enable[2][2]; + pc_timer_t timers[2][2]; int16_t filtbuf[2]; diff --git a/src/sound/snd_pas16.c b/src/sound/snd_pas16.c index ce6451647..e10387df0 100644 --- a/src/sound/snd_pas16.c +++ b/src/sound/snd_pas16.c @@ -9,9 +9,9 @@ #include "../cpu/cpu.h" #include "../io.h" #include "../pic.h" +#include "../timer.h" #include "../pit.h" #include "../dma.h" -#include "../timer.h" #include "../device.h" #include "sound.h" #include "filters.h" @@ -128,6 +128,7 @@ typedef struct pas16_t { uint32_t l[3]; int64_t c[3]; + pc_timer_t timer[3]; uint8_t m[3]; uint8_t ctrl, ctrls[2]; int wp, rm[3], wm[3]; @@ -202,9 +203,7 @@ pas16_log(const char *fmt, ...) static uint8_t pas16_in(uint16_t port, void *p) { pas16_t *pas16 = (pas16_t *)p; - uint8_t temp; -/* if (CS == 0xCA53 && pc == 0x3AFC) - fatal("here");*/ + uint8_t temp = 0xff; switch ((port - pas16->base) + 0x388) { case 0x388: case 0x389: case 0x38a: case 0x38b: @@ -290,27 +289,15 @@ static uint8_t pas16_in(uint16_t port, void *p) case 0xff8b: /*Master mode read*/ temp = 0x20 | 0x10 | 0x01; /*AT bus, XT/AT timing*/ break; - - default: - temp = 0xff; - break; } -/* if (port != 0x388 && port != 0x389 && port != 0xb8b) */pas16_log("pas16_in : port %04X return %02X %04X:%04X\n", port, temp, CS,cpu_state.pc); -/* if (CS == 0x1FF4 && pc == 0x0585) - { - if (output) - fatal("here"); - output = 3; - }*/ + pas16_log("pas16_in : port %04X return %02X %04X:%04X\n", port, temp, CS,cpu_state.pc); return temp; } static void pas16_out(uint16_t port, uint8_t val, void *p) { pas16_t *pas16 = (pas16_t *)p; -/* if (port != 0x388 && port != 0x389) */pas16_log("pas16_out : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); -/* if (CS == 0x369 && pc == 0x2AC5) - fatal("here\n");*/ + pas16_log("pas16_out : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); switch ((port - pas16->base) + 0x388) { case 0x388: case 0x389: case 0x38a: case 0x38b: @@ -415,8 +402,6 @@ static void pas16_out(uint16_t port, uint8_t val, void *p) fatal("here\n"); output = 3; } -/* if (CS == 0x1FF4 && pc == 0x0431) - output = 3;*/ } static void pas16_pit_out(uint16_t port, uint8_t val, void *p) @@ -430,7 +415,7 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) { if (!(val & 0x20)) { - if (val & 2) pas16->pit.rl[0] = pas16->pit.c[0] / (PITCONST * (1 << TIMER_SHIFT)); + if (val & 2) pas16->pit.rl[0] = timer_get_remaining_u64(&pit.timer[0]) / PITCONST;; if (val & 4) pas16->pit.rl[1] = pas16->pit.c[1]; if (val & 8) pas16->pit.rl[2] = pas16->pit.c[2]; } @@ -440,16 +425,19 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) pas16->pit.ctrls[t] = pas16->pit.ctrl = val; if (t == 3) { - pas16_log("PAS16: bad PIT reg select\n"); + printf("Bad PIT reg select\n"); return; } if (!(pas16->pit.ctrl & 0x30)) { - pas16->pit.rl[t] = pas16->pit.c[t]; - if (!t) - pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT)); - if (pas16->pit.c[t] < 0) - pas16->pit.rl[t] = 0; + if (!t) + pas16->pit.rl[t] = timer_get_remaining_u64(&pit.timer[t]) / PITCONST; + else + { + pas16->pit.rl[t] = pas16->pit.c[t]; + if (pas16->pit.c[t] < 0) + pas16->pit.rl[t] = 0; + } pas16->pit.ctrl |= 0x30; pas16->pit.rereadlatch[t] = 0; pas16->pit.rm[t] = 3; @@ -463,9 +451,10 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) if (!pas16->pit.rm[t]) { pas16->pit.rm[t] = 3; - pas16->pit.rl[t] = pit.c[t]; - if (!t) - pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT)); + if (!t) + pas16->pit.rl[t] = timer_get_remaining_u64(&pit.timer[t]) / PITCONST; + else + pas16->pit.rl[t] = pas16->pit.c[t]; } pas16->pit.rereadlatch[t] = 1; } @@ -481,7 +470,7 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) pas16->pit.thit[t] = 0; pas16->pit.c[t] = pas16->pit.l[t]; if (!t) - pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); pas16->pit.enable[t] = 1; break; case 2: @@ -489,7 +478,7 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) pas16->pit.thit[t] = 0; pas16->pit.c[t] = pas16->pit.l[t]; if (!t) - pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); pas16->pit.enable[t] = 1; break; case 0: @@ -497,7 +486,7 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) pas16->pit.l[t] |= (val << 8); pas16->pit.c[t] = pas16->pit.l[t]; if (!t) - pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); pas16->pit.thit[t] = 0; pas16->pit.wm[t] = 3; pas16->pit.enable[t] = 1; @@ -513,7 +502,7 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) pas16->pit.l[t] |= 0x10000; pas16->pit.c[t] = pas16->pit.l[t]; if (!t) - pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); } break; } @@ -532,8 +521,8 @@ static uint8_t pas16_pit_in(uint16_t port, void *p) pas16->pit.rereadlatch[t] = 0; if (!t) { - pas16->pit.rl[t] = pas16->pit.c[t] / (PITCONST * (1 << TIMER_SHIFT)); - if ((pas16->pit.c[t] / (PITCONST * (1 << TIMER_SHIFT))) > 65536) + pas16->pit.rl[t] = timer_get_remaining_u64(&pit.timer[t]) / PITCONST; + if ((timer_get_remaining_u64(&pit.timer[t]) / PITCONST) > 65536) pas16->pit.rl[t] = 0xFFFF; } else @@ -585,13 +574,12 @@ static void pas16_pcm_poll(void *p) if (pas16->pit.m[0] & 2) { if (pas16->pit.l[0]) - pas16->pit.c[0] += (pas16->pit.l[0] * PITCONST * (1 << TIMER_SHIFT)); + timer_advance_u64(&pas16->pit.timer[0], pas16->pit.l[0] * PITCONST); else - pas16->pit.c[0] += (0x10000 * PITCONST * (1 << TIMER_SHIFT)); + timer_advance_u64(&pas16->pit.timer[0], 0x10000 * PITCONST); } else { - pas16->pit.c[0] = -1; pas16->pit.enable[0] = 0; } @@ -755,7 +743,7 @@ static void *pas16_init(const device_t *info) io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16); - timer_add(pas16_pcm_poll, &pas16->pit.c[0], &pas16->pit.enable[0], pas16); + timer_add(&pas16->pit.timer[0], pas16_pcm_poll, pas16, 0); sound_add_handler(pas16_get_buffer, pas16); diff --git a/src/sound/snd_pssj.c b/src/sound/snd_pssj.c index 1b6af8caf..8714c540c 100644 --- a/src/sound/snd_pssj.c +++ b/src/sound/snd_pssj.c @@ -25,8 +25,8 @@ typedef struct pssj_t int amplitude; int irq; - int64_t timer_count; - int64_t enable; + pc_timer_t timer_count; + int enable; int wave_pos; int pulse_width; @@ -49,7 +49,11 @@ static void pssj_write(uint16_t port, uint8_t val, void *p) { case 0: pssj->ctrl = val; + if (!pssj->enable && ((val & 4) && (pssj->ctrl & 3))) + timer_set_delay_u64(&pssj->timer_count, (TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400))); pssj->enable = (val & 4) && (pssj->ctrl & 3); + if (!pssj->enable) + timer_disable(&pssj->timer_count); sn74689_set_extra_divide(&pssj->sn76489, val & 0x40); if (!(val & 8)) pssj->irq = 0; @@ -168,7 +172,7 @@ static void pssj_callback(void *p) pssj->wave_pos = (pssj->wave_pos + 1) & 31; } - pssj->timer_count += (int64_t)(TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400)); + timer_advance_u64(&pssj->timer_count, (TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400))); } static void pssj_get_buffer(int32_t *buffer, int len, void *p) @@ -192,7 +196,7 @@ void *pssj_init(const device_t *info) sn76489_init(&pssj->sn76489, 0x00c0, 0x0004, PSSJ, 3579545); io_sethandler(0x00C4, 0x0004, pssj_read, NULL, NULL, pssj_write, NULL, NULL, pssj); - timer_add(pssj_callback, &pssj->timer_count, &pssj->enable, pssj); + timer_add(&pssj->timer_count, pssj_callback, pssj, pssj->enable); sound_add_handler(pssj_get_buffer, pssj); return pssj; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 3c6083771..66fe11520 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -26,6 +26,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mca.h" #include "../mem.h" #include "../rom.h" @@ -518,8 +519,8 @@ void sb_ct1335_mixer_write(uint16_t addr, uint8_t val, void *p) mixer->cd = sb_att_4dbstep_3bits[(mixer->regs[0x08] >> 1)&0x7]; mixer->voice = sb_att_7dbstep_2bits[(mixer->regs[0x0A] >> 1)&0x3]; - sound_set_cd_volume(((uint32_t)mixer->master * (uint32_t)mixer->cd * 4) / 65535, - ((uint32_t)mixer->master * (uint32_t)mixer->cd * 4) / 65535); + sound_set_cd_volume(((uint32_t)mixer->master * (uint32_t)mixer->cd) / 65535, + ((uint32_t)mixer->master * (uint32_t)mixer->cd) / 65535); } } @@ -639,8 +640,8 @@ void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p) } /* TODO: pcspeaker volume? Or is it not worth? */ - sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l * 4) / 65535, - ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r * 4) / 65535); + sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, + ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); } } @@ -805,8 +806,8 @@ void sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *p) mixer->treble_r = mixer->regs[0x45] >> 4; /*TODO: pcspeaker volume, with "output_selector" check? or better not? */ - sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l * 4) / 65535, - ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r * 4) / 65535); + sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, + ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); sb_log("sb_ct1745: Received register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); } } @@ -963,6 +964,14 @@ void sb_mcv_write(int port, uint8_t val, void *p) } } +uint8_t sb_mcv_feedb(void *p) +{ + sb_t *sb = (sb_t *)p; + + return (sb->pos_regs[2] & 1); +} + + static int sb_pro_mcv_irqs[4] = {7, 5, 3, 3}; uint8_t sb_pro_mcv_read(int port, void *p) @@ -1079,7 +1088,7 @@ void *sb_mcv_init() sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); sound_add_handler(sb_get_buffer_sb2, sb); /* I/O handlers activated in sb_mcv_write */ - mca_add(sb_mcv_read, sb_mcv_write, sb); + mca_add(sb_mcv_read, sb_mcv_write, sb_mcv_feedb, sb); sb->pos_regs[0] = 0x84; sb->pos_regs[1] = 0x50; return sb; @@ -1215,7 +1224,7 @@ void *sb_pro_mcv_init() sound_add_handler(sb_get_buffer_sbpro, sb); /* I/O handlers activated in sb_pro_mcv_write */ - mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb); + mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb_mcv_feedb, sb); sb->pos_regs[0] = 0x03; sb->pos_regs[1] = 0x51; diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index feb3581f9..a5f36886e 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -182,7 +182,9 @@ void sb_irqc(sb_dsp_t *dsp, int irq8) void sb_dsp_reset(sb_dsp_t *dsp) { - dsp->sbenable = dsp->sb_enable_i = 0; + timer_disable(&dsp->output_timer); + timer_disable(&dsp->input_timer); + dsp->sb_command = 0; dsp->sb_8_length = 0xffff; @@ -199,7 +201,6 @@ void sb_dsp_reset(sb_dsp_t *dsp) dsp->sbe2count = 0; dsp->sbreset = 0; - dsp->sbenable = dsp->sb_enable_i = dsp->sb_count_i = 0; dsp->record_pos_read=0; dsp->record_pos_write=SB_DSP_REC_SAFEFTY_MARGIN; @@ -226,15 +227,15 @@ void sb_doreset(sb_dsp_t *dsp) void sb_dsp_speed_changed(sb_dsp_t *dsp) { - if (dsp->sb_timeo < 256LL) - dsp->sblatcho = TIMER_USEC * (256LL - dsp->sb_timeo); + if (dsp->sb_timeo < 256) + dsp->sblatcho = TIMER_USEC * (256 - dsp->sb_timeo); else - dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256LL))); + dsp->sblatcho = (uint64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256))); - if (dsp->sb_timei < 256LL) - dsp->sblatchi = TIMER_USEC * (256LL - dsp->sb_timei); + if (dsp->sb_timei < 256) + dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_timei); else - dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256LL))); + dsp->sblatchi = (uint64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256))); } void sb_add_data(sb_dsp_t *dsp, uint8_t v) @@ -249,7 +250,7 @@ void sb_add_data(sb_dsp_t *dsp, uint8_t v) void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) { - dsp->sb_pausetime = -1LL; + dsp->sb_pausetime = -1; if (dma8) { dsp->sb_8_length = len; @@ -259,9 +260,8 @@ void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len dsp->sb_8_enable = 1; if (dsp->sb_16_enable && dsp->sb_16_output) dsp->sb_16_enable = 0; dsp->sb_8_output = 1; - timer_process(); - dsp->sbenable = dsp->sb_8_enable; - timer_update_outstanding(); + if (!timer_is_enabled(&dsp->output_timer)) + timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); dsp->sbleftright = 0; dsp->sbdacpos = 0; } @@ -274,9 +274,8 @@ void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len dsp->sb_16_enable = 1; if (dsp->sb_8_enable && dsp->sb_8_output) dsp->sb_8_enable = 0; dsp->sb_16_output = 1; - timer_process(); - dsp->sbenable = dsp->sb_16_enable; - timer_update_outstanding(); + if (!timer_is_enabled(&dsp->output_timer)) + timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); } } @@ -291,9 +290,8 @@ void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int l dsp->sb_8_enable = 1; if (dsp->sb_16_enable && !dsp->sb_16_output) dsp->sb_16_enable = 0; dsp->sb_8_output = 0; - timer_process(); - dsp->sb_enable_i = dsp->sb_8_enable; - timer_update_outstanding(); + if (!timer_is_enabled(&dsp->input_timer)) + timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); } else { @@ -304,9 +302,8 @@ void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int l dsp->sb_16_enable = 1; if (dsp->sb_8_enable && !dsp->sb_8_output) dsp->sb_8_enable = 0; dsp->sb_16_output = 0; - timer_process(); - dsp->sb_enable_i = dsp->sb_16_enable; - timer_update_outstanding(); + if (!timer_is_enabled(&dsp->input_timer)) + timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); } memset(dsp->record_buffer,0,sizeof(dsp->record_buffer)); } @@ -387,15 +384,13 @@ void sb_exec_command(sb_dsp_t *dsp) sb_add_data(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8) ^0x80); /*Due to the current implementation, I need to emulate a samplerate, even if this * mode does not imply such samplerate. Position is increased in sb_poll_i*/ - if (dsp->sb_enable_i==0) + if (!timer_is_enabled(&dsp->input_timer)) { - dsp->sb_timei = 256LL - 22LL; - dsp->sblatchi = TIMER_USEC * 22LL; + dsp->sb_timei = 256 - 22; + dsp->sblatchi = TIMER_USEC * 22; temp = 1000000 / 22; dsp->sb_freq = temp; - timer_process(); - dsp->sb_enable_i = 1; - timer_update_outstanding(); + timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); } break; case 0x24: /*8-bit single cycle DMA input*/ @@ -435,7 +430,7 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x41: /*Set output sampling rate*/ case 0x42: /*Set input sampling rate*/ if (dsp->sb_type < SB16) break; - dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); + dsp->sblatcho = (uint64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); 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); @@ -482,9 +477,8 @@ void sb_exec_command(sb_dsp_t *dsp) break; case 0x80: /*Pause DAC*/ dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8); - timer_process(); - dsp->sbenable = 1; - timer_update_outstanding(); + 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; @@ -673,10 +667,7 @@ void sb_write(uint16_t a, uint8_t v, void *priv) dsp->onebyte_midi = 0; return; } - timer_process(); - dsp->wb_time = TIMER_USEC * 1LL; - dsp->wb_full = 1LL; - timer_update_outstanding(); + 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); @@ -727,7 +718,7 @@ uint8_t sb_read(uint16_t a, void *priv) dsp->busy_count = 0; if (dsp->wb_full || (dsp->busy_count & 2)) { - dsp->wb_full = dsp->wb_time; + dsp->wb_full = timer_is_enabled(&dsp->wb_timer); return 0xff; } return 0x7f; @@ -745,9 +736,6 @@ uint8_t sb_read(uint16_t a, void *priv) static void sb_wb_clear(void *p) { - sb_dsp_t *dsp = (sb_dsp_t *)p; - - dsp->wb_time = 0LL; } void sb_dsp_set_mpu(mpu_t *src_mpu) @@ -763,13 +751,13 @@ void sb_dsp_init(sb_dsp_t *dsp, int type) dsp->sb_irqnum = 7; dsp->sb_8_dmanum = 1; dsp->sb_16_dmanum = 5; - mpu = NULL; + mpu = NULL; sb_doreset(dsp); - timer_add(pollsb, &dsp->sbcount, &dsp->sbenable, dsp); - timer_add(sb_poll_i, &dsp->sb_count_i, &dsp->sb_enable_i, dsp); - timer_add(sb_wb_clear, &dsp->wb_time, &dsp->wb_time, dsp); + timer_add(&dsp->output_timer, pollsb, dsp, 0); + timer_add(&dsp->input_timer, sb_poll_i, dsp, 0); + timer_add(&dsp->wb_timer, sb_wb_clear, dsp, 0); /*Initialise SB16 filter to same cutoff as 8-bit SBs (3.2 kHz). This will be recalculated when a set frequency command is sent.*/ @@ -800,7 +788,7 @@ void pollsb(void *p) sb_dsp_t *dsp = (sb_dsp_t *)p; int tempi,ref; - dsp->sbcount += dsp->sblatcho; + timer_advance_u64(&dsp->output_timer, dsp->sblatcho); if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output) { int data[2]; @@ -962,8 +950,12 @@ void pollsb(void *p) if (dsp->sb_8_length < 0) { - if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; - else dsp->sb_8_enable = dsp->sbenable=0; + if (dsp->sb_8_autoinit) + dsp->sb_8_length = dsp->sb_8_autolen; + else { + dsp->sb_8_enable = 0; + timer_disable(&dsp->output_timer); + } sb_irq(dsp, 1); } } @@ -1013,17 +1005,21 @@ void pollsb(void *p) { sb_dsp_log("16DMA over %i\n",dsp->sb_16_autoinit); if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; - else dsp->sb_16_enable = dsp->sbenable = 0; + else { + dsp->sb_16_enable = 0; + timer_disable(&dsp->output_timer); + } sb_irq(dsp, 0); } } - if (dsp->sb_pausetime > -1LL) + if (dsp->sb_pausetime > -1) { dsp->sb_pausetime--; - if (dsp->sb_pausetime < 0LL) + if (dsp->sb_pausetime < 0) { sb_irq(dsp, 1); - dsp->sbenable = dsp->sb_8_enable; + if (!dsp->sb_8_enable) + timer_disable(&dsp->output_timer); sb_dsp_log("SB pause over\n"); } } @@ -1033,7 +1029,7 @@ void sb_poll_i(void *p) { sb_dsp_t *dsp = (sb_dsp_t *)p; int processed=0; - dsp->sb_count_i += dsp->sblatchi; + 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) @@ -1068,8 +1064,12 @@ void sb_poll_i(void *p) if (dsp->sb_8_length < 0) { - if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; - else dsp->sb_8_enable = dsp->sb_enable_i = 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; @@ -1112,8 +1112,12 @@ void sb_poll_i(void *p) if (dsp->sb_16_length < 0) { - if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; - else dsp->sb_16_enable = dsp->sb_enable_i = 0; + 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; diff --git a/src/sound/snd_sb_dsp.h b/src/sound/snd_sb_dsp.h index e4587c529..2772e2254 100644 --- a/src/sound/snd_sb_dsp.h +++ b/src/sound/snd_sb_dsp.h @@ -6,7 +6,7 @@ typedef struct sb_dsp_t int sb_8_dmanum; int sb_16_length, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output; int sb_16_dmanum; - int64_t sb_pausetime; + int sb_pausetime; uint8_t sb_read_data[256]; int sb_read_wp, sb_read_rp; @@ -42,17 +42,17 @@ typedef struct sb_dsp_t uint8_t sbreaddat; uint8_t sb_command; uint8_t sb_test; - int64_t sb_timei, sb_timeo; + int sb_timei, sb_timeo; int sb_irq8, sb_irq16; uint8_t sb_asp_regs[256]; - int64_t sbenable, sb_enable_i; + int sbenable, sb_enable_i; - int64_t sbcount, sb_count_i; + pc_timer_t output_timer, input_timer; - int64_t sblatcho, sblatchi; + uint64_t sblatcho, sblatchi; uint16_t sb_addr; @@ -60,7 +60,8 @@ typedef struct sb_dsp_t int asp_data_len; - int64_t wb_time, wb_full; + pc_timer_t wb_timer; + int wb_full; int busy_count; diff --git a/src/sound/snd_speaker.c b/src/sound/snd_speaker.c index 6ddb772a9..9c40d5e89 100644 --- a/src/sound/snd_speaker.c +++ b/src/sound/snd_speaker.c @@ -3,6 +3,7 @@ #include #include #include "../86box.h" +#include "../timer.h" #include "../pit.h" #include "sound.h" #include "snd_speaker.h" @@ -45,16 +46,19 @@ speaker_update(void) } -static void +void speaker_get_buffer(int32_t *buffer, int len, void *p) { - int c; + int32_t c, val; speaker_update(); if (!speaker_mute) { - for (c = 0; c < len * 2; c++) - buffer[c] += speaker_buffer[c >> 1]; + for (c = 0; c < len * 2; c += 2) { + val = speaker_buffer[c >> 1]; + buffer[c] += val; + buffer[c + 1] += val; + } } speaker_pos = 0; diff --git a/src/sound/snd_wss.c b/src/sound/snd_wss.c index 3a7be52b6..838547997 100644 --- a/src/sound/snd_wss.c +++ b/src/sound/snd_wss.c @@ -24,6 +24,7 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mca.h" #include "../pic.h" #include "../dma.h" @@ -150,11 +151,18 @@ static void ncr_audio_mca_write(int port, uint8_t val, void *p) if (wss->opl_enabled) io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); - io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); - io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + io_sethandler(addr, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_sethandler(addr+4, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); } } +static uint8_t ncr_audio_mca_feedb(void *p) +{ + wss_t *wss = (wss_t *)p; + + return (wss->pos_regs[2] & 1); +} + void *ncr_audio_init(const device_t *info) { wss_t *wss = malloc(sizeof(wss_t)); @@ -164,14 +172,14 @@ void *ncr_audio_init(const device_t *info) opl3_init(&wss->opl); ad1848_init(&wss->ad1848); - ad1848_setirq(&wss->ad1848, 7); - ad1848_setdma(&wss->ad1848, 3); + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); - mca_add(ncr_audio_mca_read, ncr_audio_mca_write, wss); + mca_add(ncr_audio_mca_read, ncr_audio_mca_write, ncr_audio_mca_feedb, wss); wss->pos_regs[0] = 0x16; wss->pos_regs[1] = 0x51; - sound_add_handler(wss_get_buffer, wss); + sound_add_handler(wss_get_buffer, wss); return wss; } diff --git a/src/sound/sound.c b/src/sound/sound.c index 5f0cd3373..12875f4f1 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -74,7 +74,8 @@ static int32_t *outbuffer; static float *outbuffer_ex; static int16_t *outbuffer_ex_int16; static int sound_handlers_num; -static int64_t sound_poll_time = 0LL, sound_poll_latch; +static pc_timer_t sound_poll_timer; +static uint64_t sound_poll_latch; static int16_t cd_buffer[CDROM_NUM][CD_BUFLEN * 2]; static float cd_out_buffer[CD_BUFLEN * 2]; @@ -261,6 +262,7 @@ sound_cd_thread(void *param) /*Apply ATAPI channel select*/ cd_buffer_temp[0] = cd_buffer_temp[1] = 0.0; +#if 0 if (channel_select[0] & 1) cd_buffer_temp[0] += ((float) cd_buffer[i][c]) * audio_vol_l; if (channel_select[0] & 2) @@ -269,6 +271,25 @@ sound_cd_thread(void *param) cd_buffer_temp[0] += ((float) cd_buffer[i][c + 1]) * audio_vol_r; if (channel_select[1] & 2) cd_buffer_temp[1] += ((float) cd_buffer[i][c + 1]) * audio_vol_r; +#else + if ((audio_vol_l != 0.0) && (channel_select[0] != 0)) { + if (channel_select[0] & 1) + cd_buffer_temp[0] += ((float) cd_buffer[i][c]); /* Channel 0 => Port 0 */ + if (channel_select[0] & 2) + cd_buffer_temp[0] += ((float) cd_buffer[i][c + 1]); /* Channel 1 => Port 0 */ + + cd_buffer_temp[0] *= audio_vol_l; /* Multiply Port 0 by Port 0 volume */ + } + + if ((audio_vol_r != 0.0) && (channel_select[1] != 0)) { + if (channel_select[1] & 1) + cd_buffer_temp[1] += ((float) cd_buffer[i][c]); /* Channel 0 => Port 1 */ + if (channel_select[1] & 2) + cd_buffer_temp[1] += ((float) cd_buffer[i][c + 1]); /* Channel 1 => Port 1 */ + + cd_buffer_temp[1] *= audio_vol_r; /* Multiply Port 1 by Port 1 volume */ + } +#endif /*Apply sound card CD volume*/ cd_buffer_temp[0] *= ((float) cd_vol_l) / 65535.0; @@ -364,7 +385,7 @@ sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p void sound_poll(void *priv) { - sound_poll_time += sound_poll_latch; + timer_advance_u64(&sound_poll_timer, sound_poll_latch); midi_poll(); @@ -411,7 +432,7 @@ sound_poll(void *priv) void sound_speed_changed(void) { - sound_poll_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / 48000.0)); + sound_poll_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / 48000.0)); } @@ -423,7 +444,7 @@ sound_reset(void) midi_device_init(); inital(); - timer_add(sound_poll, &sound_poll_time, TIMER_ALWAYS_ENABLED, NULL); + timer_add(&sound_poll_timer, sound_poll, NULL, 1); sound_handlers_num = 0; @@ -499,6 +520,4 @@ sound_cd_thread_reset(void) sound_cd_thread_end(); cd_thread_enable = available_cdrom_drives ? 1 : 0; - - secondary_ide_check(); } diff --git a/src/timer.c b/src/timer.c index 02d5a1bd2..600b28c06 100644 --- a/src/timer.c +++ b/src/timer.c @@ -6,132 +6,242 @@ #include "timer.h" -#define TIMERS_MAX 64 +uint64_t TIMER_USEC; +uint32_t timer_target; + +/*Enabled timers are stored in a linked list, with the first timer to expire at + the head.*/ +static pc_timer_t *timer_head = NULL; + +/* Are we initialized? */ +static int timer_inited = 0; -static struct +void +timer_enable(pc_timer_t *timer) { - int64_t present; - void (*callback)(void *priv); - void *priv; - int64_t *enable; - int64_t *count; -} timers[TIMERS_MAX]; + pc_timer_t *timer_node = timer_head; + if (!timer_inited || (timer == NULL)) + return; -int64_t TIMER_USEC; -int64_t timers_present = 0; -int64_t timer_one = 1; - -int64_t timer_count = 0, timer_latch = 0; -int64_t timer_start = 0; + if (timer->flags & TIMER_ENABLED) + timer_disable(timer); + if (timer->next || timer->prev) + fatal("timer_enable - timer->next\n"); -void timer_process(void) -{ - int64_t c; - int64_t process = 0; - /*Get actual elapsed time*/ - int64_t diff = timer_latch - timer_count; - int64_t enable[TIMERS_MAX]; + timer->flags |= TIMER_ENABLED; - timer_latch = 0; + /*List currently empty - add to head*/ + if (!timer_head) { + timer_head = timer; + timer->next = timer->prev = NULL; +#if 0 + timer_target = timer_head->ts_integer; +#else + timer_target = timer_head->ts.ts32.integer; +#endif + return; + } - for (c = 0; c < timers_present; c++) - { - /* This is needed to avoid timer crashes on hard reset. */ - if ((timers[c].enable == NULL) || (timers[c].count == NULL)) - { - continue; + timer_node = timer_head; + + while(1) { + /*Timer expires before timer_node. Add to list in front of timer_node*/ + if (TIMER_LESS_THAN(timer, timer_node)) { + timer->next = timer_node; + timer->prev = timer_node->prev; + timer_node->prev = timer; + if (timer->prev) + timer->prev->next = timer; + else { + timer_head = timer; +#if 0 + timer_target = timer_head->ts_integer; +#else + timer_target = timer_head->ts.ts32.integer; +#endif } - enable[c] = *timers[c].enable; - if (*timers[c].enable) - { - *timers[c].count = *timers[c].count - diff; - if (*timers[c].count <= 0) - process = 1; - } - } - - if (!process) - return; - - while (1) - { - int64_t lowest = 1, lowest_c; - - for (c = 0; c < timers_present; c++) - { - if (enable[c]) - { - if (*timers[c].count < lowest) - { - lowest = *timers[c].count; - lowest_c = c; - } - } - } - - if (lowest > 0) - break; - - timers[lowest_c].callback(timers[lowest_c].priv); - enable[lowest_c] = *timers[lowest_c].enable; - } -} - - -void timer_update_outstanding(void) -{ - int64_t c; - timer_latch = 0x7fffffffffffffff; - for (c = 0; c < timers_present; c++) - { - if (*timers[c].enable && *timers[c].count < timer_latch) - timer_latch = *timers[c].count; + return; } - timer_count = timer_latch = (timer_latch + ((1 << TIMER_SHIFT) - 1)); -} - -void timer_reset(void) -{ - timers_present = 0; - timer_latch = timer_count = 0; -} - - -int64_t timer_add(void (*callback)(void *priv), int64_t *count, int64_t *enable, void *priv) -{ - int64_t i = 0; - - if (timers_present < TIMERS_MAX) - { - if (timers_present != 0) - { - /* This is the sanity check - it goes through all present timers and makes sure we're not adding a timer that already exists. */ - for (i = 0; i < timers_present; i++) - { - if (timers[i].present && (timers[i].callback == callback) && (timers[i].priv == priv) && (timers[i].count == count) && (timers[i].enable == enable)) - { - return 0; - } - } - } - - timers[timers_present].present = 1; - timers[timers_present].callback = callback; - timers[timers_present].priv = priv; - timers[timers_present].count = count; - timers[timers_present].enable = enable; - timers_present++; - return timers_present - 1; + /*timer_node is last in the list. Add timer to end of list*/ + if (!timer_node->next) { + timer_node->next = timer; + timer->prev = timer_node; + return; } - return -1; + + timer_node = timer_node->next; + } } -void timer_set_callback(int64_t timer, void (*callback)(void *priv)) +void +timer_disable(pc_timer_t *timer) { - timers[timer].callback = callback; + if (!timer_inited || (timer == NULL) || !(timer->flags & TIMER_ENABLED)) + return; + + if (!timer->next && !timer->prev && timer != timer_head) + fatal("timer_disable - !timer->next\n"); + + timer->flags &= ~TIMER_ENABLED; + + if (timer->prev) + timer->prev->next = timer->next; + else + timer_head = timer->next; + if (timer->next) + timer->next->prev = timer->prev; + timer->prev = timer->next = NULL; +} + + +static void +timer_remove_head(void) +{ + pc_timer_t *timer; + + if (!timer_inited) + return; + + if (timer_head) { + timer = timer_head; + timer_head = timer->next; + if (timer_head) + timer_head->prev = NULL; + timer->next = timer->prev = NULL; + timer->flags &= ~TIMER_ENABLED; + } +} + + +void +timer_process(void) +{ + pc_timer_t *timer; + + if (!timer_inited || !timer_head) + return; + + while(1) { + timer = timer_head; + + if (!TIMER_LESS_THAN_VAL(timer, (uint32_t)tsc)) + break; + + timer_remove_head(); + + if (timer->flags & TIMER_SPLIT) + timer_advance_ex(timer, 0); /* We're splitting a > 1 s period into multiple <= 1 s periods. */ + else if (timer->callback != NULL) /* Make sure it's no NULL, so that we can have a NULL callback when no operation is needed. */ + timer->callback(timer->p); + } + +#if 0 + timer_target = timer_head->ts_integer; +#else + timer_target = timer_head->ts.ts32.integer; +#endif +} + + +void +timer_close(void) +{ + timer_head = NULL; + + timer_inited = 0; +} + + +void +timer_init(void) +{ + timer_target = 0ULL; + tsc = 0; + + timer_inited = 1; +} + + +void +timer_add(pc_timer_t *timer, void (*callback)(void *p), void *p, int start_timer) +{ + memset(timer, 0, sizeof(pc_timer_t)); + + timer->callback = callback; + timer->p = p; + timer->flags = 0; + timer->prev = timer->next = NULL; + if (start_timer) + timer_set_delay_u64(timer, 0); +} + + +/* The API for big timer periods starts here. */ +void +timer_stop(pc_timer_t *timer) +{ + if (!timer_inited || (timer == NULL)) + return; + + timer->period = 0.0; + timer_disable(timer); + timer->flags &= ~TIMER_SPLIT; +} + + +static void +timer_do_period(pc_timer_t *timer, uint64_t period, int start) +{ + if (!timer_inited || (timer == NULL)) + return; + + if (start) + timer_set_delay_u64(timer, period); + else + timer_advance_u64(timer, period); +} + + +void +timer_advance_ex(pc_timer_t *timer, int start) +{ + if (!timer_inited || (timer == NULL)) + return; + + if (timer->period > MAX_USEC) { + timer_do_period(timer, MAX_USEC64 * TIMER_USEC, start); + timer->period -= MAX_USEC; + timer->flags |= TIMER_SPLIT; + } else { + if (timer->period > 0.0) + timer_do_period(timer, (uint64_t) (timer->period * ((double) TIMER_USEC)), start); + timer->period = 0.0; + timer->flags &= ~TIMER_SPLIT; + } +} + + +void +timer_on(pc_timer_t *timer, double period, int start) +{ + if (!timer_inited || (timer == NULL)) + return; + + timer->period = period; + timer_advance_ex(timer, start); +} + + +void +timer_on_auto(pc_timer_t *timer, double period) +{ + if (!timer_inited || (timer == NULL)) + return; + + timer_on(timer, period, (timer->period == 0.0)); } diff --git a/src/timer.h b/src/timer.h index 5806a4b6b..9941c3fdd 100644 --- a/src/timer.h +++ b/src/timer.h @@ -1,57 +1,228 @@ #ifndef _TIMER_H_ #define _TIMER_H_ +#include "cpu/cpu.h" -extern int64_t timer_start; +/* Maximum period, currently 1 second. */ +#define MAX_USEC64 1000000ULL +#define MAX_USEC 1000000.0 -#define timer_start_period(cycles) \ - timer_start = cycles; +#define TIMER_SPLIT 2 +#define TIMER_ENABLED 1 -#define timer_end_period(cycles) \ - do \ - { \ - int64_t diff = timer_start - (cycles); \ - timer_count -= diff; \ - timer_start = cycles; \ - if (timer_count <= 0) \ - { \ - timer_process(); \ - timer_update_outstanding(); \ - } \ - } while (0) -#define timer_clock() \ - do \ - { \ - int64_t diff; \ - if (AT) \ - { \ - diff = timer_start - (cycles << TIMER_SHIFT); \ - timer_start = cycles << TIMER_SHIFT; \ - } \ - else \ - { \ - diff = timer_start - (cycles * xt_cpu_multi); \ - timer_start = cycles * xt_cpu_multi; \ - } \ - timer_count -= diff; \ - timer_process(); \ - timer_update_outstanding(); \ - } while (0) +#pragma pack(push,1) +typedef struct +{ + uint32_t frac; + uint32_t integer; +} ts_struct_t; +#pragma pack(pop) -extern void timer_process(void); -extern void timer_update_outstanding(void); -extern void timer_reset(void); -extern int64_t timer_add(void (*callback)(void *priv), int64_t *count, int64_t *enable, void *priv); -extern void timer_set_callback(int64_t timer, void (*callback)(void *priv)); +typedef union +{ + uint64_t ts64; + ts_struct_t ts32; +} ts_t; -#define TIMER_ALWAYS_ENABLED &timer_one -extern int64_t timer_count; -extern int64_t timer_one; +/*Timers are based on the CPU Time Stamp Counter. Timer timestamps are in a + 32:32 fixed point format, with the integer part compared against the TSC. The + fractional part is used when advancing the timestamp to ensure a more accurate + period. + + As the timer only stores 32 bits of integer timestamp, and the TSC is 64 bits, + the timer period can only be at most 0x7fffffff CPU cycles. To allow room for + (optimistic) CPU frequency growth, timer period must be at most 1 second. -#define TIMER_SHIFT 6 + When a timer callback is called, the timer has been disabled. If the timer is + to repeat, the callback must call timer_advance_u64(). This is a change from + the old timer API.*/ +typedef struct pc_timer_t +{ +#ifdef USE_PCEM_TIMER + uint32_t ts_integer; + uint32_t ts_frac; +#else + ts_t ts; +#endif + int flags, pad; /* The flags are defined above. */ + double period; /* This is used for large period timers to count + the microseconds and split the period. */ -extern int64_t TIMER_USEC; + void (*callback)(void *p); + void *p; + + struct pc_timer_t *prev, *next; +} pc_timer_t; + +/*Timestamp of nearest enabled timer. CPU emulation must call timer_process() + when TSC matches or exceeds this.*/ +extern uint32_t timer_target; + +/*Enable timer, without updating timestamp*/ +extern void timer_enable(pc_timer_t *timer); +/*Disable timer*/ +extern void timer_disable(pc_timer_t *timer); + +/*Process any pending timers*/ +extern void timer_process(void); + +/*Reset timer system*/ +extern void timer_close(void); +extern void timer_init(void); + +/*Add new timer. If start_timer is set, timer will be enabled with a zero + timestamp - this is useful for permanently enabled timers*/ +extern void timer_add(pc_timer_t *timer, void (*callback)(void *p), void *p, int start_timer); + +/*1us in 32:32 format*/ +extern uint64_t TIMER_USEC; + +/*True if timer a expires before timer b*/ +#if 0 +#define TIMER_LESS_THAN(a, b) ((int32_t)((a)->ts_integer - (b)->ts_integer) <= 0) +#else +#define TIMER_LESS_THAN(a, b) ((int64_t)((a)->ts.ts64 - (b)->ts.ts64) <= 0) +#endif +/*True if timer a expires before 32 bit integer timestamp b*/ +#if 0 +#define TIMER_LESS_THAN_VAL(a, b) ((int32_t)((a)->ts_integer - (b)) <= 0) +#else +#define TIMER_LESS_THAN_VAL(a, b) ((int32_t)((a)->ts.ts32.integer - (b)) <= 0) +#endif +/*True if 32 bit integer timestamp a expires before 32 bit integer timestamp b*/ +#define TIMER_VAL_LESS_THAN_VAL(a, b) ((int32_t)((a) - (b)) <= 0) + + +/*Advance timer by delay, specified in 32:32 format. This should be used to + resume a recurring timer in a callback routine*/ +static __inline void +timer_advance_u64(pc_timer_t *timer, uint64_t delay) +{ +#if 0 + uint32_t int_delay = delay >> 32; + uint32_t frac_delay = delay & 0xffffffff; + + if ((frac_delay + timer->ts_frac) < frac_delay) + timer->ts_integer++; + timer->ts_frac += frac_delay; + timer->ts_integer += int_delay; +#else + timer->ts.ts64 += delay; +#endif + + timer_enable(timer); +} + + +/*Set a timer to the given delay, specified in 32:32 format. This should be used + when starting a timer*/ +static __inline void +timer_set_delay_u64(pc_timer_t *timer, uint64_t delay) +{ +#if 0 + uint32_t int_delay = delay >> 32; + uint32_t frac_delay = delay & 0xffffffff; + + timer->ts_frac = frac_delay; + timer->ts_integer = int_delay + (uint32_t)tsc; +#else + timer->ts.ts64 = 0ULL; + timer->ts.ts32.integer = tsc; + timer->ts.ts64 += delay; +#endif + + timer_enable(timer); +} + + +/*True if timer currently enabled*/ +static __inline int +timer_is_enabled(pc_timer_t *timer) +{ + return !!(timer->flags & TIMER_ENABLED); +} + + +/*Return integer timestamp of timer*/ +static __inline uint32_t +timer_get_ts_int(pc_timer_t *timer) +{ +#if 0 + return timer->ts_integer; +#else + return timer->ts.ts32.integer; +#endif +} + + +/*Return remaining time before timer expires, in us. If the timer has already + expired then return 0*/ +static __inline uint32_t +timer_get_remaining_us(pc_timer_t *timer) +{ + int64_t remaining; + + if (timer->flags & TIMER_ENABLED) { +#if 0 + remaining = (((uint64_t)timer->ts_integer << 32) | timer->ts_frac) - (tsc << 32); +#else + remaining = (int64_t) (timer->ts.ts64 - (uint64_t)(tsc << 32)); +#endif + + if (remaining < 0) + return 0; + return remaining / TIMER_USEC; + } + + return 0; +} + + +/*Return remaining time before timer expires, in 32:32 timestamp format. If the + timer has already expired then return 0*/ +static __inline uint64_t +timer_get_remaining_u64(pc_timer_t *timer) +{ + int64_t remaining; + + if (timer->flags & TIMER_ENABLED) { +#if 0 + remaining = (((uint64_t)timer->ts_integer << 32) | timer->ts_frac) - (tsc << 32); +#else + remaining = (int64_t) (timer->ts.ts64 - (uint64_t)(tsc << 32)); +#endif + + if (remaining < 0) + return 0; + return remaining; + } + + return 0; +} + + +/*Set timer callback function*/ +static __inline void +timer_set_callback(pc_timer_t *timer, void (*callback)(void *p)) +{ + timer->callback = callback; +} + + +/*Set timer private data*/ +static __inline void +timer_set_p(pc_timer_t *timer, void *p) +{ + timer->p = p; +} + + +/* The API for big timer periods starts here. */ +extern void timer_stop(pc_timer_t *timer); +extern void timer_advance_ex(pc_timer_t *timer, int start); +extern void timer_on(pc_timer_t *timer, double period, int start); +extern void timer_on_auto(pc_timer_t *timer, double period); #endif /*_TIMER_H_*/ diff --git a/src/ui.h b/src/ui.h index 19ae2ca3d..efe64800f 100644 --- a/src/ui.h +++ b/src/ui.h @@ -58,6 +58,7 @@ extern void ui_sb_update_panes(void); extern void ui_sb_update_tip(int meaning); extern void ui_sb_check_menu_item(int tag, int id, int chk); extern void ui_sb_enable_menu_item(int tag, int id, int val); +extern void ui_sb_timer_callback(int pane); extern void ui_sb_update_icon(int tag, int val); extern void ui_sb_update_icon_state(int tag, int active); extern void ui_sb_set_text_w(wchar_t *wstr); diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index 3a59a8999..648772c77 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -26,6 +26,7 @@ #include "../mem.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "video.h" #include "vid_ati18800.h" #include "vid_ati_eeprom.h" diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index 4850d13c4..a37f65033 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -8,7 +8,7 @@ * * ATI 28800 emulation (VGA Charger and Korean VGA) * - * Version: @(#)vid_ati28800.c 1.0.26 2018/10/18 + * Version: @(#)vid_ati28800.c 1.0.27 2019/05/17 * * Authors: Sarah Walker, * Miran Grca, @@ -30,6 +30,7 @@ #include "../mem.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "video.h" #include "vid_ati28800.h" #include "vid_ati_eeprom.h" @@ -59,26 +60,28 @@ typedef struct ati28800_t { - svga_t svga; - ati_eeprom_t eeprom; - - rom_t bios_rom; - - uint8_t regs[256]; - int index; - - uint32_t memory; - uint8_t id; + svga_t svga; + ati_eeprom_t eeprom; - uint8_t port_03dd_val; - uint16_t get_korean_font_kind; - int in_get_korean_font_kind_set; - int get_korean_font_enabled; - int get_korean_font_index; - uint16_t get_korean_font_base; - int ksc5601_mode_enabled; + rom_t bios_rom; + + uint8_t regs[256]; + int index; + uint16_t vtotal; + + uint32_t memory; + uint8_t id; + + uint8_t port_03dd_val; + uint16_t get_korean_font_kind; + int in_get_korean_font_kind_set; + int get_korean_font_enabled; + int get_korean_font_index; + uint16_t get_korean_font_base; + int ksc5601_mode_enabled; } ati28800_t; + static video_timings_t timing_ati28800 = {VIDEO_ISA, 3, 3, 6, 5, 5, 10}; @@ -104,375 +107,404 @@ ati28800_log(const char *fmt, ...) static void ati28800_recalctimings(svga_t *svga); -static void ati28800_out(uint16_t addr, uint8_t val, void *p) + +static void +ati28800_out(uint16_t addr, uint8_t val, void *p) { - ati28800_t *ati28800 = (ati28800_t *)p; - svga_t *svga = &ati28800->svga; - uint8_t old; - - ati28800_log("ati28800_out : %04X %02X\n", addr, val); + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint8_t old; - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) - addr ^= 0x60; + ati28800_log("ati28800_out : %04X %02X\n", addr, val); - switch (addr) - { - case 0x1ce: - ati28800->index = val; - break; - case 0x1cf: - old=ati28800->regs[ati28800->index]; - ati28800->regs[ati28800->index] = val; - ati28800_log("ATI write reg=%02x\n", ati28800->index); - switch (ati28800->index) - { - case 0xbe: - case 0xbd: - if (ati28800->regs[0xbe] & 8) /*Read/write bank mode*/ - { - svga->read_bank = (((ati28800->regs[0xb2] >> 5) & 7) * 0x10000); - svga->write_bank = (((ati28800->regs[0xb2] >> 1) & 7) * 0x10000); - } - else /*Single bank mode*/ - { - svga->read_bank = (((ati28800->regs[0xb2] >> 1) & 7) * 0x10000); - svga->write_bank = (((ati28800->regs[0xb2] >> 1) & 7) * 0x10000); - } - break; - case 0xb3: - ati_eeprom_write(&ati28800->eeprom, val & 8, val & 2, val & 1); - break; - case 0xb6: - if((old ^ val) & 0x10) svga_recalctimings(svga); - break; - case 0xb8: - if((old ^ val) & 0x40) svga_recalctimings(svga); - break; - case 0xb9: - if((old ^ val) & 2) svga_recalctimings(svga); - break; - } - break; + if (((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; - case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - sc1502x_ramdac_out(addr, val, svga->ramdac, svga); - return; - - case 0x3D4: - svga->crtcreg = val & 0x3f; - return; - case 0x3D5: - if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) - return; - if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) - val = (svga->crtc[7] & ~0x10) | (val & 0x10); - - old = svga->crtc[svga->crtcreg]; - svga->crtc[svga->crtcreg] = val; - if (old != val) - { - if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) - { - svga->fullchange = changeframecount; - svga_recalctimings(svga); - } - } - break; - } - svga_out(addr, val, svga); -} - -void ati28800k_out(uint16_t addr, uint8_t val, void *p) -{ - ati28800_t *ati28800 = (ati28800_t *)p; - svga_t *svga = &ati28800->svga; - uint16_t oldaddr = addr; - - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) - addr ^= 0x60; - - switch (addr) - { - case 0x1CF: - if(ati28800->index == 0xBF && ((ati28800->regs[0xBF] ^ val) & 0x20)) - { - ati28800->ksc5601_mode_enabled = val & 0x20; - svga_recalctimings(svga); - - } - ati28800_out(oldaddr, val, p); - break; - case 0x3DD: - ati28800->port_03dd_val = val; - if(val == 1) ati28800->get_korean_font_enabled = 0; - if(ati28800->in_get_korean_font_kind_set) - { - ati28800->get_korean_font_kind = (val << 8) | (ati28800->get_korean_font_kind & 0xFF); - ati28800->get_korean_font_enabled = 1; - ati28800->get_korean_font_index = 0; - ati28800->in_get_korean_font_kind_set = 0; - } - break; - case 0x3DE: - ati28800->in_get_korean_font_kind_set = 0; - if(ati28800->get_korean_font_enabled) - { - if((ati28800->get_korean_font_base & 0x7F) > 0x20 && (ati28800->get_korean_font_base & 0x7F) < 0x7F) - fontdatksc5601_user[(ati28800->get_korean_font_kind & 4) * 24 + (ati28800->get_korean_font_base & 0x7F) - 0x20].chr[ati28800->get_korean_font_index] = val; - ati28800->get_korean_font_index++; - ati28800->get_korean_font_index &= 0x1F; - } - else - - { - switch(ati28800->port_03dd_val) - { - case 0x10: - ati28800->get_korean_font_base = ((val & 0x7F) << 7) | (ati28800->get_korean_font_base & 0x7F); - break; - case 8: - ati28800->get_korean_font_base = (ati28800->get_korean_font_base & 0x3F80) | (val & 0x7F); - break; - case 1: - ati28800->get_korean_font_kind = (ati28800->get_korean_font_kind & 0xFF00) | val; - if(val & 2) - ati28800->in_get_korean_font_kind_set = 1; - break; - } - break; - } - default: - ati28800_out(oldaddr, val, p); - break; - } -} - -static uint8_t ati28800_in(uint16_t addr, void *p) -{ - ati28800_t *ati28800 = (ati28800_t *)p; - svga_t *svga = &ati28800->svga; - uint8_t temp; - - if (addr != 0x3da) ati28800_log("ati28800_in : %04X ", addr); - - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; - - switch (addr) - { - case 0x1ce: - temp = ati28800->index; - break; - case 0x1cf: - switch (ati28800->index) - { - case 0xaa: - temp = ati28800->id; - break; - - case 0xb0: - if (ati28800->memory == 1024) - temp = 0x08; - else if (ati28800->memory == 512) - temp = 0x10; - else - temp = 0x00; - ati28800->regs[0xb0] |= temp; - break; - - case 0xb7: - temp = ati28800->regs[ati28800->index] & ~8; - if (ati_eeprom_read(&ati28800->eeprom)) - temp |= 8; - break; - - default: - temp = ati28800->regs[ati28800->index]; - break; - } - break; - - case 0x3c2: - if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) - temp = 0; - else - temp = 0x10; - break; - - case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - return sc1502x_ramdac_in(addr, svga->ramdac, svga); - - case 0x3D4: - temp = svga->crtcreg; - break; - case 0x3D5: - temp = svga->crtc[svga->crtcreg]; - break; - default: - temp = svga_in(addr, svga); - break; - } - if (addr != 0x3da) ati28800_log("%02X\n", temp); - return temp; -} - -uint8_t ati28800k_in(uint16_t addr, void *p) -{ - ati28800_t *ati28800 = (ati28800_t *)p; - svga_t *svga = &ati28800->svga; - uint16_t oldaddr = addr; - uint8_t temp = 0xFF; - - if (addr != 0x3da) ati28800_log("ati28800k_in : %04X ", addr); - - if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; - - switch (addr) - { - case 0x3DE: - if (ati28800->get_korean_font_enabled) - { - switch(ati28800->get_korean_font_kind >> 8) - { - case 4: /* ROM font */ - temp = fontdatksc5601[ati28800->get_korean_font_base].chr[ati28800->get_korean_font_index++]; - break; - case 2: /* User defined font */ - if((ati28800->get_korean_font_base & 0x7F) > 0x20 && (ati28800->get_korean_font_base & 0x7F) < 0x7F) - temp = fontdatksc5601_user[(ati28800->get_korean_font_kind & 4) * 24 + (ati28800->get_korean_font_base & 0x7F) - 0x20].chr[ati28800->get_korean_font_index]; - else - temp = 0xFF; - ati28800->get_korean_font_index++; - break; - default: - break; - } - ati28800->get_korean_font_index &= 0x1F; - } - break; - default: - temp = ati28800_in(oldaddr, p); - break; - } - if (addr != 0x3da) ati28800_log("%02X\n", temp); - return temp; -} - -static void ati28800_recalctimings(svga_t *svga) -{ - ati28800_t *ati28800 = (ati28800_t *)svga->p; - - switch(((ati28800->regs[0xbe] & 0x10) >> 1) | ((ati28800->regs[0xb9] & 2) << 1) | ((svga->miscout & 0x0C) >> 2)) - { - case 0x00: svga->clock = cpuclock / 42954000.0; break; - case 0x01: svga->clock = cpuclock / 48771000.0; break; - case 0x02: pclog ("clock 2\n"); break; - case 0x03: svga->clock = cpuclock / 36000000.0; break; - case 0x04: svga->clock = cpuclock / 50350000.0; break; - case 0x05: svga->clock = cpuclock / 56640000.0; break; - case 0x06: pclog ("clock 2\n"); break; - case 0x07: svga->clock = cpuclock / 44900000.0; break; - case 0x08: svga->clock = cpuclock / 30240000.0; break; - case 0x09: svga->clock = cpuclock / 32000000.0; break; - case 0x0A: svga->clock = cpuclock / 37500000.0; break; - case 0x0B: svga->clock = cpuclock / 39000000.0; break; - case 0x0C: svga->clock = cpuclock / 40000000.0; break; - case 0x0D: svga->clock = cpuclock / 56644000.0; break; - case 0x0E: svga->clock = cpuclock / 75000000.0; break; - case 0x0F: svga->clock = cpuclock / 65000000.0; break; - default: break; - } - - if(ati28800->regs[0xb8] & 0x40) - svga->clock *= 2; - - if (ati28800->regs[0xb6] & 0x10) - { - svga->hdisp <<= 1; - svga->htotal <<= 1; - svga->rowoffset <<= 1; - } - - if(svga->crtc[0x17] & 4) - { - svga->vtotal <<= 1; - svga->dispend <<= 1; - svga->vsyncstart <<= 1; - svga->split <<= 1; - svga->vblankstart <<= 1; - } - - if (!svga->scrblank && (ati28800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ - { - switch (svga->bpp) - { - case 8: - svga->render = svga_render_8bpp_highres; - svga->rowoffset <<= 1; - svga->ma <<= 1; - break; - - case 15: - svga->render = svga_render_15bpp_highres; - svga->hdisp >>= 1; - svga->rowoffset <<= 1; - svga->ma <<= 1; - break; + switch (addr) { + case 0x1ce: + ati28800->index = val; + break; + case 0x1cf: + old = ati28800->regs[ati28800->index]; + ati28800->regs[ati28800->index] = val; + ati28800_log("ATI 28800 write reg=0x%02X, val=0x%02X\n", ati28800->index, val); + switch (ati28800->index) { + case 0xa3: + ati28800->regs[0xa3] = val & 0x1f; + svga_recalctimings(svga); + break; + case 0xa6: + ati28800->regs[0xa6] = val & 0xc9; + break; + case 0xab: + ati28800->regs[0xab] = val & 0xdf; + break; + case 0xb0: + ati28800->regs[0xb0] = val & 0x7d; + svga_recalctimings(svga); + break; + case 0xb1: + ati28800->regs[0xb0] = val & 0x7f; + break; + case 0xb2: + if (ati28800->regs[0xbe] & 0x08) { /* Read/write bank mode */ + svga->read_bank = (((val & 0x01) << 3) | ((val & 0xe0) >> 5)) * 0x10000; + svga->write_bank = ((val & 0x1e) >> 1) * 0x10000; + } else { /* Single bank mode */ + svga->read_bank = ((val & 0x1e) >> 1) * 0x10000; + svga->write_bank = ((val & 0x1e) >> 1) * 0x10000; } - } + break; + case 0xb3: + ati28800->regs[0xb3] = val & 0xef; + ati_eeprom_write(&ati28800->eeprom, val & 8, val & 2, val & 1); + break; + case 0xb6: + if ((old ^ val) & 0x10) + svga_recalctimings(svga); + break; + case 0xb8: + if ((old ^ val) & 0x40) + svga_recalctimings(svga); + break; + case 0xb9: + if ((old ^ val) & 2) + svga_recalctimings(svga); + break; + } + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + sc1502x_ramdac_out(addr, val, svga->ramdac, svga); + return; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if ((ati28800->regs[0xb4] & 0x10) && (svga->crtcreg == 0x0a && svga->crtcreg == 0x0b)) + return; + if ((ati28800->regs[0xb4] & 0x20) && ((svga->crtc[0x08] & 0x7f) && (svga->crtc[0x14] & 0x1f))) + return; + if ((ati28800->regs[0xb4] & 0x40) && ((svga->crtcreg >= 0x00 && svga->crtcreg <= 0x06) && + (svga->crtc[0x07] & 0x10) != 0x10)) + return; + + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); } -void ati28800k_recalctimings(svga_t *svga) + +static void +ati28800k_out(uint16_t addr, uint8_t val, void *p) { - ati28800_t *ati28800 = (ati28800_t *) svga->p; + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint16_t oldaddr = addr; - ati28800_recalctimings(svga); - - if (svga->render == svga_render_text_80 && ati28800->ksc5601_mode_enabled) - { - svga->render = svga_render_text_80_ksc5601; - } + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + + switch (addr) { + case 0x1CF: + if (ati28800->index == 0xBF && ((ati28800->regs[0xBF] ^ val) & 0x20)) { + ati28800->ksc5601_mode_enabled = val & 0x20; + svga_recalctimings(svga); + } + ati28800_out(oldaddr, val, p); + break; + case 0x3DD: + ati28800->port_03dd_val = val; + if (val == 1) + ati28800->get_korean_font_enabled = 0; + if (ati28800->in_get_korean_font_kind_set) { + ati28800->get_korean_font_kind = (val << 8) | (ati28800->get_korean_font_kind & 0xFF); + ati28800->get_korean_font_enabled = 1; + ati28800->get_korean_font_index = 0; + ati28800->in_get_korean_font_kind_set = 0; + } + break; + case 0x3DE: + ati28800->in_get_korean_font_kind_set = 0; + if (ati28800->get_korean_font_enabled) { + if ((ati28800->get_korean_font_base & 0x7F) > 0x20 && (ati28800->get_korean_font_base & 0x7F) < 0x7F) { + fontdatksc5601_user[(ati28800->get_korean_font_kind & 4) * 24 + + (ati28800->get_korean_font_base & 0x7F) - 0x20].chr[ati28800->get_korean_font_index] = val; + } + ati28800->get_korean_font_index++; + ati28800->get_korean_font_index &= 0x1F; + } else { + switch (ati28800->port_03dd_val) { + case 0x10: + ati28800->get_korean_font_base = ((val & 0x7F) << 7) | (ati28800->get_korean_font_base & 0x7F); + break; + case 8: + ati28800->get_korean_font_base = (ati28800->get_korean_font_base & 0x3F80) | (val & 0x7F); + break; + case 1: + ati28800->get_korean_font_kind = (ati28800->get_korean_font_kind & 0xFF00) | val; + if (val & 2) + ati28800->in_get_korean_font_kind_set = 1; + break; + } + break; + } + default: + ati28800_out(oldaddr, val, p); + break; + } } + +static uint8_t +ati28800_in(uint16_t addr, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint8_t temp; + + if (addr != 0x3da) + ati28800_log("ati28800_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + + switch (addr) { + case 0x1ce: + temp = ati28800->index; + break; + case 0x1cf: + switch (ati28800->index) { + case 0xa0: + temp = 0x10; + break; + case 0xaa: + temp = ati28800->id; + break; + case 0xb0: + if (ati28800->memory == 1024) + temp = 0x08; + else if (ati28800->memory == 512) + temp = 0x10; + else + temp = 0x00; + break; + case 0xb7: + temp = ati28800->regs[ati28800->index] & ~8; + if (ati_eeprom_read(&ati28800->eeprom)) + temp |= 8; + break; + + default: + temp = ati28800->regs[ati28800->index]; + break; + } + break; + + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) + temp = 0; + else + temp = 0x10; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return sc1502x_ramdac_in(addr, svga->ramdac, svga); + + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } + if (addr != 0x3da) + ati28800_log("%02X\n", temp); + return temp; +} + + +static uint8_t +ati28800k_in(uint16_t addr, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint16_t oldaddr = addr; + uint8_t temp = 0xFF; + + if (addr != 0x3da) + ati28800_log("ati28800k_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + + switch (addr) { + case 0x3DE: + if (ati28800->get_korean_font_enabled) { + switch (ati28800->get_korean_font_kind >> 8) { + case 4: /* ROM font */ + temp = fontdatksc5601[ati28800->get_korean_font_base].chr[ati28800->get_korean_font_index++]; + break; + case 2: /* User defined font */ + if ((ati28800->get_korean_font_base & 0x7F) > 0x20 && (ati28800->get_korean_font_base & 0x7F) < 0x7F) { + temp = fontdatksc5601_user[(ati28800->get_korean_font_kind & 4) * 24 + + (ati28800->get_korean_font_base & 0x7F) - 0x20].chr[ati28800->get_korean_font_index]; + } else + temp = 0xFF; + ati28800->get_korean_font_index++; + break; + default: + break; + } + ati28800->get_korean_font_index &= 0x1F; + } + break; + default: + temp = ati28800_in(oldaddr, p); + break; + } + if (addr != 0x3da) + ati28800_log("%02X\n", temp); + return temp; +} + + +static void +ati28800_recalctimings(svga_t *svga) +{ + ati28800_t *ati28800 = (ati28800_t *)svga->p; + + switch (((ati28800->regs[0xbe] & 0x10) >> 1) | ((ati28800->regs[0xb9] & 2) << 1) | + ((svga->miscout & 0x0C) >> 2)) { + case 0x00: svga->clock = (cpuclock * (double)(1ull << 32)) / 42954000.0; break; + case 0x01: svga->clock = (cpuclock * (double)(1ull << 32)) / 48771000.0; break; + case 0x02: ati28800_log ("clock 2\n"); break; + case 0x03: svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; break; + case 0x04: svga->clock = (cpuclock * (double)(1ull << 32)) / 50350000.0; break; + case 0x05: svga->clock = (cpuclock * (double)(1ull << 32)) / 56640000.0; break; + case 0x06: ati28800_log ("clock 2\n"); break; + case 0x07: svga->clock = (cpuclock * (double)(1ull << 32)) / 44900000.0; break; + case 0x08: svga->clock = (cpuclock * (double)(1ull << 32)) / 30240000.0; break; + case 0x09: svga->clock = (cpuclock * (double)(1ull << 32)) / 32000000.0; break; + case 0x0A: svga->clock = (cpuclock * (double)(1ull << 32)) / 37500000.0; break; + case 0x0B: svga->clock = (cpuclock * (double)(1ull << 32)) / 39000000.0; break; + case 0x0C: svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break; + case 0x0D: svga->clock = (cpuclock * (double)(1ull << 32)) / 56644000.0; break; + case 0x0E: svga->clock = (cpuclock * (double)(1ull << 32)) / 75000000.0; break; + case 0x0F: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; + default: break; + } + + if (ati28800->regs[0xb8] & 0x40) + svga->clock *= 2; + + if (ati28800->regs[0xa3] & 0x10) + svga->ma |= 0x10000; + + if (ati28800->regs[0xb0] & 0x40) + svga->ma |= 0x20000; + + if (ati28800->regs[0xb6] & 0x10) { + svga->hdisp <<= 1; + svga->htotal <<= 1; + svga->rowoffset <<= 1; + } + + if (svga->crtc[0x17] & 4) { + svga->vtotal <<= 1; + svga->dispend <<= 1; + svga->vsyncstart <<= 1; + svga->split <<= 1; + svga->vblankstart <<= 1; + } + + if (!svga->scrblank && (ati28800->regs[0xb0] & 0x20)) { /* Extended 256 colour modes */ + switch (svga->bpp) { + case 8: + svga->render = svga_render_8bpp_highres; + svga->rowoffset <<= 1; + svga->ma <<= 1; + break; + case 15: + svga->render = svga_render_15bpp_highres; + svga->hdisp >>= 1; + svga->rowoffset <<= 1; + svga->ma <<= 1; + break; + } + } +} + + +static void +ati28800k_recalctimings(svga_t *svga) +{ + ati28800_t *ati28800 = (ati28800_t *) svga->p; + + ati28800_recalctimings(svga); + + if (svga->render == svga_render_text_80 && ati28800->ksc5601_mode_enabled) + svga->render = svga_render_text_80_ksc5601; +} + + void * ati28800k_init(const device_t *info) { - ati28800_t *ati28800 = malloc(sizeof(ati28800_t)); - memset(ati28800, 0, sizeof(ati28800_t)); + ati28800_t *ati28800 = (ati28800_t *) malloc(sizeof(ati28800_t)); + memset(ati28800, 0, sizeof(ati28800_t)); - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ati28800); + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_ati28800); - ati28800->memory = device_get_config_int("memory"); - - ati28800->port_03dd_val = 0; - ati28800->get_korean_font_base = 0; - ati28800->get_korean_font_index = 0; - ati28800->get_korean_font_enabled = 0; - ati28800->get_korean_font_kind = 0; - ati28800->in_get_korean_font_kind_set = 0; - ati28800->ksc5601_mode_enabled = 0; - - rom_init(&ati28800->bios_rom, BIOS_ATIKOR_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - loadfont(FONT_ATIKOR_PATH, 6); - - svga_init(&ati28800->svga, ati28800, ati28800->memory << 10, /*Memory size, default 512KB*/ - ati28800k_recalctimings, - ati28800k_in, ati28800k_out, - NULL, - NULL); + ati28800->memory = device_get_config_int("memory"); - ati28800->svga.ramdac = device_add(&sc1502x_ramdac_device); + ati28800->port_03dd_val = 0; + ati28800->get_korean_font_base = 0; + ati28800->get_korean_font_index = 0; + ati28800->get_korean_font_enabled = 0; + ati28800->get_korean_font_kind = 0; + ati28800->in_get_korean_font_kind_set = 0; + ati28800->ksc5601_mode_enabled = 0; - io_sethandler(0x01ce, 0x0002, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); - io_sethandler(0x03c0, 0x0020, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + rom_init(&ati28800->bios_rom, BIOS_ATIKOR_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + loadfont(FONT_ATIKOR_PATH, 6); - ati28800->svga.miscout = 1; - ati28800->svga.ksc5601_sbyte_mask = 0; + svga_init(&ati28800->svga, ati28800, ati28800->memory << 10, /*Memory size, default 512KB*/ + ati28800k_recalctimings, + ati28800k_in, ati28800k_out, + NULL, + NULL); - ati_eeprom_load(&ati28800->eeprom, L"atikorvga.nvr", 0); + ati28800->svga.ramdac = device_add(&sc1502x_ramdac_device); - return ati28800; + io_sethandler(0x01ce, 0x0002, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + io_sethandler(0x03c0, 0x0020, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + + ati28800->svga.miscout = 1; + ati28800->svga.ksc5601_sbyte_mask = 0; + + ati_eeprom_load(&ati28800->eeprom, L"atikorvga.nvr", 0); + + return ati28800; } + static void * ati28800_init(const device_t *info) { @@ -531,23 +563,21 @@ ati28800_init(const device_t *info) ati28800->svga.miscout = 1; - switch (info->local) - { - case VGAWONDERXL: - ati_eeprom_load(&ati28800->eeprom, L"ati28800xl.nvr", 0); - break; - + switch (info->local) { + case VGAWONDERXL: + ati_eeprom_load(&ati28800->eeprom, L"ati28800xl.nvr", 0); + break; + #if defined(DEV_BRANCH) && defined(USE_XL24) - case VGAWONDERXL24: - ati_eeprom_load(&ati28800->eeprom, L"ati28800xl24.nvr", 0); - break; + case VGAWONDERXL24: + ati_eeprom_load(&ati28800->eeprom, L"ati28800xl24.nvr", 0); + break; #endif - default: - ati_eeprom_load(&ati28800->eeprom, L"ati28800.nvr", 0); - break; - } - + default: + ati_eeprom_load(&ati28800->eeprom, L"ati28800.nvr", 0); + break; + } return(ati28800); } diff --git a/src/video/vid_ati68860_ramdac.c b/src/video/vid_ati68860_ramdac.c index c764d40fe..c814352b2 100644 --- a/src/video/vid_ati68860_ramdac.c +++ b/src/video/vid_ati68860_ramdac.c @@ -44,6 +44,7 @@ #include "../86box.h" #include "../device.h" #include "../mem.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_ati68860_ramdac.h" diff --git a/src/video/vid_ati_eeprom.c b/src/video/vid_ati_eeprom.c index 4bcd9d702..3a01bfedd 100644 --- a/src/video/vid_ati_eeprom.c +++ b/src/video/vid_ati_eeprom.c @@ -23,6 +23,7 @@ #include "../86box.h" #include "../device.h" #include "../mem.h" +#include "../timer.h" #include "../nvr.h" #include "vid_ati_eeprom.h" diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 4f416cc9d..932f205b8 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -27,6 +27,7 @@ #include "../device.h" #include "../io.h" #include "../mem.h" +#include "../timer.h" #include "../pci.h" #include "../rom.h" #include "../plat.h" @@ -470,7 +471,7 @@ void mach64_recalctimings(svga_t *svga) svga->hdisp_time = svga->hdisp = ((mach64->crtc_h_total_disp >> 16) & 255) + 1; svga->vsyncstart = (mach64->crtc_v_sync_strt_wid & 2047) + 1; svga->rowoffset = (mach64->crtc_off_pitch >> 22); - svga->clock = cpuclock / clock_gen->output_clock; + svga->clock = (cpuclock * (double)(1ull << 32)) / clock_gen->output_clock; svga->ma_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2; svga->linedbl = svga->rowcount = 0; svga->split = 0xffffff; @@ -2798,17 +2799,17 @@ void mach64_hwcursor_draw(svga_t *svga, int displine) for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) { dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] = (dat & 1) ? col1 : col0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x + 32 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x + 32 + x_add] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] = (dat & 1) ? col1 : col0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x + 33 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x + 33 + x_add] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] = (dat & 1) ? col1 : col0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x + 34 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x + 34 + x_add] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] = (dat & 1) ? col1 : col0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x + 35 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x + 35 + x_add] ^= 0xFFFFFF; dat >>= 2; offset += 4; } @@ -2967,7 +2968,7 @@ void mach64_overlay_draw(svga_t *svga, int displine) int graphics_key_fn = (mach64->overlay_key_cntl >> 4) & 5; int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf; - p = &((uint32_t *)buffer32->line[displine])[32 + mach64->svga.overlay_latch.x]; + p = &buffer32->line[displine][32 + mach64->svga.overlay_latch.x]; if (mach64->scaler_update) { diff --git a/src/video/vid_att20c49x_ramdac.c b/src/video/vid_att20c49x_ramdac.c index bc3af28e8..1077c7e54 100644 --- a/src/video/vid_att20c49x_ramdac.c +++ b/src/video/vid_att20c49x_ramdac.c @@ -24,6 +24,7 @@ #include "../86box.h" #include "../device.h" #include "../mem.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_att20c49x_ramdac.h" diff --git a/src/video/vid_bt48x_ramdac.c b/src/video/vid_bt48x_ramdac.c index 6fb88771b..9919d4fac 100644 --- a/src/video/vid_bt48x_ramdac.c +++ b/src/video/vid_bt48x_ramdac.c @@ -25,6 +25,7 @@ #include "../86box.h" #include "../device.h" #include "../mem.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_bt48x_ramdac.h" @@ -42,16 +43,16 @@ enum { static void bt48x_set_bpp(bt48x_ramdac_t *ramdac, svga_t *svga) { - if ((!(ramdac->cr2 & 0x20)) || ((ramdac->type >= BT485A) && ((ramdac->cr3 & 0x60) == 0x60))) + if ((!(ramdac->cmd_r2 & 0x20)) || ((ramdac->type >= BT485A) && ((ramdac->cmd_r3 & 0x60) == 0x60))) svga->bpp = 8; - else if ((ramdac->type >= BT485A) && ((ramdac->cr3 & 0x60) == 0x40)) + else if ((ramdac->type >= BT485A) && ((ramdac->cmd_r3 & 0x60) == 0x40)) svga->bpp = 24; - else switch (ramdac->cr1 & 0x60) { + else switch (ramdac->cmd_r1 & 0x60) { case 0x00: svga->bpp = 32; break; case 0x20: - if (ramdac->cr1 & 0x08) + if (ramdac->cmd_r1 & 0x08) svga->bpp = 16; else svga->bpp = 15; @@ -89,7 +90,7 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *r svga->dac_status = addr & 0x03; svga->dac_addr = val; if (ramdac->type >= BT485) - svga->dac_addr |= ((int) (ramdac->cr3 & 0x03) << 8); + svga->dac_addr |= ((int) (ramdac->cmd_r3 & 0x03) << 8); if (svga->dac_status) svga->dac_addr = (svga->dac_addr + 1) & da_mask; break; @@ -131,30 +132,30 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *r } break; case 0x06: /* Command Register 0 (RS value = 0110) */ - ramdac->cr0 = val; + ramdac->cmd_r0 = val; svga->ramdac_type = (val & 0x02) ? RAMDAC_8BIT : RAMDAC_6BIT; break; case 0x08: /* Command Register 1 (RS value = 1000) */ - ramdac->cr1 = val; + ramdac->cmd_r1 = val; bt48x_set_bpp(ramdac, svga); break; case 0x09: /* Command Register 2 (RS value = 1001) */ - ramdac->cr2 = val; - svga->hwcursor.ena = !!(val & 0x03); + ramdac->cmd_r2 = val; + svga->dac_hwcursor.ena = !!(val & 0x03); bt48x_set_bpp(ramdac, svga); break; case 0x0a: - if ((ramdac->type >= BT485) && (ramdac->cr0 & 0x80)) { + if ((ramdac->type >= BT485) && (ramdac->cmd_r0 & 0x80)) { switch ((svga->dac_addr & ((ramdac->type >= BT485A) ? 0xff : 0x3f))) { case 0x01: /* Command Register 3 (RS value = 1010) */ - ramdac->cr3 = val; + ramdac->cmd_r3 = val; if (ramdac->type >= BT485A) bt48x_set_bpp(ramdac, svga); - svga->hwcursor.xsize = svga->hwcursor.ysize = (val & 4) ? 64 : 32; - svga->hwcursor.yoff = (svga->hwcursor.ysize == 32) ? 32 : 0; - svga->hwcursor.x = ramdac->hwc_x - svga->hwcursor.xsize; - svga->hwcursor.y = ramdac->hwc_y - svga->hwcursor.ysize; + svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = (val & 4) ? 64 : 32; + svga->dac_hwcursor.yoff = (svga->dac_hwcursor.ysize == 32) ? 32 : 0; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; svga->dac_addr = (svga->dac_addr & 0x00ff) | ((val & 0x03) << 8); svga_recalctimings(svga); break; @@ -165,7 +166,7 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *r if (ramdac->type != BT485A) break; else if (svga->dac_addr == 2) { - ramdac->cr4 = val; + ramdac->cmd_r4 = val; break; } break; @@ -174,7 +175,7 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *r break; case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ index = svga->dac_addr & da_mask; - if ((ramdac->type >= BT485) && (svga->hwcursor.xsize == 64)) + if ((ramdac->type >= BT485) && (svga->dac_hwcursor.xsize == 64)) cd = (uint8_t *) ramdac->cursor64_data; else { index &= 0xff; @@ -187,19 +188,19 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt48x_ramdac_t *r break; case 0x0c: /* Cursor X Low Register (RS value = 1100) */ ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val; - svga->hwcursor.x = ramdac->hwc_x - svga->hwcursor.xsize; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; break; case 0x0d: /* Cursor X High Register (RS value = 1101) */ ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8); - svga->hwcursor.x = ramdac->hwc_x - svga->hwcursor.xsize; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; break; case 0x0e: /* Cursor Y Low Register (RS value = 1110) */ ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val; - svga->hwcursor.y = ramdac->hwc_y - svga->hwcursor.ysize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; break; case 0x0f: /* Cursor Y High Register (RS value = 1111) */ ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8); - svga->hwcursor.y = ramdac->hwc_y - svga->hwcursor.ysize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; break; } @@ -260,23 +261,23 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_ramdac_t *ramdac, svga_t } break; case 0x06: /* Command Register 0 (RS value = 0110) */ - temp = ramdac->cr0; + temp = ramdac->cmd_r0; break; case 0x08: /* Command Register 1 (RS value = 1000) */ - temp = ramdac->cr1; + temp = ramdac->cmd_r1; break; case 0x09: /* Command Register 2 (RS value = 1001) */ - temp = ramdac->cr2; + temp = ramdac->cmd_r2; break; case 0x0a: - if ((ramdac->type >= BT485) && (ramdac->cr0 & 0x80)) { + if ((ramdac->type >= BT485) && (ramdac->cmd_r0 & 0x80)) { switch ((svga->dac_addr & ((ramdac->type >= BT485A) ? 0xff : 0x3f))) { case 0x00: default: temp = ramdac->status | (svga->dac_status ? 0x04 : 0x00); break; case 0x01: - temp = ramdac->cr3 & 0xfc; + temp = ramdac->cmd_r3 & 0xfc; temp |= (svga->dac_addr & 0x300) >> 8; break; case 0x02: @@ -286,7 +287,7 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_ramdac_t *ramdac, svga_t if (ramdac->type != BT485A) break; else if (svga->dac_addr == 2) { - temp = ramdac->cr4; + temp = ramdac->cmd_r4; break; } else { /* TODO: Red, Green, and Blue Signature Analysis Registers */ @@ -300,7 +301,7 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, bt48x_ramdac_t *ramdac, svga_t break; case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ index = (svga->dac_addr - 1) & da_mask; - if ((ramdac->type >= BT485) && (svga->hwcursor.xsize == 64)) + if ((ramdac->type >= BT485) && (svga->dac_hwcursor.xsize == 64)) cd = (uint8_t *) ramdac->cursor64_data; else { index &= 0xff; @@ -334,7 +335,7 @@ bt48x_hwcursor_draw(svga_t *svga, int displine) { int x, xx, comb, b0, b1; uint16_t dat[2]; - int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int offset = svga->dac_hwcursor_latch.x - svga->dac_hwcursor_latch.xoff; int y_add, x_add; int pitch, bppl, mode, x_pos, y_pos; uint32_t clr1, clr2, clr3, *p; @@ -351,25 +352,25 @@ bt48x_hwcursor_draw(svga_t *svga, int displine) /* The planes come in two parts, and each plane is 1bpp, so a 32x32 cursor has 4 bytes per line, and a 64x64 cursor has 8 bytes per line. */ - pitch = (svga->hwcursor_latch.xsize >> 3); /* Bytes per line. */ + pitch = (svga->dac_hwcursor_latch.xsize >> 3); /* Bytes per line. */ /* A 32x32 cursor has 128 bytes per line, and a 64x64 cursor has 512 bytes per line. */ - bppl = (pitch * svga->hwcursor_latch.ysize); /* Bytes per plane. */ - mode = ramdac->cr2 & 0x03; + bppl = (pitch * svga->dac_hwcursor_latch.ysize); /* Bytes per plane. */ + mode = ramdac->cmd_r2 & 0x03; - if (svga->interlace && svga->hwcursor_oddeven) - svga->hwcursor_latch.addr += pitch; + if (svga->interlace && svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; - if (svga->hwcursor_latch.xsize == 64) + if (svga->dac_hwcursor_latch.xsize == 64) cd = (uint8_t *) ramdac->cursor64_data; else cd = (uint8_t *) ramdac->cursor32_data; - for (x = 0; x < svga->hwcursor_latch.xsize; x += 16) { - dat[0] = (cd[svga->hwcursor_latch.addr] << 8) | - cd[svga->hwcursor_latch.addr + 1]; - dat[1] = (cd[svga->hwcursor_latch.addr + bppl] << 8) | - cd[svga->hwcursor_latch.addr + bppl + 1]; + for (x = 0; x < svga->dac_hwcursor_latch.xsize; x += 16) { + dat[0] = (cd[svga->dac_hwcursor_latch.addr] << 8) | + cd[svga->dac_hwcursor_latch.addr + 1]; + dat[1] = (cd[svga->dac_hwcursor_latch.addr + bppl] << 8) | + cd[svga->dac_hwcursor_latch.addr + bppl + 1]; for (xx = 0; xx < 16; xx++) { b0 = (dat[0] >> (15 - xx)) & 1; @@ -378,9 +379,9 @@ bt48x_hwcursor_draw(svga_t *svga, int displine) y_pos = displine + y_add; x_pos = offset + 32 + x_add; - p = ((uint32_t *)buffer32->line[y_pos]); + p = buffer32->line[y_pos]; - if (offset >= svga->hwcursor_latch.x) { + if (offset >= svga->dac_hwcursor_latch.x) { switch (mode) { case 1: /* Three Color */ switch (comb) { @@ -422,11 +423,11 @@ bt48x_hwcursor_draw(svga_t *svga, int displine) } offset++; } - svga->hwcursor_latch.addr += 2; + svga->dac_hwcursor_latch.addr += 2; } - if (svga->interlace && !svga->hwcursor_oddeven) - svga->hwcursor_latch.addr += pitch; + if (svga->interlace && !svga->dac_hwcursor_oddeven) + svga->dac_hwcursor_latch.addr += pitch; } diff --git a/src/video/vid_bt48x_ramdac.h b/src/video/vid_bt48x_ramdac.h index 186e70101..ce952e1e8 100644 --- a/src/video/vid_bt48x_ramdac.h +++ b/src/video/vid_bt48x_ramdac.h @@ -24,11 +24,11 @@ typedef struct uint8_t cursor32_data[256]; uint8_t cursor64_data[1024]; int hwc_y, hwc_x; - uint8_t cr0; - uint8_t cr1; - uint8_t cr2; - uint8_t cr3; - uint8_t cr4; + uint8_t cmd_r0; + uint8_t cmd_r1; + uint8_t cmd_r2; + uint8_t cmd_r3; + uint8_t cmd_r4; uint8_t status; uint8_t type; } bt48x_ramdac_t; diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index dd13236dc..f74a52e23 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -25,10 +25,10 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_cga.h" @@ -52,56 +52,6 @@ static video_timings_t timing_cga = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; void cga_recalctimings(cga_t *cga); -#ifdef CGA_DEBUG -void -cga_print(cga_t *cga) -{ - int x_res = cga->crtc[0x02]; - int hchar = 3; - char ncol = '4'; - - if (!(cga->cgamode & 0x08)) - return; - -#if 0 - if (cga->cgamode & 1) - x_res <<= 3; - else if (!(cga->cgamode & 2)) - x_res <<= 4; - else if (!(cga->cgamode & 16)) - x_res <<= 3; - else - x_res <<= 4; -#else - if ((cga->cgamode & 0x12) == 0x02) - hchar++; - else if ((cga->cgamode & 0x03) == 0x00) - hchar++; - x_res <<= hchar; -#endif - - if ((cga->cgamode & 0x12) == 0x12) - ncol = '8'; - else if ((cga->cgamode & 0x03) == 0x01) - ncol = '8'; - if ((cga->cgamode & 0x12) == 0x10) - ncol = 't'; - else if ((cga->cgamode & 0x03) == 0x03) - ncol = 'g'; - -#if 0 - pclog("HSync Pos: %i chars (%i p), VSync Pos: %i chars (%i p)\n", cga->crtc[0x02], x_res, - cga->crtc[0x07], cga->crtc[0x07] * (cga->crtc[0x09] + 1)); -#else - pclog("[%c%c%i] HSync Pos: %i chars (%i p), VSync Pos: %i chars (%i p)\n", - (cga->cgamode & 2) ? 'G' : 'T', ncol, hchar, - cga->crtc[0x02], x_res, - cga->crtc[0x07], cga->crtc[0x07] * (cga->crtc[0x09] + 1)); -#endif -} -#endif - - void cga_out(uint16_t addr, uint8_t val, void *p) { @@ -148,16 +98,21 @@ cga_in(uint16_t addr, void *p) { cga_t *cga = (cga_t *) p; + uint8_t ret = 0xff; + switch (addr) { case 0x3D4: - return cga->crtcreg; + ret = cga->crtcreg; + break; case 0x3D5: - return cga->crtc[cga->crtcreg]; + ret = cga->crtc[cga->crtcreg]; + break; case 0x3DA: - return cga->cgastat; + ret = cga->cgastat; + break; } - return 0xFF; + return ret; } @@ -168,7 +123,7 @@ cga_waitstates(void *p) int ws; ws = ws_array[cycles & 0xf]; - cycles -= ws; + sub_cycles(ws); } @@ -179,8 +134,9 @@ cga_write(uint32_t addr, uint8_t val, void *p) cga->vram[addr & 0x3fff] = val; if (cga->snow_enabled) { - cga->charbuffer[ ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc] = val; - cga->charbuffer[(((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val; + int offset = ((timer_get_remaining_u64(&cga->timer) / CGACONST) * 2) & 0xfc; + cga->charbuffer[offset] = cga->vram[addr & 0x3fff]; + cga->charbuffer[offset | 1] = cga->vram[addr & 0x3fff]; } egawrites++; cga_waitstates(cga); @@ -194,8 +150,9 @@ cga_read(uint32_t addr, void *p) cga_waitstates(cga); if (cga->snow_enabled) { - cga->charbuffer[ ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc] = cga->vram[addr & 0x3fff]; - cga->charbuffer[(((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = cga->vram[addr & 0x3fff]; + int offset = ((timer_get_remaining_u64(&cga->timer) / CGACONST) * 2) & 0xfc; + cga->charbuffer[offset] = cga->vram[addr & 0x3fff]; + cga->charbuffer[offset | 1] = cga->vram[addr & 0x3fff]; } egareads++; return cga->vram[addr & 0x3fff]; @@ -218,8 +175,8 @@ cga_recalctimings(cga_t *cga) _dispofftime = disptime - _dispontime; _dispontime = _dispontime * CGACONST; _dispofftime = _dispofftime * CGACONST; - cga->dispontime = (int64_t)(_dispontime * (1LL << TIMER_SHIFT)); - cga->dispofftime = (int64_t)(_dispofftime * (1LL << TIMER_SHIFT)); + cga->dispontime = (uint64_t)(_dispontime); + cga->dispofftime = (uint64_t)(_dispofftime); } @@ -239,7 +196,7 @@ cga_poll(void *p) int oldsc; if (!cga->linepos) { - cga->vidtime += cga->dispofftime; + timer_advance_u64(&cga->timer, cga->dispofftime); cga->cgastat |= 1; cga->linepos = 1; oldsc = cga->sc; @@ -253,24 +210,24 @@ cga_poll(void *p) cga->lastline = cga->displine; for (c = 0; c < 8; c++) { if ((cga->cgamode & 0x12) == 0x12) { - buffer->line[(cga->displine << 1)][c] = - buffer->line[(cga->displine << 1) + 1][c] = 0; + buffer32->line[(cga->displine << 1)][c] = + buffer32->line[(cga->displine << 1) + 1][c] = 0; if (cga->cgamode & 1) { - buffer->line[(cga->displine << 1)][c + (cga->crtc[1] << 3) + 8] = - buffer->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 3) + 8] = 0; + buffer32->line[(cga->displine << 1)][c + (cga->crtc[1] << 3) + 8] = + buffer32->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 3) + 8] = 0; } else { - buffer->line[(cga->displine << 1)][c + (cga->crtc[1] << 4) + 8] = - buffer->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 4) + 8] = 0; + buffer32->line[(cga->displine << 1)][c + (cga->crtc[1] << 4) + 8] = + buffer32->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 4) + 8] = 0; } } else { - buffer->line[(cga->displine << 1)][c] = - buffer->line[(cga->displine << 1) + 1][c] = (cga->cgacol & 15) + 16; + buffer32->line[(cga->displine << 1)][c] = + buffer32->line[(cga->displine << 1) + 1][c] = (cga->cgacol & 15) + 16; if (cga->cgamode & 1) { - buffer->line[(cga->displine << 1)][c + (cga->crtc[1] << 3) + 8] = - buffer->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 3) + 8] = (cga->cgacol & 15) + 16; + buffer32->line[(cga->displine << 1)][c + (cga->crtc[1] << 3) + 8] = + buffer32->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 3) + 8] = (cga->cgacol & 15) + 16; } else { - buffer->line[(cga->displine << 1)][c + (cga->crtc[1] << 4) + 8] = - buffer->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 4) + 8] = (cga->cgacol & 15) + 16; + buffer32->line[(cga->displine << 1)][c + (cga->crtc[1] << 4) + 8] = + buffer32->line[(cga->displine << 1) + 1][c + (cga->crtc[1] << 4) + 8] = (cga->cgacol & 15) + 16; } } } @@ -291,14 +248,14 @@ cga_poll(void *p) cols[0] = (attr >> 4) + 16; if (drawcursor) { for (c = 0; c < 8; c++) { - buffer->line[(cga->displine << 1)][(x << 3) + c + 8] = - buffer->line[(cga->displine << 1) + 1][(x << 3) + c + 8] = + buffer32->line[(cga->displine << 1)][(x << 3) + c + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } } else { for (c = 0; c < 8; c++) { - buffer->line[(cga->displine << 1)][(x << 3) + c + 8] = - buffer->line[(cga->displine << 1) + 1][(x << 3) + c + 8] = + buffer32->line[(cga->displine << 1)][(x << 3) + c + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } } @@ -322,18 +279,18 @@ cga_poll(void *p) cga->ma++; if (drawcursor) { for (c = 0; c < 8; c++) { - buffer->line[(cga->displine << 1)][(x << 4) + (c << 1) + 8] = - buffer->line[(cga->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = - buffer->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 8] = - buffer->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(cga->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(cga->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } } else { for (c = 0; c < 8; c++) { - buffer->line[(cga->displine << 1)][(x << 4) + (c << 1) + 8] = - buffer->line[(cga->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = - buffer->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 8] = - buffer->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(cga->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(cga->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } } @@ -342,17 +299,17 @@ cga_poll(void *p) cols[0] = (cga->cgacol & 15) | 16; col = (cga->cgacol & 16) ? 24 : 16; if (cga->cgamode & 4) { - cols[1] = col | 3; - cols[2] = col | 4; - cols[3] = col | 7; + cols[1] = col | 3; /* Cyan */ + cols[2] = col | 4; /* Red */ + cols[3] = col | 7; /* White */ } else if (cga->cgacol & 32) { - cols[1] = col | 3; - cols[2] = col | 5; - cols[3] = col | 7; + cols[1] = col | 3; /* Cyan */ + cols[2] = col | 5; /* Magenta */ + cols[3] = col | 7; /* White */ } else { - cols[1] = col | 2; - cols[2] = col | 4; - cols[3] = col | 6; + cols[1] = col | 2; /* Green */ + cols[2] = col | 4; /* Red */ + cols[3] = col | 6; /* Yellow */ } for (x = 0; x < cga->crtc[1]; x++) { if (cga->cgamode & 8) @@ -361,10 +318,10 @@ cga_poll(void *p) dat = 0; cga->ma++; for (c = 0; c < 8; c++) { - buffer->line[(cga->displine << 1)][(x << 4) + (c << 1) + 8] = - buffer->line[(cga->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = - buffer->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 8] = - buffer->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(cga->displine << 1)][(x << 4) + (c << 1) + 8] = + buffer32->line[(cga->displine << 1)][(x << 4) + (c << 1) + 1 + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; dat <<= 2; } @@ -378,8 +335,8 @@ cga_poll(void *p) dat = 0; cga->ma++; for (c = 0; c < 16; c++) { - buffer->line[(cga->displine << 1)][(x << 4) + c + 8] = - buffer->line[(cga->displine << 1) + 1][(x << 4) + c + 8] = + buffer32->line[(cga->displine << 1)][(x << 4) + c + 8] = + buffer32->line[(cga->displine << 1) + 1][(x << 4) + c + 8] = cols[dat >> 15]; dat <<= 1; } @@ -388,11 +345,11 @@ cga_poll(void *p) } else { cols[0] = ((cga->cgamode & 0x12) == 0x12) ? 0 : (cga->cgacol & 15) + 16; if (cga->cgamode & 1) { - hline(buffer, 0, (cga->displine << 1), (cga->crtc[1] << 3) + 16, cols[0]); - hline(buffer, 0, (cga->displine << 1) + 1, (cga->crtc[1] << 3) + 16, cols[0]); + hline(buffer32, 0, (cga->displine << 1), ((cga->crtc[1] << 3) + 16) << 2, cols[0]); + hline(buffer32, 0, (cga->displine << 1) + 1, ((cga->crtc[1] << 3) + 16) << 2, cols[0]); } else { - hline(buffer, 0, (cga->displine << 1), (cga->crtc[1] << 4) + 16, cols[0]); - hline(buffer, 0, (cga->displine << 1) + 1, (cga->crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, (cga->displine << 1), ((cga->crtc[1] << 4) + 16) << 2, cols[0]); + hline(buffer32, 0, (cga->displine << 1) + 1, ((cga->crtc[1] << 4) + 16) << 2, cols[0]); } } @@ -402,11 +359,6 @@ cga_poll(void *p) x = (cga->crtc[1] << 4) + 16; if (cga->composite) { - for (c = 0; c < x; c++) { - buffer32->line[(cga->displine << 1)][c] = buffer->line[(cga->displine << 1)][c] & 0xf; - buffer32->line[(cga->displine << 1) + 1][c] = buffer->line[(cga->displine << 1) + 1][c] & 0xf; - } - if (cga->cgamode & 0x10) border = 0x00; else @@ -423,7 +375,7 @@ cga_poll(void *p) if (cga->displine >= 360) cga->displine = 0; } else { - cga->vidtime += cga->dispontime; + timer_advance_u64(&cga->timer, cga->dispontime); cga->linepos = 0; if (cga->vsynctime) { cga->vsynctime--; @@ -486,9 +438,6 @@ cga_poll(void *p) else x = (cga->crtc[1] << 4) + 16; cga->lastline++; -#ifdef CGA_DEBUG - cga_print(cga); -#endif if ((cga->cgamode & 8) && x && (cga->lastline - cga->firstline) && ((x != xsize) || (((cga->lastline - cga->firstline) << 1) != ysize) || video_force_resize_get())) { @@ -551,6 +500,7 @@ cga_poll(void *p) void cga_init(cga_t *cga) { + timer_add(&cga->timer, cga_poll, cga, 1); cga->composite = 0; } @@ -572,7 +522,7 @@ cga_standalone_init(const device_t *info) cga->vram = malloc(0x4000); cga_comp_init(cga->revision); - timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); + timer_add(&cga->timer, cga_poll, cga, 1); mem_mapping_add(&cga->mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL /*cga->vram*/, MEM_MAPPING_EXTERNAL, cga); io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); diff --git a/src/video/vid_cga.h b/src/video/vid_cga.h index 839c810fa..aa37f7fad 100644 --- a/src/video/vid_cga.h +++ b/src/video/vid_cga.h @@ -36,8 +36,8 @@ typedef struct cga_t uint16_t ma, maback; int oddeven; - int64_t dispontime, dispofftime; - int64_t vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; diff --git a/src/video/vid_cga_comp.c b/src/video/vid_cga_comp.c index d53dc3ea4..b5e87078f 100644 --- a/src/video/vid_cga_comp.c +++ b/src/video/vid_cga_comp.c @@ -9,13 +9,13 @@ * IBM CGA composite filter, borrowed from reenigne's DOSBox * patch and ported to C. * - * Version: @(#)vid_cga_comp.c 1.0.4 2018/10/02 + * Version: @(#)vid_cga_comp.c 1.0.5 2019/03/24 * * Authors: reenigne, * Miran Grca, * - * Copyright 2015-2018 reenigne. - * Copyright 2015-2018 Miran Grca. + * Copyright 2015-2019 reenigne. + * Copyright 2015-2019 Miran Grca. */ #include #include @@ -24,6 +24,7 @@ #include #include #include "../86box.h" +#include "../timer.h" #include "../mem.h" #include "vid_cga.h" #include "vid_cga_comp.h" @@ -168,7 +169,7 @@ static int temp[SCALER_MAXWIDTH + 10]={0}; static int atemp[SCALER_MAXWIDTH + 2]={0}; static int btemp[SCALER_MAXWIDTH + 2]={0}; -Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine) +Bit32u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit32u *TempLine) { int x; Bit32u x2; @@ -176,7 +177,7 @@ Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool d int w = blocks*4; int *o; - Bit8u *rgbi; + Bit32u *rgbi; int *b; int *i; Bit32u* srgb; @@ -207,12 +208,12 @@ Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool d b = &CGA_Composite_Table[border*68]; for (x = 0; x < 4; ++x) OUT(b[(x+3)&3]); - OUT(CGA_Composite_Table[(border<<6) | ((*rgbi)<<2) | 3]); + OUT(CGA_Composite_Table[(border<<6) | ((*rgbi & 0x0f)<<2) | 3]); for (x = 0; x < w-1; ++x) { - OUT(CGA_Composite_Table[(rgbi[0]<<6) | (rgbi[1]<<2) | (x&3)]); + OUT(CGA_Composite_Table[((rgbi[0] & 0x0f)<<6) | ((rgbi[1] & 0x0f)<<2) | (x&3)]); ++rgbi; } - OUT(CGA_Composite_Table[((*rgbi)<<6) | (border<<2) | 3]); + OUT(CGA_Composite_Table[((*rgbi & 0x0f)<<6) | (border<<2) | 3]); for (x = 0; x < 5; ++x) OUT(b[x&3]); diff --git a/src/video/vid_cga_comp.h b/src/video/vid_cga_comp.h index fbea172e7..fc19ae252 100644 --- a/src/video/vid_cga_comp.h +++ b/src/video/vid_cga_comp.h @@ -9,12 +9,12 @@ * IBM CGA composite filter, borrowed from reenigne's DOSBox * patch and ported to C. * - * Version: @(#)vid_cga.h 1.0.0 2017/05/30 + * Version: @(#)vid_cga.h 1.0.1 2018/03/24 * * Author: reenigne, * Miran Grca, - * Copyright 2015-2017 reenigne. - * Copyright 2015-2017 Miran Grca. + * Copyright 2015-2018 reenigne. + * Copyright 2015-2018 Miran Grca. */ #define Bit8u uint8_t @@ -24,4 +24,4 @@ void update_cga16_color(uint8_t cgamode); void cga_comp_init(int revision); -Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine); +Bit32u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit32u *TempLine); diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 31fb49807..fee260cfc 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -9,17 +9,13 @@ * Emulation of select Cirrus Logic cards (CL-GD 5428, * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). * - * Version: @(#)vid_cl_54xx.c 1.0.27 2019/01/13 + * Version: @(#)vid_cl_54xx.c 1.0.28 2019/07/05 * - * Authors: Sarah Walker, - * Barry Rodewald, - * TheCollector1995, + * Authors: TheCollector1995, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2018 Barry Rodewald - * Copyright 2016-2018 TheCollector1995. - * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2019 TheCollector1995. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -28,12 +24,13 @@ #include #include #include "../86box.h" - #include "../cpu/cpu.h" +#include "../cpu/cpu.h" #include "../io.h" #include "../mem.h" #include "../pci.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" @@ -115,9 +112,12 @@ #define CIRRUS_BLT_START 0x02 #define CIRRUS_BLT_RESET 0x04 #define CIRRUS_BLT_FIFOUSED 0x10 +#define CIRRUS_BLT_PAUSED 0x20 +#define CIRRUS_BLT_APERTURE2 0x40 #define CIRRUS_BLT_AUTOSTART 0x80 // control 0x33 +#define CIRRUS_BLTMODEEXT_BACKGROUNDONLY 0x08 #define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04 #define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02 #define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 @@ -133,6 +133,7 @@ typedef struct gd54xx_t { mem_mapping_t mmio_mapping; mem_mapping_t linear_mapping; + mem_mapping_t aperture2_mapping; svga_t svga; @@ -152,41 +153,42 @@ typedef struct gd54xx_t } ramdac; struct { - uint32_t fg_col, bg_col; uint16_t width, height; uint16_t dst_pitch, src_pitch; - uint32_t dst_addr, src_addr; - uint8_t mask, mode, rop; - uint8_t modeext; - uint8_t status; uint16_t trans_col, trans_mask; + uint16_t height_internal; + uint8_t status, pad; + uint8_t mask, mode, rop, modeext; + + uint32_t fg_col, bg_col; uint32_t dst_addr_backup, src_addr_backup; - uint16_t width_backup, height_internal; + uint32_t dst_addr, src_addr; + uint32_t sys_src32, sys_cnt; + /* Internal state */ + int pixel_width, pattern_x; int x_count, y_count; - int sys_tx; - uint8_t sys_cnt; - uint32_t sys_buf; - uint16_t pixel_cnt; - uint16_t scan_cnt; + int xx_count, dir; + int unlock_special; } blt; - int pci, vlb; + int pci, vlb; + int countminusone; - uint8_t pci_regs[256]; - uint8_t int_line; + uint8_t pci_regs[256]; + uint8_t int_line; uint8_t fc; /* Feature Connector */ - - int card; - uint32_t lfb_base; + int card; - int mmio_vram_overlap; + uint32_t lfb_base; - uint32_t extpallook[256]; - PALETTE extpal; + int mmio_vram_overlap; + + uint32_t extpallook[256]; + PALETTE extpal; } gd54xx_t; @@ -197,6 +199,8 @@ static video_timings_t timing_gd54xx_vlb_pci = {VIDEO_BUS, 4, 4, 8, 10, 10, 2 static void gd543x_mmio_write(uint32_t addr, uint8_t val, void *p); static void +gd543x_mmio_writeb(uint32_t addr, uint8_t val, void *p); +static void gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p); static void gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p); @@ -213,27 +217,45 @@ gd54xx_recalc_banking(gd54xx_t *gd54xx); static void gd543x_recalc_mapping(gd54xx_t *gd54xx); +static void +gd54xx_reset_blit(gd54xx_t *gd54xx); static void -gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga); +gd54xx_start_blit(uint32_t cpu_dat, uint32_t count, gd54xx_t *gd54xx, svga_t *svga); + /* Returns 1 if the card is a 5422+ */ static int gd54xx_is_5422(svga_t *svga) { - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422) - return 1; - else - return 0; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422) + return 1; + else + return 0; } + +/* Returns 1 if the card supports the 8-bpp/16-bpp transparency color or mask. */ +static int +gd54xx_has_transp(svga_t *svga, int mask) +{ + if (((svga->crtc[0x27] == CIRRUS_ID_CLGD5446) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5480)) && + !mask) + return 1; /* 5446 and 5480 have mask but not transparency. */ + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5426) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5428)) + return 1; /* 5426 and 5428 have both. */ + else + return 0; /* The rest have neither. */ +} + + /* Returns 1 if the card is a 5434, 5436/46, or 5480. */ static int gd54xx_is_5434(svga_t *svga) { - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) - return 1; - else - return 0; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) + return 1; + else + return 0; } @@ -381,10 +403,10 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) return; break; case 0x07: - if (!gd54xx_is_5422(svga)) { - svga->seqregs[svga->seqaddr] &= 0x0f; + if (gd54xx_is_5422(svga)) gd543x_recalc_mapping(gd54xx); - } + else + svga->seqregs[svga->seqaddr] &= 0x0f; if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5429) svga->set_reset_disabled = svga->seqregs[7] & 1; case 0x17: @@ -443,34 +465,51 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) break; } return; + case 0x3ce: + /* Per the CL-GD 5446 manual: bits 0-5 are the GDC register index, bits 6-7 are reserved. */ + svga->gdcaddr = val/* & 0x3f*/; + return; case 0x3cf: - if (svga->gdcaddr == 0) - gd543x_mmio_write(0xb8000, val, gd54xx); - if (svga->gdcaddr == 1) - gd543x_mmio_write(0xb8004, val, gd54xx); - - if (svga->gdcaddr == 5) { - svga->gdcreg[5] = val; - if (svga->gdcreg[0xb] & 0x04) - svga->writemode = svga->gdcreg[5] & 7; - else - svga->writemode = svga->gdcreg[5] & 3; - svga->readmode = val & 8; - svga->chain2_read = val & 0x10; - return; - } + o = svga->gdcreg[svga->gdcaddr]; + svga->gdcreg[svga->gdcaddr] = val; - if (svga->gdcaddr == 6) { - if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { - svga->gdcreg[6] = val; - gd543x_recalc_mapping(gd54xx); + if (svga->gdcaddr <= 8) { + switch (svga->gdcaddr) { + case 0: + gd543x_mmio_write(0xb8000, val, gd54xx); + break; + case 1: + gd543x_mmio_write(0xb8004, val, gd54xx); + break; + case 2: + svga->colourcompare = val; + break; + case 4: + svga->readplane = val & 3; + break; + case 5: + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = val & 7; + else + svga->writemode = val & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + break; + case 6: + if ((o ^ val) & 0x0c) + gd543x_recalc_mapping(gd54xx); + break; + case 7: + svga->colournocare = val; + break; } - svga->gdcreg[6] = val; - return; - } - if (svga->gdcaddr > 8) { - svga->gdcreg[svga->gdcaddr & 0x3f] = val; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4; + if ((svga->gdcaddr == 5 && (val ^ o) & 0x70) || + (svga->gdcaddr == 6 && (val ^ o) & 1)) + svga_recalctimings(svga); + } else { switch (svga->gdcaddr) { case 0x09: case 0x0a: case 0x0b: gd54xx_recalc_banking(gd54xx); @@ -479,110 +518,108 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) else svga->writemode = svga->gdcreg[5] & 3; break; - - case 0x10: + + case 0x10: gd543x_mmio_write(0xb8001, val, gd54xx); break; - case 0x11: + case 0x11: gd543x_mmio_write(0xb8005, val, gd54xx); break; - case 0x12: + case 0x12: gd543x_mmio_write(0xb8002, val, gd54xx); break; - case 0x13: + case 0x13: gd543x_mmio_write(0xb8006, val, gd54xx); break; - case 0x14: + case 0x14: gd543x_mmio_write(0xb8003, val, gd54xx); break; - case 0x15: + case 0x15: gd543x_mmio_write(0xb8007, val, gd54xx); break; - - case 0x20: + + case 0x20: gd543x_mmio_write(0xb8008, val, gd54xx); break; - case 0x21: + case 0x21: gd543x_mmio_write(0xb8009, val, gd54xx); break; - case 0x22: + case 0x22: gd543x_mmio_write(0xb800a, val, gd54xx); break; - case 0x23: + case 0x23: gd543x_mmio_write(0xb800b, val, gd54xx); break; - case 0x24: + case 0x24: gd543x_mmio_write(0xb800c, val, gd54xx); break; - case 0x25: + case 0x25: gd543x_mmio_write(0xb800d, val, gd54xx); break; - case 0x26: + case 0x26: gd543x_mmio_write(0xb800e, val, gd54xx); break; - case 0x27: + case 0x27: gd543x_mmio_write(0xb800f, val, gd54xx); break; - - case 0x28: + + case 0x28: gd543x_mmio_write(0xb8010, val, gd54xx); break; - case 0x29: + case 0x29: gd543x_mmio_write(0xb8011, val, gd54xx); break; - case 0x2a: + case 0x2a: gd543x_mmio_write(0xb8012, val, gd54xx); break; - case 0x2c: + case 0x2c: gd543x_mmio_write(0xb8014, val, gd54xx); break; - case 0x2d: + case 0x2d: gd543x_mmio_write(0xb8015, val, gd54xx); break; - case 0x2e: + case 0x2e: gd543x_mmio_write(0xb8016, val, gd54xx); break; - case 0x2f: + case 0x2f: gd543x_mmio_write(0xb8017, val, gd54xx); break; - case 0x30: + case 0x30: gd543x_mmio_write(0xb8018, val, gd54xx); break; - - case 0x32: + + case 0x32: gd543x_mmio_write(0xb801a, val, gd54xx); break; - case 0x33: + case 0x33: gd543x_mmio_write(0xb801b, val, gd54xx); break; - - case 0x31: + + case 0x31: gd543x_mmio_write(0xb8040, val, gd54xx); break; - - case 0x34: + + case 0x34: gd543x_mmio_write(0xb801c, val, gd54xx); break; - - case 0x35: + + case 0x35: gd543x_mmio_write(0xb801d, val, gd54xx); break; - case 0x38: + case 0x38: gd543x_mmio_write(0xb8020, val, gd54xx); break; - case 0x39: + case 0x39: gd543x_mmio_write(0xb8021, val, gd54xx); - break; - + break; } - return; } - break; + return; case 0x3D4: svga->crtcreg = val & 0x3f; return; @@ -696,11 +733,117 @@ gd54xx_in(uint16_t addr, void *p) } gd54xx->ramdac.state++; break; + case 0x3ce: + return svga->gdcaddr & 0x3f; case 0x3cf: - if (svga->gdcaddr > 8) { - return svga->gdcreg[svga->gdcaddr & 0x3f]; - } - break; + if (svga->gdcaddr >= 0x10) { + switch (svga->gdcaddr) { + case 0x10: + temp = gd543x_mmio_read(0xb8001, gd54xx); + break; + case 0x11: + temp = gd543x_mmio_read(0xb8005, gd54xx); + break; + case 0x12: + temp = gd543x_mmio_read(0xb8002, gd54xx); + break; + case 0x13: + temp = gd543x_mmio_read(0xb8006, gd54xx); + break; + case 0x14: + temp = gd543x_mmio_read(0xb8003, gd54xx); + break; + case 0x15: + temp = gd543x_mmio_read(0xb8007, gd54xx); + break; + + case 0x20: + temp = gd543x_mmio_read(0xb8008, gd54xx); + break; + case 0x21: + temp = gd543x_mmio_read(0xb8009, gd54xx); + break; + case 0x22: + temp = gd543x_mmio_read(0xb800a, gd54xx); + break; + case 0x23: + temp = gd543x_mmio_read(0xb800b, gd54xx); + break; + case 0x24: + temp = gd543x_mmio_read(0xb800c, gd54xx); + break; + case 0x25: + temp = gd543x_mmio_read(0xb800d, gd54xx); + break; + case 0x26: + temp = gd543x_mmio_read(0xb800e, gd54xx); + break; + case 0x27: + temp = gd543x_mmio_read(0xb800f, gd54xx); + break; + + case 0x28: + temp = gd543x_mmio_read(0xb8010, gd54xx); + break; + case 0x29: + temp = gd543x_mmio_read(0xb8011, gd54xx); + break; + case 0x2a: + temp = gd543x_mmio_read(0xb8012, gd54xx); + break; + + case 0x2c: + temp = gd543x_mmio_read(0xb8014, gd54xx); + break; + case 0x2d: + temp = gd543x_mmio_read(0xb8015, gd54xx); + break; + case 0x2e: + temp = gd543x_mmio_read(0xb8016, gd54xx); + break; + + case 0x2f: + temp = gd543x_mmio_read(0xb8017, gd54xx); + break; + case 0x30: + temp = gd543x_mmio_read(0xb8018, gd54xx); + break; + + case 0x32: + temp = gd543x_mmio_read(0xb801a, gd54xx); + break; + + case 0x33: + temp = gd543x_mmio_read(0xb801b, gd54xx); + break; + + case 0x31: + temp = gd543x_mmio_read(0xb8040, gd54xx); + break; + + case 0x34: + temp = gd543x_mmio_read(0xb801c, gd54xx); + break; + + case 0x35: + temp = gd543x_mmio_read(0xb801d, gd54xx); + break; + + case 0x38: + temp = gd543x_mmio_read(0xb8020, gd54xx); + break; + + case 0x39: + temp = gd543x_mmio_read(0xb8021, gd54xx); + break; + + default: + temp = 0xff; + break; + } + } else + temp = svga->gdcreg[svga->gdcaddr]; + return temp; case 0x3D4: return svga->crtcreg; case 0x3D5: @@ -769,8 +912,9 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) gd54xx->mmio_vram_overlap = 0; - if (!(svga->seqregs[7] & 0xf0)) { + if (!gd54xx_is_5422(svga) || !(svga->seqregs[7] & 0xf0)) { mem_mapping_disable(&gd54xx->linear_mapping); + mem_mapping_disable(&gd54xx->aperture2_mapping); switch (svga->gdcreg[6] & 0x0c) { case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); @@ -790,9 +934,13 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) gd54xx->mmio_vram_overlap = 1; break; } - if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) - mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); - else + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) { + if (gd54xx->mmio_vram_overlap) { + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x08000); + } else + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + } else mem_mapping_disable(&gd54xx->mmio_mapping); } else { uint32_t base, size; @@ -822,18 +970,20 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) mem_mapping_disable(&svga->mapping); mem_mapping_set_addr(&gd54xx->linear_mapping, base, size); if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) { - if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) { - if (size >= (4 * 1024 * 1024)) - mem_mapping_disable(&gd54xx->mmio_mapping); /* MMIO is handled in the linear read/write functions */ - else { - mem_mapping_set_addr(&gd54xx->linear_mapping, base, size - 256); - mem_mapping_set_addr(&gd54xx->mmio_mapping, base + size - 256, 0x00100); - } - } else + if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) + mem_mapping_disable(&gd54xx->mmio_mapping); /* MMIO is handled in the linear read/write functions */ + else mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); } else mem_mapping_disable(&gd54xx->mmio_mapping); - } + + if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) && (gd54xx->blt.status & CIRRUS_BLT_APERTURE2) && + ((gd54xx->blt.mode & (CIRRUS_BLTMODE_COLOREXPAND | CIRRUS_BLTMODE_MEMSYSSRC)) == + (CIRRUS_BLTMODE_COLOREXPAND | CIRRUS_BLTMODE_MEMSYSSRC))) + mem_mapping_set_addr(&gd54xx->aperture2_mapping, 0xbc000, 0x04000); + else + mem_mapping_disable(&gd54xx->aperture2_mapping); + } } @@ -916,7 +1066,7 @@ gd54xx_recalctimings(svga_t *svga) clocksel = (svga->miscout >> 2) & 3; if (!gd54xx->vclk_n[clocksel] || !gd54xx->vclk_d[clocksel]) - svga->clock = cpuclock / ((svga->miscout & 0xc) ? 28322000.0 : 25175000.0); + svga->clock = (cpuclock * (float)(1ull << 32)) / ((svga->miscout & 0xc) ? 28322000.0 : 25175000.0); else { int n = gd54xx->vclk_n[clocksel] & 0x7f; int d = (gd54xx->vclk_d[clocksel] & 0x3e) >> 1; @@ -933,13 +1083,13 @@ gd54xx_recalctimings(svga_t *svga) break; } } - svga->clock = cpuclock / freq; + svga->clock = (cpuclock * (double)(1ull << 32)) / freq; } - if (gd54xx->vram_size == (1 << 19)) /* Note : why 512Kb VRAM cards do not wrap */ - svga->vram_display_mask = gd54xx->vram_mask; - else - svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; + if (gd54xx->vram_size == (1 << 19)) /* Note : why 512Kb VRAM cards do not wrap */ + svga->vram_display_mask = gd54xx->vram_mask; + else + svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; } static @@ -1028,71 +1178,18 @@ gd54xx_rop(gd54xx_t *gd54xx, uint8_t *res, uint8_t *dst, const uint8_t *src) { static void -gd54xx_memsrc_rop(gd54xx_t *gd54xx, svga_t *svga, uint8_t src, uint8_t dst) +gd54xx_mem_sys_src_write(gd54xx_t *gd54xx, uint8_t val) { - uint8_t res = src; - svga->changedvram[(gd54xx->blt.dst_addr_backup & svga->vram_mask) >> 12] = changeframecount; - - gd54xx_rop(gd54xx, &res, &dst, (const uint8_t *) &src); - - /* handle transparency compare */ - if (gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { /* TODO: 16-bit compare */ - /* if ROP result matches the transparency colour, don't change the pixel */ - if ((res & (~gd54xx->blt.trans_mask & 0xff)) == ((gd54xx->blt.trans_col & 0xff) & (~gd54xx->blt.trans_mask & 0xff))) - return; + if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && + !(gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)) { + gd54xx_start_blit(val, 8, gd54xx, &gd54xx->svga); + } else { + gd54xx->blt.sys_src32 &= ~(0xff << (gd54xx->blt.sys_cnt << 3)); + gd54xx->blt.sys_src32 |= (val << (gd54xx->blt.sys_cnt << 3)); + gd54xx->blt.sys_cnt = (gd54xx->blt.sys_cnt + 1) & 3; + if (gd54xx->blt.sys_cnt == 0) + gd54xx_start_blit(gd54xx->blt.sys_src32, 32, gd54xx, &gd54xx->svga); } - - svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask] = res; -} - - -/* non colour-expanded BitBLTs from system memory must be doubleword sized, extra bytes are ignored */ -static void -gd54xx_blit_dword(gd54xx_t *gd54xx, svga_t *svga) -{ - /* TODO: add support for reverse direction */ - uint8_t x, pixel; - - for (x=0;x<32;x+=8) { - pixel = ((gd54xx->blt.sys_buf & (0xff << x)) >> x); - if(gd54xx->blt.pixel_cnt <= gd54xx->blt.width) - gd54xx_memsrc_rop(gd54xx, svga, pixel, svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask]); - gd54xx->blt.dst_addr_backup++; - gd54xx->blt.pixel_cnt++; - } - if (gd54xx->blt.pixel_cnt > gd54xx->blt.width) { - gd54xx->blt.pixel_cnt = 0; - gd54xx->blt.scan_cnt++; - gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr + (gd54xx->blt.dst_pitch*gd54xx->blt.scan_cnt); - } - if (gd54xx->blt.scan_cnt > gd54xx->blt.height) { - gd54xx->blt.sys_tx = 0; /* BitBLT complete */ - gd543x_recalc_mapping(gd54xx); - } -} - - -static void -gd54xx_blt_write_w(uint32_t addr, uint16_t val, void *p) -{ - gd54xx_t *gd54xx = (gd54xx_t *)p; - - gd54xx_start_blit(val, 16, gd54xx, &gd54xx->svga); -} - - -static void -gd54xx_blt_write_l(uint32_t addr, uint32_t val, void *p) -{ - gd54xx_t *gd54xx = (gd54xx_t *)p; - - if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) { - gd54xx_start_blit(val & 0xff, 8, gd54xx, &gd54xx->svga); - gd54xx_start_blit((val>>8) & 0xff, 8, gd54xx, &gd54xx->svga); - gd54xx_start_blit((val>>16) & 0xff, 8, gd54xx, &gd54xx->svga); - gd54xx_start_blit((val>>24) & 0xff, 8, gd54xx, &gd54xx->svga); - } else - gd54xx_start_blit(val, 32, gd54xx, &gd54xx->svga); } @@ -1102,21 +1199,13 @@ gd54xx_write(uint32_t addr, uint8_t val, void *p) gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - if ((svga->seqregs[0x07] & 0x01) == 0) { - svga_write(addr, val, svga); + if (gd54xx->countminusone && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_mem_sys_src_write(gd54xx, val); return; } - if (gd54xx->blt.sys_tx) { - if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { - gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); - gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); - gd54xx->blt.sys_cnt++; - if(gd54xx->blt.sys_cnt >= 4) { - gd54xx_blit_dword(gd54xx, svga); - gd54xx->blt.sys_cnt = 0; - } - } + if ((svga->seqregs[0x07] & 0x01) == 0) { + svga_write(addr, val, svga); return; } @@ -1133,14 +1222,14 @@ gd54xx_writew(uint32_t addr, uint16_t val, void *p) gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - if ((svga->seqregs[0x07] & 0x01) == 0) { - svga_writew(addr, val, svga); + if (gd54xx->countminusone && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr + 1, val >> 8, gd54xx); return; } - if (gd54xx->blt.sys_tx) { - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr+1, val >> 8, gd54xx); + if ((svga->seqregs[0x07] & 0x01) == 0) { + svga_writew(addr, val, svga); return; } @@ -1162,16 +1251,16 @@ gd54xx_writel(uint32_t addr, uint32_t val, void *p) gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - if ((svga->seqregs[0x07] & 0x01) == 0) { - svga_writel(addr, val, svga); + if (gd54xx->countminusone && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr + 1, val >> 8, gd54xx); + gd54xx_write(addr + 2, val >> 16, gd54xx); + gd54xx_write(addr + 3, val >> 24, gd54xx); return; } - if (gd54xx->blt.sys_tx) { - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr+1, val >> 8, gd54xx); - gd54xx_write(addr+2, val >> 16, gd54xx); - gd54xx_write(addr+3, val >> 24, gd54xx); + if ((svga->seqregs[0x07] & 0x01) == 0) { + svga_writel(addr, val, svga); return; } @@ -1248,20 +1337,28 @@ gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) static uint8_t gd54xx_get_aperture(uint32_t addr) { - uint32_t ap = addr >> 22; - return (uint8_t) (ap & 0x03); + uint32_t ap = addr >> 22; + return (uint8_t) (ap & 0x03); } static uint8_t gd54xx_readb_linear(uint32_t addr, void *p) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; uint8_t ap = gd54xx_get_aperture(addr); addr &= 0x003fffff; /* 4 MB mask */ + if ((svga->seqregs[0x07] & 0x01) == 0) + return svga_read_linear(addr, svga); + + if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) + return gd543x_mmio_read(addr & 0x000000ff, gd54xx); + } + switch (ap) { case 0: default: @@ -1278,61 +1375,44 @@ gd54xx_readb_linear(uint32_t addr, void *p) return 0xff; } - if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) - return gd543x_mmio_read(addr & 0x000000ff, gd54xx); - } - - return svga_read_linear(addr, p); + return svga_read_linear(addr, svga); } static uint16_t gd54xx_readw_linear(uint32_t addr, void *p) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; uint8_t ap = gd54xx_get_aperture(addr); - uint16_t temp, temp2; + uint16_t temp; addr &= 0x003fffff; /* 4 MB mask */ - if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x07] & 0x01) == 0) + return svga_readw_linear(addr, svga); + + if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) { if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { - if (ap == 2) - addr ^= 0x00000002; - temp = gd543x_mmio_readw(addr & 0x000000ff, gd54xx); - - switch(ap) { - case 0: - default: - return temp; - case 1: - case 2: - temp2 = temp >> 8; - temp2 |= ((temp & 0xff) << 8); - return temp; - case 3: - return 0xffff; - } + return temp; } } switch (ap) { case 0: default: - return svga_readw_linear(addr, p); + return svga_readw_linear(addr, svga); case 2: /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ addr ^= 0x00000002; case 1: - temp = svga_readb_linear(addr + 1, p); - temp |= (svga_readb_linear(addr, p) << 8); + temp = svga_readb_linear(addr + 1, svga); + temp |= (svga_readb_linear(addr, svga) << 8); if (svga->fast) - cycles -= video_timing_read_w; + sub_cycles(video_timing_read_w); return temp; case 3: @@ -1344,64 +1424,46 @@ gd54xx_readw_linear(uint32_t addr, void *p) static uint32_t gd54xx_readl_linear(uint32_t addr, void *p) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; uint8_t ap = gd54xx_get_aperture(addr); - uint32_t temp, temp2; + uint32_t temp; addr &= 0x003fffff; /* 4 MB mask */ - if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x07] & 0x01) == 0) + return svga_readl_linear(addr, svga); + + if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) { if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { temp = gd543x_mmio_readl(addr & 0x000000ff, gd54xx); - - switch(ap) { - case 0: - default: - return temp; - case 1: - temp2 = temp >> 24; - temp2 |= ((temp >> 16) & 0xff) << 8; - temp2 |= ((temp >> 8) & 0xff) << 16; - temp2 |= (temp & 0xff) << 24; - - return temp2; - case 2: - temp2 = (temp >> 8) & 0xff; - temp2 |= (temp & 0xff) << 8; - temp2 = ((temp >> 24) & 0xff) << 16; - temp2 = ((temp >> 16) & 0xff) << 24; - - return temp2; - case 3: - return 0xffffffff; - } + return temp; } } switch (ap) { case 0: default: - return svga_readw_linear(addr, p); + return svga_readl_linear(addr, svga); case 1: - temp = svga_readb_linear(addr + 1, p); - temp |= (svga_readb_linear(addr, p) << 8); - temp |= (svga_readb_linear(addr + 3, p) << 16); - temp |= (svga_readb_linear(addr + 2, p) << 24); + temp = svga_readb_linear(addr + 1, svga); + temp |= (svga_readb_linear(addr, svga) << 8); + temp |= (svga_readb_linear(addr + 3, svga) << 16); + temp |= (svga_readb_linear(addr + 2, svga) << 24); if (svga->fast) - cycles -= video_timing_read_l; + sub_cycles(video_timing_read_l); return temp; case 2: - temp = svga_readb_linear(addr + 3, p); - temp |= (svga_readb_linear(addr + 2, p) << 8); - temp |= (svga_readb_linear(addr + 1, p) << 16); - temp |= (svga_readb_linear(addr, p) << 24); + temp = svga_readb_linear(addr + 3, svga); + temp |= (svga_readb_linear(addr + 2, svga) << 8); + temp |= (svga_readb_linear(addr + 1, svga) << 16); + temp |= (svga_readb_linear(addr, svga) << 24); if (svga->fast) - cycles -= video_timing_read_l; + sub_cycles(video_timing_read_l); return temp; case 3: @@ -1410,15 +1472,92 @@ gd54xx_readl_linear(uint32_t addr, void *p) } +static int +gd54xx_aperture2_enabled(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) + return 0; + + if (!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)) + return 0; + + if (!(gd54xx->blt.status & CIRRUS_BLT_APERTURE2)) + return 0; + + return 1; +} + + +static void +gd5436_aperture2_writeb(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if (gd54xx->countminusone && gd54xx_aperture2_enabled(gd54xx) && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) + gd54xx_mem_sys_src_write(gd54xx, val); +} + + +static void +gd5436_aperture2_writew(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if (gd54xx->countminusone && gd54xx_aperture2_enabled(gd54xx) && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd5436_aperture2_writeb(addr, val, gd54xx); + gd5436_aperture2_writeb(addr + 1, val >> 8, gd54xx); + } +} + + +static void +gd5436_aperture2_writel(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if (gd54xx->countminusone && gd54xx_aperture2_enabled(gd54xx) && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd5436_aperture2_writeb(addr, val, gd54xx); + gd5436_aperture2_writeb(addr + 1, val >> 8, gd54xx); + gd5436_aperture2_writeb(addr + 2, val >> 16, gd54xx); + gd5436_aperture2_writeb(addr + 3, val >> 24, gd54xx); + } +} + + static void gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; uint8_t ap = gd54xx_get_aperture(addr); + + if ((svga->seqregs[0x07] & 0x01) == 0) { + svga_write_linear(addr, val, svga); + return; + } + addr &= 0x003fffff; /* 4 MB mask */ + if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + gd543x_mmio_write(addr & 0x000000ff, val, gd54xx); + return; + } + } + + /* Do mem sys src writes here if the blitter is neither paused, nor is there a second aperture. */ + if (gd54xx->countminusone && !gd54xx_aperture2_enabled(gd54xx) && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_mem_sys_src_write(gd54xx, val); + return; + } + switch (ap) { case 0: default: @@ -1435,24 +1574,6 @@ gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) return; } - if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) - gd543x_mmio_write(addr & 0x000000ff, val, gd54xx); - } - - if (gd54xx->blt.sys_tx) { - if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { - gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); - gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); - gd54xx->blt.sys_cnt++; - if(gd54xx->blt.sys_cnt >= 4) { - gd54xx_blit_dword(gd54xx, svga); - gd54xx->blt.sys_cnt = 0; - } - } - return; - } - svga_write_linear(addr, val, svga); } @@ -1460,39 +1581,33 @@ gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) static void gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; uint8_t ap = gd54xx_get_aperture(addr); - uint16_t temp; - if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { - switch(ap) { - case 0: - default: - gd543x_mmio_writew(addr & 0x000000ff, val, gd54xx); - return; - case 2: - addr ^= 0x00000002; - case 1: - temp = (val >> 8); - temp |= ((val & 0xff) << 8); - gd543x_mmio_writew(addr & 0x000000ff, temp, gd54xx); - case 3: - return; - } - } - } - - if (gd54xx->blt.sys_tx) { - gd54xx_writeb_linear(addr, val, svga); - gd54xx_writeb_linear(addr+1, val >> 8, svga); + if ((svga->seqregs[0x07] & 0x01) == 0) { + svga_writew_linear(addr, val, svga); return; } addr &= 0x003fffff; /* 4 MB mask */ + if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + gd543x_mmio_writew(addr & 0x000000ff, val, gd54xx); + return; + } + } + + /* Do mem sys src writes here if the blitter is neither paused, nor is there a second aperture. */ + if (gd54xx->countminusone && !gd54xx_aperture2_enabled(gd54xx) && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_writeb_linear(addr, val, gd54xx); + gd54xx_writeb_linear(addr + 1, val >> 8, gd54xx); + return; + } + if (svga->writemode < 4) { switch(ap) { case 0: @@ -1506,7 +1621,7 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) svga_writeb_linear(addr, val >> 8, svga); if (svga->fast) - cycles -= video_timing_write_w; + sub_cycles(video_timing_write_w); case 3: return; } @@ -1532,49 +1647,35 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) static void gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) { - svga_t *svga = (svga_t *)p; - gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; uint8_t ap = gd54xx_get_aperture(addr); - uint32_t temp; - if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { - switch(ap) { - case 0: - default: - gd543x_mmio_writel(addr & 0x000000ff, val, gd54xx); - return; - case 2: - temp = (val >> 24); - temp |= ((val >> 16) & 0xff) << 8; - temp |= ((val >> 8) & 0xff) << 16; - temp |= (val & 0xff) << 24; - gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); - return; - case 1: - temp = ((val >> 8) & 0xff); - temp |= (val & 0xff) << 8; - temp |= (val >> 24) << 16; - temp |= ((val >> 16) & 0xff) << 24; - gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); - return; - case 3: - return; - } - } - } - - if (gd54xx->blt.sys_tx) { - gd54xx_writeb_linear(addr, val, svga); - gd54xx_writeb_linear(addr+1, val >> 8, svga); - gd54xx_writeb_linear(addr+2, val >> 16, svga); - gd54xx_writeb_linear(addr+3, val >> 24, svga); + if ((svga->seqregs[0x07] & 0x01) == 0) { + svga_writel_linear(addr, val, svga); return; } addr &= 0x003fffff; /* 4 MB mask */ - + + if ((addr >= (svga->vram_max - 256)) && (addr < svga->vram_max)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + gd543x_mmio_writel(addr & 0x000000ff, val, gd54xx); + return; + } + } + + /* Do mem sys src writes here if the blitter is neither paused, nor is there a second aperture. */ + if (gd54xx->countminusone && !gd54xx_aperture2_enabled(gd54xx) && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_writeb_linear(addr, val, gd54xx); + gd54xx_writeb_linear(addr + 1, val >> 8, gd54xx); + gd54xx_writeb_linear(addr + 2, val >> 16, gd54xx); + gd54xx_writeb_linear(addr + 3, val >> 24, gd54xx); + return; + } + if (svga->writemode < 4) { switch(ap) { case 0: @@ -1597,7 +1698,7 @@ gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) } if (svga->fast) - cycles -= video_timing_write_l; + sub_cycles(video_timing_write_l); } else { switch(ap) { case 0: @@ -1634,6 +1735,9 @@ gd54xx_read(uint32_t addr, void *p) if ((svga->seqregs[0x07] & 0x01) == 0) return svga_read(addr, svga); + if (gd54xx->countminusone) + return 0xff; + addr &= svga->banked_mask; addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; return svga_read_linear(addr, svga); @@ -1649,6 +1753,9 @@ gd54xx_readw(uint32_t addr, void *p) if ((svga->seqregs[0x07] & 0x01) == 0) return svga_readw(addr, svga); + if (gd54xx->countminusone) + return 0xffff; + addr &= svga->banked_mask; addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; return svga_readw_linear(addr, svga); @@ -1664,6 +1771,9 @@ gd54xx_readl(uint32_t addr, void *p) if ((svga->seqregs[0x07] & 0x01) == 0) return svga_readl(addr, svga); + if (gd54xx->countminusone) + return 0xffffffff; + addr &= svga->banked_mask; addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; return svga_readl_linear(addr, svga); @@ -1685,176 +1795,185 @@ gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; - + uint8_t old; + if (gd543x_do_mmio(svga, addr)) { switch (addr & 0xff) { - case 0x00: - if (gd54xx_is_5434(svga)) + case 0x00: + if (gd54xx_is_5434(svga)) gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffffff00) | val; - else + else gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00) | val; - break; - case 0x01: - if (gd54xx_is_5434(svga)) + break; + case 0x01: + if (gd54xx_is_5434(svga)) gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffff00ff) | (val << 8); - else + else gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ff) | (val << 8); - break; - case 0x02: - if (gd54xx_is_5434(svga)) + break; + case 0x02: + if (gd54xx_is_5434(svga)) gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00ffff) | (val << 16); - break; - case 0x03: - if (gd54xx_is_5434(svga)) + break; + case 0x03: + if (gd54xx_is_5434(svga)) gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ffffff) | (val << 24); - break; + break; - case 0x04: - if (gd54xx_is_5434(svga)) + case 0x04: + if (gd54xx_is_5434(svga)) gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffffff00) | val; - else + else gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00) | val; - break; - case 0x05: - if (gd54xx_is_5434(svga)) + break; + case 0x05: + if (gd54xx_is_5434(svga)) gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffff00ff) | (val << 8); - else + else gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ff) | (val << 8); - break; - case 0x06: - if (gd54xx_is_5434(svga)) + break; + case 0x06: + if (gd54xx_is_5434(svga)) gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00ffff) | (val << 16); - break; - case 0x07: - if (gd54xx_is_5434(svga)) + break; + case 0x07: + if (gd54xx_is_5434(svga)) gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ffffff) | (val << 24); - break; + break; - case 0x08: - gd54xx->blt.width = (gd54xx->blt.width & 0xff00) | val; - break; - case 0x09: - gd54xx->blt.width = (gd54xx->blt.width & 0x00ff) | (val << 8); - if (gd54xx_is_5434(svga)) + case 0x08: + gd54xx->blt.width = (gd54xx->blt.width & 0xff00) | val; + break; + case 0x09: + gd54xx->blt.width = (gd54xx->blt.width & 0x00ff) | (val << 8); + if (gd54xx_is_5434(svga)) gd54xx->blt.width &= 0x1fff; - else + else gd54xx->blt.width &= 0x07ff; - break; - case 0x0a: - gd54xx->blt.height = (gd54xx->blt.height & 0xff00) | val; - break; - case 0x0b: - gd54xx->blt.height = (gd54xx->blt.height & 0x00ff) | (val << 8); - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) - gd54xx->blt.height &= 0x07ff; - else - gd54xx->blt.height &= 0x03ff; - break; - case 0x0c: - gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0xff00) | val; - break; - case 0x0d: - gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0x00ff) | (val << 8); - break; - case 0x0e: - gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0xff00) | val; - break; - case 0x0f: - gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0x00ff) | (val << 8); - break; + break; + case 0x0a: + gd54xx->blt.height = (gd54xx->blt.height & 0xff00) | val; + break; + case 0x0b: + gd54xx->blt.height = (gd54xx->blt.height & 0x00ff) | (val << 8); + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + gd54xx->blt.height &= 0x07ff; + else + gd54xx->blt.height &= 0x03ff; + break; + case 0x0c: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0xff00) | val; + break; + case 0x0d: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0x00ff) | (val << 8); + gd54xx->blt.dst_pitch &= 0x1fff; + break; + case 0x0e: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0xff00) | val; + break; + case 0x0f: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0x00ff) | (val << 8); + gd54xx->blt.src_pitch &= 0x1fff; + break; - case 0x10: - gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xffff00) | val; - break; - case 0x11: - gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xff00ff) | (val << 8); - break; - case 0x12: - gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0x00ffff) | (val << 16); - if (gd54xx_is_5434(svga)) + case 0x10: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xffff00) | val; + break; + case 0x11: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xff00ff) | (val << 8); + break; + case 0x12: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) gd54xx->blt.dst_addr &= 0x3fffff; - else + else gd54xx->blt.dst_addr &= 0x1fffff; - - if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) && (gd54xx->blt.status & CIRRUS_BLT_AUTOSTART)) { - if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { - gd54xx->blt.sys_tx = 1; - gd54xx->blt.sys_cnt = 0; - gd54xx->blt.sys_buf = 0; - gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; - gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; - gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; - } else - gd54xx_start_blit(0, -1, gd54xx, svga); - } - break; - case 0x14: - gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xffff00) | val; - break; - case 0x15: - gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xff00ff) | (val << 8); - break; - case 0x16: - gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0x00ffff) | (val << 16); - if (gd54xx_is_5434(svga)) + if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) && (gd54xx->blt.status & CIRRUS_BLT_AUTOSTART) && + !(gd54xx->blt.status & CIRRUS_BLT_BUSY)) { + gd54xx->blt.status |= CIRRUS_BLT_BUSY; + gd54xx_start_blit(0, 0xffffffff, gd54xx, svga); + } + break; + + case 0x14: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xffff00) | val; + break; + case 0x15: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xff00ff) | (val << 8); + break; + case 0x16: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) gd54xx->blt.src_addr &= 0x3fffff; - else + else gd54xx->blt.src_addr &= 0x1fffff; - break; + break; - case 0x17: - gd54xx->blt.mask = val; - break; - case 0x18: - gd54xx->blt.mode = val; - break; + case 0x17: + gd54xx->blt.mask = val; + break; + case 0x18: + gd54xx->blt.mode = val; + gd543x_recalc_mapping(gd54xx); + break; - case 0x1a: - gd54xx->blt.rop = val; - break; + case 0x1a: + gd54xx->blt.rop = val; + break; - case 0x1b: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) - gd54xx->blt.modeext = val; - break; - - case 0x1c: - gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0xff00) | val; - break; - - case 0x1d: - gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0x00ff) | (val << 8); - break; - - case 0x20: - gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0xff00) | val; - break; - - case 0x21: - gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0x00ff) | (val << 8); - break; - - case 0x40: - gd54xx->blt.status = val; - if (gd54xx->blt.status & CIRRUS_BLT_START) { - if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { - gd54xx->blt.sys_tx = 1; - gd54xx->blt.sys_cnt = 0; - gd54xx->blt.sys_buf = 0; - gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; - gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; - gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; - } else - gd54xx_start_blit(0, -1, gd54xx, svga); - } - break; - } + case 0x1b: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + gd54xx->blt.modeext = val; + break; + + case 0x1c: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0xff00) | val; + break; + case 0x1d: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0x00ff) | (val << 8); + break; + + case 0x20: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0xff00) | val; + break; + case 0x21: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0x00ff) | (val << 8); + break; + + case 0x40: + old = gd54xx->blt.status; + gd54xx->blt.status = val; + gd543x_recalc_mapping(gd54xx); + if (!(old & CIRRUS_BLT_RESET) && (gd54xx->blt.status & CIRRUS_BLT_RESET)) + gd54xx_reset_blit(gd54xx); + else if (!(old & CIRRUS_BLT_START) && (gd54xx->blt.status & CIRRUS_BLT_START)) { + gd54xx->blt.status |= CIRRUS_BLT_BUSY; + gd54xx_start_blit(0, 0xffffffff, gd54xx, svga); + } + break; + } } else if (gd54xx->mmio_vram_overlap) gd54xx_write(addr, val, gd54xx); } +static void +gd543x_mmio_writeb(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (!gd543x_do_mmio(svga, addr) && gd54xx->countminusone && + !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd54xx_mem_sys_src_write(gd54xx, val); + return; + } + + gd543x_mmio_write(addr, val, p); +} + + static void gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p) { @@ -1863,10 +1982,15 @@ gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p) if (gd543x_do_mmio(svga, addr)) { gd543x_mmio_write(addr, val & 0xff, gd54xx); - gd543x_mmio_write(addr+1, val >> 8, gd54xx); + gd543x_mmio_write(addr + 1, val >> 8, gd54xx); } else if (gd54xx->mmio_vram_overlap) { - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr+1, val >> 8, gd54xx); + if (gd54xx->countminusone && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr + 1, val >> 8, gd54xx); + } else { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr + 1, val >> 8, gd54xx); + } } } @@ -1883,10 +2007,17 @@ gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p) gd543x_mmio_write(addr+2, val >> 16, gd54xx); gd543x_mmio_write(addr+3, val >> 24, gd54xx); } else if (gd54xx->mmio_vram_overlap) { - gd54xx_write(addr, val, gd54xx); - gd54xx_write(addr+1, val >> 8, gd54xx); - gd54xx_write(addr+2, val >> 16, gd54xx); - gd54xx_write(addr+3, val >> 24, gd54xx); + if (gd54xx->countminusone && !(gd54xx->blt.status & CIRRUS_BLT_PAUSED)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr+1, val >> 8, gd54xx); + gd543x_mmio_write(addr+2, val >> 16, gd54xx); + gd543x_mmio_write(addr+3, val >> 24, gd54xx); + } else { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + gd54xx_write(addr+2, val >> 16, gd54xx); + gd54xx_write(addr+3, val >> 24, gd54xx); + } } } @@ -1896,17 +2027,135 @@ gd543x_mmio_read(uint32_t addr, void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; svga_t *svga = &gd54xx->svga; + uint8_t ret = 0xff; if (gd543x_do_mmio(svga, addr)) { switch (addr & 0xff) { - case 0x40: /*BLT status*/ - return 0; + case 0x00: + ret = gd54xx->blt.bg_col & 0xff; + break; + case 0x01: + ret = (gd54xx->blt.bg_col >> 8) & 0xff; + break; + case 0x02: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.bg_col >> 16) & 0xff; + break; + case 0x03: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.bg_col >> 24) & 0xff; + break; + + case 0x04: + ret = gd54xx->blt.fg_col & 0xff; + break; + case 0x05: + ret = (gd54xx->blt.fg_col >> 8) & 0xff; + break; + case 0x06: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.fg_col >> 16) & 0xff; + break; + case 0x07: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.fg_col >> 24) & 0xff; + break; + + case 0x08: + ret = gd54xx->blt.width & 0xff; + break; + case 0x09: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.width >> 8) & 0x1f; + else + ret = (gd54xx->blt.width >> 8) & 0x07; + break; + case 0x0a: + ret = gd54xx->blt.height & 0xff; + break; + case 0x0b: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + ret = (gd54xx->blt.height >> 8) & 0x07; + else + ret = (gd54xx->blt.height >> 8) & 0x03; + break; + case 0x0c: + ret = gd54xx->blt.dst_pitch & 0xff; + break; + case 0x0d: + ret = (gd54xx->blt.dst_pitch >> 8) & 0x1f; + break; + case 0x0e: + ret = gd54xx->blt.src_pitch & 0xff; + break; + case 0x0f: + ret = (gd54xx->blt.src_pitch >> 8) & 0x1f; + break; + + case 0x10: + ret = gd54xx->blt.dst_addr & 0xff; + break; + case 0x11: + ret = (gd54xx->blt.dst_addr >> 8) & 0xff; + break; + case 0x12: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.dst_addr >> 16) & 0x3f; + else + ret = (gd54xx->blt.dst_addr >> 16) & 0x1f; + break; + + case 0x14: + ret = gd54xx->blt.src_addr & 0xff; + break; + case 0x15: + ret = (gd54xx->blt.src_addr >> 8) & 0xff; + break; + case 0x16: + if (gd54xx_is_5434(svga)) + ret = (gd54xx->blt.src_addr >> 16) & 0x3f; + else + ret = (gd54xx->blt.src_addr >> 16) & 0x1f; + break; + + case 0x17: + ret = gd54xx->blt.mask; + break; + case 0x18: + ret = gd54xx->blt.mode; + break; + + case 0x1a: + ret = gd54xx->blt.rop; + break; + + case 0x1b: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + ret = gd54xx->blt.modeext; + break; + + case 0x1c: + ret = gd54xx->blt.trans_col & 0xff; + break; + case 0x1d: + ret = (gd54xx->blt.trans_col >> 8) & 0xff; + break; + + case 0x20: + ret = gd54xx->blt.trans_mask & 0xff; + break; + case 0x21: + ret = (gd54xx->blt.trans_mask >> 8) & 0xff; + break; + + case 0x40: + ret = gd54xx->blt.status; + break; } - return 0xff; /*All other registers read-only*/ - } - else if (gd54xx->mmio_vram_overlap) - return gd54xx_read(addr, gd54xx); - return 0xff; + } else if (gd54xx->mmio_vram_overlap) + ret = gd54xx_read(addr, gd54xx); + + return ret; } @@ -1952,262 +2201,359 @@ gd54xx_color_expand(gd54xx_t *gd54xx, int mask, int shift) } -static void -gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) +static int +gd54xx_get_pixel_width(gd54xx_t *gd54xx) { - int blt_mask = 0; - int x_max = 0; + int ret = 1; - int shift = 0, last_x = 0; - uint32_t src_addr = gd54xx->blt.src_addr; - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { case CIRRUS_BLTMODE_PIXELWIDTH8: - blt_mask = gd54xx->blt.mask & 7; - x_max = 8; + ret = 1; break; case CIRRUS_BLTMODE_PIXELWIDTH16: - blt_mask = gd54xx->blt.mask & 7; - x_max = 16; - blt_mask *= 2; + ret = 2; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - blt_mask = (gd54xx->blt.mask & 0x1f); - x_max = 24; + ret = 3; break; case CIRRUS_BLTMODE_PIXELWIDTH32: - blt_mask = gd54xx->blt.mask & 7; - x_max = 32; - blt_mask *= 4; + ret = 4; break; } - last_x = (x_max >> 3) - 1; + return ret; +} - if (count == -1) { + +static void +gd54xx_blit(gd54xx_t *gd54xx, uint8_t mask, uint8_t *dst, uint8_t target, int skip) +{ + /* skip indicates whether or not it is a pixel to be skipped (used for left skip); + mask indicates transparency or not (only when transparent comparison is enabled): + color expand: direct pattern bit; 1 = write, 0 = do not write + (the other way around in inverse mode); + normal 8-bpp or 16-bpp: does not match transparent color = write, + matches transparent color = do not write */ + if (gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { + if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && + (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)) + mask = !mask; + + /* If mask is 1 and it is not a pixel to be skipped, write it. */ + if (mask && !skip) + *dst = target; + } else if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && + (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_BACKGROUNDONLY)) { + /* If mask is 1 or it is not a pixel to be skipped, write it. + (Skip only background pixels.) */ + if (mask || !skip) + *dst = target; + } else { + /* If if it is not a pixel to be skipped, write it. */ + if (!skip) + *dst = target; + } +} + + +static int +gd54xx_transparent_comp(gd54xx_t *gd54xx, uint32_t xx, uint8_t src) +{ + svga_t *svga = &gd54xx->svga; + int ret = 1; + + if ((gd54xx->blt.pixel_width <= 2) && gd54xx_has_transp(svga, 0)) { + ret = src ^ ((uint8_t *) &(gd54xx->blt.trans_col))[xx]; + if (gd54xx_has_transp(svga, 1)) + ret &= ~(((uint8_t *) &(gd54xx->blt.trans_mask))[xx]); + ret = !ret; + } + + return ret; +} + + +static void +gd54xx_pattern_copy(gd54xx_t *gd54xx) +{ + uint8_t target, src, *dst; + int x, y, pattern_y, pattern_pitch; + uint32_t bitmask = 0, xx, pixel; + uint32_t srca, srca2, dsta; + svga_t *svga = &gd54xx->svga; + + pattern_pitch = gd54xx->blt.pixel_width << 3; + + if (gd54xx->blt.pixel_width == 3) + pattern_pitch = 32; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) + pattern_pitch = 1; + + dsta = gd54xx->blt.dst_addr & svga->vram_mask; + /* The vertical offset is in the three low-order bits of the Source Address register. */ + pattern_y = gd54xx->blt.src_addr & 0x07; + + /* Mode Pattern bytes Pattern line bytes + --------------------------------------------------- + Color Expansion 8 1 + 8-bpp 64 8 + 16-bpp 128 16 + 24-bpp 256 32 + 32-bpp 256 32 + */ + + /* The boundary has to be equal to the size of the pattern. */ + srca = (gd54xx->blt.src_addr & ~0x07) & svga->vram_mask; + + for (y = 0; y <= gd54xx->blt.height; y++) { + /* Go to the correct pattern line. */ + srca2 = srca + (pattern_y * pattern_pitch); + pixel = 0; + for (x = 0; x <= gd54xx->blt.width; x += gd54xx->blt.pixel_width) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) + bitmask = 1; + else + bitmask = svga->vram[srca2 & svga->vram_mask] & (0x80 >> pixel); + } + for (xx = 0; xx < gd54xx->blt.pixel_width; xx++) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) + src = gd54xx_color_expand(gd54xx, bitmask, xx); + else { + src = svga->vram[(srca2 + (x % (gd54xx->blt.pixel_width << 3)) + xx) & svga->vram_mask]; + bitmask = gd54xx_transparent_comp(gd54xx, xx, src); + } + dst = &(svga->vram[(dsta + x + xx) & svga->vram_mask]); + target = *dst; + gd54xx_rop(gd54xx, &target, &target, &src); + if (gd54xx->blt.pixel_width == 3) + gd54xx_blit(gd54xx, bitmask, dst, target, ((x + xx) < gd54xx->blt.pattern_x)); + else + gd54xx_blit(gd54xx, bitmask, dst, target, (x < gd54xx->blt.pattern_x)); + } + pixel = (pixel + 1) & 7; + svga->changedvram[((dsta + x) & svga->vram_mask) >> 12] = changeframecount; + } + pattern_y = (pattern_y + 1) & 7; + dsta += gd54xx->blt.dst_pitch; + } +} + + +static void +gd54xx_reset_blit(gd54xx_t *gd54xx) +{ + gd54xx->countminusone = 0; + gd54xx->blt.status &= ~(CIRRUS_BLT_START|CIRRUS_BLT_BUSY|CIRRUS_BLT_FIFOUSED); +} + + +static void +gd54xx_mem_sys_src(gd54xx_t *gd54xx, uint32_t cpu_dat, uint32_t count) +{ + uint8_t *dst, exp, target; + int mask_shift; + uint32_t byte_pos, bitmask = 0; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSDEST | CIRRUS_BLTMODE_PATTERNCOPY)) + gd54xx_reset_blit(gd54xx); + else if (count == 0xffffffff) { gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; - gd54xx->blt.width_backup = gd54xx->blt.width; - gd54xx->blt.height_internal = gd54xx->blt.height; - gd54xx->blt.x_count = 0; - if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) - gd54xx->blt.y_count = src_addr & 7; - else - gd54xx->blt.y_count = 0; - - if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { - if (!(svga->seqregs[7] & 0xf0)) { - mem_mapping_set_handler(&svga->mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); - mem_mapping_set_p(&svga->mapping, gd54xx); - } else { - mem_mapping_set_handler(&gd54xx->linear_mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); - mem_mapping_set_p(&gd54xx->linear_mapping, gd54xx); - } - gd543x_recalc_mapping(gd54xx); - return; - } else { - if (!(svga->seqregs[7] & 0xf0)) { - mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); - mem_mapping_set_p(&gd54xx->svga.mapping, gd54xx); - } else { - mem_mapping_set_handler(&gd54xx->linear_mapping, svga_readb_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); - mem_mapping_set_p(&gd54xx->linear_mapping, svga); - } - gd543x_recalc_mapping(gd54xx); - } - } else if (gd54xx->blt.height_internal == 0xffff) + gd54xx->blt.x_count = gd54xx->blt.xx_count = 0; + gd54xx->blt.y_count = 0; + gd54xx->countminusone = 1; + gd54xx->blt.sys_src32 = 0x00000000; + gd54xx->blt.sys_cnt = 0; return; + } else if (gd54xx->countminusone) { + if (!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) || (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)) { + if (!gd54xx->blt.xx_count && !gd54xx->blt.x_count) + byte_pos = (((gd54xx->blt.mask >> 5) & 3) << 3); + else + byte_pos = 0; + mask_shift = 31 - byte_pos; + if (!(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)) + cpu_dat >>= byte_pos; + } else + mask_shift = 7; + + while (mask_shift > -1) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + bitmask = (cpu_dat >> mask_shift) & 0x01; + exp = gd54xx_color_expand(gd54xx, bitmask, gd54xx->blt.xx_count); + } else { + exp = cpu_dat & 0xff; + bitmask = gd54xx_transparent_comp(gd54xx, gd54xx->blt.xx_count, exp); + } + + dst = &(svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask]); + target = *dst; + gd54xx_rop(gd54xx, &target, &target, &exp); + if ((gd54xx->blt.pixel_width == 3) && (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND)) + gd54xx_blit(gd54xx, bitmask, dst, target, ((gd54xx->blt.x_count + gd54xx->blt.xx_count) < gd54xx->blt.pattern_x)); + else + gd54xx_blit(gd54xx, bitmask, dst, target, (gd54xx->blt.x_count < gd54xx->blt.pattern_x)); + + gd54xx->blt.dst_addr_backup += gd54xx->blt.dir; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) + gd54xx->blt.xx_count = (gd54xx->blt.xx_count + 1) % gd54xx->blt.pixel_width; + + svga->changedvram[(gd54xx->blt.dst_addr_backup & svga->vram_mask) >> 12] = changeframecount; + + if (!gd54xx->blt.xx_count) { + /* 1 mask bit = 1 blitted pixel */ + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) + mask_shift--; + else { + cpu_dat >>= 8; + mask_shift -= 8; + } + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) + gd54xx->blt.x_count = (gd54xx->blt.x_count + gd54xx->blt.pixel_width) % (gd54xx->blt.width + 1); + else + gd54xx->blt.x_count = (gd54xx->blt.x_count + 1) % (gd54xx->blt.width + 1); + + if (!gd54xx->blt.x_count) { + gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) % (gd54xx->blt.height + 1); + if (gd54xx->blt.y_count) + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr + (gd54xx->blt.dst_pitch * gd54xx->blt.y_count * gd54xx->blt.dir); + else { + /* If we're here, the blit is over, reset. */ + gd54xx_reset_blit(gd54xx); + } + /* Stop blitting and request new data if end of line reached. */ + return; + } + } + } + } +} + + +static void +gd54xx_normal_blit(uint32_t count, gd54xx_t *gd54xx, svga_t *svga) +{ + uint8_t src = 0, dst; + uint16_t width = gd54xx->blt.width; + int x_max = 0, shift = 0, mask = 0; + uint32_t src_addr = gd54xx->blt.src_addr; + uint32_t dst_addr = gd54xx->blt.dst_addr; + + x_max = gd54xx->blt.pixel_width << 3; + + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.height_internal = gd54xx->blt.height; + gd54xx->blt.x_count = 0; + gd54xx->blt.y_count = 0; while (count) { - uint8_t src = 0, dst; - int mask = 0; + src = 0; + mask = 0; - if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { - if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { - if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) - mask = !!(cpu_dat >> 31); - else - mask = !!(cpu_dat & 0x80); - - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - shift = 0; - break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - shift = (gd54xx->blt.x_count & 1); - break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - shift = (gd54xx->blt.x_count % 3); - break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - shift = (gd54xx->blt.x_count & 3); - break; - } - - src = gd54xx_color_expand(gd54xx, mask, shift); - - if (shift == last_x) { - cpu_dat <<= 1; - count--; - } - } else { - /*This must stay for general purpose Cirrus drivers to render fine in WinNT 3.5x*/ - src = cpu_dat & 0xff; - cpu_dat >>= 8; - count -= 8; - mask = 1; - } + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / gd54xx->blt.pixel_width)); + shift = (gd54xx->blt.x_count % gd54xx->blt.pixel_width); + src = gd54xx_color_expand(gd54xx, mask, shift); } else { - switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { - case 0x00: - src = svga->vram[gd54xx->blt.src_addr & svga->vram_mask]; - src_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); - gd54xx->blt.src_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); - mask = 1; - break; - case CIRRUS_BLTMODE_PATTERNCOPY: - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - src = svga->vram[(src_addr & (svga->vram_mask & ~7)) + (gd54xx->blt.y_count << 3) + (gd54xx->blt.x_count & 7)]; - break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - src = svga->vram[(src_addr & (svga->vram_mask & ~15)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; - break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - src = svga->vram[(src_addr & (svga->vram_mask & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count % 24)]; - break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - src = svga->vram[(src_addr & (svga->vram_mask & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count & 31)]; - break; - } - mask = 1; - break; - case CIRRUS_BLTMODE_COLOREXPAND: - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> gd54xx->blt.x_count); - shift = 0; - break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 1)); - shift = (gd54xx->blt.x_count & 1); - break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); - shift = (gd54xx->blt.x_count % 3); - break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - mask = svga->vram[src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 2)); - shift = (gd54xx->blt.x_count & 3); - break; - } - src = gd54xx_color_expand(gd54xx, mask, shift); - break; - case CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND: - if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) { - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - shift = 0; - break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - shift = (gd54xx->blt.x_count & 1); - break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - shift = (gd54xx->blt.x_count % 3); - break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - shift = (gd54xx->blt.x_count & 3); - break; - } - src = (gd54xx->blt.fg_col >> (shift << 3)); - } else { - switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { - case CIRRUS_BLTMODE_PIXELWIDTH8: - mask = svga->vram[(src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> gd54xx->blt.x_count); - shift = 0; - break; - case CIRRUS_BLTMODE_PIXELWIDTH16: - mask = svga->vram[(src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 1)); - shift = (gd54xx->blt.x_count & 1); - break; - case CIRRUS_BLTMODE_PIXELWIDTH24: - mask = svga->vram[(src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); - shift = (gd54xx->blt.x_count % 3); - break; - case CIRRUS_BLTMODE_PIXELWIDTH32: - mask = svga->vram[(src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 2)); - shift = (gd54xx->blt.x_count & 3); - break; - } - src = gd54xx_color_expand(gd54xx, mask, shift); - } - break; - } - count--; + src = svga->vram[src_addr & svga->vram_mask]; + src_addr += gd54xx->blt.dir; + mask = 1; } - dst = svga->vram[gd54xx->blt.dst_addr & svga->vram_mask]; - svga->changedvram[(gd54xx->blt.dst_addr & svga->vram_mask) >> 12] = changeframecount; + count--; + + dst = svga->vram[dst_addr & svga->vram_mask]; + svga->changedvram[(dst_addr & svga->vram_mask) >> 12] = changeframecount; gd54xx_rop(gd54xx, (uint8_t *) &dst, (uint8_t *) &dst, (const uint8_t *) &src); if ((gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)) mask = !mask; - if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && - !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !mask)) - svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; - gd54xx->blt.dst_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + /* This handles 8bpp and 16bpp non-color-expanding transparent comparisons. */ + if ((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !(gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) && + ((gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) <= CIRRUS_BLTMODE_PIXELWIDTH16) && + (src != ((gd54xx->blt.trans_mask >> (shift << 3)) & 0xff))) + mask = 0; + if (((gd54xx->blt.width - width) >= gd54xx->blt.pattern_x) && + !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !mask)) { + svga->vram[dst_addr & svga->vram_mask] = dst; + } + + dst_addr += gd54xx->blt.dir; gd54xx->blt.x_count++; if (gd54xx->blt.x_count == x_max) { gd54xx->blt.x_count = 0; - if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) == CIRRUS_BLTMODE_COLOREXPAND) + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) src_addr++; } - gd54xx->blt.width--; + width--; + if (width == 0xffff) { + width = gd54xx->blt.width; + dst_addr = gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr_backup + (gd54xx->blt.dst_pitch * gd54xx->blt.dir); + gd54xx->blt.y_count = (gd54xx->blt.y_count + gd54xx->blt.dir) & 7; - if (gd54xx->blt.width == 0xffff) { - gd54xx->blt.width = gd54xx->blt.width_backup; + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (gd54xx->blt.x_count != 0) + src_addr++; + } else + src_addr = gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr_backup + (gd54xx->blt.src_pitch * gd54xx->blt.dir); - gd54xx->blt.dst_addr = gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.dst_pitch : gd54xx->blt.dst_pitch); - - switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { - case 0x00: - src_addr = gd54xx->blt.src_addr = gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.src_pitch : gd54xx->blt.src_pitch); - break; - case CIRRUS_BLTMODE_COLOREXPAND: - if (gd54xx->blt.x_count != 0) - src_addr++; - break; - } + dst_addr &= svga->vram_mask; + gd54xx->blt.dst_addr_backup &= svga->vram_mask; + src_addr &= svga->vram_mask; + gd54xx->blt.src_addr_backup &= svga->vram_mask; gd54xx->blt.x_count = 0; - if (gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) - gd54xx->blt.y_count = (gd54xx->blt.y_count - 1) & 7; - else - gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) & 7; gd54xx->blt.height_internal--; if (gd54xx->blt.height_internal == 0xffff) { - if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { - if (!(svga->seqregs[7] & 0xf0)) { - mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); - mem_mapping_set_p(&svga->mapping, gd54xx); - } else { - mem_mapping_set_handler(&gd54xx->linear_mapping, svga_readb_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); - mem_mapping_set_p(&gd54xx->linear_mapping, svga); - } - gd543x_recalc_mapping(gd54xx); - } + gd54xx_reset_blit(gd54xx); return; } - - if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) - return; } } + + /* Count exhausted, stuff still left to blit. */ + gd54xx_reset_blit(gd54xx); +} + + +static void +gd54xx_start_blit(uint32_t cpu_dat, uint32_t count, gd54xx_t *gd54xx, svga_t *svga) +{ + if ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) && + !(gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) && + !(gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP)) + gd54xx->blt.dir = -1; + else + gd54xx->blt.dir = 1; + + gd54xx->blt.pixel_width = gd54xx_get_pixel_width(gd54xx); + + if (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + if (gd54xx->blt.pixel_width == 3) + gd54xx->blt.pattern_x = gd54xx->blt.mask & 0x1f; /* (Mask & 0x1f) bytes. */ + else + gd54xx->blt.pattern_x = (gd54xx->blt.mask & 0x07) * gd54xx->blt.pixel_width; /* (Mask & 0x07) pixels. */ + } else + gd54xx->blt.pattern_x = 0; /* No skip in normal blit mode. */ + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) + gd54xx_mem_sys_src(gd54xx, cpu_dat, count); + else if (gd54xx->blt.mode & CIRRUS_BLTMODE_PATTERNCOPY) { + gd54xx_pattern_copy(gd54xx); + gd54xx_reset_blit(gd54xx); + } else + gd54xx_normal_blit(count, gd54xx, svga); } @@ -2231,7 +2577,6 @@ cl_pci_read(int func, int addr, void *p) case PCI_REG_COMMAND: return gd54xx->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ - // case 0x07: return 0 << 1; /*Fast DEVSEL timing*/ case 0x07: return 0x02; /*Fast DEVSEL timing*/ case 0x08: return gd54xx->rev; /*Revision ID*/ @@ -2276,7 +2621,7 @@ cl_pci_write(int func, int addr, uint8_t val, void *p) case 0x13: gd54xx->lfb_base = val << 24; - gd543x_recalc_mapping(gd54xx); + gd543x_recalc_mapping(gd54xx); break; case 0x30: case 0x32: case 0x33: @@ -2298,19 +2643,20 @@ cl_pci_write(int func, int addr, uint8_t val, void *p) static void *gd54xx_init(const device_t *info) { - gd54xx_t *gd54xx = malloc(sizeof(gd54xx_t)); - svga_t *svga = &gd54xx->svga; - int id = info->local & 0xff; - int vram; - wchar_t *romfn = NULL; - memset(gd54xx, 0, sizeof(gd54xx_t)); + gd54xx_t *gd54xx = malloc(sizeof(gd54xx_t)); + svga_t *svga = &gd54xx->svga; + int id = info->local & 0xff; + int vram; + wchar_t *romfn = NULL; + memset(gd54xx, 0, sizeof(gd54xx_t)); - gd54xx->pci = !!(info->flags & DEVICE_PCI); - gd54xx->vlb = !!(info->flags & DEVICE_VLB); + gd54xx->pci = !!(info->flags & DEVICE_PCI); + gd54xx->vlb = !!(info->flags & DEVICE_VLB); - gd54xx->rev = 0; - gd54xx->has_bios = 1; - switch (id) { + gd54xx->rev = 0; + gd54xx->has_bios = 1; + + switch (id) { case CIRRUS_ID_CLGD5402: case CIRRUS_ID_CLGD5420: romfn = BIOS_GD5420_PATH; @@ -2371,63 +2717,67 @@ static void case CIRRUS_ID_CLGD5480: romfn = BIOS_GD5480_PATH; break; - } + } - if (id >= CIRRUS_ID_CLGD5420) - vram = device_get_config_int("memory"); - else - vram = 0; - if (vram) - gd54xx->vram_size = vram << 20; - else - gd54xx->vram_size = 1 << 19; - - gd54xx->vram_mask = gd54xx->vram_size - 1; + if (id >= CIRRUS_ID_CLGD5420) + vram = device_get_config_int("memory"); + else + vram = 0; - if (romfn) - rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (vram) + gd54xx->vram_size = vram << 20; + else + gd54xx->vram_size = 1 << 19; - if (info->flags & DEVICE_ISA) - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_isa); - else - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_vlb_pci); + gd54xx->vram_mask = gd54xx->vram_size - 1; - svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size, + if (romfn) + rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (info->flags & DEVICE_ISA) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_isa); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_vlb_pci); + + svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size, gd54xx_recalctimings, gd54xx_in, gd54xx_out, gd54xx_hwcursor_draw, NULL); - svga->ven_write = gd54xx_write_modes45; + svga->ven_write = gd54xx_write_modes45; - mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); - mem_mapping_set_p(&svga->mapping, gd54xx); + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&svga->mapping, gd54xx); - mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, gd543x_mmio_write, gd543x_mmio_writew, gd543x_mmio_writel, NULL, 0, gd54xx); - mem_mapping_add(&gd54xx->linear_mapping, 0, 0, gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, NULL, 0, svga); + mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, gd543x_mmio_writeb, gd543x_mmio_writew, gd543x_mmio_writel, NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_disable(&gd54xx->mmio_mapping); + mem_mapping_add(&gd54xx->linear_mapping, 0, 0, gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_disable(&gd54xx->linear_mapping); + mem_mapping_add(&gd54xx->aperture2_mapping, 0, 0, NULL, NULL, NULL, gd5436_aperture2_writeb, gd5436_aperture2_writew, gd5436_aperture2_writel, NULL, MEM_MAPPING_EXTERNAL, gd54xx); + mem_mapping_disable(&gd54xx->aperture2_mapping); - io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); - svga->hwcursor.yoff = 32; - svga->hwcursor.xoff = 0; + svga->hwcursor.yoff = 32; + svga->hwcursor.xoff = 0; - if (id >= CIRRUS_ID_CLGD5420) { - gd54xx->vclk_n[0] = 0x4a; - gd54xx->vclk_d[0] = 0x2b; - gd54xx->vclk_n[1] = 0x5b; - gd54xx->vclk_d[1] = 0x2f; - gd54xx->vclk_n[2] = 0x45; - gd54xx->vclk_d[2] = 0x30; - gd54xx->vclk_n[3] = 0x7e; - gd54xx->vclk_d[3] = 0x33; - } - else { - gd54xx->vclk_n[0] = 0x66; - gd54xx->vclk_d[0] = 0x3b; - gd54xx->vclk_n[1] = 0x5b; - gd54xx->vclk_d[1] = 0x2f; - gd54xx->vclk_n[1] = 0x45; - gd54xx->vclk_d[1] = 0x2c; - gd54xx->vclk_n[1] = 0x7e; - gd54xx->vclk_d[1] = 0x33; - } + if (id >= CIRRUS_ID_CLGD5420) { + gd54xx->vclk_n[0] = 0x4a; + gd54xx->vclk_d[0] = 0x2b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + gd54xx->vclk_n[2] = 0x45; + gd54xx->vclk_d[2] = 0x30; + gd54xx->vclk_n[3] = 0x7e; + gd54xx->vclk_d[3] = 0x33; + } else { + gd54xx->vclk_n[0] = 0x66; + gd54xx->vclk_d[0] = 0x3b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + gd54xx->vclk_n[1] = 0x45; + gd54xx->vclk_d[1] = 0x2c; + gd54xx->vclk_n[1] = 0x7e; + gd54xx->vclk_d[1] = 0x33; + } gd54xx->bank[1] = 0x8000; @@ -2441,7 +2791,7 @@ static void gd54xx->pci_regs[0x33] = 0x00; svga->crtc[0x27] = id; - + return gd54xx; } @@ -2661,36 +3011,37 @@ static const device_config_t gd5434_config[] = const device_t gd5402_isa_device = { - "Cirrus Logic GD-5402 (ACUMOS AVGA2)", - DEVICE_AT | DEVICE_ISA, - CIRRUS_ID_CLGD5402, - gd54xx_init, gd54xx_close, - NULL, - gd5420_available, /* Common BIOS between 5402 and 5420 */ - gd54xx_speed_changed, - gd54xx_force_redraw, - NULL, + "Cirrus Logic GD-5402 (ACUMOS AVGA2)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5402, + gd54xx_init, gd54xx_close, + NULL, + gd5420_available, /* Common BIOS between 5402 and 5420 */ + gd54xx_speed_changed, + gd54xx_force_redraw, + NULL, }; const device_t gd5420_isa_device = { - "Cirrus Logic GD-5420", - DEVICE_AT | DEVICE_ISA, - CIRRUS_ID_CLGD5420, - gd54xx_init, gd54xx_close, - NULL, - gd5420_available, /* Common BIOS between 5402 and 5420 */ - gd54xx_speed_changed, - gd54xx_force_redraw, - gd5422_config, + "Cirrus Logic GD-5420", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5420, + gd54xx_init, gd54xx_close, + NULL, + gd5420_available, /* Common BIOS between 5402 and 5420 */ + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5422_config, }; + const device_t gd5422_isa_device = { "Cirrus Logic GD-5422", DEVICE_AT | DEVICE_ISA, CIRRUS_ID_CLGD5422, - gd54xx_init, gd54xx_close, - NULL, - gd5422_available, /* Common BIOS between 5422 and 5424 */ + gd54xx_init, gd54xx_close, + NULL, + gd5422_available, /* Common BIOS between 5422 and 5424 */ gd54xx_speed_changed, gd54xx_force_redraw, gd5422_config, @@ -2700,9 +3051,9 @@ const device_t gd5424_vlb_device = { "Cirrus Logic GD-5424", DEVICE_VLB, CIRRUS_ID_CLGD5424, - gd54xx_init, gd54xx_close, - NULL, - gd5422_available, /* Common BIOS between 5422 and 5424 */ + gd54xx_init, gd54xx_close, + NULL, + gd5422_available, /* Common BIOS between 5422 and 5424 */ gd54xx_speed_changed, gd54xx_force_redraw, gd5422_config, diff --git a/src/video/vid_colorplus.c b/src/video/vid_colorplus.c index fbea870a4..80393ecbb 100644 --- a/src/video/vid_colorplus.c +++ b/src/video/vid_colorplus.c @@ -25,10 +25,10 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../lpt.h" #include "../pit.h" #include "../mem.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_cga.h" @@ -95,11 +95,12 @@ void colorplus_write(uint32_t addr, uint8_t val, void *p) colorplus->cga.vram[addr & 0x7fff] = val; if (colorplus->cga.snow_enabled) { - colorplus->cga.charbuffer[ ((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc] = val; - colorplus->cga.charbuffer[(((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val; + int offset = ((timer_get_remaining_u64(&colorplus->cga.timer) / CGACONST) * 2) & 0xfc; + colorplus->cga.charbuffer[offset] = colorplus->cga.vram[addr & 0x7fff]; + colorplus->cga.charbuffer[offset | 1] = colorplus->cga.vram[addr & 0x7fff]; } egawrites++; - cycles -= 4; + sub_cycles(4); } uint8_t colorplus_read(uint32_t addr, void *p) @@ -116,11 +117,12 @@ uint8_t colorplus_read(uint32_t addr, void *p) { addr &= 0x3FFF; } - cycles -= 4; + sub_cycles(4); if (colorplus->cga.snow_enabled) { - colorplus->cga.charbuffer[ ((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc] = colorplus->cga.vram[addr & 0x7fff]; - colorplus->cga.charbuffer[(((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc) | 1] = colorplus->cga.vram[addr & 0x7fff]; + int offset = ((timer_get_remaining_u64(&colorplus->cga.timer) / CGACONST) * 2) & 0xfc; + colorplus->cga.charbuffer[offset] = colorplus->cga.vram[addr & 0x7fff]; + colorplus->cga.charbuffer[offset | 1] = colorplus->cga.vram[addr & 0x7fff]; } egareads++; return colorplus->cga.vram[addr & 0x7fff]; @@ -158,7 +160,7 @@ void colorplus_poll(void *p) if (!colorplus->cga.linepos) { - colorplus->cga.vidtime += colorplus->cga.dispofftime; + timer_advance_u64(&colorplus->cga.timer, colorplus->cga.dispofftime); colorplus->cga.cgastat |= 1; colorplus->cga.linepos = 1; oldsc = colorplus->cga.sc; @@ -175,8 +177,9 @@ void colorplus_poll(void *p) /* Left / right border */ for (c = 0; c < 8; c++) { - buffer->line[colorplus->cga.displine][c] = - buffer->line[colorplus->cga.displine][c + (colorplus->cga.crtc[1] << 4) + 8] = (colorplus->cga.cgacol & 15) + 16; + buffer32->line[colorplus->cga.displine][c] = + buffer32->line[colorplus->cga.displine][c + (colorplus->cga.crtc[1] << 4) + 8] = + (colorplus->cga.cgacol & 15) + 16; } if (colorplus->control & COLORPLUS_320x200_MODE) { @@ -189,9 +192,9 @@ void colorplus_poll(void *p) colorplus->cga.ma++; for (c = 0; c < 8; c++) { - buffer->line[colorplus->cga.displine][(x << 4) + (c << 1) + 8] = - buffer->line[colorplus->cga.displine][(x << 4) + (c << 1) + 1 + 8] = - cols16[(dat0 >> 14) | ((dat1 >> 14) << 2)]; + buffer32->line[colorplus->cga.displine][(x << 4) + (c << 1) + 8] = + buffer32->line[colorplus->cga.displine][(x << 4) + (c << 1) + 1 + 8] = + cols16[(dat0 >> 14) | ((dat1 >> 14) << 2)]; dat0 <<= 2; dat1 <<= 2; } @@ -228,8 +231,8 @@ void colorplus_poll(void *p) colorplus->cga.ma++; for (c = 0; c < 16; c++) { - buffer->line[colorplus->cga.displine][(x << 4) + c + 8] = - cols[(dat0 >> 15) | ((dat1 >> 15) << 1)]; + buffer32->line[colorplus->cga.displine][(x << 4) + c + 8] = + cols[(dat0 >> 15) | ((dat1 >> 15) << 1)]; dat0 <<= 1; dat1 <<= 1; } @@ -239,18 +242,13 @@ void colorplus_poll(void *p) else /* Top / bottom border */ { cols[0] = (colorplus->cga.cgacol & 15) + 16; - hline(buffer, 0, colorplus->cga.displine, (colorplus->cga.crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, colorplus->cga.displine, (colorplus->cga.crtc[1] << 4) + 16, cols[0]); } x = (colorplus->cga.crtc[1] << 4) + 16; if (colorplus->cga.composite) - { - for (c = 0; c < x; c++) - buffer32->line[colorplus->cga.displine][c] = buffer->line[colorplus->cga.displine][c] & 0xf; - Composite_Process(colorplus->cga.cgamode, 0, x >> 2, buffer32->line[colorplus->cga.displine]); - } colorplus->cga.sc = oldsc; if (colorplus->cga.vc == colorplus->cga.crtc[7] && !colorplus->cga.sc) @@ -261,7 +259,7 @@ void colorplus_poll(void *p) } else { - colorplus->cga.vidtime += colorplus->cga.dispontime; + timer_advance_u64(&colorplus->cga.timer, colorplus->cga.dispontime); colorplus->cga.linepos = 0; if (colorplus->cga.vsynctime) { @@ -406,8 +404,8 @@ void *colorplus_standalone_init(const device_t *info) colorplus->cga.vram = malloc(0x8000); - cga_comp_init(1); - timer_add(colorplus_poll, &colorplus->cga.vidtime, TIMER_ALWAYS_ENABLED, colorplus); + cga_comp_init(colorplus->cga.revision); + timer_add(&colorplus->cga.timer, colorplus_poll, colorplus, 1); mem_mapping_add(&colorplus->cga.mapping, 0xb8000, 0x08000, colorplus_read, NULL, NULL, colorplus_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, colorplus); io_sethandler(0x03d0, 0x0010, colorplus_in, NULL, NULL, colorplus_out, NULL, NULL, colorplus); diff --git a/src/video/vid_compaq_cga.c b/src/video/vid_compaq_cga.c index e02a9ede5..7458c7ad9 100644 --- a/src/video/vid_compaq_cga.c +++ b/src/video/vid_compaq_cga.c @@ -7,10 +7,10 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_cga.h" @@ -19,10 +19,11 @@ #define CGA_RGB 0 #define CGA_COMPOSITE 1 +static uint32_t vflags; + typedef struct compaq_cga_t { cga_t cga; - uint32_t flags; } compaq_cga_t; static uint8_t mdaattr[256][2][2]; @@ -35,8 +36,8 @@ void compaq_cga_recalctimings(compaq_cga_t *self) _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; - self->cga.dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - self->cga.dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + self->cga.dispontime = (uint64_t)(_dispontime); + self->cga.dispofftime = (uint64_t)(_dispofftime); } void compaq_cga_poll(void *p) @@ -47,7 +48,8 @@ void compaq_cga_poll(void *p) int x, c; int oldvc; uint8_t chr, attr; - uint32_t cols[4]; + uint8_t border; + uint8_t cols[4]; int oldsc; int underline = 0; int blink = 0; @@ -64,7 +66,7 @@ void compaq_cga_poll(void *p) /* We are in Compaq 350-line CGA territory */ if (!self->cga.linepos) { - self->cga.vidtime += self->cga.dispofftime; + timer_advance_u64(&self->cga.timer, self->cga.dispofftime); self->cga.cgastat |= 1; self->cga.linepos = 1; oldsc = self->cga.sc; @@ -80,15 +82,15 @@ void compaq_cga_poll(void *p) } self->cga.lastline = self->cga.displine; - cols[0] = (self->cga.cgacol & 15); + cols[0] = (self->cga.cgacol & 15) + 16; for (c = 0; c < 8; c++) { - ((uint32_t *)buffer32->line[self->cga.displine])[c] = cols[0]; + buffer32->line[self->cga.displine][c] = cols[0]; if (self->cga.cgamode & 1) - ((uint32_t *)buffer32->line[self->cga.displine])[c + (self->cga.crtc[1] << 3) + 8] = cols[0]; + buffer32->line[self->cga.displine][c + (self->cga.crtc[1] << 3) + 8] = cols[0]; else - ((uint32_t *)buffer32->line[self->cga.displine])[c + (self->cga.crtc[1] << 4) + 8] = cols[0]; + buffer32->line[self->cga.displine][c + (self->cga.crtc[1] << 4) + 8] = cols[0]; } if (self->cga.cgamode & 1) { @@ -97,11 +99,11 @@ void compaq_cga_poll(void *p) chr = self->cga.charbuffer[x << 1]; attr = self->cga.charbuffer[(x << 1) + 1]; drawcursor = ((self->cga.ma == ca) && self->cga.con && self->cga.cursoron); - if (self->flags) { + if (vflags) { underline = 0; blink = ((self->cga.cgablink & 8) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); } - if (self->flags && (self->cga.cgamode & 0x80)) + if (vflags && (self->cga.cgamode & 0x80)) { cols[0] = mdaattr[attr][blink][0]; cols[1] = mdaattr[attr][blink][1]; @@ -111,7 +113,7 @@ void compaq_cga_poll(void *p) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; - if (self->flags) { + if (vflags) { if (blink) cols[1] = cols[0]; } else { @@ -124,20 +126,20 @@ void compaq_cga_poll(void *p) cols[1] = (attr & 15) + 16; cols[0] = (attr >> 4) + 16; } - if (self->flags && underline) + if (vflags && underline) { for (c = 0; c < 8; c++) - ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = mdaattr[attr][blink][1]; + buffer32->line[self->cga.displine][(x << 3) + c + 8] = mdaattr[attr][blink][1]; } else if (drawcursor) { for (c = 0; c < 8; c++) - ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; + buffer32->line[self->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) - ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[self->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; } self->cga.ma++; } @@ -149,11 +151,11 @@ void compaq_cga_poll(void *p) chr = self->cga.vram[((self->cga.ma << 1) & 0x3fff)]; attr = self->cga.vram[(((self->cga.ma << 1) + 1) & 0x3fff)]; drawcursor = ((self->cga.ma == ca) && self->cga.con && self->cga.cursoron); - if (self->flags) { + if (vflags) { underline = 0; blink = ((self->cga.cgablink & 8) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); } - if (self->flags && (self->cga.cgamode & 0x80)) + if (vflags && (self->cga.cgamode & 0x80)) { cols[0] = mdaattr[attr][blink][0]; cols[1] = mdaattr[attr][blink][1]; @@ -163,7 +165,7 @@ void compaq_cga_poll(void *p) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; - if (self->flags) { + if (vflags) { if (blink) cols[1] = cols[0]; } else { @@ -177,23 +179,26 @@ void compaq_cga_poll(void *p) cols[0] = (attr >> 4) + 16; } self->cga.ma++; - if (self->flags && underline) + if (vflags && underline) { for (c = 0; c < 8; c++) - ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 8] = - ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 9] = mdaattr[attr][blink][1]; + buffer32->line[self->cga.displine][(x << 4)+(c << 1) + 8] = + buffer32->line[self->cga.displine][(x << 4)+(c << 1) + 9] = + mdaattr[attr][blink][1]; } else if (drawcursor) { for (c = 0; c < 8; c++) - ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 8] = - ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + buffer32->line[self->cga.displine][(x << 4)+(c << 1) + 8] = + buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1 + 8] = + cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) - ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 8] = - ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 8] = + buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1 + 8] = + cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; } } } @@ -201,8 +206,8 @@ void compaq_cga_poll(void *p) else { cols[0] = (self->cga.cgacol & 15) + 16; - if (self->cga.cgamode & 1) hline(buffer32, 0, self->cga.displine, (self->cga.crtc[1] << 3) + 16, cols[0]); - else hline(buffer32, 0, self->cga.displine, (self->cga.crtc[1] << 4) + 16, cols[0]); + if (self->cga.cgamode & 1) hline(buffer32, 0, self->cga.displine, (self->cga.crtc[1] << 3) + 16, cols[0]); + else hline(buffer32, 0, self->cga.displine, (self->cga.crtc[1] << 4) + 16, cols[0]); } if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3) + 16; @@ -210,19 +215,16 @@ void compaq_cga_poll(void *p) if (self->cga.composite) { - for (c = 0; c < x; c++) - buffer32->line[self->cga.displine][c] = ((uint32_t *)buffer32->line[self->cga.displine])[c] & 0xf; - - if (self->flags) - Composite_Process(self->cga.cgamode & 0x7F, 0, x >> 2, buffer32->line[self->cga.displine]); + if (self->cga.cgamode & 0x10) + border = 0x00; else - Composite_Process(self->cga.cgamode, 0, x >> 2, buffer32->line[self->cga.displine]); + border = self->cga.cgacol & 0x0f; + + if (vflags) + Composite_Process(self->cga.cgamode & 0x7F, border, x >> 2, buffer32->line[self->cga.displine]); + else + Composite_Process(self->cga.cgamode, border, x >> 2, buffer32->line[self->cga.displine]); } - else - { - for (c = 0; c < x; c++) - buffer->line[self->cga.displine][c] = ((uint32_t *)buffer32->line[self->cga.displine])[c]; - } self->cga.sc = oldsc; if (self->cga.vc == self->cga.crtc[7] && !self->cga.sc) @@ -233,7 +235,7 @@ void compaq_cga_poll(void *p) } else { - self->cga.vidtime += self->cga.dispontime; + timer_advance_u64(&self->cga.timer, self->cga.dispontime); self->cga.linepos = 0; if (self->cga.vsynctime) { @@ -375,8 +377,8 @@ void *compaq_cga_init(const device_t *info) self->cga.vram = malloc(0x4000); cga_comp_init(self->cga.revision); - timer_add(compaq_cga_poll, &self->cga.vidtime, TIMER_ALWAYS_ENABLED, self); - mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, self->cga.vram, MEM_MAPPING_EXTERNAL, self); + timer_add(&self->cga.timer, compaq_cga_poll, self, 1); + mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL /*self->cga.vram*/, MEM_MAPPING_EXTERNAL, self); io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, self); if (info->local) { @@ -399,7 +401,7 @@ void *compaq_cga_init(const device_t *info) mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = 16; } - self->flags = info->local; + vflags = info->local; overscan_x = overscan_y = 16; @@ -407,6 +409,8 @@ void *compaq_cga_init(const device_t *info) cga_palette = (self->cga.rgb_type << 1); cgapal_rebuild(); + self->cga.crtc[9] = 13; + return self; } diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index dc1012034..bf6f8d376 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -26,10 +26,10 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_ega.h" @@ -185,6 +185,7 @@ void ega_out(uint16_t addr, uint8_t val, void *p) ega->attraddr = val & 31; else { + o = ega->attrregs[ega->attraddr & 31]; ega->attrregs[ega->attraddr & 31] = val; if (ega->attraddr < 16) fullchange = changeframecount; @@ -196,15 +197,26 @@ void ega_out(uint16_t addr, uint8_t val, void *p) else ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); } } + /* Recalculate timings on change of attribute register 0x11 + (overscan border color) too. */ + if ((ega->attraddr == 0x10) || (ega->attraddr == 0x11)) { + ega->overscan_color = ega->vres ? pallook16[val & 0x0f] : pallook64[val & 0x3f]; + if (o != val) + ega_recalctimings(ega); + } } ega->attrff ^= 1; break; case 0x3c2: + o = ega->miscout; egaswitchread = (val & 0xc) >> 2; ega->vres = !(val & 0x80); ega->pallook = ega->vres ? pallook16 : pallook64; ega->vidclock = val & 4; /*printf("3C2 write %02X\n",val);*/ ega->miscout=val; + ega->overscan_color = ega->vres ? pallook16[ega->attrregs[0x11] & 0x0f] : pallook64[ega->attrregs[0x11] & 0x3f]; + if ((o ^ val) & 0x80) + ega_recalctimings(ega); break; case 0x3c4: ega->seqaddr = val; @@ -368,31 +380,32 @@ void ega_recalctimings(ega_t *ega) ega->rowoffset = ega->crtc[0x13]; ega->rowcount = ega->crtc[9] & 0x1f; - overscan_y = (ega->rowcount + 1) << 1; if (ega->vidclock) crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0)); else crtcconst = (ega->seqregs[1] & 1) ? CGACONST : (CGACONST * (9.0 / 8.0)); - if (ega->seqregs[1] & 8) - { + if (enable_overscan) { + overscan_y = (ega->rowcount + 1) << 1; + + if (ega->seqregs[1] & 8) + overscan_y <<= 1; + if (overscan_y < 16) + overscan_y = 16; + } + + if (ega->seqregs[1] & 8) { disptime = (double) ((ega->crtc[0] + 2) << 1); _dispontime = (double) ((ega->crtc[1] + 1) << 1); - - overscan_y <<= 1; } else { disptime = (double) (ega->crtc[0] + 2); _dispontime = (double) (ega->crtc[1] + 1); } - if (overscan_y < 16) - { - overscan_y = 16; - } _dispofftime = disptime - _dispontime; _dispontime = _dispontime * crtcconst; _dispofftime = _dispofftime * crtcconst; - ega->dispontime = (int64_t)(_dispontime * (1LL << TIMER_SHIFT)); - ega->dispofftime = (int64_t)(_dispofftime * (1LL << TIMER_SHIFT)); + ega->dispontime = (uint64_t)(_dispontime); + ega->dispofftime = (uint64_t)(_dispofftime); } @@ -410,7 +423,7 @@ void ega_poll(void *p) if (!ega->linepos) { - ega->vidtime += ega->dispofftime; + timer_advance_u64(&ega->timer, ega->dispofftime); ega->stat |= 1; ega->linepos = 1; @@ -479,7 +492,7 @@ void ega_poll(void *p) } else { - ega->vidtime += ega->dispontime; + timer_advance_u64(&ega->timer, ega->dispontime); if (ega->dispon) ega->stat &= ~1; ega->linepos = 0; @@ -536,27 +549,25 @@ void ega_poll(void *p) if (ega->interlace && !ega->oddeven) ega->lastline++; if (ega->interlace && ega->oddeven) ega->firstline--; - if ((x != xsize || (ega->lastline - ega->firstline + 1) != ysize) || update_overscan || video_force_resize_get()) - { + x_add = enable_overscan ? 8 : 0; + y_add = enable_overscan ? overscan_y : 0; + x_add_ex = enable_overscan ? 16 : 0; + y_add_ex = y_add << 1; + + if ((xsize > 2032) || ((ysize + y_add_ex) > 2048)) { + x_add = x_add_ex = 0; + y_add = y_add_ex = 0; + suppress_overscan = 1; + } else + suppress_overscan = 0; + + if ((x != xsize) || ((ega->lastline - ega->firstline + 1) != ysize) || video_force_resize_get()) { xsize = x; ysize = ega->lastline - ega->firstline + 1; - if (xsize < 64) xsize = 640; - if (ysize < 32) ysize = 200; - y_add = enable_overscan ? 14 : 0; - x_add = enable_overscan ? 8 : 0; - y_add_ex = enable_overscan ? 28 : 0; - x_add_ex = enable_overscan ? 16 : 0; - - if ((xsize > 2032) || ((ysize + y_add_ex) > 2048)) - { - x_add = x_add_ex = 0; - y_add = y_add_ex = 0; - suppress_overscan = 1; - } - else - { - suppress_overscan = 0; - } + if (xsize < 64) + xsize = 640; + if (ysize < 32) + ysize = 200; if (ega->vres) set_screen_size(xsize + x_add_ex, (ysize << 1) + y_add_ex); @@ -567,56 +578,30 @@ void ega_poll(void *p) video_force_resize_set(0); } - if (enable_overscan) - { - if ((x >= 160) && ((ega->lastline - ega->firstline) >= 120)) - { + if (enable_overscan && !suppress_overscan) { + if ((x >= 160) && ((ega->lastline - ega->firstline + 1) >= 120)) { /* Draw (overscan_size - scroll size) lines of overscan on top. */ - for (i = 0; i < (y_add - (ega->crtc[8] & 0x1f)); i++) - { - q = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + for (i = 0; i < y_add; i++) { + q = &buffer32->line[i & 0x7ff][32]; for (j = 0; j < (xsize + x_add_ex); j++) - { - q[j] = ega->pallook[ega->attrregs[0x11]]; - } + q[j] = ega->overscan_color; } /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ - for (i = 0; i < (y_add + (ega->crtc[8] & 0x1f)); i++) - { - q = &((uint32_t *)buffer32->line[(ysize + y_add + i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; + for (i = 0; i < y_add_ex; i++) { + q = &buffer32->line[(ysize + y_add + i) & 0x7ff][32]; for (j = 0; j < (xsize + x_add_ex); j++) - { - q[j] = ega->pallook[ega->attrregs[0x11]]; - } + q[j] = ega->overscan_color; } - for (i = (y_add - (ega->crtc[8] & 0x1f)); i < (ysize + y_add - (ega->crtc[8] & 0x1f)); i ++) - { - q = &((uint32_t *)buffer32->line[(i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; + for (i = y_add_ex; i < (ysize + y_add); i ++) { + q = &buffer32->line[i & 0x7ff][32]; - for (j = 0; j < x_add; j++) - { - q[j] = ega->pallook[ega->attrregs[0x11]]; - q[xsize + x_add + j] = ega->pallook[ega->attrregs[0x11]]; - } - } - } - } - else - { - if (ega->crtc[8] & 0x1f) - { - /* Draw (scroll size) lines of overscan on the bottom. */ - for (i = 0; i < (ega->crtc[8] & 0x1f); i++) - { - q = &((uint32_t *)buffer32->line[(ysize + i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; - - for (j = 0; j < xsize; j++) - { - q[j] = ega->pallook[ega->attrregs[0x11]]; + for (j = 0; j < x_add; j++) { + q[j] = ega->overscan_color; + q[xsize + x_add + j] = ega->overscan_color; } } } @@ -660,7 +645,7 @@ void ega_poll(void *p) if (ega->vc == ega->vtotal) { ega->vc = 0; - ega->sc = 0; + ega->sc = ega->crtc[8] & 0x1f; ega->dispon = 1; ega->displine = (ega->interlace && ega->oddeven) ? 1 : 0; ega->scrollcache = ega->attrregs[0x13] & 7; @@ -678,7 +663,7 @@ void ega_write(uint32_t addr, uint8_t val, void *p) int writemask2 = ega->writemask; egawrites++; - cycles -= video_timing_write_b; + sub_cycles(video_timing_write_b); if (addr >= 0xB0000) addr &= 0x7fff; else addr &= 0xffff; @@ -814,7 +799,7 @@ uint8_t ega_read(uint32_t addr, void *p) int readplane = ega->readplane; egareads++; - cycles -= video_timing_read_b; + sub_cycles(video_timing_read_b); if (addr >= 0xb0000) addr &= 0x7fff; else addr &= 0xffff; @@ -980,6 +965,8 @@ void ega_init(ega_t *ega, int monitor_type, int is_mono) #ifdef JEGA ega->is_jega = 0; #endif + + timer_add(&ega->timer, ega_poll, ega, 1); } @@ -1030,119 +1017,10 @@ static void *ega_standalone_init(const device_t *info) ega->vrammask = ega->vram_limit - 1; mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, ega); - timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); return ega; } -#ifdef JEGA -uint16_t chrtosht(FILE *fp) -{ - uint16_t i, j; - i = (uint8_t) getc(fp); - j = (uint8_t) getc(fp) << 8; - return (i | j); -} - -unsigned int getfontx2header(FILE *fp, fontx_h *header) -{ - fread(header->id, ID_LEN, 1, fp); - if (strncmp(header->id, "FONTX2", ID_LEN) != 0) - { - return 1; - } - fread(header->name, NAME_LEN, 1, fp); - header->width = (uint8_t)getc(fp); - header->height = (uint8_t)getc(fp); - header->type = (uint8_t)getc(fp); - return 0; -} - -void readfontxtbl(fontxTbl *table, unsigned int size, FILE *fp) -{ - while (size > 0) - { - table->start = chrtosht(fp); - table->end = chrtosht(fp); - ++table; - --size; - } -} - -static void LoadFontxFile(wchar_t *fname) -{ - fontx_h head; - fontxTbl *table; - unsigned int code; - uint8_t size; - unsigned int i; - - if (!fname) return; - if(*fname=='\0') return; - FILE * mfile=romfopen(fname,L"rb"); - if (!mfile) - { - pclog("MSG: Can't open FONTX2 file: %s\n",fname); - return; - } - if (getfontx2header(mfile, &head) != 0) - { - fclose(mfile); - pclog("MSG: FONTX2 header is incorrect\n"); - return; - } - /* switch whether the font is DBCS or not */ - if (head.type == DBCS) - { - if (head.width == 16 && head.height == 16) - { - size = getc(mfile); - table = (fontxTbl *)calloc(size, sizeof(fontxTbl)); - readfontxtbl(table, size, mfile); - for (i = 0; i < size; i++) - { - for (code = table[i].start; code <= table[i].end; code++) - { - fread(&jfont_dbcs_16[(code * 32)], sizeof(uint8_t), 32, mfile); - } - } - } - else - { - fclose(mfile); - pclog("MSG: FONTX2 DBCS font size is not correct\n"); - return; - } - } - else - { - if (head.width == 8 && head.height == 19) - { - fread(jfont_sbcs_19, sizeof(uint8_t), SBCS19_LEN, mfile); - } - else - { - fclose(mfile); - pclog("MSG: FONTX2 SBCS font size is not correct\n"); - return; - } - } - fclose(mfile); -} - -void *jega_standalone_init(const device_t *info) -{ - ega_t *ega = (ega_t *) ega_standalone_init(info); - - LoadFontxFile(L"roms/video/ega/JPNHN19X.FNT"); - LoadFontxFile(L"roms/video/ega/JPNZN16X.FNT"); - - ega->is_jega = 1; - - return ega; -} -#endif - static int ega_standalone_available(void) { diff --git a/src/video/vid_ega.h b/src/video/vid_ega.h index e5590d052..30944c64a 100644 --- a/src/video/vid_ega.h +++ b/src/video/vid_ega.h @@ -39,69 +39,40 @@ typedef struct ega_t { rom_t bios_rom; - uint8_t crtcreg; + uint8_t crtcreg, gdcaddr, attraddr, attrff, + attr_palette_enable, seqaddr, miscout, + writemask, la, lb, lc, ld, + stat, colourcompare, colournocare, scrblank; uint8_t crtc[32]; uint8_t gdcreg[16]; - int gdcaddr; uint8_t attrregs[32]; - int attraddr, attrff; - int attr_palette_enable; uint8_t seqregs[64]; - int seqaddr; - - uint8_t miscout; - int vidclock; - - uint8_t la, lb, lc, ld; - - uint8_t stat; - - int fast; - uint8_t colourcompare, colournocare; - int readmode, writemode, readplane; - int chain4, chain2_read, chain2_write; - int oddeven_page, oddeven_chain; - int extvram; - uint8_t writemask; - uint32_t charseta, charsetb; - uint8_t egapal[16]; + + uint8_t *vram; + + int vidclock, fast, extvram, vres, + readmode, writemode, readplane, vrammask, + chain4, chain2_read, chain2_write, con, + oddeven_page, oddeven_chain, vc, sc, + dispon, hdisp_on, cursoron, blink, + linepos, vslines, linecountff, oddeven, + lowres, interlace, lindebl, rowcount, + vtotal, dispend, vsyncstart, split, + hdisp, htotal, hdisp_time, rowoffset, + vblankstart, scrollcache, firstline, lastline, + firstline_draw, lastline_draw, + displine, video_res_x, video_res_y, video_bpp; + + uint32_t charseta, charsetb, ma_latch, ma, + maback, ca, vram_limit, overscan_color; + uint32_t *pallook; - int vtotal, dispend, vsyncstart, split, vblankstart; - int hdisp, htotal, hdisp_time, rowoffset; - int lowres, interlace; - int linedbl, rowcount; + uint64_t dispontime, dispofftime; + pc_timer_t timer; + double clock; - uint32_t ma_latch; - - int vres; - - int64_t dispontime, dispofftime; - int64_t vidtime; - - uint8_t scrblank; - - int dispon; - int hdisp_on; - - uint32_t ma, maback, ca; - int vc; - int sc; - int linepos, vslines, linecountff, oddeven; - int con, cursoron, blink; - int scrollcache; - - int firstline, lastline; - int firstline_draw, lastline_draw; - int displine; - - uint8_t *vram; - int vrammask; - - uint32_t vram_limit; - - int video_res_x, video_res_y, video_bpp; #ifdef JEGA uint8_t RMOD1, RMOD2, RDAGS, RDFFB, RDFSB, RDFAP, RPESL, RPULP, RPSSC, RPSSU, RPSSL; diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index 06b697cc8..b80434521 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -22,6 +22,7 @@ #include #include "../86box.h" #include "../device.h" +#include "../timer.h" #include "../mem.h" #include "../rom.h" #include "video.h" @@ -53,16 +54,16 @@ void ega_render_blank(ega_t *ega) switch (ega->seqregs[1] & 9) { case 0: - for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[dl])[(x * 9) + xx + 32 + x_add] = 0; + for (xx = 0; xx < 9; xx++) buffer32->line[dl][(x * 9) + xx + 32 + x_add] = 0; break; case 1: - for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[dl])[(x * 8) + xx + 32 + x_add] = 0; + for (xx = 0; xx < 8; xx++) buffer32->line[dl][(x * 8) + xx + 32 + x_add] = 0; break; case 8: - for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[dl])[(x * 18) + xx + 32 + x_add] = 0; + for (xx = 0; xx < 18; xx++) buffer32->line[dl][(x * 18) + xx + 32 + x_add] = 0; break; case 9: - for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[dl])[(x * 16) + xx + 32 + x_add] = 0; + for (xx = 0; xx < 16; xx++) buffer32->line[dl][(x * 16) + xx + 32 + x_add] = 0; break; } } @@ -111,20 +112,20 @@ void ega_render_text_standard(ega_t *ega, int drawcursor) if (ega->seqregs[1] & 1) { for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[dl])[((x << 4) + 32 + (xx << 1) + x_add) & 2047] = - ((uint32_t *)buffer32->line[dl])[((x << 4) + 33 + (xx << 1) + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + buffer32->line[dl][((x << 4) + 32 + (xx << 1) + x_add) & 2047] = + buffer32->line[dl][((x << 4) + 33 + (xx << 1) + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; } else { for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + (xx << 1) + x_add) & 2047] = - ((uint32_t *)buffer32->line[dl])[((x * 18) + 33 + (xx << 1) + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + buffer32->line[dl][((x * 18) + 32 + (xx << 1) + x_add) & 2047] = + buffer32->line[dl][((x * 18) + 33 + (xx << 1) + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) - ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 16 + x_add) & 2047] = - ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 17 + x_add) & 2047] = bg; + buffer32->line[dl][((x * 18) + 32 + 16 + x_add) & 2047] = + buffer32->line[dl][((x * 18) + 32 + 17 + x_add) & 2047] = bg; else - ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 16 + x_add) & 2047] = - ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 17 + x_add) & 2047] = (dat & 1) ? fg : bg; + buffer32->line[dl][((x * 18) + 32 + 16 + x_add) & 2047] = + buffer32->line[dl][((x * 18) + 32 + 17 + x_add) & 2047] = (dat & 1) ? fg : bg; } } else @@ -132,16 +133,16 @@ void ega_render_text_standard(ega_t *ega, int drawcursor) if (ega->seqregs[1] & 1) { for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[dl])[((x << 3) + 32 + xx + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + buffer32->line[dl][((x << 3) + 32 + xx + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; } else { for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[dl])[((x * 9) + 32 + xx + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + buffer32->line[dl][((x * 9) + 32 + xx + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) - ((uint32_t *)buffer32->line[dl])[((x * 9) + 32 + 8 + x_add) & 2047] = bg; + buffer32->line[dl][((x * 9) + 32 + 8 + x_add) & 2047] = bg; else - ((uint32_t *)buffer32->line[dl])[((x * 9) + 32 + 8 + x_add) & 2047] = (dat & 1) ? fg : bg; + buffer32->line[dl][((x * 9) + 32 + 8 + x_add) & 2047] = (dat & 1) ? fg : bg; } } ega->ma += 4; @@ -171,13 +172,13 @@ void ega_jega_render_blit_text(ega_t *ega, int x, int dl, int start, int width, { for (xx = start; xx < (start + width); xx++) for (xxx = 0; xxx < cw; xxx++) - ((uint32_t *)buffer32->line[dl])[(((x * width) + 32 + (xxx << 1) + ((xx << 1) * cw)) & 2047) + x_add] = - ((uint32_t *)buffer32->line[dl])[(((x * width) + 33 + (xxx << 1) + ((xx << 1) * cw)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + buffer32->line[dl][(((x * width) + 32 + (xxx << 1) + ((xx << 1) * cw)) & 2047) + x_add] = + buffer32->line[dl][(((x * width) + 33 + (xxx << 1) + ((xx << 1) * cw)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; } else { for (xx = start; xx < (start + width); xx++) - ((uint32_t *)buffer32->line[dl])[(((x * width) + 32 + xxx + (xx * cw)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + buffer32->line[dl][(((x * width) + 32 + xxx + (xx * cw)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; } } @@ -414,14 +415,14 @@ void ega_render_2bpp(ega_t *ega) ega->ma &= ega->vrammask; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 14 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 15 + offset] = ega->pallook[ega->egapal[edat[1] & 3]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 12 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 13 + offset] = ega->pallook[ega->egapal[(edat[1] >> 2) & 3]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 10 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 11 + offset] = ega->pallook[ega->egapal[(edat[1] >> 4) & 3]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 8 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 9 + offset] = ega->pallook[ega->egapal[(edat[1] >> 6) & 3]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 6 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 7 + offset] = ega->pallook[ega->egapal[(edat[0] >> 0) & 3]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 4 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 5 + offset] = ega->pallook[ega->egapal[(edat[0] >> 2) & 3]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 2 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 3 + offset] = ega->pallook[ega->egapal[(edat[0] >> 4) & 3]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 1 + offset] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]]; + buffer32->line[dl][(x << 4) + 14 + offset] = buffer32->line[ega->displine][(x << 4) + 15 + offset] = ega->pallook[ega->egapal[edat[1] & 3]]; + buffer32->line[dl][(x << 4) + 12 + offset] = buffer32->line[ega->displine][(x << 4) + 13 + offset] = ega->pallook[ega->egapal[(edat[1] >> 2) & 3]]; + buffer32->line[dl][(x << 4) + 10 + offset] = buffer32->line[ega->displine][(x << 4) + 11 + offset] = ega->pallook[ega->egapal[(edat[1] >> 4) & 3]]; + buffer32->line[dl][(x << 4) + 8 + offset] = buffer32->line[ega->displine][(x << 4) + 9 + offset] = ega->pallook[ega->egapal[(edat[1] >> 6) & 3]]; + buffer32->line[dl][(x << 4) + 6 + offset] = buffer32->line[ega->displine][(x << 4) + 7 + offset] = ega->pallook[ega->egapal[(edat[0] >> 0) & 3]]; + buffer32->line[dl][(x << 4) + 4 + offset] = buffer32->line[ega->displine][(x << 4) + 5 + offset] = ega->pallook[ega->egapal[(edat[0] >> 2) & 3]]; + buffer32->line[dl][(x << 4) + 2 + offset] = buffer32->line[ega->displine][(x << 4) + 3 + offset] = ega->pallook[ega->egapal[(edat[0] >> 4) & 3]]; + buffer32->line[dl][(x << 4) + offset] = buffer32->line[ega->displine][(x << 4) + 1 + offset] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]]; } } @@ -473,17 +474,17 @@ void ega_render_4bpp_lowres(ega_t *ega) ega->ma &= ega->vrammask; dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 4) + 14 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 12 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 4) + 14 + offset + x_add] = buffer32->line[dl][(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 4) + 12 + offset + x_add] = buffer32->line[dl][(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 4) + 10 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 8 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 4) + 10 + offset + x_add] = buffer32->line[dl][(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 4) + 8 + offset + x_add] = buffer32->line[dl][(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 4) + 6 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + 4 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 4) + 6 + offset + x_add] = buffer32->line[dl][(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 4) + 4 + offset + x_add] = buffer32->line[dl][(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 4) + 2 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 4) + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 4) + 2 + offset + x_add] = buffer32->line[dl][(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 4) + offset + x_add] = buffer32->line[dl][(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; } } @@ -535,16 +536,16 @@ void ega_render_4bpp_highres(ega_t *ega) ega->ma &= ega->vrammask; dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 3) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 3) + 6 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 3) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 3) + 6 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 3) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 3) + 4 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 3) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 3) + 4 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 3) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 3) + 2 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 3) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 3) + 2 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); - ((uint32_t *)buffer32->line[dl])[(x << 3) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[dl])[(x << 3) + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 3) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + buffer32->line[dl][(x << 3) + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; } } diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index 9864b0847..3702098df 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -48,6 +48,7 @@ #include "../mem.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" @@ -147,8 +148,6 @@ et4000k_in(uint16_t addr, void *priv) et4000_t *dev = (et4000_t *)priv; uint8_t val = 0xff; -// if (addr != 0x3da) pclog("IN ET4000 %04X\n", addr); - switch (addr) { case 0x22cb: return dev->port_22cb_val; @@ -334,8 +333,6 @@ et4000k_out(uint16_t addr, uint8_t val, void *priv) { et4000_t *dev = (et4000_t *)priv; -// pclog("ET4000k out %04X %02X\n", addr, val); - switch (addr) { case 0x22cb: dev->port_22cb_val = (dev->port_22cb_val & 0xf0) | (val & 0x0f); @@ -420,15 +417,15 @@ et4000_recalctimings(svga_t *svga) break; case 3: - svga->clock = cpuclock / 40000000.0; + svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break; case 5: - svga->clock = cpuclock / 65000000.0; + svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; default: - svga->clock = cpuclock / 36000000.0; + svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; break; } @@ -477,6 +474,13 @@ et4000_mca_write(int port, uint8_t val, void *priv) } +static uint8_t +et4000_mca_feedb(void *priv) +{ + return 1; +} + + static void * et4000_init(const device_t *info) { @@ -510,7 +514,7 @@ et4000_init(const device_t *info) et4000_in,NULL,NULL, et4000_out,NULL,NULL, dev); dev->pos_regs[0] = 0xf2; /* ET4000 MCA board ID */ dev->pos_regs[1] = 0x80; - mca_add(et4000_mca_read, et4000_mca_write, dev); + mca_add(et4000_mca_read, et4000_mca_write, et4000_mca_feedb, dev); break; case 2: /* Korean ET4000 */ @@ -543,8 +547,6 @@ et4000_init(const device_t *info) rom_init(&dev->bios_rom, (wchar_t *) fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - /* pclog("VIDEO: %s (vram=%dKB)\n", dev->name, dev->vram_size>>10); */ - return(dev); } diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 05aaf83a4..bc45fcd12 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -31,6 +31,7 @@ #include "../pci.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "../plat.h" #include "video.h" #include "vid_svga.h" @@ -352,7 +353,7 @@ void et4000w32p_recalctimings(svga_t *svga) if (svga->crtc[0x3F] & 0x01) svga->htotal += 256; if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; - svga->clock = cpuclock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); + svga->clock = (cpuclock * (double)(1ull << 32)) / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); switch (svga->bpp) { @@ -1083,17 +1084,17 @@ void et4000w32p_hwcursor_draw(svga_t *svga, int displine) for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) { dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 32] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 32] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x_add + x + 32] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x_add + x + 32] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 33 + x_add] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 33 + x_add] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x_add + x + 33 + x_add] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x_add + x + 33 + x_add] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 34] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 34] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x_add + x + 34] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x_add + x + 34] ^= 0xFFFFFF; dat >>= 2; - if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 35] = (dat & 1) ? 0xFFFFFF : 0; - else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 35] ^= 0xFFFFFF; + if (!(dat & 2)) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x_add + x + 35] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) buffer32->line[displine + y_add][svga->hwcursor_latch.x + x_add + x + 35] ^= 0xFFFFFF; dat >>= 2; offset += 4; } diff --git a/src/video/vid_et4000w32i.c b/src/video/vid_et4000w32i.c deleted file mode 100644 index f77055e37..000000000 --- a/src/video/vid_et4000w32i.c +++ /dev/null @@ -1,427 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * The below is (with some removals) a reasonable emulation - * of the ET4000/W32i blitter. Unfortunately the Diamond - * Stealth 32 is actually an ET4000/W32p! Which has a different - * blitter. If only I'd dug out and looked at the card before - * trying to emulate it. - * - * This might be of use for an attempt at an ET4000/W32i. - * - * Version: @(#)vid_et4000w32i.c 1.0.2 2017/11/04 - * - * Author: Sarah Walker, - * - * Copyright 2008-2017 Sarah Walker. - */ -#if 0 - -#include -#include -#include -#include -#include "../86box.h" - -int et4k_b8000; - -struct -{ - struct - { - uint32_t pattern_addr,source_addr,dest_addr; - uint16_t pattern_off,source_off,dest_off; - uint8_t vbus,xy_dir; - uint8_t pattern_wrap,source_wrap; - uint16_t count_x,count_y; - uint8_t ctrl_routing,ctrl_reload; - uint8_t rop_fg,rop_bg; - uint16_t pos_x,pos_y; - } queued,internal; - uint32_t pattern_addr,source_addr,dest_addr; - uint32_t pattern_back,dest_back; - int pattern_x,source_x; - int pattern_x_back; - int pattern_y,source_y; - uint8_t status; - uint32_t cpu_input; - int cpu_input_num; -} acl; - -#define ACL_WRST 1 -#define ACL_RDST 2 -#define ACL_XYST 4 -#define ACL_SSO 8 - -struct -{ - uint32_t base[3]; - uint8_t ctrl; -} mmu; - -void et4000w32_reset() -{ - acl.status=0; - acl.cpu_input_num=0; -} - -void et4000w32_blit_start(); -void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input); - -int et4000w32_vbus[4]={1,2,4,4}; - -void et4000w32_mmu_write(uint32_t addr, uint8_t val) -{ - int bank; - pclog("ET4K write %08X %02X %i %02X %02X %04X(%08X):%08X %04X %04X %02X %08X\n",addr,val,acl.cpu_input_num,acl.status,acl.internal.ctrl_routing,CS,cs,pc,CS,DI,mmu.ctrl,mmu.base[2]); - switch (addr&0x6000) - { - case 0x0000: /*MMU 0*/ - case 0x2000: /*MMU 1*/ - case 0x4000: /*MMU 2*/ - bank=(addr>>13)&3; - if (mmu.ctrl&(1<>12]=changeframecount; - } - break; - case 0x6000: - switch (addr&0x7FFF) - { - case 0x7F00: mmu.base[0]=(mmu.base[0]&0xFFFFFF00)|val; break; - case 0x7F01: mmu.base[0]=(mmu.base[0]&0xFFFF00FF)|(val<<8); break; - case 0x7F02: mmu.base[0]=(mmu.base[0]&0xFF00FFFF)|(val<<16); break; - case 0x7F03: mmu.base[0]=(mmu.base[0]&0x00FFFFFF)|(val<<24); break; - case 0x7F04: mmu.base[1]=(mmu.base[1]&0xFFFFFF00)|val; break; - case 0x7F05: mmu.base[1]=(mmu.base[1]&0xFFFF00FF)|(val<<8); break; - case 0x7F06: mmu.base[1]=(mmu.base[1]&0xFF00FFFF)|(val<<16); break; - case 0x7F07: mmu.base[1]=(mmu.base[1]&0x00FFFFFF)|(val<<24); break; - case 0x7F08: mmu.base[2]=(mmu.base[2]&0xFFFFFF00)|val; break; - case 0x7F09: mmu.base[2]=(mmu.base[2]&0xFFFF00FF)|(val<<8); break; - case 0x7F0A: mmu.base[2]=(mmu.base[2]&0xFF00FFFF)|(val<<16); break; - case 0x7F0B: mmu.base[2]=(mmu.base[2]&0x00FFFFFF)|(val<<24); break; - case 0x7F13: mmu.ctrl=val; break; - - case 0x7F80: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFFFF00)|val; break; - case 0x7F81: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFF00FF)|(val<<8); break; - case 0x7F82: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFF00FFFF)|(val<<16); break; - case 0x7F83: acl.queued.pattern_addr=(acl.queued.pattern_addr&0x00FFFFFF)|(val<<24); break; - case 0x7F84: acl.queued.source_addr =(acl.queued.source_addr &0xFFFFFF00)|val; break; - case 0x7F85: acl.queued.source_addr =(acl.queued.source_addr &0xFFFF00FF)|(val<<8); break; - case 0x7F86: acl.queued.source_addr =(acl.queued.source_addr &0xFF00FFFF)|(val<<16); break; - case 0x7F87: acl.queued.source_addr =(acl.queued.source_addr &0x00FFFFFF)|(val<<24); break; - case 0x7F88: acl.queued.pattern_off=(acl.queued.pattern_off&0xFF00)|val; break; - case 0x7F89: acl.queued.pattern_off=(acl.queued.pattern_off&0x00FF)|(val<<8); break; - case 0x7F8A: acl.queued.source_off =(acl.queued.source_off &0xFF00)|val; break; - case 0x7F8B: acl.queued.source_off =(acl.queued.source_off &0x00FF)|(val<<8); break; - case 0x7F8C: acl.queued.dest_off =(acl.queued.dest_off &0xFF00)|val; break; - case 0x7F8D: acl.queued.dest_off =(acl.queued.dest_off &0x00FF)|(val<<8); break; - case 0x7F8E: acl.queued.vbus=val; break; - case 0x7F8F: acl.queued.xy_dir=val; break; - case 0x7F90: acl.queued.pattern_wrap=val; break; - case 0x7F92: acl.queued.source_wrap=val; break; - case 0x7F98: acl.queued.count_x =(acl.queued.count_x &0xFF00)|val; break; - case 0x7F99: acl.queued.count_x =(acl.queued.count_x &0x00FF)|(val<<8); break; - case 0x7F9A: acl.queued.count_y =(acl.queued.count_y &0xFF00)|val; break; - case 0x7F9B: acl.queued.count_y =(acl.queued.count_y &0x00FF)|(val<<8); break; - case 0x7F9C: acl.queued.ctrl_routing=val; break; - case 0x7F9D: acl.queued.ctrl_reload =val; break; - case 0x7F9E: acl.queued.rop_bg =val; break; - case 0x7F9F: acl.queued.rop_fg =val; break; - case 0x7FA0: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFFFF00)|val; break; - case 0x7FA1: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFF00FF)|(val<<8); break; - case 0x7FA2: acl.queued.dest_addr =(acl.queued.dest_addr &0xFF00FFFF)|(val<<16); break; - case 0x7FA3: acl.queued.dest_addr =(acl.queued.dest_addr &0x00FFFFFF)|(val<<24); - acl.internal=acl.queued; - et4000w32_blit_start(); - acl.cpu_input_num=0; - if (!(acl.queued.ctrl_routing&0x37)) - { - et4000w32_blit(0xFFFFFF, ~0, 0, 0); - } - break; - } - break; - } -} - -uint8_t et4000w32_mmu_read(uint32_t addr) -{ - int bank; - pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc); - switch (addr&0x6000) - { - case 0x0000: /*MMU 0*/ - case 0x2000: /*MMU 1*/ - case 0x4000: /*MMU 2*/ - bank=(addr>>13)&3; - if (mmu.ctrl&(1<>8; - case 0x7F02: return mmu.base[0]>>16; - case 0x7F03: return mmu.base[0]>>24; - case 0x7F04: return mmu.base[1]; - case 0x7F05: return mmu.base[1]>>8; - case 0x7F06: return mmu.base[1]>>16; - case 0x7F07: return mmu.base[1]>>24; - case 0x7F08: return mmu.base[2]; - case 0x7F09: return mmu.base[2]>>8; - case 0x7F0A: return mmu.base[2]>>16; - case 0x7F0B: return mmu.base[2]>>24; - case 0x7F13: return mmu.ctrl; - - case 0x7F36: -// if (acl.internal.pos_x!=acl.internal.count_x || acl.internal.pos_y!=acl.internal.count_y) return acl.status | ACL_XYST; - return acl.status & ~(ACL_XYST | ACL_SSO); - case 0x7F80: return acl.internal.pattern_addr; - case 0x7F81: return acl.internal.pattern_addr>>8; - case 0x7F82: return acl.internal.pattern_addr>>16; - case 0x7F83: return acl.internal.pattern_addr>>24; - case 0x7F84: return acl.internal.source_addr; - case 0x7F85: return acl.internal.source_addr>>8; - case 0x7F86: return acl.internal.source_addr>>16; - case 0x7F87: return acl.internal.source_addr>>24; - case 0x7F88: return acl.internal.pattern_off; - case 0x7F89: return acl.internal.pattern_off>>8; - case 0x7F8A: return acl.internal.source_off; - case 0x7F8B: return acl.internal.source_off>>8; - case 0x7F8C: return acl.internal.dest_off; - case 0x7F8D: return acl.internal.dest_off>>8; - case 0x7F8E: return acl.internal.vbus; - case 0x7F8F: return acl.internal.xy_dir; - case 0x7F90: return acl.internal.pattern_wrap; - case 0x7F92: return acl.internal.source_wrap; - case 0x7F98: return acl.internal.count_x; - case 0x7F99: return acl.internal.count_x>>8; - case 0x7F9A: return acl.internal.count_y; - case 0x7F9B: return acl.internal.count_y>>8; - case 0x7F9C: return acl.internal.ctrl_routing; - case 0x7F9D: return acl.internal.ctrl_reload; - case 0x7F9E: return acl.internal.rop_bg; - case 0x7F9F: return acl.internal.rop_fg; - case 0x7FA0: return acl.internal.dest_addr; - case 0x7FA1: return acl.internal.dest_addr>>8; - case 0x7FA2: return acl.internal.dest_addr>>16; - case 0x7FA3: return acl.internal.dest_addr>>24; - } - return 0xFF; - } -} - -int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; -int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; - -void et4000w32_blit_start() -{ - pclog("Blit - %08X %08X %08X (%i,%i) %i %i %i %02X %02X %02X\n",acl.internal.pattern_addr,acl.internal.source_addr,acl.internal.dest_addr,acl.internal.dest_addr%640,acl.internal.dest_addr/640,acl.internal.xy_dir,acl.internal.count_x,acl.internal.count_y,acl.internal.rop_fg,acl.internal.rop_bg, acl.internal.ctrl_routing); - acl.pattern_addr=acl.internal.pattern_addr; - acl.source_addr =acl.internal.source_addr; - acl.dest_addr =acl.internal.dest_addr; - acl.dest_back =acl.dest_addr; - acl.internal.pos_x=acl.internal.pos_y=0; - acl.pattern_x=acl.source_x=acl.pattern_y=acl.source_y=0; - acl.status = ACL_XYST; - if (!(acl.internal.ctrl_routing&7) || (acl.internal.ctrl_routing&4)) acl.status |= ACL_SSO; - if (et4000w32_wrap_x[acl.internal.pattern_wrap&7]) - { - acl.pattern_x=acl.pattern_addr&et4000w32_wrap_x[acl.internal.pattern_wrap&7]; - acl.pattern_addr&=~et4000w32_wrap_x[acl.internal.pattern_wrap&7]; - } - if (!(acl.internal.pattern_wrap&0x80)) - { - acl.pattern_y=(acl.pattern_addr/(et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1))&(et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1); - acl.pattern_addr&=~(((et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1)*et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])-1); - } - acl.pattern_x_back=acl.pattern_x; - acl.pattern_back=acl.pattern_addr; -} - -void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input) -{ - int c,d; - uint8_t pattern,source,dest,out; - uint8_t rop; - -// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",acl.internal.count_x,acl.internal.count_y,acl.dest_addr,acl.dest_addr%640,acl.dest_addr/640,acl.source_addr,acl.pattern_addr); -// pclog("Blit exec - %i %i %i\n",count,acl.internal.pos_x,acl.internal.pos_y); - while (count--) - { - pclog("%i,%i : ",acl.internal.pos_x,acl.internal.pos_y); - if (acl.internal.xy_dir&1) - { - pattern=vram[(acl.pattern_addr-acl.pattern_x)&0x1FFFFF]; - source =vram[(acl.source_addr -acl.source_x) &0x1FFFFF]; - pclog("%06X %06X ",(acl.pattern_addr-acl.pattern_x)&0x1FFFFF,(acl.source_addr -acl.source_x) &0x1FFFFF); - } - else - { - pattern=vram[(acl.pattern_addr+acl.pattern_x)&0x1FFFFF]; - source =vram[(acl.source_addr +acl.source_x) &0x1FFFFF]; - pclog("%06X %06X ",(acl.pattern_addr+acl.pattern_x)&0x1FFFFF,(acl.source_addr +acl.source_x) &0x1FFFFF); - } - if (cpu_input==2) - { - source=sdat&0xFF; - sdat>>=8; - } - dest=vram[acl.dest_addr &0x1FFFFF]; - out=0; - pclog("%06X %i %08X ",acl.dest_addr,mix&1,mix); - rop = (mix & 1) ? acl.internal.rop_fg:acl.internal.rop_bg; - mix>>=1; mix|=0x80000000; - for (c=0;c<8;c++) - { - d=(dest & (1<>12]=changeframecount; - - acl.pattern_x++; - acl.pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; - acl.source_x++; - acl.source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; - if (acl.internal.xy_dir&1) acl.dest_addr--; - else acl.dest_addr++; - - acl.internal.pos_x++; - if (acl.internal.pos_x>acl.internal.count_x) - { - if (acl.internal.xy_dir&2) - { - acl.pattern_addr-=(acl.internal.pattern_off+1); - acl.source_addr -=(acl.internal.source_off +1); - acl.dest_back=acl.dest_addr=acl.dest_back-(acl.internal.dest_off+1); - } - else - { - acl.pattern_addr+=acl.internal.pattern_off+1; - acl.source_addr +=acl.internal.source_off +1; - acl.dest_back=acl.dest_addr=acl.dest_back+acl.internal.dest_off+1; - } - acl.pattern_x = acl.pattern_x_back; - acl.source_x = 0; - acl.pattern_y++; - if (acl.pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) - { - acl.pattern_y=0; - acl.pattern_addr=acl.pattern_back; - } - acl.source_y++; - if (acl.source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) - { - acl.source_y=0; - acl.source_addr=acl.internal.source_addr; - } - - acl.internal.pos_y++; - if (acl.internal.pos_y>acl.internal.count_y) - { - acl.status = 0; - return; - } - acl.internal.pos_x=0; - if (cpu_input) return; - } - } -} - -/* for (y=0;y<=acl.internal.count_y;y++) - { - dest_back=acl.dest_addr; - for (x=0;x<=acl.internal.count_x;x++) - { - if (acl.internal.xy_dir&1) - { - pattern=vram[(acl.pattern_addr-pattern_x)&0x1FFFFF]; - source =vram[(acl.source_addr -source_x) &0x1FFFFF]; - } - else - { - pattern=vram[(acl.pattern_addr+pattern_x)&0x1FFFFF]; - source =vram[(acl.source_addr +source_x) &0x1FFFFF]; - } - dest=vram[acl.dest_addr &0x1FFFFF]; - out=0; - for (c=0;c<8;c++) - { - d=(dest&(1<>12]=changeframecount; - - pattern_x++; - pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; - source_x++; - source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; - if (acl.internal.xy_dir&1) acl.dest_addr--; - else acl.dest_addr++; - } - acl.pattern_addr+=acl.internal.pattern_off+1; - acl.source_addr +=acl.internal.source_off+1; - acl.dest_addr=dest_back+acl.internal.dest_off+1; - pattern_y++; - if (pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) - { - pattern_y=0; - acl.pattern_addr=acl.internal.pattern_addr; - } - source_y++; - if (source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) - { - source_y=0; - acl.source_addr=acl.internal.source_addr; - } - }*/ - -#endif diff --git a/src/video/vid_genius.c b/src/video/vid_genius.c index 9eb978e6d..89f40da8c 100644 --- a/src/video/vid_genius.c +++ b/src/video/vid_genius.c @@ -8,13 +8,13 @@ * * MDSI Genius VHR emulation. * - * Version: @(#)vid_genius.c 1.0.11 2018/09/19 + * Version: @(#)vid_genius.c 1.0.12 2019/03/17 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -22,11 +22,12 @@ #include #include #include "../86box.h" +#include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "../plat.h" #include "video.h" @@ -103,6 +104,8 @@ typedef struct genius_t uint8_t mda_crtc[32]; /* The 'CRTC' as the host PC sees it */ int mda_crtcreg; /* Current CRTC register */ + uint8_t cga_crtc[32]; /* The 'CRTC' as the host PC sees it */ + int cga_crtcreg; /* Current CRTC register */ uint8_t genius_control; /* Native control register * I think bit 0 enables the full * framebuffer. @@ -126,526 +129,669 @@ typedef struct genius_t int enabled; /* Display enabled, 0 or 1 */ int detach; /* Detach cursor, 0 or 1 */ - int64_t dispontime, dispofftime; - int64_t vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int linepos, displine; int vc; int dispon, blink; - int64_t vsynctime; + int vsynctime; uint8_t *vram; } genius_t; -static uint32_t genius_pal[4]; +static uint8_t genius_pal[4]; /* Mapping of attributes to colours, in MDA emulation mode */ -static int mdacols[256][2][2]; +static uint8_t mdaattr[256][2][2]; void genius_recalctimings(genius_t *genius); void genius_write(uint32_t addr, uint8_t val, void *p); uint8_t genius_read(uint32_t addr, void *p); -void genius_out(uint16_t addr, uint8_t val, void *p) +void +genius_out(uint16_t addr, uint8_t val, void *p) { - genius_t *genius = (genius_t *)p; + genius_t *genius = (genius_t *)p; - switch (addr) - { - case 0x3b0: /* Command / control register */ + switch (addr) { + case 0x3b0: /* Command / control register */ genius->genius_control = val; if (val & 1) - { mem_mapping_set_addr(&genius->mapping, 0xa0000, 0x28000); - } else - { mem_mapping_set_addr(&genius->mapping, 0xb0000, 0x10000); - } - break; - case 0x3b1: + case 0x3b1: genius->genius_charh = val; break; - /* Emulated CRTC, register select */ - case 0x3b2: case 0x3b4: case 0x3b6: - case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: - genius->mda_crtcreg = val & 31; - break; + /* Emulated CRTC, register select */ + case 0x3b2: case 0x3b4: case 0x3b6: + genius->mda_crtcreg = val & 31; + break; - /* Emulated CRTC, value */ - case 0x3b3: case 0x3b5: case 0x3b7: - case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: - genius->mda_crtc[genius->mda_crtcreg] = val; - genius_recalctimings(genius); - return; + /* Emulated CRTC, value */ + case 0x3b3: case 0x3b5: case 0x3b7: + genius->mda_crtc[genius->mda_crtcreg] = val; + genius_recalctimings(genius); + return; - /* Emulated MDA control register */ - case 0x3b8: - genius->mda_ctrl = val; - return; - /* Emulated CGA control register */ - case 0x3D8: - genius->cga_ctrl = val; - return; - /* Emulated CGA colour register */ - case 0x3D9: - genius->cga_colour = val; - return; - } + /* Emulated MDA control register */ + case 0x3b8: + genius->mda_ctrl = val; + return; + + /* Emulated CRTC, register select */ + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + genius->cga_crtcreg = val & 31; + break; + + /* Emulated CRTC, value */ + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + genius->cga_crtc[genius->cga_crtcreg] = val; + genius_recalctimings(genius); + return; + + /* Emulated CGA control register */ + case 0x3d8: + genius->cga_ctrl = val; + return; + /* Emulated CGA colour register */ + case 0x3d9: + genius->cga_colour = val; + return; + } } -uint8_t genius_in(uint16_t addr, void *p) + +uint8_t +genius_in(uint16_t addr, void *p) { - genius_t *genius = (genius_t *)p; - - switch (addr) - { - case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: - case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: - return genius->mda_crtcreg; - case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: - case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: - return genius->mda_crtc[genius->mda_crtcreg]; - case 0x3b8: - return genius->mda_ctrl; - case 0x3d9: - return genius->cga_colour; - case 0x3ba: - return genius->mda_stat; - case 0x3d8: - return genius->cga_ctrl; - case 0x3da: - return genius->cga_stat; - } - return 0xff; + genius_t *genius = (genius_t *)p; + uint8_t ret = 0xff; + + switch (addr) { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + ret = genius->mda_crtcreg; + break; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + ret = genius->mda_crtc[genius->mda_crtcreg]; + break; + case 0x3b8: + ret = genius->mda_ctrl; + break; + case 0x3ba: + ret = genius->mda_stat; + break; + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + ret = genius->cga_crtcreg; + break; + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + ret = genius->cga_crtc[genius->cga_crtcreg]; + break; + case 0x3d8: + ret = genius->cga_ctrl; + break; + case 0x3d9: + ret = genius->cga_colour; + break; + case 0x3da: + ret = genius->cga_stat; + break; + } + + return ret; } -void genius_write(uint32_t addr, uint8_t val, void *p) + +static void +genius_waitstates(void) { - genius_t *genius = (genius_t *)p; - egawrites++; - - if (genius->genius_control & 1) - { - addr = addr % 0x28000; - } + int ws_array[16] = {3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8}; + int ws; + + ws = ws_array[cycles & 0xf]; + sub_cycles(ws); +} + + +void +genius_write(uint32_t addr, uint8_t val, void *p) +{ + genius_t *genius = (genius_t *)p; + egawrites++; + genius_waitstates(); + + if (genius->genius_control & 1) { + if ((addr >= 0xa0000) && (addr < 0xb0000)) + addr = (addr - 0xa0000) & 0xffff; + else if ((addr >= 0xb0000) && (addr < 0xb8000)) + addr = ((addr - 0xb0000) & 0x7fff) + 0x10000; else + addr = ((addr - 0xb8000) & 0xffff) + 0x18000; + } else { /* If hi-res memory is disabled, only visible in the B000 segment */ - { - addr = (addr & 0xFFFF) + 0x10000; - } - genius->vram[addr] = val; -} - - - -uint8_t genius_read(uint32_t addr, void *p) -{ - genius_t *genius = (genius_t *)p; - egareads++; - - if (genius->genius_control & 1) - { - addr = addr % 0x28000; - } + if (addr >= 0xb8000) + addr = (addr & 0x3FFF) + 0x18000; else - /* If hi-res memory is disabled, only visible in the B000 segment */ - { - addr = (addr & 0xFFFF) + 0x10000; - } - return genius->vram[addr]; + addr = (addr & 0x7FFF) + 0x10000; + } + + genius->vram[addr] = val; } -void genius_recalctimings(genius_t *genius) -{ - double disptime; - double _dispontime, _dispofftime; - disptime = 0x31; - _dispontime = 0x28; - _dispofftime = disptime - _dispontime; - _dispontime *= MDACONST; - _dispofftime *= MDACONST; - genius->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - genius->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +uint8_t +genius_read(uint32_t addr, void *p) +{ + genius_t *genius = (genius_t *)p; + uint8_t ret; + egareads++; + genius_waitstates(); + + if (genius->genius_control & 1) { + if ((addr >= 0xa0000) && (addr < 0xb0000)) + addr = (addr - 0xa0000) & 0xffff; + else if ((addr >= 0xb0000) && (addr < 0xb8000)) + addr = ((addr - 0xb0000) & 0x7fff) + 0x10000; + else + addr = ((addr - 0xb8000) & 0xffff) + 0x18000; + } else { + /* If hi-res memory is disabled, only visible in the B000 segment */ + if (addr >= 0xb8000) + addr = (addr & 0x3FFF) + 0x18000; + else + addr = (addr & 0x7FFF) + 0x10000; + } + + ret = genius->vram[addr]; + return ret; +} + + +void +genius_recalctimings(genius_t *genius) +{ + double disptime; + double _dispontime, _dispofftime; + + disptime = 0x31; + _dispontime = 0x28; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + genius->dispontime = (uint64_t)(_dispontime); + genius->dispofftime = (uint64_t)(_dispofftime); +} + + +static int +genius_lines(genius_t *genius) +{ + int ret = 350; + + switch (genius->genius_charh & 0x13) { + case 0x00: + ret = 990; /* 80x66 */ + break; + case 0x01: + ret = 980; /* 80x70 */ + break; + case 0x02: + ret = 988; /* Guess: 80x76 */ + break; + case 0x03: + ret = 984; /* 80x82 */ + break; + case 0x10: + ret = 375; /* Logic says 80x33 but it appears to be 80x25 */ + break; + case 0x11: + ret = 490; /* Guess: 80x35, fits the logic as well, half of 80x70 */ + break; + case 0x12: + ret = 494; /* Guess: 80x38 */ + break; + case 0x13: + ret = 492; /* 80x41 */ + break; + } + + return ret; } /* Draw a single line of the screen in either text mode */ -void genius_textline(genius_t *genius, uint8_t background) +static void +genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) { - int x; - int w = 80; /* 80 characters across */ - int cw = 9; /* Each character is 9 pixels wide */ - uint8_t chr, attr; - uint8_t bitmap[2]; - int blink, c, row; - int drawcursor, cursorline; - uint16_t addr; - uint8_t sc; - int charh; - uint16_t ma = (genius->mda_crtc[13] | (genius->mda_crtc[12] << 8)) & 0x3fff; - uint16_t ca = (genius->mda_crtc[15] | (genius->mda_crtc[14] << 8)) & 0x3fff; - unsigned char *framebuf = genius->vram + 0x10000; - uint32_t col; + int w = 80; /* 80 characters across */ + int cw = 9; /* Each character is 9 pixels wide */ + uint8_t chr, attr, sc, ctrl; + uint8_t *crtc, bitmap[2]; + int x, blink, c, row, charh; + int drawcursor, cursorline; + uint16_t addr; + uint16_t ma = (genius->mda_crtc[13] | (genius->mda_crtc[12] << 8)) & 0x3fff; + uint16_t ca = (genius->mda_crtc[15] | (genius->mda_crtc[14] << 8)) & 0x3fff; + unsigned char *framebuf = genius->vram + 0x10000; + uint32_t col, dl = genius->displine; - /* Character height is 12-15 */ + /* Character height is 12-15 */ + if (mda) { + if (genius->displine >= genius_lines(genius)) + return; + + crtc = genius->mda_crtc; + ctrl = genius->mda_ctrl; charh = 15 - (genius->genius_charh & 3); - if (genius->genius_charh & 0x10) - { - row = ((genius->displine >> 1) / charh); - sc = ((genius->displine >> 1) % charh); - } - else - { - row = (genius->displine / charh); - sc = (genius->displine % charh); - } - addr = ((ma & ~1) + row * w) * 2; - ma += (row * w); - - if ((genius->mda_crtc[10] & 0x60) == 0x20) - { - cursorline = 0; +#if 0 + if (genius->genius_charh & 0x10) { + row = ((dl >> 1) / charh); + sc = ((dl >> 1) % charh); + } else { + row = (dl / charh); + sc = (dl % charh); } - else - { - cursorline = ((genius->mda_crtc[10] & 0x1F) <= sc) && - ((genius->mda_crtc[11] & 0x1F) >= sc); +#else + row = (dl / charh); + sc = (dl % charh); +#endif + } else { + if ((genius->displine < 512) || (genius->displine >= 912)) + return; + + crtc = genius->cga_crtc; + ctrl = genius->cga_ctrl; + framebuf += 0x08000; + + dl -= 512; + w = crtc[1]; + cw = 8; + charh = crtc[9] + 1; + + row = ((dl >> 1) / charh); + sc = ((dl >> 1) % charh); + } + + ma = (crtc[13] | (crtc[12] << 8)) & 0x3fff; + ca = (crtc[15] | (crtc[14] << 8)) & 0x3fff; + + addr = ((ma & ~1) + row * w) * 2; + + if (!mda) + dl += 512; + + ma += (row * w); + + if ((crtc[10] & 0x60) == 0x20) + cursorline = 0; + else + cursorline = ((crtc[10] & 0x1F) <= sc) && ((crtc[11] & 0x1F) >= sc); + + for (x = 0; x < w; x++) { +#if 0 + if ((genius->genius_charh & 0x10) && ((addr + 2 * x) > 0x0FFF)) + chr = 0x00; + if ((genius->genius_charh & 0x10) && ((addr + 2 * x + 1) > 0x0FFF)) + attr = 0x00; +#endif + chr = framebuf[(addr + 2 * x) & 0x3FFF]; + attr = framebuf[(addr + 2 * x + 1) & 0x3FFF]; + + drawcursor = ((ma == ca) && cursorline && genius->enabled && (ctrl & 8)); + + switch (crtc[10] & 0x60) { + case 0x00: drawcursor = drawcursor && (genius->blink & 16); break; + case 0x60: drawcursor = drawcursor && (genius->blink & 32); break; } - for (x = 0; x < w; x++) - { - chr = framebuf[(addr + 2 * x) & 0x3FFF]; - attr = framebuf[(addr + 2 * x + 1) & 0x3FFF]; - drawcursor = ((ma == ca) && cursorline && genius->enabled && - (genius->mda_ctrl & 8)); + blink = ((genius->blink & 16) && (ctrl & 0x20) && (attr & 0x80) && !drawcursor); - switch (genius->mda_crtc[10] & 0x60) - { - case 0x00: drawcursor = drawcursor && (genius->blink & 16); break; - case 0x60: drawcursor = drawcursor && (genius->blink & 32); break; + if (ctrl & 0x20) attr &= 0x7F; + + /* MDA underline */ + if (mda && (sc == charh) && ((attr & 7) == 1)) { + col = mdaattr[attr][blink][1]; + + if (genius->genius_control & 0x20) + col ^= 15; + + for (c = 0; c < cw; c++) { + if (col != background) { + if (cols80) + buffer32->line[dl][(x * cw) + c] = col; + else { + buffer32->line[dl][((x * cw) << 1) + (c << 1)] = + buffer32->line[dl][((x * cw) << 1) + (c << 1) + 1] = col; + } + } } - blink = ((genius->blink & 16) && - (genius->mda_ctrl & 0x20) && - (attr & 0x80) && !drawcursor); + } else { /* Draw 8 pixels of character */ + if (mda) + bitmap[0] = fontdat8x12[chr][sc]; + else + bitmap[0] = fontdat[chr][sc]; - if (genius->mda_ctrl & 0x20) attr &= 0x7F; - /* MDA underline */ - if (sc == charh && ((attr & 7) == 1)) - { - col = mdacols[attr][blink][1]; + for (c = 0; c < 8; c++) { + col = mdaattr[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; + if (!(genius->enabled) || !(ctrl & 8)) + col = mdaattr[0][0][0]; if (genius->genius_control & 0x20) - { - col ^= 0xffffff; - } + col ^= 15; - for (c = 0; c < cw; c++) - { - if (col != background) - ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] = col; + if (col != background) { + if (cols80) + buffer32->line[dl][(x * cw) + c] = col; + else { + buffer32->line[dl][((x * cw) << 1) + (c << 1)] = + buffer32->line[dl][((x * cw) << 1) + (c << 1) + 1] = col; + } } } - else /* Draw 8 pixels of character */ - { - bitmap[0] = fontdat8x12[chr][sc]; - for (c = 0; c < 8; c++) - { - col = mdacols[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; - if (!(genius->enabled) || !(genius->mda_ctrl & 8)) - col = mdacols[0][0][0]; - - if (genius->genius_control & 0x20) - { - col ^= 0xffffff; - } - if (col != background) - { - ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] = col; - } - } + + if (cw == 9) { /* The ninth pixel column... */ - if ((chr & ~0x1f) == 0xc0) - { + if ((chr & ~0x1f) == 0xc0) { /* Echo column 8 for the graphics chars */ - col = ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 7]; - if (col != background) - ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 8] = col; - } - else /* Otherwise fill with background */ - { - col = mdacols[attr][blink][0]; - if (genius->genius_control & 0x20) - { - col ^= 0xffffff; + if (cols80) { + col = buffer32->line[dl][(x * cw) + 7]; + if (col != background) + buffer32->line[dl][(x * cw) + 8] = col; + } else { + col = buffer32->line[dl][((x * cw) << 1) + 14]; + if (col != background) { + buffer32->line[dl][((x * cw) << 1) + 16] = + buffer32->line[dl][((x * cw) << 1) + 17] = col; + } + } + } else { /* Otherwise fill with background */ + col = mdaattr[attr][blink][0]; + if (genius->genius_control & 0x20) + col ^= 15; + if (col != background) { + if (cols80) + buffer32->line[dl][(x * cw) + 8] = col; + else { + buffer32->line[dl][((x * cw) << 1) + 16] = + buffer32->line[dl][((x * cw) << 1) + 17] = col; + } } - if (col != background) - ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 8] = col; } - if (drawcursor) - { - for (c = 0; c < cw; c++) - ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] ^= mdacols[attr][0][1]; - } - ++ma; } + + if (drawcursor) { + for (c = 0; c < cw; c++) { + if (cols80) + buffer32->line[dl][(x * cw) + c] ^= mdaattr[attr][0][1]; + else { + buffer32->line[dl][((x * cw) << 1) + (c << 1)] ^= mdaattr[attr][0][1]; + buffer32->line[dl][((x * cw) << 1) + (c << 1) + 1] ^= mdaattr[attr][0][1]; + } + } + } + ++ma; } + } } + /* Draw a line in the CGA 640x200 mode */ -void genius_cgaline(genius_t *genius) +void +genius_cgaline(genius_t *genius) { - int x, c; - uint32_t dat; - uint32_t ink; - uint32_t addr; + int x, c; + uint32_t dat, addr; + uint8_t ink_f, ink_b; - ink = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; - /* We draw the CGA at row 600 */ - if (genius->displine < 600) - { - return; - } - addr = 0x18000 + 80 * ((genius->displine - 600) >> 2); - if ((genius->displine - 600) & 2) - { - addr += 0x2000; - } + ink_f = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; + ink_b = (genius->genius_control & 0x20) ? genius_pal[3] : genius_pal[0]; - for (x = 0; x < 80; x++) - { - dat = genius->vram[addr]; - addr++; + /* We draw the CGA at row 512 */ + if ((genius->displine < 512) || (genius->displine >= 912)) + return; - for (c = 0; c < 8; c++) - { - if (dat & 0x80) - { - ((uint32_t *)buffer32->line[genius->displine])[x*8 + c] = ink; - } - dat = dat << 1; - } + addr = 0x18000 + 80 * ((genius->displine - 512) >> 2); + if ((genius->displine - 512) & 2) + addr += 0x2000; + + for (x = 0; x < 80; x++) { + dat = genius->vram[addr]; + addr++; + + for (c = 0; c < 8; c++) { + if (dat & 0x80) + buffer32->line[genius->displine][(x << 3) + c] = ink_f; + else + buffer32->line[genius->displine][(x << 3) + c] = ink_b; + + dat = dat << 1; } + } } + /* Draw a line in the native high-resolution mode */ -void genius_hiresline(genius_t *genius) +void +genius_hiresline(genius_t *genius) { - int x, c; - uint32_t dat; - uint32_t ink; - uint32_t addr; - - ink = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; - /* The first 512 lines live at A0000 */ - if (genius->displine < 512) - { - addr = 128 * genius->displine; - } - else /* The second 496 live at B8000 */ - { - addr = 0x18000 + 128 * (genius->displine - 512); - } + int x, c; + uint32_t dat, addr; + uint8_t ink_f, ink_b; - for (x = 0; x < 91; x++) - { - dat = genius->vram[addr]; - addr++; + ink_f = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; + ink_b = (genius->genius_control & 0x20) ? genius_pal[3] : genius_pal[0]; - for (c = 0; c < 8; c++) - { - if (dat & 0x80) - { - ((uint32_t *)buffer32->line[genius->displine])[x*8 + c] = ink; - } - dat = dat << 1; - } + /* The first 512 lines live at A0000 */ + if (genius->displine < 512) + addr = 128 * genius->displine; + else /* The second 496 live at B8000 */ + addr = 0x18000 + (128 * (genius->displine - 512)); + + for (x = 0; x < 91; x++) { + dat = genius->vram[addr + x]; + + for (c = 0; c < 8; c++) { + if (dat & 0x80) + buffer32->line[genius->displine][(x << 3) + c] = ink_f; + else + buffer32->line[genius->displine][(x << 3) + c] = ink_b; + + dat = dat << 1; } + } } -void genius_poll(void *p) -{ - genius_t *genius = (genius_t *)p; - int x; - uint8_t background; - if (!genius->linepos) - { - genius->vidtime += genius->dispofftime; - genius->cga_stat |= 1; - genius->mda_stat |= 1; - genius->linepos = 1; - if (genius->dispon) - { - if (genius->genius_control & 0x20) - { - background = genius_pal[3]; - } - else - { - background = genius_pal[0]; - } - if (genius->displine == 0) - { - video_wait_for_buffer(); - } - /* Start off with a blank line */ - for (x = 0; x < GENIUS_XSIZE; x++) - { - ((uint32_t *)buffer32->line[genius->displine])[x] = background; - } - /* If graphics display enabled, draw graphics on top - * of the blanked line */ - if (genius->cga_ctrl & 8) - { - if (genius->genius_control & 8) - { +void +genius_poll(void *p) +{ + genius_t *genius = (genius_t *)p; + int x; + uint8_t background; + + if (!genius->linepos) { + timer_advance_u64(&genius->timer, genius->dispofftime); + genius->cga_stat |= 1; + genius->mda_stat |= 1; + genius->linepos = 1; + + if (genius->dispon) { + if (genius->genius_control & 0x20) + background = genius_pal[3]; + else + background = genius_pal[0]; + + if (genius->displine == 0) + video_wait_for_buffer(); + + /* Start off with a blank line */ + for (x = 0; x < GENIUS_XSIZE; x++) + buffer32->line[genius->displine][x] = background; + + /* If graphics display enabled, draw graphics on top + * of the blanked line */ + if (genius->cga_ctrl & 8) { + if (((genius->genius_control & 0x11) == 0x00) || (genius->genius_control & 0x08)) + genius_cgaline(genius); + else if ((genius->genius_control & 0x11) == 0x01) + genius_hiresline(genius); + else { + if (genius->cga_ctrl & 2) genius_cgaline(genius); - } - else - { - genius_hiresline(genius); + else { + if (genius->cga_ctrl & 1) + genius_textline(genius, background, 0, 1); + else + genius_textline(genius, background, 0, 0); } } - /* If MDA display is enabled, draw MDA text on top - * of the lot */ - if (genius->mda_ctrl & 8) - { - genius_textline(genius, background); - } - } - genius->displine++; - /* Hardcode a fixed refresh rate and VSYNC timing */ - if (genius->displine == 1008) /* Start of VSYNC */ - { - genius->cga_stat |= 8; - genius->dispon = 0; - } - if (genius->displine == 1040) /* End of VSYNC */ - { - genius->displine = 0; - genius->cga_stat &= ~8; - genius->dispon = 1; } - } - else - { - if (genius->dispon) - { - genius->cga_stat &= ~1; - genius->mda_stat &= ~1; - } - genius->vidtime += genius->dispontime; - genius->linepos = 0; - if (genius->displine == 1008) - { + /* If MDA display is enabled, draw MDA text on top + * of the lot */ + if (genius->mda_ctrl & 8) + genius_textline(genius, background, 1, 1); + } + genius->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (genius->displine == 1008) { /* Start of VSYNC */ + genius->cga_stat |= 8; + genius->mda_stat |= 8; + genius->dispon = 0; + } + if (genius->displine == 1040) { /* End of VSYNC */ + genius->displine = 0; + genius->cga_stat &= ~8; + genius->mda_stat &= ~8; + genius->dispon = 1; + } + } else { + if (genius->dispon) { + genius->cga_stat &= ~1; + genius->mda_stat &= ~1; + } + timer_advance_u64(&genius->timer, genius->dispontime); + genius->linepos = 0; + + if (genius->displine == 1008) { /* Hardcode GENIUS_XSIZE * GENIUS_YSIZE window size */ - if (GENIUS_XSIZE != xsize || GENIUS_YSIZE != ysize) - { - xsize = GENIUS_XSIZE; - ysize = GENIUS_YSIZE; - if (xsize < 64) xsize = 656; - if (ysize < 32) ysize = 200; - set_screen_size(xsize, ysize); + if (GENIUS_XSIZE != xsize || GENIUS_YSIZE != ysize) { + xsize = GENIUS_XSIZE; + ysize = GENIUS_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); - if (video_force_resize_get()) - video_force_resize_set(0); - } - video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + if (video_force_resize_get()) + video_force_resize_set(0); + } - frames++; - /* Fixed 728x1008 resolution */ - video_res_x = GENIUS_XSIZE; - video_res_y = GENIUS_YSIZE; - video_bpp = 1; - genius->blink++; - } - } + video_blit_memtoscreen_8(0, 0, 0, ysize, xsize, ysize); + + frames++; + /* Fixed 728x1008 resolution */ + video_res_x = GENIUS_XSIZE; + video_res_y = GENIUS_YSIZE; + video_bpp = 1; + genius->blink++; + } + } } -void *genius_init(const device_t *info) + +void +*genius_init(const device_t *info) { - int c; - genius_t *genius = malloc(sizeof(genius_t)); - memset(genius, 0, sizeof(genius_t)); - video_inform(VIDEO_FLAG_TYPE_MDA, &timing_genius); + int c; + genius_t *genius = malloc(sizeof(genius_t)); - /* 160k video RAM */ - genius->vram = malloc(0x28000); + memset(genius, 0, sizeof(genius_t)); - loadfont(BIOS_ROM_PATH, 4); + video_inform(VIDEO_FLAG_TYPE_MDA, &timing_genius); - timer_add(genius_poll, &genius->vidtime, TIMER_ALWAYS_ENABLED, genius); + /* 160k video RAM */ + genius->vram = malloc(0x28000); - /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in - * high-resolution modes) */ - mem_mapping_add(&genius->mapping, 0xb0000, 0x10000, genius_read, NULL, NULL, genius_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, genius); - /* Respond to both MDA and CGA I/O ports */ - io_sethandler(0x03b0, 0x000C, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); - io_sethandler(0x03d0, 0x0010, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); + loadfont(BIOS_ROM_PATH, 4); - genius_pal[0] = makecol(0x00, 0x00, 0x00); - genius_pal[1] = makecol(0x55, 0x55, 0x55); - genius_pal[2] = makecol(0xaa, 0xaa, 0xaa); - genius_pal[3] = makecol(0xff, 0xff, 0xff); + timer_add(&genius->timer, genius_poll, genius, 1); - /* MDA attributes */ - /* I don't know if the Genius's MDA emulation actually does - * emulate bright / non-bright. For the time being pretend it does. */ - for (c = 0; c < 256; c++) - { - mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = genius_pal[0]; - if (c & 8) mdacols[c][0][1] = genius_pal[3]; - else mdacols[c][0][1] = genius_pal[2]; - } - mdacols[0x70][0][1] = genius_pal[0]; - mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = genius_pal[3]; - mdacols[0xF0][0][1] = genius_pal[0]; - mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = genius_pal[3]; - mdacols[0x78][0][1] = genius_pal[2]; - mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = genius_pal[3]; - mdacols[0xF8][0][1] = genius_pal[2]; - mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = genius_pal[3]; - mdacols[0x00][0][1] = mdacols[0x00][1][1] = genius_pal[0]; - mdacols[0x08][0][1] = mdacols[0x08][1][1] = genius_pal[0]; - mdacols[0x80][0][1] = mdacols[0x80][1][1] = genius_pal[0]; - mdacols[0x88][0][1] = mdacols[0x88][1][1] = genius_pal[0]; + /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in + * high-resolution modes) */ + mem_mapping_add(&genius->mapping, 0xb0000, 0x10000, genius_read, NULL, NULL, genius_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, genius); + + /* Respond to both MDA and CGA I/O ports */ + io_sethandler(0x03b0, 0x000C, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); + io_sethandler(0x03d0, 0x0010, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); + + genius_pal[0] = 0 + 16; /* 0 */ + genius_pal[1] = 8 + 16; /* 8 */ + genius_pal[2] = 7 + 16; /* 7 */ + genius_pal[3] = 15 + 16; /* F */ + + /* MDA attributes */ + /* I don't know if the Genius's MDA emulation actually does + * emulate bright / non-bright. For the time being pretend it does. */ + for (c = 0; c < 256; c++) { + mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = genius_pal[0]; + if (c & 8) mdaattr[c][0][1] = genius_pal[3]; + else mdaattr[c][0][1] = genius_pal[2]; + } + mdaattr[0x70][0][1] = genius_pal[0]; + mdaattr[0x70][0][0] = mdaattr[0x70][1][0] = mdaattr[0x70][1][1] = genius_pal[3]; + mdaattr[0xF0][0][1] = genius_pal[0]; + mdaattr[0xF0][0][0] = mdaattr[0xF0][1][0] = mdaattr[0xF0][1][1] = genius_pal[3]; + mdaattr[0x78][0][1] = genius_pal[2]; + mdaattr[0x78][0][0] = mdaattr[0x78][1][0] = mdaattr[0x78][1][1] = genius_pal[3]; + mdaattr[0xF8][0][1] = genius_pal[2]; + mdaattr[0xF8][0][0] = mdaattr[0xF8][1][0] = mdaattr[0xF8][1][1] = genius_pal[3]; + mdaattr[0x00][0][1] = mdaattr[0x00][1][1] = genius_pal[0]; + mdaattr[0x08][0][1] = mdaattr[0x08][1][1] = genius_pal[0]; + mdaattr[0x80][0][1] = mdaattr[0x80][1][1] = genius_pal[0]; + mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = genius_pal[0]; /* Start off in 80x25 text mode */ - genius->cga_stat = 0xF4; - genius->genius_mode = 2; - genius->enabled = 1; - genius->genius_charh = 0x90; /* Native character height register */ - return genius; + genius->cga_stat = 0xF4; + genius->genius_mode = 2; + genius->enabled = 1; + genius->genius_charh = 0x90; /* Native character height register */ + genius->genius_control |= 0x10; + return genius; } -void genius_close(void *p) + +void +genius_close(void *p) { - genius_t *genius = (genius_t *)p; + genius_t *genius = (genius_t *)p; - free(genius->vram); - free(genius); + free(genius->vram); + free(genius); } -static int genius_available() + +static int +genius_available() { - return rom_present(BIOS_ROM_PATH); + return rom_present(BIOS_ROM_PATH); } -void genius_speed_changed(void *p) + +void +genius_speed_changed(void *p) { - genius_t *genius = (genius_t *)p; - - genius_recalctimings(genius); + genius_t *genius = (genius_t *)p; + + genius_recalctimings(genius); } + const device_t genius_device = { "Genius VHR", diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index 1fae48528..54c1dfc3a 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -26,9 +26,9 @@ #include "../mem.h" #include "../rom.h" #include "../io.h" +#include "../timer.h" #include "../lpt.h" #include "../pit.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_hercules.h" @@ -44,9 +44,9 @@ typedef struct { ctrl2, stat; - int64_t dispontime, + uint64_t dispontime, dispofftime; - int64_t vidtime; + pc_timer_t timer; int firstline, lastline; @@ -61,7 +61,7 @@ typedef struct { cursoron; int dispon, blink; - int64_t vsynctime; + int vsynctime; int vadj; int cols[256][2][2]; @@ -81,14 +81,20 @@ recalc_timings(hercules_t *dev) disptime = dev->crtc[0] + 1; _dispontime = dev->crtc[1]; _dispofftime = disptime - _dispontime; - _dispontime *= MDACONST; - _dispofftime *= MDACONST; + _dispontime *= HERCCONST; + _dispofftime *= HERCCONST; - dev->dispontime = (int64_t)(_dispontime * (1LL << TIMER_SHIFT)); - dev->dispofftime = (int64_t)(_dispofftime * (1LL << TIMER_SHIFT)); + dev->dispontime = (uint64_t)(_dispontime); + dev->dispofftime = (uint64_t)(_dispofftime); } +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + static void hercules_out(uint16_t addr, uint8_t val, void *priv) { @@ -108,7 +114,7 @@ hercules_out(uint16_t addr, uint8_t val, void *priv) case 0x03b5: case 0x03b7: old = dev->crtc[dev->crtcreg]; - dev->crtc[dev->crtcreg] = val; + dev->crtc[dev->crtcreg] = val & crtcmask[dev->crtcreg]; /* * Fix for Generic Turbo XT BIOS, which @@ -118,23 +124,36 @@ hercules_out(uint16_t addr, uint8_t val, void *priv) dev->crtc[10] = 0xb; dev->crtc[11] = 0xc; } +#if 0 if (old ^ val) recalc_timings(dev); +#else + if (old != val) { + if ((dev->crtcreg < 0xe) || (dev->crtcreg > 0x10)) { + fullchange = changeframecount; + recalc_timings(dev); + } + } +#endif break; case 0x03b8: old = dev->ctrl; + if (!(dev->ctrl2 & 0x01) && !(val & 0x02)) + val = (val & 0xfd) | (dev->ctrl & 0x02); + if (!(dev->ctrl2 & 0x02) && !(val & 0x80)) + val = (val & 0x7f) | (dev->ctrl & 0x80); dev->ctrl = val; + if (val & 0x80) + mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x08000); if (old ^ val) recalc_timings(dev); break; case 0x03bf: dev->ctrl2 = val; - if (val & 0x02) - mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x10000); - else - mem_mapping_set_addr(&dev->mapping, 0xb0000, 0x08000); break; default: @@ -166,8 +185,17 @@ hercules_in(uint16_t addr, void *priv) case 0x03ba: ret = 0x72; /* Hercules ident */ +#if 0 if (dev->stat & 0x08) ret |= 0x88; +#else + if (dev->stat & 0x08) + ret |= 0x80; +#endif + if ((dev->stat & 0x09) == 0x01) + ret |= (dev->stat & 0x01); + if ((ret & 0x81) == 0x80) + ret |= 0x08; break; default: @@ -185,7 +213,7 @@ hercules_waitstates(void *p) int ws; ws = ws_array[cycles & 0xf]; - cycles -= ws; + sub_cycles(ws); } @@ -194,7 +222,11 @@ hercules_write(uint32_t addr, uint8_t val, void *priv) { hercules_t *dev = (hercules_t *)priv; - dev->vram[addr & 0xffff] = val; + if (dev->ctrl2 & 0x01) + dev->vram[addr & 0xffff] = val; + else + dev->vram[addr & 0x0fff] = val; + hercules_waitstates(dev); } @@ -204,7 +236,11 @@ hercules_read(uint32_t addr, void *priv) { hercules_t *dev = (hercules_t *)priv; - return(dev->vram[addr & 0xffff]); + if (dev->ctrl2 & 0x01) + return(dev->vram[addr & 0xffff]); + else + return(dev->vram[addr & 0x0fff]); + hercules_waitstates(dev); } @@ -222,7 +258,7 @@ hercules_poll(void *priv) ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; if (! dev->linepos) { - dev->vidtime += dev->dispofftime; + timer_advance_u64(&dev->timer, dev->dispofftime); dev->stat |= 1; dev->linepos = 1; oldsc = dev->sc; @@ -237,20 +273,22 @@ hercules_poll(void *priv) } dev->lastline = dev->displine; - if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) { + // if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) { + if (dev->ctrl & 2) { ca = (dev->sc & 3) * 0x2000; - if ((dev->ctrl & 0x80) && (dev->ctrl2 & 2)) + // if ((dev->ctrl & 0x80) && (dev->ctrl2 & 2)) + if (dev->ctrl & 0x80) ca += 0x8000; for (x = 0; x < dev->crtc[1]; x++) { if (dev->ctrl & 8) + // dat = (dev->vram[((dev->ma << 1) & 0x1fff) + ca] << 8) | dev->vram[((dev->ma << 1) & 0x1fff) + ca + 1]; dat = (dev->vram[((dev->ma << 1) & 0x1fff) + ca] << 8) | dev->vram[((dev->ma << 1) & 0x1fff) + ca + 1]; else dat = 0; dev->ma++; - for (c = 0; c < 16; c++) { - buffer->line[dev->displine][(x << 4) + c] = (dat & (32768 >> c)) ? 7 : 0; - } + for (c = 0; c < 16; c++) + buffer32->line[dev->displine][(x << 4) + c] = (dat & (32768 >> c)) ? 7 : 0; for (c = 0; c < 16; c += 8) video_blend((x << 4) + c, dev->displine); } @@ -266,21 +304,21 @@ hercules_poll(void *priv) if (dev->sc == 12 && ((attr & 7) == 1)) { for (c = 0; c < 9; c++) - buffer->line[dev->displine][(x * 9) + c] = dev->cols[attr][blink][1]; + buffer32->line[dev->displine][(x * 9) + c] = dev->cols[attr][blink][1]; } else { for (c = 0; c < 8; c++) - buffer->line[dev->displine][(x * 9) + c] = dev->cols[attr][blink][(fontdatm[chr][dev->sc] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[dev->displine][(x * 9) + c] = dev->cols[attr][blink][(fontdatm[chr][dev->sc] & (1 << (c ^ 7))) ? 1 : 0]; if ((chr & ~0x1f) == 0xc0) - buffer->line[dev->displine][(x * 9) + 8] = dev->cols[attr][blink][fontdatm[chr][dev->sc] & 1]; - else - buffer->line[dev->displine][(x * 9) + 8] = dev->cols[attr][blink][0]; + buffer32->line[dev->displine][(x * 9) + 8] = dev->cols[attr][blink][fontdatm[chr][dev->sc] & 1]; + else + buffer32->line[dev->displine][(x * 9) + 8] = dev->cols[attr][blink][0]; } dev->ma++; if (drawcursor) { for (c = 0; c < 9; c++) - buffer->line[dev->displine][(x * 9) + c] ^= dev->cols[attr][0][1]; + buffer32->line[dev->displine][(x * 9) + c] ^= dev->cols[attr][0][1]; } } } @@ -293,7 +331,7 @@ hercules_poll(void *priv) if (dev->displine >= 500) dev->displine = 0; } else { - dev->vidtime += dev->dispontime; + timer_advance_u64(&dev->timer, dev->dispontime); dev->linepos = 0; if (dev->vsynctime) { @@ -346,13 +384,14 @@ hercules_poll(void *priv) dev->displine = 0; dev->vsynctime = 16;//(crtcm[3]>>4)+1; if (dev->crtc[7]) { - if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) + // if ((dev->ctrl & 2) && (dev->ctrl2 & 1)) + if (dev->ctrl & 2) x = dev->crtc[1] << 4; else x = dev->crtc[1] * 9; dev->lastline++; - if ((dev->ctrl & 8) && + if ((dev->ctrl & 8) && x && (dev->lastline - dev->firstline) && ((x != xsize) || ((dev->lastline - dev->firstline) != ysize) || video_force_resize_get())) { xsize = x; ysize = dev->lastline - dev->firstline; @@ -407,7 +446,7 @@ hercules_init(const device_t *info) dev->vram = (uint8_t *)malloc(0x10000); - timer_add(hercules_poll, &dev->vidtime, TIMER_ALWAYS_ENABLED, dev); + timer_add(&dev->timer, hercules_poll, dev, 1); mem_mapping_add(&dev->mapping, 0xb0000, 0x08000, hercules_read,NULL,NULL, hercules_write,NULL,NULL, diff --git a/src/video/vid_herculesplus.c b/src/video/vid_herculesplus.c index d3ea2efda..2a4497bce 100644 --- a/src/video/vid_herculesplus.c +++ b/src/video/vid_herculesplus.c @@ -24,10 +24,10 @@ #include "../86box.h" #include "../io.h" #include "../lpt.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_herculesplus.h" @@ -71,8 +71,8 @@ typedef struct { uint8_t ctrl, ctrl2, stat; - int64_t dispontime, dispofftime; - int64_t vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; @@ -81,7 +81,7 @@ typedef struct { uint16_t ma, maback; int con, coff, cursoron; int dispon, blink; - int64_t vsynctime; + int vsynctime; int vadj; int cols[256][2][2]; @@ -101,11 +101,11 @@ recalc_timings(herculesplus_t *dev) disptime = dev->crtc[0] + 1; _dispontime = dev->crtc[1]; _dispofftime = disptime - _dispontime; - _dispontime *= MDACONST; - _dispofftime *= MDACONST; + _dispontime *= HERCCONST; + _dispofftime *= HERCCONST; - dev->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - dev->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + dev->dispontime = (uint64_t)(_dispontime); + dev->dispofftime = (uint64_t)(_dispofftime); } @@ -257,7 +257,7 @@ draw_char_rom(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) } for (i = 0; i < cw; i++) { - buffer->line[dev->displine][x * cw + i] = (val & 0x100) ? ifg : ibg; + buffer32->line[dev->displine][x * cw + i] = (val & 0x100) ? ifg : ibg; val = val << 1; } } @@ -320,7 +320,7 @@ draw_char_ram4(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) if ((attr & 0x77) == 0) cfg = ibg; /* 'blank' attribute */ - buffer->line[dev->displine][x * cw + i] = dev->cols[attr][blink][cfg]; + buffer32->line[dev->displine][x * cw + i] = dev->cols[attr][blink][cfg]; val = val << 1; } } @@ -405,7 +405,7 @@ draw_char_ram48(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) else cfg |= ibg; - buffer->line[dev->displine][(x * cw) + i] = dev->cols[attr][blink][cfg]; + buffer32->line[dev->displine][(x * cw) + i] = dev->cols[attr][blink][cfg]; val = val << 1; } } @@ -449,7 +449,7 @@ text_line(herculesplus_t *dev, uint16_t ca) col = dev->cols[attr][0][1]; for (c = 0; c < cw; c++) - buffer->line[dev->displine][x * cw + c] = col; + buffer32->line[dev->displine][x * cw + c] = col; } } } @@ -478,7 +478,7 @@ graphics_line(herculesplus_t *dev) for (c = 0; c < 16; c++) { val >>= 1; - buffer->line[dev->displine][(x << 4) + c] = (val & 1) ? 7 : 0; + buffer32->line[dev->displine][(x << 4) + c] = (val & 1) ? 7 : 0; } for (c = 0; c < 16; c += 8) @@ -495,7 +495,7 @@ herculesplus_poll(void *priv) int x, oldvc, oldsc; if (! dev->linepos) { - dev->vidtime += dev->dispofftime; + timer_advance_u64(&dev->timer, dev->dispofftime); dev->stat |= 1; dev->linepos = 1; oldsc = dev->sc; @@ -519,7 +519,7 @@ herculesplus_poll(void *priv) if (dev->displine >= 500) dev->displine = 0; } else { - dev->vidtime += dev->dispontime; + timer_advance_u64(&dev->timer, dev->dispontime); if (dev->dispon) dev->stat &= ~1; dev->linepos = 0; @@ -621,7 +621,7 @@ herculesplus_init(const device_t *info) dev->vram = (uint8_t *)malloc(0x10000); /* 64k VRAM */ - timer_add(herculesplus_poll, &dev->vidtime, TIMER_ALWAYS_ENABLED, dev); + timer_add(&dev->timer, herculesplus_poll, dev, 1); mem_mapping_add(&dev->mapping, 0xb0000, 0x10000, herculesplus_read,NULL,NULL, diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c new file mode 100644 index 000000000..f7866dfee --- /dev/null +++ b/src/video/vid_ht216.c @@ -0,0 +1,1232 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Video 7 VGA 1024i emulation. + * + * Version: @(#)vid_ht216.c 1.0.0 2019/04/05 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2019 Sarah Walker. + * Copyright 2019 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../pic.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_ht216.h" + + +typedef struct ht216_t +{ + svga_t svga; + + mem_mapping_t linear_mapping; + + rom_t bios_rom; + + uint32_t vram_mask; + + int ext_reg_enable; + int clk_sel; + + uint8_t read_bank_reg[2], write_bank_reg[2]; + uint32_t read_bank[2], write_bank[2]; + uint8_t misc, pad; + uint16_t id; + + uint8_t bg_latch[8]; + + uint8_t ht_regs[256]; +} ht216_t; + + +#define HT_MISC_PAGE_SEL (1 << 5) + +/*Shifts CPU VRAM read address by 3 bits, for use with fat pixel colour expansion*/ +#define HT_REG_C8_MOVSB (1 << 0) +#define HT_REG_C8_E256 (1 << 4) +#define HT_REG_C8_XLAM (1 << 6) + +#define HT_REG_CD_FP8PCEXP (1 << 1) +#define HT_REG_CD_BMSKSL (3 << 2) +#define HT_REG_CD_RMWMDE (1 << 5) +/*Use GDC data rotate as offset when reading VRAM data into latches*/ +#define HT_REG_CD_ASTODE (1 << 6) +#define HT_REG_CD_EXALU (1 << 7) + +#define HT_REG_E0_SBAE (1 << 7) + +#define HT_REG_F9_XPSEL (1 << 0) + +/*Enables A[14:15] of VRAM address in chain-4 modes*/ +#define HT_REG_FC_ECOLRE (1 << 2) + +#define HT_REG_FE_FBRC (1 << 1) +#define HT_REG_FE_FBMC (3 << 2) +#define HT_REG_FE_FBRSL (3 << 4) + + +void ht216_remap(ht216_t *ht216); + +void ht216_out(uint16_t addr, uint8_t val, void *p); +uint8_t ht216_in(uint16_t addr, void *p); + + +#define BIOS_G2_GC205_PATH L"roms/video/video7/BIOS.BIN" +#define BIOS_VIDEO7_VGA_1024I_PATH L"roms/video/video7/Video Seven VGA 1024i - BIOS - v2.19 - 435-0062-05 - U17 - 27C256.BIN" +#define BIOS_HT216_32_PATH L"roms/video/video7/ht216-32.bin" + +static video_timings_t timing_v7vga = {VIDEO_ISA, 5, 5, 9, 20, 20, 30}; + + +#ifdef ENABLE_HT216_LOG +int ht216_do_log = ENABLE_HT216_LOG; + + +static void +ht216_log(const char *fmt, ...) +{ + va_list ap; + + if (ht216_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define ht216_log(fmt, ...) +#endif + + +void +ht216_out(uint16_t addr, uint8_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + uint8_t old; + + ht216_log("ht216 %i out %04X %02X %04X:%04X\n", svga->miscout & 1, addr, val, CS, cpu_state.pc); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c2: + ht216->clk_sel = (ht216->clk_sel & ~3) | ((val & 0x0c) >> 2); + ht216->misc = val; + ht216->read_bank_reg[0] = (ht216->read_bank_reg[0] & ~0x20) | ((val & HT_MISC_PAGE_SEL) ? 0x20 : 0); + ht216->write_bank_reg[0] = (ht216->write_bank_reg[0] & ~0x20) | ((val & HT_MISC_PAGE_SEL) ? 0x20 : 0); + ht216_remap(ht216); + svga_recalctimings(&ht216->svga); + break; + + case 0x3c5: + if (svga->seqaddr == 4) { + svga->chain4 = val & 8; + ht216_remap(ht216); + } else if (svga->seqaddr == 6) { + if (val == 0xea) + ht216->ext_reg_enable = 1; + else if (val == 0xae) + ht216->ext_reg_enable = 0; + } else if (svga->seqaddr >= 0x80 && ht216->ext_reg_enable) { + old = ht216->ht_regs[svga->seqaddr & 0xff]; + ht216->ht_regs[svga->seqaddr & 0xff] = val; + switch (svga->seqaddr & 0xff) { + case 0x83: + svga->attraddr = val & 0x1f; + svga->attrff = (val & 0x80) ? 1 : 0; + break; + + case 0x94: + svga->hwcursor.addr = ((val << 6) | (3 << 14) | ((ht216->ht_regs[0xff] & 0x60) << 11)) << 2; + break; + case 0x9c: case 0x9d: + svga->hwcursor.x = ht216->ht_regs[0x9d] | ((ht216->ht_regs[0x9c] & 7) << 8); + break; + case 0x9e: case 0x9f: + svga->hwcursor.y = ht216->ht_regs[0x9f] | ((ht216->ht_regs[0x9e] & 3) << 8); + break; + + case 0xa0: + svga->latch = (svga->latch & 0xffffff00) | val; + break; + case 0xa1: + svga->latch = (svga->latch & 0xffff00ff) | (val << 8); + break; + case 0xa2: + svga->latch = (svga->latch & 0xff00ffff) | (val << 16); + break; + case 0xa3: + svga->latch = (svga->latch & 0x00ffffff) | (val << 24); + break; + case 0xa4: + ht216->clk_sel = (val >> 2) & 0xf; + svga->miscout = (svga->miscout & ~0xc) | ((ht216->clk_sel & 3) << 2); + break; + case 0xa5: + svga->hwcursor.ena = val & 0x80; + break; + + case 0xc8: + if ((old ^ val) & 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + break; + + case 0xe8: + ht216->read_bank_reg[0] = val; + ht216->write_bank_reg[0] = val; + break; + case 0xe9: + ht216->read_bank_reg[1] = val; + ht216->write_bank_reg[1] = val; + break; + case 0xf6: + svga->vram_display_mask = (val & 0x40) ? ht216->vram_mask : 0x3ffff; + ht216->read_bank_reg[0] = (ht216->read_bank_reg[0] & ~0xc0) | ((val & 0xc) << 4); + ht216->write_bank_reg[0] = (ht216->write_bank_reg[0] & ~0xc0) | ((val & 0x3) << 6); + break; + case 0xf9: + ht216->read_bank_reg[0] = (ht216->read_bank_reg[0] & ~0x10) | ((val & 1) ? 0x10 : 0); + ht216->write_bank_reg[0] = (ht216->write_bank_reg[0] & ~0x10) | ((val & 1) ? 0x10 : 0); + break; + case 0xff: + svga->hwcursor.addr = ((ht216->ht_regs[0x94] << 6) | (3 << 14) | ((val & 0x60) << 11)) << 2; + break; + } + switch (svga->seqaddr & 0xff) { + case 0xa4: case 0xf6: case 0xfc: + svga->fullchange = changeframecount; + svga_recalctimings(&ht216->svga); + break; + } + switch (svga->seqaddr & 0xff) { + case 0xc8: case 0xc9: case 0xcf: + case 0xe0: case 0xe8: case 0xe9: + case 0xf6: case 0xf9: + ht216_remap(ht216); + break; + } + return; + } + break; + + case 0x3cf: + if (svga->gdcaddr == 6) { + if (val & 8) + svga->banked_mask = 0x7fff; + else + svga->banked_mask = 0xffff; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(&ht216->svga); + } + } + break; + + case 0x46e8: + io_removehandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + mem_mapping_disable(&ht216->svga.mapping); + mem_mapping_disable(&ht216->linear_mapping); + if (val & 8) { + io_sethandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + mem_mapping_enable(&ht216->svga.mapping); + ht216_remap(ht216); + } + break; + } + + svga_out(addr, val, svga); +} + + +uint8_t +ht216_in(uint16_t addr, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c2: + break; + + case 0x3c5: + if (svga->seqaddr == 6) + return ht216->ext_reg_enable; + if (svga->seqaddr >= 0x80) { + if (ht216->ext_reg_enable) { + switch (svga->seqaddr & 0xff) { + case 0x83: + if (svga->attrff) + return svga->attraddr | 0x80; + return svga->attraddr; + + case 0x8e: return ht216->id & 0xff; + case 0x8f: return (ht216->id >> 8) & 0xff; + + case 0xa0: + return svga->latch & 0xff; + case 0xa1: + return (svga->latch >> 8) & 0xff; + case 0xa2: + return (svga->latch >> 16) & 0xff; + case 0xa3: + return (svga->latch >> 24) & 0xff; + +#if 0 + case 0xf7: + return 0x01; + case 0xff: + return 0x80; +#endif + } + return ht216->ht_regs[svga->seqaddr & 0xff]; + } else + return 0xff; + } + break; + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if (svga->crtcreg == 0x1f) + return svga->crtc[0xc] ^ 0xea; + return svga->crtc[svga->crtcreg]; + } + + return svga_in(addr, svga); +} + + +void +ht216_remap(ht216_t *ht216) +{ + svga_t *svga = &ht216->svga; + + mem_mapping_disable(&ht216->linear_mapping); + if (ht216->ht_regs[0xc8] & HT_REG_C8_XLAM) { + uint32_t linear_base = ((ht216->ht_regs[0xc9] & 0xf) << 20) | (ht216->ht_regs[0xcf] << 24); + + mem_mapping_set_addr(&ht216->linear_mapping, linear_base, 0x100000); + + /*Linear mapping enabled*/ + } else { + uint8_t read_bank_reg[2] = {ht216->read_bank_reg[0], ht216->read_bank_reg[1]}; + uint8_t write_bank_reg[2] = {ht216->write_bank_reg[0], ht216->write_bank_reg[1]}; + + if (!svga->chain4 || !(ht216->ht_regs[0xfc] & HT_REG_FC_ECOLRE)) { + read_bank_reg[0] &= ~0x30; + read_bank_reg[1] &= ~0x30; + write_bank_reg[0] &= ~0x30; + write_bank_reg[1] &= ~0x30; + } + + ht216->read_bank[0] = read_bank_reg[0] << 12; + ht216->write_bank[0] = write_bank_reg[0] << 12; + if (ht216->ht_regs[0xe0] & HT_REG_E0_SBAE) { + /*Split bank*/ + ht216->read_bank[1] = read_bank_reg[1] << 12; + ht216->write_bank[1] = write_bank_reg[1] << 12; + } else { + ht216->read_bank[1] = ht216->read_bank[0] + (svga->chain4 ? 0x8000 : 0x20000); + ht216->write_bank[1] = ht216->write_bank[0] + (svga->chain4 ? 0x8000 : 0x20000); + } + + if (!svga->chain4) { + ht216->read_bank[0] >>= 2; + ht216->read_bank[1] >>= 2; + ht216->write_bank[0] >>= 2; + ht216->write_bank[1] >>= 2; + } + } +} + + +void +ht216_recalctimings(svga_t *svga) +{ + ht216_t *ht216 = (ht216_t *)svga->p; + + switch (ht216->clk_sel) { + case 5: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; + case 6: svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break; + case 10: svga->clock = (cpuclock * (double)(1ull << 32)) / 80000000.0; break; + } + svga->lowres = !(ht216->ht_regs[0xc8] & HT_REG_C8_E256); + svga->ma_latch |= ((ht216->ht_regs[0xf6] & 0x30) << 12); + svga->interlace = ht216->ht_regs[0xe0] & 1; + + if ((svga->bpp == 8) && !svga->lowres) + svga->render = svga_render_8bpp_highres; +} + + +static void +ht216_hwcursor_draw(svga_t *svga, int displine) +{ + int x; + uint32_t dat[2]; + int offset = svga->hwcursor_latch.x + 32; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 4; + + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 24) | + (svga->vram[svga->hwcursor_latch.addr+1] << 16) | + (svga->vram[svga->hwcursor_latch.addr+2] << 8) | + svga->vram[svga->hwcursor_latch.addr+3]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr+128] << 24) | + (svga->vram[svga->hwcursor_latch.addr+128+1] << 16) | + (svga->vram[svga->hwcursor_latch.addr+128+2] << 8) | + svga->vram[svga->hwcursor_latch.addr+128+3]; + + for (x = 0; x < 32; x++) { + if (!(dat[0] & 0x80000000)) + ((uint32_t *)buffer32->line[displine])[offset + x] = 0; + if (dat[1] & 0x80000000) + ((uint32_t *)buffer32->line[displine])[offset + x] ^= 0xffffff; + + dat[0] <<= 1; + dat[1] <<= 1; + } + + svga->hwcursor_latch.addr += 4; + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 4; +} + + +static __inline uint8_t +extalu(int op, uint8_t input_a, uint8_t input_b) +{ + uint8_t val; + + switch (op) { + case 0x0: val = 0; break; + case 0x1: val = ~(input_a | input_b); break; + case 0x2: val = input_a & ~input_b; break; + case 0x3: val = ~input_b; break; + case 0x4: val = ~input_a & input_b; break; + case 0x5: val = ~input_a; break; + case 0x6: val = input_a ^ input_b; break; + case 0x7: val = ~(input_a & input_b); break; + case 0x8: val = input_a & input_b; break; + case 0x9: val = ~(input_a ^ input_b); break; + case 0xa: val = input_a; break; + case 0xb: val = input_a | ~input_b; break; + case 0xc: val = input_b; break; + case 0xd: val = ~input_a | input_b; break; + case 0xe: val = input_a | input_b; break; + case 0xf: default: val = 0xff; break; + } + + return val; +} + + +static void +ht216_dm_write(ht216_t *ht216, uint32_t addr, uint8_t cpu_dat, uint8_t cpu_dat_unexpanded) +{ + svga_t *svga = &ht216->svga; + uint8_t vala, valb, valc, vald, wm = svga->writemask; + int writemask2 = svga->writemask; + uint8_t fg_data[4] = {0, 0, 0, 0}; + + if (!(svga->gdcreg[6] & 1)) + svga->fullchange = 2; + if (svga->chain4 || svga->fb_only) { + writemask2=1<<(addr&3); + addr&=~3; + } else if (svga->chain2_write) { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + addr <<= 2; + } else + addr<<=2; + if (addr >= svga->vram_max) + return; + + svga->changedvram[addr >> 12]=changeframecount; + + switch (ht216->ht_regs[0xfe] & HT_REG_FE_FBMC) { + case 0x00: + fg_data[0] = fg_data[1] = fg_data[2] = fg_data[3] = cpu_dat; + break; + case 0x04: + if (ht216->ht_regs[0xfe] & HT_REG_FE_FBRC) { + if (addr & 4) { + fg_data[0] = (cpu_dat_unexpanded & (1 << (((addr + 4) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[1] = (cpu_dat_unexpanded & (1 << (((addr + 5) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[2] = (cpu_dat_unexpanded & (1 << (((addr + 6) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[3] = (cpu_dat_unexpanded & (1 << (((addr + 7) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + } else { + fg_data[0] = (cpu_dat_unexpanded & (1 << (((addr + 0) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[1] = (cpu_dat_unexpanded & (1 << (((addr + 1) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[2] = (cpu_dat_unexpanded & (1 << (((addr + 2) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[3] = (cpu_dat_unexpanded & (1 << (((addr + 3) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + } + } else { + if (addr & 4) { + fg_data[0] = (ht216->ht_regs[0xf5] & (1 << (((addr + 4) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[1] = (ht216->ht_regs[0xf5] & (1 << (((addr + 5) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[2] = (ht216->ht_regs[0xf5] & (1 << (((addr + 6) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[3] = (ht216->ht_regs[0xf5] & (1 << (((addr + 7) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + } else { + fg_data[0] = (ht216->ht_regs[0xf5] & (1 << (((addr + 0) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[1] = (ht216->ht_regs[0xf5] & (1 << (((addr + 1) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[2] = (ht216->ht_regs[0xf5] & (1 << (((addr + 2) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[3] = (ht216->ht_regs[0xf5] & (1 << (((addr + 3) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + } + } + break; + case 0x08: + fg_data[0] = ht216->ht_regs[0xec]; + fg_data[1] = ht216->ht_regs[0xed]; + fg_data[2] = ht216->ht_regs[0xee]; + fg_data[3] = ht216->ht_regs[0xef]; + break; + case 0x0c: + fg_data[0] = ht216->ht_regs[0xec]; + fg_data[1] = ht216->ht_regs[0xed]; + fg_data[2] = ht216->ht_regs[0xee]; + fg_data[3] = ht216->ht_regs[0xef]; + break; + } + + switch (svga->writemode) { + case 1: + if (writemask2 & 1) svga->vram[addr] = svga->latch & 0xff; + if (writemask2 & 2) svga->vram[addr | 0x1] = (svga->latch >> 8) & 0xff; + if (writemask2 & 4) svga->vram[addr | 0x2] = (svga->latch >> 16) & 0xff; + if (writemask2 & 8) svga->vram[addr | 0x3] = (svga->latch >> 24) & 0xff; + break; + case 0: + if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + (!svga->gdcreg[1] || svga->set_reset_disabled)) { + if (writemask2 & 1) svga->vram[addr] = fg_data[0]; + if (writemask2 & 2) svga->vram[addr | 0x1] = fg_data[1]; + if (writemask2 & 4) svga->vram[addr | 0x2] = fg_data[2]; + if (writemask2 & 8) svga->vram[addr | 0x3] = fg_data[3]; + } else { + if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + else vala = fg_data[0]; + if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + else valb = fg_data[1]; + if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + else valc = fg_data[2]; + if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + else vald = fg_data[3]; + + switch (svga->gdcreg[3] & 0x18) { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | ((svga->latch & 0xff) & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (((svga->latch >> 8) & 0xff) & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (((svga->latch >> 16) & 0xff) & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (((svga->latch >> 24) & 0xff) & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & (svga->latch & 0xff); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & ((svga->latch >> 8) & 0xff); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & ((svga->latch >> 16) & 0xff); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & ((svga->latch >> 24) & 0xff); + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->latch & 0xff); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | ((svga->latch >> 8) & 0xff); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | ((svga->latch >> 16) & 0xff); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | ((svga->latch >> 24) & 0xff); + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ (svga->latch & 0xff); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ ((svga->latch >> 8) & 0xff); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ ((svga->latch >> 16) & 0xff); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ ((svga->latch >> 24) & 0xff); + break; + } + } + break; + case 2: + if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { + if (writemask2 & 1) svga->vram[addr] = (((cpu_dat & 1) ? 0xff : 0) & svga->gdcreg[8]) | ((svga->latch & 0xff) & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (((cpu_dat & 2) ? 0xff : 0) & svga->gdcreg[8]) | (((svga->latch >> 8) & 0xff) & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (((cpu_dat & 4) ? 0xff : 0) & svga->gdcreg[8]) | (((svga->latch >> 16) & 0xff) & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (((cpu_dat & 8) ? 0xff : 0) & svga->gdcreg[8]) | (((svga->latch >> 24) & 0xff) & ~svga->gdcreg[8]); + } else { + vala = ((cpu_dat & 1) ? 0xff : 0); + valb = ((cpu_dat & 2) ? 0xff : 0); + valc = ((cpu_dat & 4) ? 0xff : 0); + vald = ((cpu_dat & 8) ? 0xff : 0); + switch (svga->gdcreg[3] & 0x18) { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | ((svga->latch & 0xff) & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (((svga->latch >> 8) & 0xff) & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (((svga->latch >> 16) & 0xff) & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (((svga->latch >> 24) & 0xff) & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & (svga->latch & 0xff); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & ((svga->latch >> 8) & 0xff); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & ((svga->latch >> 16) & 0xff); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & ((svga->latch >> 24) & 0xff); + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->latch & 0xff); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | ((svga->latch >> 8) & 0xff); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | ((svga->latch >> 16) & 0xff); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | ((svga->latch >> 24) & 0xff); + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ (svga->latch & 0xff); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ ((svga->latch >> 8) & 0xff); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ ((svga->latch >> 16) & 0xff); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ ((svga->latch >> 24) & 0xff); + break; + } + } + break; + case 3: + wm = svga->gdcreg[8]; + svga->gdcreg[8] &= cpu_dat; + + vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + switch (svga->gdcreg[3] & 0x18) { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | ((svga->latch & 0xff) & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (((svga->latch >> 8) & 0xff) & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (((svga->latch >> 16) & 0xff) & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (((svga->latch >> 24) & 0xff) & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & (svga->latch & 0xff); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & ((svga->latch >> 8) & 0xff); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & ((svga->latch >> 16) & 0xff); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & ((svga->latch >> 24) & 0xff); + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->latch & 0xff); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | ((svga->latch >> 8) & 0xff); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | ((svga->latch >> 16) & 0xff); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | ((svga->latch >> 24) & 0xff); + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ (svga->latch & 0xff); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ ((svga->latch >> 8) & 0xff); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ ((svga->latch >> 16) & 0xff); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ ((svga->latch >> 24) & 0xff); + break; + } + svga->gdcreg[8] = wm; + break; + } +} + + +static void +ht216_dm_extalu_write(ht216_t *ht216, uint32_t addr, uint8_t cpu_dat, uint8_t bit_mask, uint8_t cpu_dat_unexpanded, uint8_t rop_select) +{ + /*Input B = CD.5 + Input A = FE[3:2] + 00 = Set/Reset output mode + output = CPU-side ALU input + 01 = Solid fg/bg mode (3C4:FA/FB) + Bit mask = 3CF.F5 or CPU byte + 10 = Dithered fg (3CF:EC-EF) + 11 = RMW (dest data) (set if CD.5 = 1) + F/B ROP select = FE[5:4] + 00 = CPU byte + 01 = Bit mask (3CF:8) + 1x = (3C4:F5)*/ + svga_t *svga = &ht216->svga; + uint8_t input_a = 0, input_b = 0; + uint8_t fg, bg; + uint8_t output; + + if (ht216->ht_regs[0xcd] & HT_REG_CD_RMWMDE) /*RMW*/ + input_b = svga->vram[addr]; + else + input_b = ht216->bg_latch[addr & 7]; + + switch (ht216->ht_regs[0xfe] & HT_REG_FE_FBMC) { + case 0x00: + input_a = cpu_dat; + break; + case 0x04: + if (ht216->ht_regs[0xfe] & HT_REG_FE_FBRC) + input_a = (cpu_dat_unexpanded & (1 << ((addr & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + else + input_a = (ht216->ht_regs[0xf5] & (1 << ((addr & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + break; + case 0x08: + input_a = ht216->ht_regs[0xec + (addr & 3)]; + break; + case 0x0c: + input_a = ht216->bg_latch[addr & 7]; + break; + } + + fg = extalu(ht216->ht_regs[0xce] >> 4, input_a, input_b); + bg = extalu(ht216->ht_regs[0xce] & 0xf, input_a, input_b); + output = (fg & rop_select) | (bg & ~rop_select); + svga->vram[addr] = (svga->vram[addr] & ~bit_mask) | (output & bit_mask); + svga->changedvram[addr >> 12] = changeframecount; +} + + +static void +ht216_write_common(ht216_t *ht216, uint32_t addr, uint8_t val) +{ + /*Input B = CD.5 + Input A = FE[3:2] + 00 = Set/Reset output mode + output = CPU-side ALU input + 01 = Solid fg/bg mode (3C4:FA/FB) + Bit mask = 3CF.F5 or CPU byte + 10 = Dithered fg (3CF:EC-EF) + 11 = RMW (dest data) (set if CD.5 = 1) + F/B ROP select = FE[5:4] + 00 = CPU byte + 01 = Bit mask (3CF:8) + 1x = (3C4:F5) + */ + svga_t *svga = &ht216->svga; + uint8_t bit_mask = 0, rop_select = 0; + + sub_cycles(video_timing_write_b); + + egawrites++; + + addr &= 0xfffff; + + val = svga_rotate[svga->gdcreg[3] & 7][val]; + + if (ht216->ht_regs[0xcd] & HT_REG_CD_EXALU) { + /*Extended ALU*/ + switch (ht216->ht_regs[0xfe] & HT_REG_FE_FBRSL) { + case 0x00: + rop_select = val; + break; + case 0x10: + rop_select = svga->gdcreg[8]; + break; + case 0x20: case 0x30: + rop_select = ht216->ht_regs[0xf5]; + break; + } + switch (ht216->ht_regs[0xcd] & HT_REG_CD_BMSKSL) { + case 0x00: + bit_mask = svga->gdcreg[8]; + break; + case 0x04: + bit_mask = val; + break; + case 0x08: case 0x0c: + bit_mask = ht216->ht_regs[0xf5]; + break; + } + + if (ht216->ht_regs[0xcd] & HT_REG_CD_FP8PCEXP) { /*1->8 bit expansion*/ + addr = (addr << 3) & 0xfffff; + ht216_dm_extalu_write(ht216, addr, (val & 0x80) ? 0xff : 0, (bit_mask & 0x80) ? 0xff : 0, val, (rop_select & 0x80) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 1, (val & 0x40) ? 0xff : 0, (bit_mask & 0x40) ? 0xff : 0, val, (rop_select & 0x40) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 2, (val & 0x20) ? 0xff : 0, (bit_mask & 0x20) ? 0xff : 0, val, (rop_select & 0x20) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 3, (val & 0x10) ? 0xff : 0, (bit_mask & 0x10) ? 0xff : 0, val, (rop_select & 0x10) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 4, (val & 0x08) ? 0xff : 0, (bit_mask & 0x08) ? 0xff : 0, val, (rop_select & 0x08) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 5, (val & 0x04) ? 0xff : 0, (bit_mask & 0x04) ? 0xff : 0, val, (rop_select & 0x04) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 6, (val & 0x02) ? 0xff : 0, (bit_mask & 0x02) ? 0xff : 0, val, (rop_select & 0x02) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 7, (val & 0x01) ? 0xff : 0, (bit_mask & 0x01) ? 0xff : 0, val, (rop_select & 0x01) ? 0xff : 0); + } else + ht216_dm_extalu_write(ht216, addr, val, bit_mask, val, rop_select); + } else { + if (ht216->ht_regs[0xcd] & HT_REG_CD_FP8PCEXP) { /*1->8 bit expansion*/ + addr = (addr << 3) & 0xfffff; + ht216_dm_write(ht216, addr, (val & 0x80) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 1, (val & 0x40) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 2, (val & 0x20) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 3, (val & 0x10) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 4, (val & 0x08) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 5, (val & 0x04) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 6, (val & 0x02) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 7, (val & 0x01) ? 0xff : 0, val); + } else + ht216_dm_write(ht216, addr, val, val); + } +} + + +static void +ht216_write(uint32_t addr, uint8_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + ht216->write_bank[(addr >> 15) & 1]; + + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) + svga_write_linear(addr, val, &ht216->svga); + else + ht216_write_common(ht216, addr, val); +} + + +static void +ht216_writew(uint32_t addr, uint16_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + ht216->write_bank[(addr >> 15) & 1]; + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) + svga_writew_linear(addr, val, &ht216->svga); + else { + ht216_write_common(ht216, addr, val); + ht216_write_common(ht216, addr+1, val >> 8); + } +} + + +static void +ht216_writel(uint32_t addr, uint32_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + ht216->write_bank[(addr >> 15) & 1]; + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) + svga_writel_linear(addr, val, &ht216->svga); + else { + ht216_write_common(ht216, addr, val); + ht216_write_common(ht216, addr+1, val >> 8); + ht216_write_common(ht216, addr+2, val >> 16); + ht216_write_common(ht216, addr+3, val >> 24); + } +} + + +static void +ht216_write_linear(uint32_t addr, uint8_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + if (!svga->chain4) /*Bits 16 and 17 of linear address seem to be unused in planar modes*/ + addr = (addr & 0xffff) | ((addr & 0xc0000) >> 2); + + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) + svga_write_linear(addr, val, &ht216->svga); + else + ht216_write_common(ht216, addr, val); +} + + +static void +ht216_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + if (!svga->chain4) + addr = (addr & 0xffff) | ((addr & 0xc0000) >> 2); + + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) + svga_writew_linear(addr, val, &ht216->svga); + else { + ht216_write_common(ht216, addr, val); + ht216_write_common(ht216, addr+1, val >> 8); + } +} + + +static void +ht216_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + if (!svga->chain4) + addr = (addr & 0xffff) | ((addr & 0xc0000) >> 2); + + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) + svga_writel_linear(addr, val, &ht216->svga); + else { + ht216_write_common(ht216, addr, val); + ht216_write_common(ht216, addr+1, val >> 8); + ht216_write_common(ht216, addr+2, val >> 16); + ht216_write_common(ht216, addr+3, val >> 24); + } +} + + +static uint8_t +ht216_read_common(ht216_t *ht216, uint32_t addr) +{ + svga_t *svga = &ht216->svga; + uint8_t temp, temp2, temp3, temp4, or; + int readplane = svga->readplane; + int offset; + uint32_t latch_addr; + + if (ht216->ht_regs[0xc8] & HT_REG_C8_MOVSB) + addr <<= 3; + + addr &= 0xfffff; + + sub_cycles(video_timing_read_b); + + egareads++; + + if (svga->chain4 || svga->fb_only) { + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + + latch_addr = (addr & svga->vram_mask) & ~7; + if (ht216->ht_regs[0xcd] & HT_REG_CD_ASTODE) + latch_addr += (svga->gdcreg[3] & 7); + ht216->bg_latch[0] = svga->vram[latch_addr]; + ht216->bg_latch[1] = svga->vram[latch_addr + 1]; + ht216->bg_latch[2] = svga->vram[latch_addr + 2]; + ht216->bg_latch[3] = svga->vram[latch_addr + 3]; + ht216->bg_latch[4] = svga->vram[latch_addr + 4]; + ht216->bg_latch[5] = svga->vram[latch_addr + 5]; + ht216->bg_latch[6] = svga->vram[latch_addr + 6]; + ht216->bg_latch[7] = svga->vram[latch_addr + 7]; + + return svga->vram[addr & svga->vram_mask]; + } else if (svga->chain2_read) { + readplane = (readplane & 2) | (addr & 1); + addr &= ~1; + addr <<= 2; + } else + addr <<= 2; + + addr &= svga->decode_mask; + + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + + latch_addr = addr & ~7; + if (ht216->ht_regs[0xcd] & HT_REG_CD_ASTODE) { + offset = addr & 7; + + ht216->bg_latch[0] = svga->vram[latch_addr | offset]; + ht216->bg_latch[1] = svga->vram[latch_addr | ((offset + 1) & 7)]; + ht216->bg_latch[2] = svga->vram[latch_addr | ((offset + 2) & 7)]; + ht216->bg_latch[3] = svga->vram[latch_addr | ((offset + 3) & 7)]; + ht216->bg_latch[4] = svga->vram[latch_addr | ((offset + 4) & 7)]; + ht216->bg_latch[5] = svga->vram[latch_addr | ((offset + 5) & 7)]; + ht216->bg_latch[6] = svga->vram[latch_addr | ((offset + 6) & 7)]; + ht216->bg_latch[7] = svga->vram[latch_addr | ((offset + 7) & 7)]; + } else { + ht216->bg_latch[0] = svga->vram[latch_addr]; + ht216->bg_latch[1] = svga->vram[latch_addr | 1]; + ht216->bg_latch[2] = svga->vram[latch_addr | 2]; + ht216->bg_latch[3] = svga->vram[latch_addr | 3]; + ht216->bg_latch[4] = svga->vram[latch_addr | 4]; + ht216->bg_latch[5] = svga->vram[latch_addr | 5]; + ht216->bg_latch[6] = svga->vram[latch_addr | 6]; + ht216->bg_latch[7] = svga->vram[latch_addr | 7]; + } + or = addr & 4; + svga->latch = ht216->bg_latch[0 | or] | (ht216->bg_latch[1 | or] << 8) | + (ht216->bg_latch[2 | or] << 16) | (ht216->bg_latch[3 | or] << 24); + if (svga->readmode) { + temp = svga->latch & 0xff; + temp ^= (svga->colourcompare & 1) ? 0xff : 0; + temp &= (svga->colournocare & 1) ? 0xff : 0; + temp2 = (svga->latch >> 8) & 0xff; + temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; + temp2 &= (svga->colournocare & 2) ? 0xff : 0; + temp3 = (svga->latch >> 16) & 0xff; + temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; + temp3 &= (svga->colournocare & 4) ? 0xff : 0; + temp4 = (svga->latch >> 24) & 0xff; + temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; + temp4 &= (svga->colournocare & 8) ? 0xff : 0; + return ~(temp | temp2 | temp3 | temp4); + } + + return svga->vram[addr | readplane]; +} + + +static uint8_t +ht216_read(uint32_t addr, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + ht216->read_bank[(addr >> 15) & 1]; + + return ht216_read_common(ht216, addr); +} + + +static uint8_t +ht216_read_linear(uint32_t addr, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + if (svga->chain4) + return ht216_read_common(ht216, addr); + else + return ht216_read_common(ht216, (addr & 0xffff) | ((addr & 0xc0000) >> 2)); +} + + +void +*ht216_init(const device_t *info, uint32_t mem_size, int has_rom) +{ + ht216_t *ht216 = malloc(sizeof(ht216_t)); + svga_t *svga; + + memset(ht216, 0, sizeof(ht216_t)); + svga = &ht216->svga; + + io_sethandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + io_sethandler(0x46e8, 0x0001, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + + if (has_rom == 1) + rom_init(&ht216->bios_rom, BIOS_VIDEO7_VGA_1024I_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + else if (has_rom == 2) + rom_init(&ht216->bios_rom, BIOS_G2_GC205_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + else if (has_rom == 3) + rom_init(&ht216->bios_rom, BIOS_HT216_32_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_v7vga); + + svga_init(&ht216->svga, ht216, mem_size, + ht216_recalctimings, + ht216_in, ht216_out, + ht216_hwcursor_draw, + NULL); + svga->hwcursor.ysize = 32; + ht216->vram_mask = mem_size - 1; + svga->decode_mask = mem_size - 1; + + mem_mapping_set_handler(&ht216->svga.mapping, ht216_read, NULL, NULL, ht216_write, ht216_writew, ht216_writel); + mem_mapping_set_p(&ht216->svga.mapping, ht216); + mem_mapping_add(&ht216->linear_mapping, 0, 0, ht216_read_linear, NULL, NULL, ht216_write_linear, ht216_writew_linear, ht216_writel_linear, NULL, 0, &ht216->svga); + + svga->bpp = 8; + svga->miscout = 1; + + ht216->ht_regs[0xb4] = 0x08; /*32-bit DRAM bus*/ + ht216->id = info->local; + + return ht216; +} + + +static void * +g2_gc205_init(const device_t *info) +{ + ht216_t *ht216 = ht216_init(info, 1 << 19, 2); + + return ht216; +} + + +static void * +v7_vga_1024i_init(const device_t *info) +{ + ht216_t *ht216 = ht216_init(info, device_get_config_int("memory") << 10, 1); + + return ht216; +} + + +static void * +ht216_pb410a_init(const device_t *info) +{ + ht216_t *ht216 = ht216_init(info, 1 << 20, 0); + + return ht216; +} + + +static void * +ht216_32_init(const device_t *info) +{ + ht216_t *ht216 = ht216_init(info, device_get_config_int("memory") << 10, 3); + + return ht216; +} + + +static int +g2_gc205_available(void) +{ + return rom_present(BIOS_G2_GC205_PATH); +} + + +static int +v7_vga_1024i_available(void) +{ + return rom_present(BIOS_VIDEO7_VGA_1024I_PATH); +} + + +static int +ht216_32_available(void) +{ + return rom_present(BIOS_HT216_32_PATH); +} + + +void +ht216_close(void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + + svga_close(&ht216->svga); + + free(ht216); +} + + +void +ht216_speed_changed(void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + + svga_recalctimings(&ht216->svga); +} + + +void +ht216_force_redraw(void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + + ht216->svga.fullchange = changeframecount; +} + + +static const device_config_t v7_vga_1024i_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 1024, + { + { + "512 kB", 512 + }, + { + "1 MB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t g2_gc205_device = +{ + "G2 GC205", + DEVICE_ISA, + 0x7070, + g2_gc205_init, + ht216_close, + NULL, + g2_gc205_available, + ht216_speed_changed, + ht216_force_redraw +}; + +const device_t v7_vga_1024i_device = +{ + "Video 7 VGA 1024i", + DEVICE_ISA, + 0x7010, + v7_vga_1024i_init, + ht216_close, + NULL, + v7_vga_1024i_available, + ht216_speed_changed, + ht216_force_redraw, + v7_vga_1024i_config +}; + +const device_t ht216_32_pb410a_device = +{ + "Headland HT216-32 (Packard Bell PB410A)", + DEVICE_ISA, + 0x7861, /*HT216-32*/ + ht216_pb410a_init, + ht216_close, + NULL, + NULL, + ht216_speed_changed, + ht216_force_redraw +}; + +const device_t ht216_32_device = +{ + "Headland HT216-32", + DEVICE_ISA, + 0x7861, /*HT216-32*/ + ht216_32_init, + ht216_close, + NULL, + ht216_32_available, + ht216_speed_changed, + ht216_force_redraw, + v7_vga_1024i_config +}; diff --git a/src/video/vid_ht216.h b/src/video/vid_ht216.h new file mode 100644 index 000000000..5a8572eb5 --- /dev/null +++ b/src/video/vid_ht216.h @@ -0,0 +1,22 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Video 7 VGA 1024i emulation header. + * + * Version: @(#)vid_ht216.h 1.0.0 2019/04/05 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2019 Sarah Walker. + * Copyright 2019 Miran Grca. + */ +extern const device_t g2_gc205_device; +extern const device_t v7_vga_1024i_device; +extern const device_t ht216_32_pb410a_device; +extern const device_t ht216_32_device; diff --git a/src/video/vid_icd2061.c b/src/video/vid_icd2061.c index 47cd5743b..1c1746df5 100644 --- a/src/video/vid_icd2061.c +++ b/src/video/vid_icd2061.c @@ -29,15 +29,33 @@ #include "../device.h" #include "vid_icd2061.h" + +#ifdef ENABLE_ICD2061_LOG +int icd2061_do_log = ENABLE_ICD2061_LOG; + + +static void +icd2061_log(const char *fmt, ...) +{ + va_list ap; + + if (icd2061_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define icd2061_log(fmt, ...) +#endif + + void icd2061_write(icd2061_t *icd2061, int val) { - int /*od, */nd, oc, nc; - int a/*, i*/, qa, q, pa, p, m, ps; + int nd, oc, nc; + int a, qa, q, pa, p, m, ps; -#if 0 - od = (icd2061->state & 2) >> 1; /* Old data. */ -#endif nd = (val & 2) >> 1; /* Old data. */ oc = icd2061->state & 1; /* Old clock. */ nc = val & 1; /* New clock. */ @@ -48,15 +66,19 @@ icd2061_write(icd2061_t *icd2061, int val) if (!icd2061->unlocked) { if (nd) { /* DATA high. */ icd2061->count++; - /* pclog("Low-to-high transition of CLK with DATA high, %i total\n", icd2061->count); */ + icd2061_log("Low-to-high transition of CLK with DATA high, %i total\n", icd2061->count); } else { /* DATA low. */ if (icd2061->count >= 5) { icd2061->unlocked = 1; icd2061->bit_count = icd2061->data = 0; - /* pclog("ICD2061 unlocked\n"); */ +#ifdef ENABLE_ICD2061_LOG + icd2061_log("ICD2061 unlocked\n"); +#endif } else { icd2061->count = 0; - /* pclog("ICD2061 locked\n"); */ +#ifdef ENABLE_ICD2061_LOG + icd2061_log("ICD2061 locked\n"); +#endif } } } else if (nc) { @@ -64,15 +86,12 @@ icd2061_write(icd2061_t *icd2061, int val) icd2061->bit_count++; if (icd2061->bit_count == 26) { - /* pclog("26 bits received, data = %08X\n", icd2061->data); */ + icd2061_log("26 bits received, data = %08X\n", icd2061->data); a = ((icd2061->data >> 22) & 0x07); /* A */ - /* pclog("A = %01X\n", a); */ + icd2061_log("A = %01X\n", a); if (a < 3) { -#if 0 - i = ((icd2061->data >> 18) & 0x0f); /* I */ -#endif pa = ((icd2061->data >> 11) & 0x7f); /* P' (ICD2061) / N' (ICS9161) */ m = ((icd2061->data >> 8) & 0x07); /* M (ICD2061) / R (ICS9161) */ qa = ((icd2061->data >> 1) & 0x7f); /* Q' (ICD2061) / M' (ICS9161) */ @@ -84,14 +103,16 @@ icd2061_write(icd2061_t *icd2061, int val) icd2061->freq[a] = ((float)(p * ps) / (float)(q * m)) * 14318184.0f; - /* pclog("P = %02X, M = %01X, Q = %02X, freq[%i] = %f\n", p, m, q, a, icd2061->freq[a]); */ + icd2061_log("P = %02X, M = %01X, Q = %02X, freq[%i] = %f\n", p, m, q, a, icd2061->freq[a]); } else if (a == 6) { icd2061->ctrl = ((icd2061->data >> 13) & 0xff); - /* pclog("ctrl = %02X\n", icd2061->ctrl); */ + icd2061_log("ctrl = %02X\n", icd2061->ctrl); } icd2061->count = icd2061->bit_count = icd2061->data = 0; icd2061->unlocked = 0; - /* pclog("ICD2061 locked\n"); */ +#ifdef ENABLE_ICD2061_LOG + icd2061_log("ICD2061 locked\n"); +#endif } } } diff --git a/src/video/vid_im1024.c b/src/video/vid_im1024.c new file mode 100644 index 000000000..0f276a103 --- /dev/null +++ b/src/video/vid_im1024.c @@ -0,0 +1,1026 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of the ImageManager 1024 video controller. + * + * Just enough of the Vermont Microsystems IM-1024 is implemented + * to support the Windows 1.03 driver. Functions are partially + * implemented or hardwired to the behavior expected by the + * Windows driver. + * + * One major difference seems to be that in hex mode, coordinates + * are passed as 2-byte integer words rather than 4-byte + * fixed-point fractions. + * + * It is unknown what triggers this, so for now it's always on. + * + * As well as the usual PGC ring buffer at 0xC6000, the IM1024 + * appears to have an alternate method of passing commands. This + * is enabled by setting 0xC6330 to 1, and then: + * + * CX = count to write + * SI -> bytes to write + * + * Set pending bytes to 0 + * Read [C6331]. This gives number of bytes that can be written: + * 0xFF => 0, 0xFE => 1, 0xFD => 2 etc. + * Write that number of bytes to C6000. + * If there are more to come, go back to reading [C6331]. + * + * As far as can be determined, at least one byte is always + * written; there is no provision to pause if the queue is full. + * + * This is implemented by holding a FIFO of unlimited depth in + * the IM1024 to receive the data. + * + * Version: @(#)vid_im1024.c 1.0.3 2019/03/03 + * + * Authors: Fred N. van Kempen, + * John Elliott, + * + * Copyright 2019 Fred N. van Kempen. + * Copyright 2019 John Elliott. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../pit.h" +#include "../plat.h" +#include "video.h" +#include "vid_pgc.h" +#include "vid_im1024.h" + + +#define BIOS_ROM_PATH L"roms/video/im1024/im1024font.bin" + + +typedef struct { + pgc_t pgc; + + uint8_t fontx[256]; + uint8_t fonty[256]; + uint8_t font[256][128]; + + uint8_t *fifo; + unsigned fifo_len, + fifo_wrptr, + fifo_rdptr; +} im1024_t; + + +static video_timings_t timing_im1024 = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + + +#ifdef ENABLE_IM1024_LOG +int im1024_do_log = ENABLE_IM1024_LOG; + + +static void +im1024_log(const char *fmt, ...) +{ + va_list ap; + + if (im1024_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define im1024_log(fmt, ...) +#endif + + +static void +fifo_write(im1024_t *dev, uint8_t val) +{ + im1024_log("IM1024: fifo_write: %02x [rd=%04x wr=%04x]\n", + val, dev->fifo_rdptr, dev->fifo_wrptr); + + if (((dev->fifo_wrptr + 1) % dev->fifo_len) == dev->fifo_rdptr) { + /* FIFO is full. Double its size. */ + uint8_t *buf; + + im1024_log("IM1024: fifo_resize: %i to %i\n", + dev->fifo_len, 2 * dev->fifo_len); + + buf = realloc(dev->fifo, 2 * dev->fifo_len); + if (buf == NULL) return; + + /* Move the [0..wrptr] range to the newly-allocated area [len..len+wrptr] */ + memmove(buf + dev->fifo_len, buf, dev->fifo_wrptr); + dev->fifo = buf; + dev->fifo_wrptr += dev->fifo_len; + dev->fifo_len *= 2; + } + + /* Append to the queue. */ + dev->fifo[dev->fifo_wrptr++] = val; + + /* Wrap if end of buffer reached. */ + if (dev->fifo_wrptr >= dev->fifo_len) + dev->fifo_wrptr = 0; +} + + +static int +fifo_read(im1024_t *dev) +{ + uint8_t ret; + + if (dev->fifo_wrptr == dev->fifo_rdptr) + return -1; /* FIFO empty */ + + ret = dev->fifo[dev->fifo_rdptr++]; + if (dev->fifo_rdptr >= dev->fifo_len) + dev->fifo_rdptr = 0; + + im1024_log("IM1024: fifo_read: %02x\n", ret); + + return(ret); +} + + +/* + * Where a normal PGC would just read from the ring buffer at 0xC6300, + * the IM-1024 can read from either this or from its internal FIFO. + * + * The internal FIFO has priority. + */ +static int +input_byte(pgc_t *pgc, uint8_t *result) +{ + im1024_t *dev = (im1024_t *)pgc; + + /* If input buffer empty, wait for it to fill. */ + while (!pgc->stopped && (dev->fifo_wrptr == dev->fifo_rdptr) && + (pgc->mapram[0x300] == pgc->mapram[0x301])) { + pgc->waiting_input_fifo = 1; + pgc_sleep(pgc); + } + + if (pgc->stopped) + return(0); + + if (pgc->mapram[0x3ff]) { + /* Reset triggered. */ + pgc_reset(pgc); + return(0); + } + + if (dev->fifo_wrptr == dev->fifo_rdptr) { + *result = pgc->mapram[pgc->mapram[0x301]]; + pgc->mapram[0x301]++; + } else + *result = fifo_read(dev); + + return(1); +} + + +/* Macros to disable clipping and save clip state. */ +#define PUSHCLIP { \ + uint16_t vp_x1, vp_x2, vp_y1, vp_y2; \ + vp_x1 = pgc->vp_x1; \ + vp_y1 = pgc->vp_y1; \ + vp_x2 = pgc->vp_x2; \ + vp_y2 = pgc->vp_y2; \ + pgc->vp_x1 = 0; \ + pgc->vp_y1 = 0; \ + pgc->vp_x2 = pgc->maxw - 1; \ + pgc->vp_y2 = pgc->maxh - 1; \ + +/* And to restore clip state */ +#define POPCLIP \ + pgc->vp_x1 = vp_x1; \ + pgc->vp_y1 = vp_y1; \ + pgc->vp_x2 = vp_x2; \ + pgc->vp_y2 = vp_y2; \ + } + + +/* Override memory read to return FIFO space. */ +static uint8_t +im1024_read(uint32_t addr, void *priv) +{ + im1024_t *dev = (im1024_t *)priv; + + if (addr == 0xc6331 && dev->pgc.mapram[0x330] == 1) { + /* Hardcode that there are 128 bytes free. */ + return(0x80); + } + + return(pgc_read(addr, &dev->pgc)); +} + + +/* Override memory write to handle writes to the FIFO. */ +static void +im1024_write(uint32_t addr, uint8_t val, void *priv) +{ + im1024_t *dev = (im1024_t *)priv; + + /* + * If we are in 'fast' input mode, send all + * writes to the internal FIFO. + */ + if (addr >= 0xc6000 && addr < 0xc6100 && dev->pgc.mapram[0x330] == 1) { + fifo_write(dev, val); + + im1024_log("IM1024: write(%02x)\n", val); + + if (dev->pgc.waiting_input_fifo) { + dev->pgc.waiting_input_fifo = 0; + pgc_wake(&dev->pgc); + } + return; + } + + pgc_write(addr, val, &dev->pgc); +} + + +/* + * I don't know what the IMGSIZ command does, only that the + * Windows driver issues it. So just parse and ignore it. + */ +static void +hndl_imgsiz(pgc_t *pgc) +{ +#if 0 + im1024_t *dev = (im1024_t *)pgc; +#endif + int16_t w, h; + uint8_t a, b; + + if (! pgc_param_word(pgc, &w)) return; + if (! pgc_param_word(pgc, &h)) return; + if (! pgc_param_byte(pgc, &a)) return; + if (! pgc_param_byte(pgc, &b)) return; + + im1024_log("IM1024: IMGSIZ %i,%i,%i,%i\n", w, h, a, b); +} + + +/* + * I don't know what the IPREC command does, only that the + * Windows driver issues it. So just parse and ignore it. + */ +static void +hndl_iprec(pgc_t *pgc) +{ +#if 0 + im1024_t *dev = (im1024_t *)pgc; +#endif + uint8_t param; + + if (! pgc_param_byte(pgc, ¶m)) return; + + im1024_log("IM1024: IPREC %i\n", param); +} + + +/* + * Set drawing mode. + * + * 0 => Draw + * 1 => Invert + * 2 => XOR (IM-1024) + * 3 => AND (IM-1024) + */ +static void +hndl_linfun(pgc_t *pgc) +{ + uint8_t param; + + if (! pgc_param_byte(pgc, ¶m)) return; + + if (param < 4) { + pgc->draw_mode = param; + im1024_log("IM1024: LINFUN(%i)\n", param); + } else + pgc_error(pgc, PGC_ERROR_RANGE); +} + + +/* + * I think PAN controls which part of the 1024x1024 framebuffer + * is displayed in the 1024x800 visible screen. + */ +static void +hndl_pan(pgc_t *pgc) +{ + int16_t x, y; + + if (! pgc_param_word(pgc, &x)) return; + if (! pgc_param_word(pgc, &y)) return; + + im1024_log("IM1024: PAN %i,%i\n", x, y); + + pgc->pan_x = x; + pgc->pan_y = y; +} + + +/* PLINE draws a non-filled polyline at a fixed position. */ +static void +hndl_pline(pgc_t *pgc) +{ + int16_t x[257], y[257]; + uint16_t linemask = pgc->line_pattern; + uint8_t count; + unsigned n; + + if (! pgc_param_byte(pgc, &count)) return; + + im1024_log("IM1024: PLINE (%i) ", count); + for (n = 0; n < count; n++) { + if (! pgc_param_word(pgc, &x[n])) return; + if (! pgc_param_word(pgc, &y[n])) return; + im1024_log(" (%i,%i)\n", x[n], y[n]); + } + + for (n = 1; n < count; n++) { + linemask = pgc_draw_line(pgc, x[n - 1] << 16, y[n - 1] << 16, + x[n] << 16, y[n] << 16, linemask); + } +} + + +/* + * Blit a single row of pixels from one location to another. + * + * To avoid difficulties if the two overlap, read both rows + * into memory, process them there, and write the result back. + */ +static void +blkmov_row(pgc_t *pgc, int16_t x0, int16_t x1, int16_t x2, int16_t sy, int16_t ty) +{ + uint8_t src[1024]; + uint8_t dst[1024]; + int16_t x; + + for (x = x0; x <= x1; x++) { + src[x - x0] = pgc_read_pixel(pgc, x, sy); + dst[x - x0] = pgc_read_pixel(pgc, x - x0 + x2, ty); + } + + for (x = x0; x <= x1; x++) switch (pgc->draw_mode) { + default: + case 0: + pgc_write_pixel(pgc, (x - x0 + x2), ty, src[x - x0]); + break; + + case 1: + pgc_write_pixel(pgc, (x - x0 + x2), ty, dst[x - x0] ^ 0xff); + break; + + case 2: + pgc_write_pixel(pgc, (x - x0 + x2), ty, src[x - x0] ^ dst[x - x0]); + break; + + case 3: + pgc_write_pixel(pgc, (x - x0 + x2), ty, src[x - x0] & dst[x - x0]); + break; + } +} + + +/* + * BLKMOV blits a rectangular area from one location to another. + * + * Clipping is disabled. + */ +static void +hndl_blkmov(pgc_t *pgc) +{ + int16_t x0, y0; + int16_t x1, y1; + int16_t x2, y2; + int16_t y; + + if (! pgc_param_word(pgc, &x0)) return; + if (! pgc_param_word(pgc, &y0)) return; + if (! pgc_param_word(pgc, &x1)) return; + if (! pgc_param_word(pgc, &y1)) return; + if (! pgc_param_word(pgc, &x2)) return; + if (! pgc_param_word(pgc, &y2)) return; + + im1024_log("IM1024: BLKMOV %i,%i,%i,%i,%i,%i\n", x0,y0,x1,y1,x2,y2); + + /* Disable clipping. */ + PUSHCLIP + + /* + * Either go down from the top, or up from the bottom, + * depending whether areas might overlap. + */ + if (y2 <= y0) { + for (y = y0; y <= y1; y++) + blkmov_row(pgc, x0, x1, x2, y, y - y0 + y2); + } else { + for (y = y1; y >= y0; y--) + blkmov_row(pgc, x0, x1, x2, y, y - y0 + y2); + } + + /* Restore clipping. */ + POPCLIP +} + + +/* + * Override the PGC ELIPSE command to parse its + * parameters as words rather than coordinates. + */ +static void +hndl_ellipse(pgc_t *pgc) +{ + int16_t x, y; + + if (! pgc_param_word(pgc, &x)) return; + if (! pgc_param_word(pgc, &y)) return; + + im1024_log("IM1024: ELLIPSE %i,%i @ %i,%i\n", + x, y, pgc->x >> 16, pgc->y >> 16); + + pgc_draw_ellipse(pgc, x << 16, y << 16); +} + + +/* + * Override the PGC MOVE command to parse its + * parameters as words rather than coordinates. + */ +static void +hndl_move(pgc_t *pgc) +{ + int16_t x, y; + + if (! pgc_param_word(pgc, &x)) return; + if (! pgc_param_word(pgc, &y)) return; + + im1024_log("IM1024: MOVE %i,%i\n", x, y); + + pgc->x = x << 16; + pgc->y = y << 16; +} + + +/* + * Override the PGC DRAW command to parse its + * parameters as words rather than coordinates. + */ +static void +hndl_draw(pgc_t *pgc) +{ + int16_t x, y; + + if (! pgc_param_word(pgc, &x)) return; + if (! pgc_param_word(pgc, &y)) return; + + im1024_log("IM1024: DRAW %i,%i to %i,%i\n", pgc->x >> 16, pgc->y >> 16, x, y); + + pgc_draw_line(pgc, pgc->x, pgc->y, x << 16, y << 16, pgc->line_pattern); + + pgc->x = x << 16; + pgc->y = y << 16; +} + + +/* + * Override the PGC POLY command to parse its + * parameters as words rather than coordinates. + */ +static void +hndl_poly(pgc_t *pgc) +{ + int32_t *x, *y, *nx, *ny; + int16_t xw, yw, mask; + unsigned realcount = 0; + unsigned n, as = 256; + int parsing = 1; + uint8_t count; + + x = (int32_t *)malloc(as * sizeof(int32_t)); + y = (int32_t *)malloc(as * sizeof(int32_t)); + if (!x || !y) { +#ifdef ENABLE_IM1024_LOG + im1024_log("IM1024: POLY: out of memory\n"); +#endif + return; + } + + while (parsing) { + if (! pgc_param_byte(pgc, &count)) return; + + if (count + realcount >= as) { + nx = (int32_t *)realloc(x, 2 * as * sizeof(int32_t)); + ny = (int32_t *)realloc(y, 2 * as * sizeof(int32_t)); + if (!x || !y) { +#ifdef ENABLE_IM1024_LOG + im1024_log("IM1024: poly: realloc failed\n"); +#endif + break; + } + x = nx; + y = ny; + as *= 2; + } + + for (n = 0; n < count; n++) { + if (! pgc_param_word(pgc, &xw)) return; + if (! pgc_param_word(pgc, &yw)) return; + + /* Skip degenerate line segments. */ + if (realcount > 0 && + (xw << 16) == x[realcount - 1] && + (yw << 16) == y[realcount - 1]) continue; + + x[realcount] = xw << 16; + y[realcount] = yw << 16; + realcount++; + } + + /* + * If we are in a command list, peek ahead to see if the next + * command is also POLY. If so, that's a continuation of this + * polygon! + */ + parsing = 0; + if (pgc->clcur && (pgc->clcur->rdptr+1) < pgc->clcur->wrptr && + pgc->clcur->list[pgc->clcur->rdptr] == 0x30) { +#ifdef ENABLE_IM1024_LOG + im1024_log("IM1024: POLY continues!\n"); +#endif + parsing = 1; + + /* Swallow the POLY. */ + pgc->clcur->rdptr++; + } + }; + + im1024_log("IM1024: POLY (%i) fill_mode=%i\n", realcount, pgc->fill_mode); +#ifdef ENABLE_IM1024_LOG + for (n = 0; n < realcount; n++) { + im1024_log(" (%i,%i)\n", x[n] >> 16, y[n] >> 16); + } +#endif + + if (pgc->fill_mode) + pgc_fill_polygon(pgc, realcount, x, y); + + /* Now draw borders. */ + mask = pgc->line_pattern; + for (n = 1; n < realcount; n++) + mask = pgc_draw_line(pgc, x[n - 1], y[n - 1], x[n], y[n], mask); + pgc_draw_line(pgc, x[realcount - 1], y[realcount - 1], x[0], y[0], mask); + + free(y); + free(x); +} + + +static int +parse_poly(pgc_t *pgc, pgc_cl_t *cl, int c) +{ + uint8_t count; + +#ifdef ENABLE_IM1024_LOG + im1024_log("IM1024: parse_poly\n"); +#endif + + if (! pgc_param_byte(pgc, &count)) return 0; + + im1024_log("IM1024: parse_poly: count=%02x\n", count); + if (! pgc_cl_append(cl, count)) { + pgc_error(pgc, PGC_ERROR_OVERFLOW); + return 0; + } + + im1024_log("IM1024: parse_poly: parse %i words\n", 2 * count); + + return pgc_parse_words(pgc, cl, count * 2); +} + + +/* + * Override the PGC RECT command to parse its + * parameters as words rather than coordinates. + */ +static void +hndl_rect(pgc_t *pgc) +{ + int16_t x0, y0, x1, y1, p, q; + + x0 = pgc->x >> 16; + y0 = pgc->y >> 16; + + if (! pgc_param_word(pgc, &x1)) return; + if (! pgc_param_word(pgc, &y1)) return; + + /* Convert to raster coords. */ + pgc_sto_raster(pgc, &x0, &y0); + pgc_sto_raster(pgc, &x1, &y1); + + if (x0 > x1) { p = x0; x0 = x1; x1 = p; } + if (y0 > y1) { q = y0; y0 = y1; y1 = q; } + im1024_log("IM1024: RECT (%i,%i) -> (%i,%i)\n", x0, y0, x1, y1); + + if (pgc->fill_mode) { + for (p = y0; p <= y1; p++) + pgc_fill_line_r(pgc, x0, x1, p); + } else { + /* Outline: 4 lines. */ + p = pgc->line_pattern; + p = pgc_draw_line_r(pgc, x0, y0, x1, y0, p); + p = pgc_draw_line_r(pgc, x1, y0, x1, y1, p); + p = pgc_draw_line_r(pgc, x1, y1, x0, y1, p); + p = pgc_draw_line_r(pgc, x0, y1, x0, y0, p); + } +} + + +/* + * FIXME: + * Define a font character. + * + * Text drawing should probably be implemented in + * vid_pgc.c rather than here.. + */ +static void +hndl_tdefin(pgc_t *pgc) +{ + im1024_t *dev = (im1024_t *)pgc; + uint8_t ch, bt; + uint8_t rows, cols; + unsigned len, n; + + if (! pgc_param_byte(pgc, &ch)) return; + if (! pgc_param_byte(pgc, &cols)) return; + if (! pgc_param_byte(pgc, &rows)) return; + + im1024_log("IM1024: TDEFIN (%i,%i,%i) 0x%02x 0x%02x\n", + ch, rows, cols, pgc->mapram[0x300], pgc->mapram[0x301]); + + len = ((cols + 7) / 8) * rows; + for (n = 0; n < len; n++) { + if (! pgc_param_byte(pgc, &bt)) return; + + if (n < sizeof(dev->font[ch])) + dev->font[ch][n] = bt; + } + + dev->fontx[ch] = cols; + dev->fonty[ch] = rows; +} + + +static void +hndl_tsize(pgc_t *pgc) +{ + int16_t size; + + if (!pgc_param_word(pgc, &size)) return; + im1024_log("IM1024: TSIZE(%i)\n", size); + + pgc->tsize = size << 16; +} + + +static void +hndl_twrite(pgc_t *pgc) +{ + uint8_t buf[256]; + im1024_t *dev = (im1024_t *)pgc; + uint8_t count, mask, *row; + int x, y, wb, n; + int16_t x0 = pgc->x >> 16; + int16_t y0 = pgc->y >> 16; + + if (! pgc_param_byte(pgc, &count)) return; + + for (n = 0; n < count; n++) + if (! pgc_param_byte(pgc, &buf[n])) return; + buf[count] = 0; + + pgc_sto_raster(pgc, &x0, &y0); + + im1024_log("IM1024: TWRITE (%i) x0=%i y0=%i\n", count, x0, y0); + + for (n = 0; n < count; n++) { + wb = (dev->fontx[buf[n]] + 7) / 8; + im1024_log("IM1024: ch=0x%02x w=%i h=%i wb=%i\n", + buf[n], dev->fontx[buf[n]], dev->fonty[buf[n]], wb); + + for (y = 0; y < dev->fonty[buf[n]]; y++) { + mask = 0x80; + row = &dev->font[buf[n]][y * wb]; + for (x = 0; x < dev->fontx[buf[n]]; x++) { + if (row[0] & mask) + pgc_plot(pgc, x + x0, y0 - y); + mask = mask >> 1; + if (mask == 0) { + mask = 0x80; + row++; + } + } + } + + x0 += dev->fontx[buf[n]]; + } +} + + +static void +hndl_txt88(pgc_t *pgc) +{ + uint8_t buf[256]; + uint8_t count, mask, *row; + int16_t x0 = pgc->x >> 16; + int16_t y0 = pgc->y >> 16; + unsigned n; + int x, y; + + if (! pgc_param_byte(pgc, &count)) return; + + for (n = 0; n < count; n++) + if (! pgc_param_byte(pgc, &buf[n])) return; + buf[count] = 0; + + pgc_sto_raster(pgc, &x0, &y0); + + im1024_log("IM204: TXT88 (%i) x0=%i y0=%i\n", count, x0, y0); + + for (n = 0; n < count; n++) { + im1024_log("ch=0x%02x w=12 h=18\n", buf[n]); + + for (y = 0; y < 18; y++) { + mask = 0x80; + row = &fontdat12x18[buf[n]][y * 2]; + for (x = 0; x < 12; x++) { + if (row[0] & mask) pgc_plot(pgc, x + x0, y0 - y); + mask = mask >> 1; + if (mask == 0) { + mask = 0x80; + row++; + } + } + } + + x0 += 12; + } +} + + +static void +hndl_imagew(pgc_t *pgc) +{ + int16_t vp_x1, vp_y1, vp_x2, vp_y2; + int16_t row1, col1, col2; + uint8_t v1, v2; + + if (! pgc_param_word(pgc, &row1)) return; + if (! pgc_param_word(pgc, &col1)) return; + if (! pgc_param_word(pgc, &col2)) return; + + /* Already using raster coordinates, no need to convert. */ + im1024_log("IM1024: IMAGEW (row=%i,col1=%i,col2=%i)\n", row1, col1, col2); + + vp_x1 = pgc->vp_x1; + vp_y1 = pgc->vp_y1; + vp_x2 = pgc->vp_x2; + vp_y2 = pgc->vp_y2; + + /* Disable clipping. */ + pgc->vp_x1 = 0; + pgc->vp_y1 = 0; + pgc->vp_x2 = pgc->maxw - 1; + pgc->vp_y2 = pgc->maxh - 1; + + /* In ASCII mode, what is written is a stream of bytes. */ + if (pgc->ascii_mode) { + while (col1 <= col2) { + if (! pgc_param_byte(pgc, &v1)) + return; + + pgc_write_pixel(pgc, col1, row1, v1); + col1++; + } + } else { + /* In hex mode, it's RLE compressed. */ + while (col1 <= col2) { + if (! pgc_param_byte(pgc, &v1)) return; + + if (v1 & 0x80) { + /* Literal run. */ + v1 -= 0x7f; + while (col1 <= col2 && v1 != 0) { + if (! pgc_param_byte(pgc, &v2)) return; + pgc_write_pixel(pgc, col1, row1, v2); + col1++; + v1--; + } + } else { + /* Repeated run. */ + if (! pgc_param_byte(pgc, &v2)) return; + + v1++; + while (col1 <= col2 && v1 != 0) { + pgc_write_pixel(pgc, col1, row1, v2); + col1++; + v1--; + } + } + } + } + + /* Restore clipping. */ + pgc->vp_x1 = vp_x1; + pgc->vp_y1 = vp_y1; + pgc->vp_x2 = vp_x2; + pgc->vp_y2 = vp_y2; +} + + +/* + * I have called this command DOT - I don't know its proper name. + * + * Draws a single pixel at the current location. + */ +static void +hndl_dot(pgc_t *pgc) +{ + int16_t x = pgc->x >> 16, + y = pgc->y >> 16; + + pgc_sto_raster(pgc, &x, &y); + + im1024_log("IM1024: DOT @ %i,%i ink=%i mode=%i\n", + x, y, pgc->color, pgc->draw_mode); + + pgc_plot(pgc, x, y); +} + + +/* + * This command (which I have called IMAGEX, since I don't know its real + * name) is a screen-to-memory blit. It reads a rectangle of bytes, rather + * than the single row read by IMAGER, and does not attempt to compress + * the result. + */ +static void +hndl_imagex(pgc_t *pgc) +{ + int16_t x0, x1, y0, y1; + int16_t p,q; + + if (! pgc_param_word(pgc, &x0)) return; + if (! pgc_param_word(pgc, &y0)) return; + if (! pgc_param_word(pgc, &x1)) return; + if (! pgc_param_word(pgc, &y1)) return; + + /* Already using raster coordinates, no need to convert. */ + im1024_log("IM1024: IMAGEX (%i,%i,%i,%i)\n", x0,y0,x1,y1); + + for (p = y0; p <= y1; p++) { + for (q = x0; q <= x1; q++) { + if (! pgc_result_byte(pgc, pgc_read_pixel(pgc, q, p))) + return; + } + } +} + + +/* + * Commands implemented by the IM-1024. + * + * TODO: A lot of commands need commandlist parsers. + * TODO: The IM-1024 has a lot more commands that are not included here + * (BLINK, BUTRD, COPROC, RBAND etc) because the Windows 1.03 driver + * does not use them. + */ +static const pgc_cmd_t im1024_commands[] = { + { "BLKMOV", 0xdf, hndl_blkmov, pgc_parse_words, 6 }, + { "DRAW", 0x28, hndl_draw, pgc_parse_words, 2 }, + { "D", 0x28, hndl_draw, pgc_parse_words, 2 }, + { "DOT", 0x08, hndl_dot, NULL, 0 }, + { "ELIPSE", 0x39, hndl_ellipse, pgc_parse_words, 2 }, + { "EL", 0x39, hndl_ellipse, pgc_parse_words, 2 }, + { "IMAGEW", 0xd9, hndl_imagew, NULL, 0 }, + { "IMAGEX", 0xda, hndl_imagex, NULL, 0 }, + { "IMGSIZ", 0x4e, hndl_imgsiz, NULL, 0 }, + { "IPREC", 0xe4, hndl_iprec, NULL, 0 }, + { "IW", 0xd9, hndl_imagew, NULL, 0 }, + { "L8", 0xe6, pgc_hndl_lut8, NULL, 0 }, + { "LF", 0xeb, hndl_linfun, pgc_parse_bytes, 1 }, + { "LINFUN", 0xeb, hndl_linfun, pgc_parse_bytes, 1 }, + { "LUT8", 0xe6, pgc_hndl_lut8, NULL, 0 }, + { "LUT8RD", 0x53, pgc_hndl_lut8rd,NULL, 0 }, + { "L8RD", 0x53, pgc_hndl_lut8rd,NULL, 0 }, + { "TDEFIN", 0x84, hndl_tdefin, NULL, 0 }, + { "TD", 0x84, hndl_tdefin, NULL, 0 }, + { "TSIZE", 0x81, hndl_tsize, NULL, 0 }, + { "TS", 0x81, hndl_tsize, NULL, 0 }, + { "TWRITE", 0x8b, hndl_twrite, NULL, 0 }, + { "TXT88", 0x88, hndl_txt88, NULL, 0 }, + { "PAN", 0xb7, hndl_pan, NULL, 0 }, + { "POLY", 0x30, hndl_poly, parse_poly, 0 }, + { "P", 0x30, hndl_poly, parse_poly, 0 }, + { "PLINE", 0x36, hndl_pline, NULL, 0 }, + { "PL", 0x37, hndl_pline, NULL, 0 }, + { "MOVE", 0x10, hndl_move, pgc_parse_words, 2 }, + { "M", 0x10, hndl_move, pgc_parse_words, 2 }, + { "RECT", 0x34, hndl_rect, NULL, 0 }, + { "R", 0x34, hndl_rect, NULL, 0 }, + { "******", 0x00, NULL, NULL, 0 } +}; + + +static void * +im1024_init(const device_t *info) +{ + im1024_t *dev; + + dev = (im1024_t *)malloc(sizeof(im1024_t)); + memset(dev, 0x00, sizeof(im1024_t)); + + loadfont(BIOS_ROM_PATH, 9); + + dev->fifo_len = 4096; + dev->fifo = (uint8_t *)malloc(dev->fifo_len); + dev->fifo_wrptr = 0; + dev->fifo_rdptr = 0; + + /* Create a 1024x1024 framebuffer with 1024x800 visible. */ + pgc_init(&dev->pgc, 1024, 1024, 1024, 800, input_byte, 65000000.0); + + dev->pgc.commands = im1024_commands; + + mem_mapping_set_handler(&dev->pgc.mapping, + im1024_read,NULL,NULL, im1024_write,NULL,NULL); + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_im1024); + + return(dev); +} + + +static void +im1024_close(void *priv) +{ + im1024_t *dev = (im1024_t *)priv; + + pgc_close(&dev->pgc); + + free(dev); +} + + +static int +im1024_available() +{ + return rom_present(BIOS_ROM_PATH); +} + + +static void +im1024_speed_changed(void *priv) +{ + im1024_t *dev = (im1024_t *)priv; + + pgc_speed_changed(&dev->pgc); +} + + +static const device_config_t im1024_config[] = { + { + "", "", -1 + } +}; + + +const device_t im1024_device = { + "ImageManager 1024", + DEVICE_ISA, 0, + im1024_init, im1024_close, NULL, + im1024_available, + im1024_speed_changed, + NULL, + im1024_config +}; diff --git a/src/video/vid_im1024.h b/src/video/vid_im1024.h new file mode 100644 index 000000000..bf716b1d3 --- /dev/null +++ b/src/video/vid_im1024.h @@ -0,0 +1,18 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Header of the emulation of the ImageManager 1024 video + * controller. + * + * Version: @(#)vid_im1024.h 1.0.0 2019/03/03 + * + * Authors: John Elliott, + * + * Copyright 2019 John Elliott. + */ +extern const device_t im1024_device; diff --git a/src/video/vid_incolor.c b/src/video/vid_incolor.c index 40ea0a6ab..bd0d6e36f 100644 --- a/src/video/vid_incolor.c +++ b/src/video/vid_incolor.c @@ -23,11 +23,11 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../lpt.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_incolor.h" @@ -164,8 +164,8 @@ typedef struct { uint8_t ctrl, ctrl2, stat; - int64_t dispontime, dispofftime; - int64_t vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; @@ -174,7 +174,7 @@ typedef struct { uint16_t ma, maback; int con, coff, cursoron; int dispon, blink; - int64_t vsynctime; + int vsynctime; int vadj; uint8_t palette[16]; /* EGA-style 16 -> 64 palette registers */ @@ -198,11 +198,11 @@ recalc_timings(incolor_t *dev) disptime = dev->crtc[0] + 1; _dispontime = dev->crtc[1]; _dispofftime = disptime - _dispontime; - _dispontime *= MDACONST; - _dispofftime *= MDACONST; + _dispontime *= HERCCONST; + _dispofftime *= HERCCONST; - dev->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - dev->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + dev->dispontime = (uint64_t)(_dispontime); + dev->dispofftime = (uint64_t)(_dispofftime); } @@ -505,7 +505,7 @@ draw_char_rom(incolor_t *dev, int x, uint8_t chr, uint8_t attr) } for (i = 0; i < cw; i++) { - ((uint32_t *)buffer32->line[dev->displine])[x * cw + i] = (val & 0x100) ? fg : bg; + buffer32->line[dev->displine][x * cw + i] = (val & 0x100) ? fg : bg; val = val << 1; } } @@ -623,7 +623,7 @@ draw_char_ram4(incolor_t *dev, int x, uint8_t chr, uint8_t attr) fg = dev->rgb[defpal[cfg]]; } - ((uint32_t *)buffer32->line[dev->displine])[x * cw + i] = fg; + buffer32->line[dev->displine][x * cw + i] = fg; val[0] = val[0] << 1; val[1] = val[1] << 1; val[2] = val[2] << 1; @@ -783,7 +783,7 @@ draw_char_ram48(incolor_t *dev, int x, uint8_t chr, uint8_t attr) fg = dev->rgb[defpal[cfg]]; } - ((uint32_t *)buffer32->line[dev->displine])[x * cw + i] = fg; + buffer32->line[dev->displine][x * cw + i] = fg; val[0] = val[0] << 1; val[1] = val[1] << 1; val[2] = val[2] << 1; @@ -846,7 +846,7 @@ text_line(incolor_t *dev, uint16_t ca) } for (c = 0; c < cw; c++) { - ((uint32_t *)buffer32->line[dev->displine])[x * cw + c] = col; + buffer32->line[dev->displine][x * cw + c] = col; } } } @@ -895,7 +895,7 @@ graphics_line(incolor_t *dev) col = dev->palette[ink]; else col = defpal[ink]; - ((uint32_t *)buffer32->line[dev->displine])[(x << 4) + c] = dev->rgb[col]; + buffer32->line[dev->displine][(x << 4) + c] = dev->rgb[col]; } } } @@ -911,7 +911,7 @@ incolor_poll(void *priv) int oldsc; if (! dev->linepos) { - dev->vidtime += dev->dispofftime; + timer_advance_u64(&dev->timer, dev->dispofftime); dev->stat |= 1; dev->linepos = 1; oldsc = dev->sc; @@ -936,7 +936,7 @@ incolor_poll(void *priv) if (dev->displine >= 500) dev->displine = 0; } else { - dev->vidtime += dev->dispontime; + timer_advance_u64(&dev->timer, dev->dispontime); if (dev->dispon) dev->stat &= ~1; dev->linepos = 0; @@ -1038,7 +1038,7 @@ incolor_init(const device_t *info) dev->vram = (uint8_t *)malloc(0x40000); /* 4 planes of 64k */ - timer_add(incolor_poll, &dev->vidtime, TIMER_ALWAYS_ENABLED, dev); + timer_add(&dev->timer, incolor_poll, dev, 1); mem_mapping_add(&dev->mapping, 0xb0000, 0x08000, incolor_read,NULL,NULL, incolor_write,NULL,NULL, diff --git a/src/video/vid_mda.c b/src/video/vid_mda.c index c28155492..382738b42 100644 --- a/src/video/vid_mda.c +++ b/src/video/vid_mda.c @@ -8,7 +8,7 @@ * * MDA emulation. * - * Version: @(#)vid_mda.c 1.0.12 2018/09/19 + * Version: @(#)vid_mda.c 1.0.13 2019/09/03 * * Authors: Sarah Walker, * Miran Grca, @@ -23,41 +23,15 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../lpt.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_mda.h" - -typedef struct mda_t -{ - mem_mapping_t mapping; - - uint8_t crtc[32]; - int crtcreg; - - uint8_t ctrl, stat; - - int64_t dispontime, dispofftime; - int64_t vidtime; - - int firstline, lastline; - - int linepos, displine; - int vc, sc; - uint16_t ma, maback; - int con, coff, cursoron; - int dispon, blink; - int64_t vsynctime; - int vadj; - - uint8_t *vram; -} mda_t; - static int mdacols[256][2][2]; static video_timings_t timing_mda = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; @@ -124,8 +98,8 @@ void mda_recalctimings(mda_t *mda) _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; - mda->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - mda->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + mda->dispontime = (uint64_t)(_dispontime); + mda->dispofftime = (uint64_t)(_dispofftime); } void mda_poll(void *p) @@ -140,7 +114,7 @@ void mda_poll(void *p) int blink; if (!mda->linepos) { - mda->vidtime += mda->dispofftime; + timer_advance_u64(&mda->timer, mda->dispofftime); mda->stat |= 1; mda->linepos = 1; oldsc = mda->sc; @@ -162,20 +136,20 @@ void mda_poll(void *p) if (mda->sc == 12 && ((attr & 7) == 1)) { for (c = 0; c < 9; c++) - buffer->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][1]; + buffer32->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][1]; } else { for (c = 0; c < 8; c++) - buffer->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][mda->sc] & (1 << (c ^ 7))) ? 1 : 0]; - if ((chr & ~0x1f) == 0xc0) buffer->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][mda->sc] & 1]; - else buffer->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][0]; + buffer32->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][mda->sc] & (1 << (c ^ 7))) ? 1 : 0]; + if ((chr & ~0x1f) == 0xc0) buffer32->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][mda->sc] & 1]; + else buffer32->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][0]; } mda->ma++; if (drawcursor) { for (c = 0; c < 9; c++) - buffer->line[mda->displine][(x * 9) + c] ^= mdacols[attr][0][1]; + buffer32->line[mda->displine][(x * 9) + c] ^= mdacols[attr][0][1]; } } } @@ -190,7 +164,7 @@ void mda_poll(void *p) } else { - mda->vidtime += mda->dispontime; + timer_advance_u64(&mda->timer, mda->dispontime); if (mda->dispon) mda->stat&=~1; mda->linepos=0; if (mda->vsynctime) @@ -281,19 +255,9 @@ void mda_poll(void *p) } } - -void *mda_init(const device_t *info) +void mda_init(mda_t *mda) { - int c; - mda_t *mda = malloc(sizeof(mda_t)); - memset(mda, 0, sizeof(mda_t)); - video_inform(VIDEO_FLAG_TYPE_MDA, &timing_mda); - - mda->vram = malloc(0x1000); - - timer_add(mda_poll, &mda->vidtime, TIMER_ALWAYS_ENABLED, mda); - mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, mda); - io_sethandler(0x03b0, 0x0010, mda_in, NULL, NULL, mda_out, NULL, NULL, mda); + int c; for (c = 0; c < 256; c++) { @@ -321,13 +285,34 @@ void *mda_init(const device_t *info) { cga_palette = 0; } - cgapal_rebuild(); + cgapal_rebuild(); + + timer_add(&mda->timer, mda_poll, mda, 1); +} + +void *mda_standalone_init(const device_t *info) +{ + mda_t *mda = malloc(sizeof(mda_t)); + memset(mda, 0, sizeof(mda_t)); + video_inform(VIDEO_FLAG_TYPE_MDA, &timing_mda); + + mda->vram = malloc(0x1000); + + mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, mda); + io_sethandler(0x03b0, 0x0010, mda_in, NULL, NULL, mda_out, NULL, NULL, mda); + + mda_init(mda); lpt3_init(0x3BC); return mda; } +void mda_setcol(int chr, int blink, int fg, uint8_t cga_ink) +{ + mdacols[chr][blink][fg] = 16 + cga_ink; +} + void mda_close(void *p) { mda_t *mda = (mda_t *)p; @@ -375,7 +360,7 @@ const device_t mda_device = { "MDA", DEVICE_ISA, 0, - mda_init, mda_close, NULL, + mda_standalone_init, mda_close, NULL, NULL, mda_speed_changed, NULL, diff --git a/src/video/vid_mda.h b/src/video/vid_mda.h index 4e1e78e41..82a8f5e19 100644 --- a/src/video/vid_mda.h +++ b/src/video/vid_mda.h @@ -1,4 +1,40 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ +typedef struct mda_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, stat; + + uint64_t dispontime, dispofftime; + pc_timer_t timer; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int vsynctime; + int vadj; + + uint8_t *vram; +} mda_t; + +void mda_init(mda_t *mda); +void mda_setcol(int chr, int blink, int fg, uint8_t cga_ink); +void mda_out(uint16_t addr, uint8_t val, void *p); +uint8_t mda_in(uint16_t addr, void *p); +void mda_write(uint32_t addr, uint8_t val, void *p); +uint8_t mda_read(uint32_t addr, void *p); +void mda_recalctimings(mda_t *mda); +void mda_poll(void *p); + +#ifdef EMU_DEVICE_H extern const device_t mda_device; +#endif diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index e25b0f2c8..467d2a67c 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -22,6 +22,7 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../rom.h" #include "../device.h" @@ -147,12 +148,12 @@ oti_out(uint16_t addr, uint8_t val, void *p) case 0x03: enable = (oti->vram_size >= 1024); if (val & 0xc) - svga->vram_display_mask = MIN(oti->vram_mask, 0x7ffff); + svga->vram_display_mask = MIN(oti->vram_mask, 0xfffff); break; case 0x02: /* 512 kB of memory */ enable = (oti->vram_size >= 512); if (val & 0xc) - svga->vram_display_mask = MIN(oti->vram_mask, 0xfffff); + svga->vram_display_mask = MIN(oti->vram_mask, 0x7ffff); break; } diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index e785c2624..5333980de 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -10,13 +10,13 @@ * PC2086, PC3086 use PVGA1A * MegaPC uses W90C11A * - * Version: @(#)vid_paradise.c 1.0.8 2018/09/19 + * Version: @(#)vid_paradise.c 1.0.9 2019/03/23 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -25,6 +25,7 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../rom.h" #include "../device.h" diff --git a/src/video/vid_pgc.c b/src/video/vid_pgc.c new file mode 100644 index 000000000..4f0a17837 --- /dev/null +++ b/src/video/vid_pgc.c @@ -0,0 +1,2719 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * This implements just enough of the Professional Graphics + * Controller to act as a basis for the Vermont Microsystems + * IM-1024. + * + * PGC features implemented include: + * > The CGA-compatible display modes + * > Switching to and from native mode + * > Communicating with the host PC + * + * Numerous features are implemented partially or not at all, + * such as: + * > 2D drawing + * > 3D drawing + * > Command lists + * Some of these are marked TODO. + * + * The PGC has two display modes: CGA (in which it appears in + * the normal CGA memory and I/O ranges) and native (in which + * all functions are accessed through reads and writes to 1K + * of memory at 0xC6000). + * + * The PGC's 8088 processor monitors this buffer and executes + * instructions left there for it. We simulate this behavior + * with a separate thread. + * + * **NOTE** This driver is not finished yet: + * + * - cursor will blink at very high speed if used on a machine + * with clock greater than 4.77MHz. We should "scale down" + * this speed, to become relative to a 4.77MHz-based system. + * + * - pgc_plot() should be overloaded by clones if they support + * modes other than WRITE and INVERT, like the IM-1024. + * + * - test it with the Windows 1.x driver? + * + * This is expected to be done shortly. + * + * Version: @(#)vid_pgc.c 1.0.2 2019/03/03 + * + * Authors: Fred N. van Kempen, + * John Elliott, + * + * Copyright 2019 Fred N. van Kempen. + * Copyright 2019 John Elliott. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../pit.h" +#include "../plat.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_pgc.h" + + +#define PGC_CGA_WIDTH 640 +#define PGC_CGA_HEIGHT 400 + +#define HWORD(u) ((u) >> 16) +#define LWORD(u) ((u) & 0xffff) + +#define WAKE_DELAY (TIMER_USEC * 500) + + +static const char *pgc_err_msgs[] = { + "Range \r", + "Integer \r", + "Memory \r", + "Overflow\r", + "Digit \r", + "Opcode \r", + "Running \r", + "Stack \r", + "Too long\r", + "Area \r", + "Missing \r" +}; + + +/* Initial palettes */ +static const uint32_t init_palette[6][256] = { +#include "vid_pgc_palette.h" +}; + + +static video_timings_t timing_pgc = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; + + +#ifdef ENABLE_PGC_LOG +int pgc_do_log = ENABLE_PGC_LOG; + + +static void +pgc_log(const char *fmt, ...) +{ + va_list ap; + + if (pgc_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +#define pgc_log(fmt, ...) +#endif + + +static inline int +is_whitespace(char ch) +{ + return (ch != 0 && strchr(" \r\n\t,;()+-", ch) != NULL); +} + + +/* + * Write a byte to the output buffer. + * + * If buffer is full will sleep until it is not. Returns 0 if + * a PGC reset has been triggered by a write to 0xC63FF. + */ +static int +output_byte(pgc_t *dev, uint8_t val) +{ + /* If output buffer full, wait for it to empty. */ + while (!dev->stopped && dev->mapram[0x302] == (uint8_t)(dev->mapram[0x303] - 1)) { + pgc_log("PGC: output buffer state: %02x %02x Sleeping\n", + dev->mapram[0x302], dev->mapram[0x303]); + dev->waiting_output_fifo = 1; + pgc_sleep(dev); + } + + if (dev->mapram[0x3ff]) { + /* Reset triggered. */ + pgc_reset(dev); + return 0; + } + + dev->mapram[0x100 + dev->mapram[0x302]] = val; + dev->mapram[0x302]++; + + pgc_log("PGC: output %02x: new state: %02x %02x\n", val, + dev->mapram[0x302], dev->mapram[0x303]); + + return 1; +} + + +/* Helper to write an entire string to the output buffer. */ +static int +output_string(pgc_t *dev, const char *s) +{ + while (*s) { + if (! output_byte(dev, *s)) return 0; + s++; + } + + return 1; +} + + +/* As output_byte, for the error buffer. */ +static int +error_byte(pgc_t *dev, uint8_t val) +{ + /* If error buffer full, wait for it to empty. */ + while (!dev->stopped && dev->mapram[0x304] == dev->mapram[0x305] - 1) { + dev->waiting_error_fifo = 1; + pgc_sleep(dev); + } + + if (dev->mapram[0x3ff]) { + /* Reset triggered. */ + pgc_reset(dev); + return 0; + } + + dev->mapram[0x200 + dev->mapram[0x304]] = val; + dev->mapram[0x304]++; + + return 1; +} + + +/* As output_string, for the error buffer. */ +static int +error_string(pgc_t *dev, const char *s) +{ + while (*s) { + if (! error_byte(dev, *s)) return 0; + s++; + } + + return 1; +} + + +/* + * Read next byte from the input buffer. + * + * If no byte available will sleep until one is. Returns 0 if + * a PGC reset has been triggered by a write to 0xC63FF. + */ +static int +input_byte(pgc_t *dev, uint8_t *result) +{ + /* If input buffer empty, wait for it to fill. */ + while (!dev->stopped && (dev->mapram[0x300] == dev->mapram[0x301])) { + dev->waiting_input_fifo = 1; + pgc_sleep(dev); + } + + if (dev->stopped) + return 0; + + if (dev->mapram[0x3ff]) { + /* Reset triggered. */ + pgc_reset(dev); + return 0; + } + + *result = dev->mapram[dev->mapram[0x301]]; + dev->mapram[0x301]++; + + return 1; +} + + +/* + * Read a byte and interpret as ASCII. + * + * Ignore control characters other than CR, LF or tab. + */ +static int +input_char(pgc_t *dev, char *result) +{ + uint8_t ch; + + while (1) { + if (! dev->inputbyte(dev, &ch)) return 0; + + ch &= 0x7f; + if (ch == '\r' || ch == '\n' || ch == '\t' || ch >= ' ') { + *result = toupper(ch); + return 1; + } + } +} + + +/* + * Read in the next command. + * + * This can be either as hex (1 byte) or ASCII (up to 6 characters). + */ +static int +read_command(pgc_t *dev) +{ + if (dev->stopped) + return 0; + + if (dev->clcur) + return pgc_clist_byte(dev, &dev->hex_command); + + if (dev->ascii_mode) { + char ch; + int count = 0; + + while (count < 7) { + if (dev->stopped) return 0; + + if (! input_char(dev, &ch)) return 0; + + if (is_whitespace(ch)) { + /* Pad to 6 characters */ + while (count < 6) + dev->asc_command[count++] = ' '; + dev->asc_command[6] = 0; + + return 1; + } + dev->asc_command[count++] = toupper(ch); + } + + return 1; + } + + return dev->inputbyte(dev, &dev->hex_command); +} + + +/* Read in the next command and parse it. */ +static int +parse_command(pgc_t *dev, const pgc_cmd_t **pcmd) +{ + const pgc_cmd_t *cmd; + char match[7]; + + *pcmd = NULL; + dev->hex_command = 0; + memset(dev->asc_command, ' ', 6); + dev->asc_command[6] = 0; + + if (! read_command(dev)) { + /* PGC has been reset. */ + return 0; + } + + /* + * Scan the list of valid commands. + * + * dev->commands may be a subclass list (terminated with '*') + * or the core list (terminated with '@') + */ + for (cmd = dev->commands; cmd->ascii[0] != '@'; cmd++) { + /* End of subclass command list, chain to core. */ + if (cmd->ascii[0] == '*') + cmd = dev->master; + + /* If in ASCII mode match on the ASCII command. */ + if (dev->ascii_mode && !dev->clcur) { + sprintf(match, "%-6.6s", cmd->ascii); + if (! strncmp(match, dev->asc_command, 6)) { + *pcmd = cmd; + dev->hex_command = cmd->hex; + break; + } + } else { + /* Otherwise match on the hex command. */ + if (cmd->hex == dev->hex_command) { + sprintf(dev->asc_command, "%-6.6s", cmd->ascii); + *pcmd = cmd; + break; + } + } + } + + return 1; +} + + +/* + * Beginning of a command list. + * + * Parse commands up to the next CLEND, storing + * them (in hex form) in the named command list. + */ +static void +hndl_clbeg(pgc_t *dev) +{ + const pgc_cmd_t *cmd; + uint8_t param = 0; + pgc_cl_t cl; + + if (! pgc_param_byte(dev, ¶m)) return; + pgc_log("PGC: CLBEG(%i)\n", param); + + memset(&cl, 0x00, sizeof(pgc_cl_t)); + + while (1) { + if (! parse_command(dev, &cmd)) { + /* PGC has been reset. */ + return; + } + if (!cmd) { + pgc_error(dev, PGC_ERROR_OPCODE); + return; + } else if (dev->hex_command == 0x71) { + /* CLEND */ + dev->clist[param] = cl; + return; + } else { + if (! pgc_cl_append(&cl, dev->hex_command)) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + return; + } + + if (cmd->parser) { + if (! (*cmd->parser)(dev, &cl, cmd->p)) + return; + } + } + } +} + + +static void +hndl_clend(pgc_t *dev) +{ + /* Should not happen outside a CLBEG. */ +} + + +/* + * Execute a command list. + * + * If one was already executing, remember + * it so we can return to it afterwards. + */ +static void +hndl_clrun(pgc_t *dev) +{ + pgc_cl_t *clprev = dev->clcur; + uint8_t param = 0; + + if (! pgc_param_byte(dev, ¶m)) return; + + dev->clcur = &dev->clist[param]; + dev->clcur->rdptr = 0; + dev->clcur->repeat = 1; + dev->clcur->chain = clprev; +} + + +/* Execute a command list multiple times. */ +static void +hndl_cloop(pgc_t *dev) +{ + pgc_cl_t *clprev = dev->clcur; + uint8_t param = 0; + int16_t repeat = 0; + + if (! pgc_param_byte(dev, ¶m)) return; + if (! pgc_param_word(dev, &repeat)) return; + + dev->clcur = &dev->clist[param]; + dev->clcur->rdptr = 0; + dev->clcur->repeat = repeat; + dev->clcur->chain = clprev; +} + + +/* Read back a command list. */ +static void +hndl_clread(pgc_t *dev) +{ + uint8_t param = 0; + uint32_t n; + + if (! pgc_param_byte(dev, ¶m)) return; + + for (n = 0; n < dev->clist[param].wrptr; n++) { + if (! pgc_result_byte(dev, dev->clist[param].list[n])) + return; + } +} + + +/* Delete a command list. */ +static void +hndl_cldel(pgc_t *dev) +{ + uint8_t param = 0; + + if (! pgc_param_byte(dev, ¶m)) return; + + memset(&dev->clist[param], 0, sizeof(pgc_cl_t)); +} + + +/* Clear the screen to a specified color. */ +static void +hndl_clears(pgc_t *dev) +{ + uint8_t param = 0; + uint32_t y; + + if (! pgc_param_byte(dev, ¶m)) return; + + for (y = 0; y < dev->screenh; y++) + memset(dev->vram + y * dev->maxw, param, dev->screenw); +} + + +/* Select drawing color. */ +static void +hndl_color(pgc_t *dev) +{ + uint8_t param = 0; + + if (! pgc_param_byte(dev, ¶m)) return; + + pgc_log("PGC: COLOR(%i)\n", param); + dev->color = param; +} + + +/* + * Set drawing mode. + * + * 0 => Draw + * 1 => Invert + */ +static void +hndl_linfun(pgc_t *dev) +{ + uint8_t param = 0; + + if (! pgc_param_byte(dev, ¶m)) return; + + pgc_log("PGC: LINFUN(%i)\n", param); + if (param < 2) + dev->draw_mode = param; + else + pgc_error(dev, PGC_ERROR_RANGE); +} + + +/* Set the line drawing pattern. */ +static void +hndl_linpat(pgc_t *dev) +{ + uint16_t param = 0; + + if (! pgc_param_word(dev, (int16_t *)¶m)) return; + + pgc_log("PGC: LINPAT(0x%04x)\n", param); + dev->line_pattern = param; +} + + +/* Set the polygon fill mode (0=hollow, 1=filled, 2=fast fill). */ +static void +hndl_prmfil(pgc_t *dev) +{ + uint8_t param = 0; + + if (! pgc_param_byte(dev, ¶m)) return; + + pgc_log("PGC: PRMFIL(%i)\n", param); + if (param < 3) + dev->fill_mode = param; + else + pgc_error(dev, PGC_ERROR_RANGE); +} + + +/* Set the 2D drawing position. */ +static void +hndl_move(pgc_t *dev) +{ + int32_t x = 0, y = 0; + + if (! pgc_param_coord(dev, &x)) return; + if (! pgc_param_coord(dev, &y)) return; + + pgc_log("PCG: MOVE %x.%04x,%x.%04x\n", + HWORD(x), LWORD(x), HWORD(y), LWORD(y)); + dev->x = x; + dev->y = y; +} + + +/* Set the 3D drawing position. */ +static void +hndl_move3(pgc_t *dev) +{ + int32_t x = 0, y = 0, z = 0; + + if (! pgc_param_coord(dev, &x)) return; + if (! pgc_param_coord(dev, &y)) return; + if (! pgc_param_coord(dev, &z)) return; + + dev->x = x; + dev->y = y; + dev->z = z; +} + + +/* Relative move (2D). */ +static void +hndl_mover(pgc_t *dev) +{ + int32_t x = 0, y = 0; + + if (! pgc_param_coord(dev, &x)) return; + if (! pgc_param_coord(dev, &y)) return; + + dev->x += x; + dev->y += y; +} + + +/* Relative move (3D). */ +static void +hndl_mover3(pgc_t *dev) +{ + int32_t x = 0, y = 0, z = 0; + + if (! pgc_param_coord(dev, &x)) return; + if (! pgc_param_coord(dev, &y)) return; + if (! pgc_param_coord(dev, &z)) return; + + dev->x += x; + dev->y += y; + dev->z += z; +} + + +/* Given raster coordinates, find the matching address in PGC video RAM. */ +uint8_t * +pgc_vram_addr(pgc_t *dev, int16_t x, int16_t y) +{ + int offset; + + /* We work from the bottom left-hand corner. */ + if (y < 0 || (uint32_t)y >= dev->maxh || + x < 0 || (uint32_t)x >= dev->maxw) return NULL; + + offset = (dev->maxh - 1 - y) * (dev->maxw) + x; + pgc_log("PGC: vram_addr(x=%i,y=%i) = %i\n", x, y, offset); + + if (offset < 0 || (uint32_t)offset >= (dev->maxw * dev->maxh)) + return NULL; + + return &dev->vram[offset]; +} + + +/* + * Write a screen pixel. + * X and Y are raster coordinates, ink is the value to write. + */ +void +pgc_write_pixel(pgc_t *dev, uint16_t x, uint16_t y, uint8_t ink) +{ + uint8_t *vram; + + /* Suppress out-of-range writes; clip to viewport. */ + if (x < dev->vp_x1 || x > dev->vp_x2 || x >= dev->maxw || + y < dev->vp_y1 || y > dev->vp_y2 || y >= dev->maxh) { + pgc_log("PGC: write_pixel clipped: (%i,%i) " + "vp_x1=%i vp_y1=%i vp_x2=%i vp_y2=%i " + "ink=0x%02x\n", + x, y, dev->vp_x1, dev->vp_y1, dev->vp_x2, dev->vp_y2, ink); + return; + } + + vram = pgc_vram_addr(dev, x, y); + if (vram) + *vram = ink; +} + + +/* Read a screen pixel (x and y are raster coordinates). */ +uint8_t +pgc_read_pixel(pgc_t *dev, uint16_t x, uint16_t y) +{ + uint8_t *vram; + + /* Suppress out-of-range reads. */ + if (x >= dev->maxw || y >= dev->maxh) + return 0; + + vram = pgc_vram_addr(dev, x, y); + if (vram) + return *vram; + + return 0; +} + + +/* + * Plot a point in the current color and draw mode. Raster coordinates. + * + * FIXME: this should be overloaded by clones if they support + * modes other than WRITE and INVERT, like the IM-1024. + */ +void +pgc_plot(pgc_t *dev, uint16_t x, uint16_t y) +{ + uint8_t *vram; + + /* Only allow plotting within the current viewport. */ + if (x < dev->vp_x1 || x > dev->vp_x2 || x >= dev->maxw || + y < dev->vp_y1 || y > dev->vp_y2 || y >= dev->maxh) { + pgc_log("PGC: plot clipped: (%i,%i) %i <= x <= %i; %i <= y <= %i; " + "mode=%i ink=0x%02x\n", x, y, + dev->vp_x1, dev->vp_x2, dev->vp_y1, dev->vp_y2, + dev->draw_mode, dev->color); + return; + } + + vram = pgc_vram_addr(dev, x, y); + if (! vram) return; + + /* TODO: Does not implement the PGC plane mask (set by MASK). */ + switch (dev->draw_mode) { + default: + case 0: /* WRITE */ + *vram = dev->color; + break; + + case 1: /* INVERT */ + *vram ^= 0xff; + break; + + case 2: /* XOR color */ + //FIXME: see notes + *vram ^= dev->color; + break; + + case 3: /* AND color */ + //FIXME: see notes + *vram &= dev->color; + break; + } +} + + +/* + * Draw a line (using raster coordinates). + * + * Bresenham's Algorithm from: + * + * + * The line pattern mask to use is passed in. Return value is the + * line pattern mask, rotated by the number of points drawn. + */ +uint16_t +pgc_draw_line_r(pgc_t *dev, int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint16_t linemask) +{ + int32_t dx, dy, sx, sy, err, e2; + + dx = abs(x1 - x0); + dy = abs(y1 - y0); + sx = (x0 < x1) ? 1 : -1; + sy = (y0 < y1) ? 1 : -1; + err = (dx > dy ? dx : -dy) / 2; + + for (;;) { + if (linemask & 0x8000) { + pgc_plot(dev, x0, y0); + linemask = (linemask << 1) | 1; + } else + linemask = (linemask << 1); + + if (x0 == x1 && y0 == y1) break; + + e2 = err; + if (e2 > -dx) { + err -= dy; + x0 += sx; + } + if (e2 < dy) { + err += dx; + y0 += sy; + } + } + + return linemask; +} + + +/* Draw a line (using PGC fixed-point coordinates). */ +uint16_t +pgc_draw_line(pgc_t *dev, int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint16_t linemask) +{ + pgc_log("pgc_draw_line: (%i,%i) to (%i,%i)\n", + x0 >> 16, y0 >> 16, x1 >> 16, y1 >> 16); + + /* Convert from PGC fixed-point to device coordinates */ + x0 >>= 16; + y0 >>= 16; + pgc_ito_raster(dev, &x0, &y0); + + x1 >>= 16; + y1 >>= 16; + pgc_ito_raster(dev, &x1, &y1); + + return pgc_draw_line_r(dev, x0, y0, x1, y1, linemask); +} + + +/* + * Draw a horizontal line in the current fill pattern + * (using raster coordinates). + */ +void +pgc_fill_line_r(pgc_t *dev, int32_t x0, int32_t x1, int32_t y0) +{ + int32_t mask = 0x8000 >> (x0 & 0x0f); + int32_t x; + + if (x0 > x1) { + x = x1; + x1 = x0; + x0 = x; + } + + for (x = x0; x <= x1; x++) { + if (dev->fill_pattern[y0 & 0x0F] & mask) + pgc_plot(dev, x, y0); + mask = mask >> 1; + if (mask == 0) mask = 0x8000; + } +} + + +/* For sorting polygon nodes. */ +static int +compare_double(const void *a, const void *b) +{ + const double *da = (const double *)a; + const double *db = (const double *)b; + + if (*da < *db) return 1; + if (*da > *db) return -1; + + return 0; +} + + +/* Draw a filled polygon (using PGC fixed-point coordinates). */ +void +pgc_fill_polygon(pgc_t *dev, unsigned corners, int32_t *x, int32_t *y) +{ + double *nodex; + double *dx; + double *dy; + unsigned n, nodes, i, j; + double ymin, ymax, ypos; + + pgc_log("PGC: fill_polygon(%i corners)\n", corners); + + if (corners < 2) return; /* Degenerate polygon */ + + nodex = (double *)malloc(corners * sizeof(double)); + dx = (double *)malloc(corners * sizeof(double)); + dy = (double *)malloc(corners * sizeof(double)); + if (!nodex || !dx || !dy) return; + + ymin = ymax = y[0] / 65536.0; + for (n = 0; n < corners; n++) { + /* Convert from PGC fixed-point to native floating-point. */ + dx[n] = x[n] / 65536.0; + dy[n] = y[n] / 65536.0; + + if (dy[n] < ymin) ymin = dy[n]; + if (dy[n] > ymax) ymax = dy[n]; + } + + /* Polygon fill. Based on */ + /* For each row, work out where the polygon lines intersect with + * that row. */ + for (ypos = ymin; ypos <= ymax; ypos++) { + nodes = 0; + j = corners - 1; + for (i = 0; i < corners; i++) { + if ((dy[i] < ypos && dy[j] >= ypos) || + (dy[j] < ypos && dy[i] >= ypos)) /* Line crosses */ { + nodex[nodes++] = dx[i] + (ypos-dy[i])/(dy[j]-dy[i]) * (dx[j] - dx[i]); + } + j = i; + } + + /* Sort the intersections. */ + if (nodes) + qsort(nodex, nodes, sizeof(double), compare_double); + + /* And fill between them. */ + for (i = 0; i < nodes; i += 2) { + int16_t x1 = (int16_t)nodex[i], x2 = (int16_t)nodex[i + 1], + y1 = (int16_t)ypos, y2 = (int16_t)ypos; + pgc_sto_raster(dev, &x1, &y1); + pgc_sto_raster(dev, &x2, &y2); + pgc_fill_line_r(dev, x1, x2, y1); + } + } + + free(nodex); + free(dx); + free(dy); +} + + +/* Draw a filled ellipse (using PGC fixed-point coordinates). */ +void +pgc_draw_ellipse(pgc_t *dev, int32_t x, int32_t y) +{ + /* Convert from PGC fixed-point to native floating-point. */ + double h = y / 65536.0; + double w = x / 65536.0; + double y0 = dev->y / 65536.0; + double x0 = dev->x / 65536.0; + double ypos, xpos; + double x1; + double xlast = 0.0; + int16_t linemask = dev->line_pattern; + + pgc_log("PGC: ellipse(color=%i drawmode=%i fill=%i)\n", + dev->color, dev->draw_mode, dev->fill_mode); + + pgc_dto_raster(dev, &x0, &y0); + + for (ypos = 0; ypos <= h; ypos++) { + if (ypos == 0) { + if (dev->fill_mode) + pgc_fill_line_r(dev, (uint16_t)(x0 - w), + (uint16_t)(x0 + w), (uint16_t)y0); + if (linemask & 0x8000) { + pgc_plot(dev, (uint16_t)(x0 + w), (uint16_t)y0); + pgc_plot(dev, (uint16_t)(x0 - w), (uint16_t)y0); + linemask = (linemask << 1) | 1; + } else + linemask = linemask << 1; + + xlast = w; + } else { + x1 = sqrt((h * h) - (ypos * ypos)) * w / h; + + if (dev->fill_mode) { + pgc_fill_line_r(dev, (uint16_t)(x0 - x1), + (uint16_t)(x0 + x1), + (uint16_t)(y0 + ypos)); + pgc_fill_line_r(dev, (uint16_t)(x0 - x1), + (uint16_t)(x0 + x1), + (uint16_t)(y0 - ypos)); + } + + /* Draw border. */ + for (xpos = xlast; xpos >= x1; xpos--) { + if (linemask & 0x8000) { + pgc_plot(dev, (uint16_t)(x0 + xpos), + (uint16_t)(y0 + ypos)); + pgc_plot(dev, (uint16_t)(x0 - xpos), + (uint16_t)(y0 + ypos)); + pgc_plot(dev, (uint16_t)(x0 + xpos), + (uint16_t)(y0 - ypos)); + pgc_plot(dev, (uint16_t)(x0 - xpos), + (uint16_t)(y0 - ypos)); + linemask = (linemask << 1) | 1; + } else + linemask = linemask << 1; + } + + xlast = x1; + } + } +} + + +/* Handle the ELIPSE (sic) command. */ +static void +hndl_ellipse(pgc_t *dev) +{ + int32_t x = 0, y = 0; + + if (! pgc_param_coord(dev, &x)) return; + if (! pgc_param_coord(dev, &y)) return; + + pgc_draw_ellipse(dev, x, y); +} + + +/* Handle the POLY command. */ +static void +hndl_poly(pgc_t *dev) +{ + uint8_t count; + int32_t x[256]; + int32_t y[256]; + int32_t n; + + if (! pgc_param_byte(dev, &count)) return; + + pgc_log("PGC: POLY (%i)\n", count); + for (n = 0; n < count; n++) { + if (! pgc_param_coord(dev, &x[n])) return; + if (! pgc_param_coord(dev, &y[n])) return; + } +} + + +/* Parse but don't execute a POLY command (for adding to a command list) */ +static int +parse_poly(pgc_t *dev, pgc_cl_t *cl, int c) +{ + uint8_t count; + +#ifdef ENABLE_PGC_LOG + pgc_log("PCG: parse_poly\n"); +#endif + if (! pgc_param_byte(dev, &count)) return 0; + pgc_log("PCG: parse_poly: count=%02x\n", count); + + if (! pgc_cl_append(cl, count)) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + return 0; + } + pgc_log("PCG: parse_poly: parse %i coords\n", 2 * count); + + return pgc_parse_coords(dev, cl, 2 * count); +} + + +/* Handle the DISPLAY command. */ +static void +hndl_display(pgc_t *dev) +{ + uint8_t param; + + if (! pgc_param_byte(dev, ¶m)) return; + + pgc_log("PGC: DISPLAY(%i)\n", param); + + if (param > 1) + pgc_error(dev, PGC_ERROR_RANGE); + else + pgc_setdisplay(dev, param); +} + + +/* Handle the IMAGEW command (memory to screen blit). */ +static void +hndl_imagew(pgc_t *dev) +{ + int16_t row, col1, col2; + uint8_t v1, v2; + + if (! pgc_param_word(dev, &row)) return; + if (! pgc_param_word(dev, &col1)) return; + if (! pgc_param_word(dev, &col2)) return; + + if ((uint32_t)row >= dev->screenh || + (uint32_t)col1 >= dev->maxw || (uint32_t)col2 >= dev->maxw) { + pgc_error(dev, PGC_ERROR_RANGE); + return; + } + + /* In ASCII mode, what is written is a stream of bytes. */ + if (dev->ascii_mode) { + while (col1 <= col2) { + if (! pgc_param_byte(dev, &v1)) return; + pgc_write_pixel(dev, col1, row, v1); + col1++; + } + + return; + } + + /* In hex mode, it's RLE compressed. */ + while (col1 <= col2) { + if (! pgc_param_byte(dev, &v1)) return; + + if (v1 & 0x80) { + /* Literal run. */ + v1 -= 0x7f; + while (col1 <= col2 && v1 != 0) { + if (! pgc_param_byte(dev, &v2)) return; + pgc_write_pixel(dev, col1, row, v2); + col1++; + v1--; + } + } else { + /* Repeated run. */ + if (! pgc_param_byte(dev, &v2)) return; + + v1++; + while (col1 <= col2 && v1 != 0) { + pgc_write_pixel(dev, col1, row, v2); + col1++; + v1--; + } + } + } +} + + +/* Select one of the built-in palettes. */ +static void +init_lut(pgc_t *dev, int param) +{ + if (param >= 0 && param < 6) + memcpy(dev->palette, init_palette[param], sizeof(dev->palette)); + else if (param == 0xff) + memcpy(dev->palette, dev->userpal, sizeof(dev->palette)); + else + pgc_error(dev, PGC_ERROR_RANGE); +} + + +/* Save the current palette. */ +static void +hndl_lutsav(pgc_t *dev) +{ + memcpy(dev->userpal, dev->palette, sizeof(dev->palette)); +} + + +/* Handle LUTINT (select palette). */ +static void +hndl_lutint(pgc_t *dev) +{ + uint8_t param; + + if (! pgc_param_byte(dev, ¶m)) return; + + init_lut(dev, param); +} + + +/* Handle LUTRD (read palette register). */ +static void +hndl_lutrd(pgc_t *dev) +{ + uint8_t param; + uint32_t col; + + if (! pgc_param_byte(dev, ¶m)) return; + + col = dev->palette[param]; + + pgc_result_byte(dev, (col >> 20) & 0x0f); + pgc_result_byte(dev, (col >> 12) & 0x0f); + pgc_result_byte(dev, (col >> 4) & 0x0f); +} + + +/* Handle LUT (write palette register). */ +static void +hndl_lut(pgc_t *dev) +{ + uint8_t param[4]; + int n; + + for (n = 0; n < 4; n++) { + if (! pgc_param_byte(dev, ¶m[n])) return; + if (n > 0 && param[n] > 15) { + pgc_error(dev, PGC_ERROR_RANGE); + param[n] &= 0x0f; + } + } + + dev->palette[param[0]] = makecol((param[1] * 0x11), + (param[2] * 0x11), + (param[3] * 0x11)); +} + + +/* + * LUT8RD and LUT8 are extensions implemented by several PGC clones, + * so here are functions that implement them even though they aren't + * used by the PGC. + */ +void +pgc_hndl_lut8rd(pgc_t *dev) +{ + uint8_t param; + uint32_t col; + + if (! pgc_param_byte(dev, ¶m)) return; + + col = dev->palette[param]; + + pgc_result_byte(dev, (col >> 16) & 0xff); + pgc_result_byte(dev, (col >> 8) & 0xff); + pgc_result_byte(dev, col & 0xff); +} + + +void +pgc_hndl_lut8(pgc_t *dev) +{ + uint8_t param[4]; + int n; + + for (n = 0; n < 4; n++) + if (! pgc_param_byte(dev, ¶m[n])) return; + + dev->palette[param[0]] = makecol((param[1]), (param[2]), (param[3])); +} + + +/* Handle AREAPT (set 16x16 fill pattern). */ +static void +hndl_areapt(pgc_t *dev) +{ + int16_t pat[16]; + int n; + + for (n = 0; n < 16; n++) + if (! pgc_param_word(dev, &pat[n])) return; + + pgc_log("PGC: AREAPT(%04x %04x %04x %04x...)\n", + pat[0] & 0xffff, pat[1] & 0xffff, pat[2] & 0xffff, pat[3] & 0xffff); + + memcpy(dev->fill_pattern, pat, sizeof(dev->fill_pattern)); +} + + +/* Handle CA (select ASCII mode). */ +static void +hndl_ca(pgc_t *dev) +{ + dev->ascii_mode = 1; +} + + +/* Handle CX (select hex mode). */ +static void +hndl_cx(pgc_t *dev) +{ + dev->ascii_mode = 0; +} + + +/* + * CA and CX remain valid in hex mode; they are handled + * as command 0x43 ('C') with a one-byte parameter. + */ +static void +hndl_c(pgc_t *dev) +{ + uint8_t param; + + if (! dev->inputbyte(dev, ¶m)) return; + + if (param == 'A') + dev->ascii_mode = 1; + + if (param == 'X') + dev->ascii_mode = 0; +} + + +/* RESETF resets the PGC. */ +static void +hndl_resetf(pgc_t *dev) +{ + pgc_reset(dev); +} + + +/* TJUST sets text justify settings. */ +static void +hndl_tjust(pgc_t *dev) +{ + uint8_t param[2]; + + if (! dev->inputbyte(dev, ¶m[0])) return; + if (! dev->inputbyte(dev, ¶m[1])) return; + + if (param[0] >= 1 && param[0] <= 3 && param[1] >= 1 && param[1] <= 3) { + dev->tjust_h = param[0]; + dev->tjust_v = param[1]; + } else + pgc_error(dev, PGC_ERROR_RANGE); +} + + +/* TSIZE controls text horizontal spacing. */ +static void +hndl_tsize(pgc_t *pgc) +{ + int32_t param = 0; + + if (! pgc_param_coord(pgc, ¶m)) return; + + pgc_log("PGC: TSIZE %i\n", param); + pgc->tsize = param; +} + + +/* + * VWPORT sets up the viewport (roughly, the clip rectangle) in + * raster coordinates, measured from the bottom left of the screen. + */ +static void +hndl_vwport(pgc_t *dev) +{ + int16_t x1, x2, y1, y2; + + if (! pgc_param_word(dev, &x1)) return; + if (! pgc_param_word(dev, &x2)) return; + if (! pgc_param_word(dev, &y1)) return; + if (! pgc_param_word(dev, &y2)) return; + + pgc_log("PGC: VWPORT %i,%i,%i,%i\n", x1,x2,y1,y2); + dev->vp_x1 = x1; + dev->vp_x2 = x2; + dev->vp_y1 = y1; + dev->vp_y2 = y2; +} + + +/* WINDOW defines the coordinate system in use. */ +static void +hndl_window(pgc_t *dev) +{ + int16_t x1, x2, y1, y2; + + if (! pgc_param_word(dev, &x1)) return; + if (! pgc_param_word(dev, &x2)) return; + if (! pgc_param_word(dev, &y1)) return; + if (! pgc_param_word(dev, &y2)) return; + + pgc_log("PGC: WINDOW %i,%i,%i,%i\n", x1,x2,y1,y2); + dev->win_x1 = x1; + dev->win_x2 = x2; + dev->win_y1 = y1; + dev->win_y2 = y2; +} + + +/* + * The list of commands implemented by this mini-PGC. + * + * In order to support the original PGC and clones, we support two lists; + * core commands (listed below) and subclass commands (listed in the clone). + * + * Each row has five parameters: + * ASCII-mode command + * Hex-mode command + * Function that executes this command + * Function that parses this command when building a command list + * Parameter for the parse function + * + * TODO: This list omits numerous commands present in a genuine PGC + * (ARC, AREA, AREABC, BUFFER, CIRCLE etc etc). + * TODO: Some commands don't have a parse function (for example, IMAGEW) + * + * The following ASCII entries have special meaning: + * ~~~~~~ command is valid only in hex mode + * ****** end of subclass command list, now process core command list + * @@@@@@ end of core command list + * + */ +static const pgc_cmd_t pgc_commands[] = { + { "AREAPT", 0xe7, hndl_areapt, pgc_parse_words, 16 }, + { "AP", 0xe7, hndl_areapt, pgc_parse_words, 16 }, + { "~~~~~~", 0x43, hndl_c, NULL, 0 }, + { "CA", 0xd2, hndl_ca, NULL, 0 }, + { "CLBEG", 0x70, hndl_clbeg, NULL, 0 }, + { "CB", 0x70, hndl_clbeg, NULL, 0 }, + { "CLDEL", 0x74, hndl_cldel, pgc_parse_bytes, 1 }, + { "CD", 0x74, hndl_cldel, pgc_parse_bytes, 1 }, + { "CLEND", 0x71, hndl_clend, NULL, 0 }, + { "CLRUN", 0x72, hndl_clrun, pgc_parse_bytes, 1 }, + { "CR", 0x72, hndl_clrun, pgc_parse_bytes, 1 }, + { "CLRD", 0x75, hndl_clread, pgc_parse_bytes, 1 }, + { "CRD", 0x75, hndl_clread, pgc_parse_bytes, 1 }, + { "CLOOP", 0x73, hndl_cloop, NULL, 0 }, + { "CL", 0x73, hndl_cloop, NULL, 0 }, + { "CLEARS", 0x0f, hndl_clears, pgc_parse_bytes, 1 }, + { "CLS", 0x0f, hndl_clears, pgc_parse_bytes, 1 }, + { "COLOR", 0x06, hndl_color, pgc_parse_bytes, 1 }, + { "C", 0x06, hndl_color, pgc_parse_bytes, 1 }, + { "CX", 0xd1, hndl_cx, NULL, 0 }, + { "DISPLA", 0xd0, hndl_display, pgc_parse_bytes, 1 }, + { "DI", 0xd0, hndl_display, pgc_parse_bytes, 1 }, + { "ELIPSE", 0x39, hndl_ellipse, pgc_parse_coords, 2 }, + { "EL", 0x39, hndl_ellipse, pgc_parse_coords, 2 }, + { "IMAGEW", 0xd9, hndl_imagew, NULL, 0 }, + { "IW", 0xd9, hndl_imagew, NULL, 0 }, + { "LINFUN", 0xeb, hndl_linfun, pgc_parse_bytes, 1 }, + { "LF", 0xeb, hndl_linfun, pgc_parse_bytes, 1 }, + { "LINPAT", 0xea, hndl_linpat, pgc_parse_words, 1 }, + { "LP", 0xea, hndl_linpat, pgc_parse_words, 1 }, + { "LUTINT", 0xec, hndl_lutint, pgc_parse_bytes, 1 }, + { "LI", 0xec, hndl_lutint, pgc_parse_bytes, 1 }, + { "LUTRD", 0x50, hndl_lutrd, pgc_parse_bytes, 1 }, + { "LUTSAV", 0xed, hndl_lutsav, NULL, 0 }, + { "LUT", 0xee, hndl_lut, pgc_parse_bytes, 4 }, + { "MOVE", 0x10, hndl_move, pgc_parse_coords, 2 }, + { "M", 0x10, hndl_move, pgc_parse_coords, 2 }, + { "MOVE3", 0x12, hndl_move3, pgc_parse_coords, 3 }, + { "M3", 0x12, hndl_move3, pgc_parse_coords, 3 }, + { "MOVER", 0x11, hndl_mover, pgc_parse_coords, 2 }, + { "MR", 0x11, hndl_mover, pgc_parse_coords, 2 }, + { "MOVER3", 0x13, hndl_mover3, pgc_parse_coords, 3 }, + { "MR3", 0x13, hndl_mover3, pgc_parse_coords, 3 }, + { "PRMFIL", 0xe9, hndl_prmfil, pgc_parse_bytes, 1 }, + { "PF", 0xe9, hndl_prmfil, pgc_parse_bytes, 1 }, + { "POLY", 0x30, hndl_poly, parse_poly, 0 }, + { "P", 0x30, hndl_poly, parse_poly, 0 }, + { "RESETF", 0x04, hndl_resetf, NULL, 0 }, + { "RF", 0x04, hndl_resetf, NULL, 0 }, + { "TJUST", 0x85, hndl_tjust, pgc_parse_bytes, 2 }, + { "TJ", 0x85, hndl_tjust, pgc_parse_bytes, 2 }, + { "TSIZE", 0x81, hndl_tsize, pgc_parse_coords, 1 }, + { "TS", 0x81, hndl_tsize, pgc_parse_coords, 1 }, + { "VWPORT", 0xb2, hndl_vwport, pgc_parse_words, 4 }, + { "VWP", 0xb2, hndl_vwport, pgc_parse_words, 4 }, + { "WINDOW", 0xb3, hndl_window, pgc_parse_words, 4 }, + { "WI", 0xb3, hndl_window, pgc_parse_words, 4 }, + + { "@@@@@@", 0x00, NULL, NULL, 0 } +}; + + +/* When the wake timer expires, that's when the drawing thread is actually + * woken */ +static void +wake_timer(void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: woke up\n"); +#endif + + thread_set_event(dev->pgc_wake_thread); +} + + +/* + * The PGC drawing thread main loop. + * + * Read in commands and execute them ad infinitum. + */ +static void +pgc_thread(void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + const pgc_cmd_t *cmd; + +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: thread begins\n"); +#endif + + for (;;) { + if (! parse_command(dev, &cmd)) { + /* Are we shutting down? */ + if (dev->stopped) { +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: Thread stopping...\n"); +#endif + dev->stopped = 0; + break; + } + + /* Nope, just a reset. */ + continue; + } + + pgc_log("PGC: Command: [%02x] '%s' found = %i\n", + dev->hex_command, dev->asc_command, (cmd != NULL)); + + if (cmd) { + dev->result_count = 0; + (*cmd->handler)(dev); + } else + pgc_error(dev, PGC_ERROR_OPCODE); + } + +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: thread stopped\n"); +#endif +} + + +/* Parameter passed is not a number: abort. */ +static int +err_digit(pgc_t *dev) +{ + uint8_t asc; + + do { + /* Swallow everything until the next separator */ + if (! dev->inputbyte(dev, &asc)) return 0; + } while (! is_whitespace(asc)); + + pgc_error(dev, PGC_ERROR_DIGIT); + + return 0; +} + + +/* Output a byte, either as hex or ASCII depending on the mode. */ +int +pgc_result_byte(pgc_t *dev, uint8_t val) +{ + char buf[20]; + + if (! dev->ascii_mode) + return output_byte(dev, val); + + if (dev->result_count) { + if (! output_byte(dev, ',')) return 0; + } + sprintf(buf, "%i", val); + dev->result_count++; + + return output_string(dev, buf); +} + + +/* Output a word, either as hex or ASCII depending on the mode. */ +int +pgc_result_word(pgc_t *dev, int16_t val) +{ + char buf[20]; + + if (! dev->ascii_mode) { + if (! output_byte(dev, val & 0xFF)) return 0; + return output_byte(dev, val >> 8); + } + + if (dev->result_count) { + if (! output_byte(dev, ',')) return 0; + } + sprintf(buf, "%i", val); + dev->result_count++; + + return output_string(dev, buf); +} + + +/* Report an error, either in ASCII or in hex. */ +int +pgc_error(pgc_t *dev, int err) +{ + if (dev->mapram[0x307]) { + /* Errors enabled? */ + if (dev->ascii_mode) { + if (err >= PGC_ERROR_RANGE && err <= PGC_ERROR_MISSING) + return error_string(dev, pgc_err_msgs[err]); + return error_string(dev, "Unknown error\r"); + } else { + return error_byte(dev, err); + } + } + + return 1; +} + + +/* Initialize RAM and registers to default values. */ +void +pgc_reset(pgc_t *dev) +{ + int n; + + memset(dev->mapram, 0x00, sizeof(dev->mapram)); + + /* The 'CGA disable' jumper is not currently implemented. */ + dev->mapram[0x30b] = dev->cga_enabled = 1; + dev->mapram[0x30c] = dev->cga_enabled; + dev->mapram[0x30d] = dev->cga_enabled; + + dev->mapram[0x3f8] = 0x03; /* minor version */ + dev->mapram[0x3f9] = 0x01; /* minor version */ + dev->mapram[0x3fb] = 0xa5; /* } */ + dev->mapram[0x3fc] = 0x5a; /* PGC self-test passed */ + dev->mapram[0x3fd] = 0x55; /* } */ + dev->mapram[0x3fe] = 0x5a; /* } */ + + dev->ascii_mode = 1; /* start off in ASCII mode */ + dev->line_pattern = 0xffff; + memset(dev->fill_pattern, 0xff, sizeof(dev->fill_pattern)); + dev->color = 0xff; + dev->tjust_h = 1; + dev->tjust_v = 1; + + /* Reset panning. */ + dev->pan_x = 0; + dev->pan_y = 0; + + /* Reset clipping. */ + dev->vp_x1 = 0; + dev->vp_y1 = 0; + dev->vp_x2 = dev->visw - 1; + dev->vp_y2 = dev->vish - 1; + + /* Empty command lists. */ + for (n = 0; n < 256; n++) { + dev->clist[n].wrptr = 0; + dev->clist[n].rdptr = 0; + dev->clist[n].repeat = 0; + dev->clist[n].chain = 0; + } + dev->clcur = NULL; + + /* Select CGA display. */ + dev->cga_selected = -1; + pgc_setdisplay(dev, dev->cga_enabled); + + /* Default palette is 0. */ + init_lut(dev, 0); + hndl_lutsav(dev); +} + + +/* Switch between CGA mode (DISPLAY 1) and native mode (DISPLAY 0). */ +void +pgc_setdisplay(pgc_t *dev, int cga) +{ + pgc_log("PGC: setdisplay(%i): cga_selected=%i cga_enabled=%i\n", + cga, dev->cga_selected, dev->cga_enabled); + + if (dev->cga_selected != (dev->cga_enabled && cga)) { + dev->cga_selected = (dev->cga_enabled && cga); + dev->displine = 0; + + if (dev->cga_selected) { + mem_mapping_enable(&dev->cga_mapping); + dev->screenw = PGC_CGA_WIDTH; + dev->screenh = PGC_CGA_HEIGHT; + } else { + mem_mapping_disable(&dev->cga_mapping); + dev->screenw = dev->visw; + dev->screenh = dev->vish; + } + + pgc_recalctimings(dev); + } +} + + +/* + * When idle, the PGC drawing thread sleeps. pgc_wake() awakens it - but + * not immediately. Like the Voodoo, it has a short delay so that writes + * can be batched. + */ +void +pgc_wake(pgc_t *dev) +{ + if (!timer_is_enabled(&dev->wake_timer)) + timer_set_delay_u64(&dev->wake_timer, WAKE_DELAY); +} + + +/* Wait for more input data, or for output to drain. */ +void +pgc_sleep(pgc_t *dev) +{ + uint8_t *n = NULL; + pgc_log("PGC: sleeping on %i %i %i %i 0x%02x 0x%02x\n", + dev->stopped, + dev->waiting_input_fifo, dev->waiting_output_fifo, + dev->waiting_error_fifo, dev->mapram[0x300], dev->mapram[0x301]); + + /* Avoid entering waiting state. */ + if (dev->stopped) { + dev->waiting_input_fifo = 0; + dev->waiting_output_fifo = 0; + *n = 0; + return; + } + + /* Race condition: If host wrote to the PGC during the that + * won't be noticed */ + if (dev->waiting_input_fifo && + dev->mapram[0x300] != dev->mapram[0x301]) { + dev->waiting_input_fifo = 0; + return; + } + + /* Same if they read. */ + if (dev->waiting_output_fifo && + dev->mapram[0x302] != (uint8_t)(dev->mapram[0x303] - 1)) { + dev->waiting_output_fifo = 0; + return; + } + + thread_wait_event(dev->pgc_wake_thread, -1); + thread_reset_event(dev->pgc_wake_thread); +} + + +/* Pull the next byte from the current command list. */ +int +pgc_clist_byte(pgc_t *dev, uint8_t *val) +{ + if (dev->clcur == NULL) return 0; + + if (dev->clcur->rdptr < dev->clcur->wrptr) + *val = dev->clcur->list[dev->clcur->rdptr++]; + else + *val = 0; + + /* If we've reached the end, reset to the beginning and + * (if repeating) run the repeat */ + if (dev->clcur->rdptr >= dev->clcur->wrptr) { + dev->clcur->rdptr = 0; + dev->clcur->repeat--; + if (dev->clcur->repeat == 0) + dev->clcur = dev->clcur->chain; + } + + return 1; +} + + +/* + * Read in a byte, either as hex (1 byte) or ASCII (decimal). + * Returns 0 if PGC reset detected while the value is being read. + */ +int +pgc_param_byte(pgc_t *dev, uint8_t *val) +{ + int32_t c; + + if (dev->clcur) + return pgc_clist_byte(dev, val); + + if (! dev->ascii_mode) + return dev->inputbyte(dev, val); + + if (! pgc_param_coord(dev, &c)) return 0; + + c = (c >> 16); /* drop fractional part */ + if (c > 255) { + pgc_error(dev, PGC_ERROR_RANGE); + return 0; + } + *val = (uint8_t)c; + + return 1; +} + + +/* + * Read in a word, either as hex (2 bytes) or ASCII (decimal). + * Returns 0 if PGC reset detected while the value is being read. + */ +int +pgc_param_word(pgc_t *dev, int16_t *val) +{ + uint8_t lo, hi; + int32_t c; + + if (dev->clcur) { + if (! pgc_clist_byte(dev, &lo)) return 0; + if (! pgc_clist_byte(dev, &hi)) return 0; + *val = (((int16_t)hi) << 8) | lo; + + return 1; + } + + if (! dev->ascii_mode) { + if (! dev->inputbyte(dev, &lo)) return 0; + if (! dev->inputbyte(dev, &hi)) return 0; + *val = (((int16_t)hi) << 8) | lo; + + return 1; + } + + if (! pgc_param_coord(dev, &c)) return 0; + + c = (c >> 16); + if (c > 0x7fff || c < -0x7fff) { + pgc_error(dev, PGC_ERROR_RANGE); + return 0; + } + *val = (int16_t)c; + + return 1; +} + + +typedef enum { + PS_MAIN, + PS_FRACTION, + PS_EXPONENT +} parse_state_t; + + +/* + * Read in a PGC coordinate. + * + * Either as hex (4 bytes) or ASCII (xxxx.yyyyEeee) + * + * Returns 0 if PGC reset detected while the value is being read. + */ +int +pgc_param_coord(pgc_t *dev, int32_t *value) +{ + uint8_t asc; + int sign = 1; + int esign = 1; + int n; + uint16_t dp = 1; + uint16_t integer = 0; + uint16_t frac = 0; + uint16_t exponent = 0; + uint32_t res; + parse_state_t state = PS_MAIN; + uint8_t encoded[4]; + + /* If there is a command list running, pull the bytes out of that + * command list */ + if (dev->clcur) { + for (n = 0; n < 4; n++) + if (! pgc_clist_byte(dev, &encoded[n])) return 0; + integer = (((int16_t)encoded[1]) << 8) | encoded[0]; + frac = (((int16_t)encoded[3]) << 8) | encoded[2]; + + *value = (((int32_t)integer) << 16) | frac; + return 1; + } + + /* If in hex mode, read in the encoded integer and fraction parts + * from the hex stream */ + if (! dev->ascii_mode) { + for (n = 0; n < 4; n++) + if (! dev->inputbyte(dev, &encoded[n])) return 0; + integer = (((int16_t)encoded[1]) << 8) | encoded[0]; + frac = (((int16_t)encoded[3]) << 8) | encoded[2]; + + *value = (((int32_t)integer) << 16) | frac; + return 1; + } + + /* Parsing an ASCII value; skip separators. */ + do { + if (! dev->inputbyte(dev, &asc)) return 0; + if (asc == '-') sign = -1; + } while (is_whitespace(asc)); + + /* There had better be a digit next. */ + if (! isdigit(asc)) { + pgc_error(dev, PGC_ERROR_MISSING); + return 0; + } + + do { + switch (asc) { + /* Decimal point is acceptable in 'main' state + * (start of fraction) not otherwise */ + case '.': + if (state == PS_MAIN) { + if (! dev->inputbyte(dev, &asc)) return 0; + state = PS_FRACTION; + continue; + } else { + pgc_error(dev, PGC_ERROR_MISSING); + return err_digit(dev); + } + break; + + /* Scientific notation. */ + case 'd': + case 'D': + case 'e': + case 'E': + esign = 1; + if (! dev->inputbyte(dev, &asc)) return 0; + if (asc == '-') { + sign = -1; + if (! dev->inputbyte(dev, &asc)) return 0; + } + state = PS_EXPONENT; + continue; + + /* Should be a number or a separator. */ + default: + if (is_whitespace(asc)) break; + if (! isdigit(asc)) { + pgc_error(dev, PGC_ERROR_MISSING); + return err_digit(dev); + } + asc -= '0'; /* asc is digit */ + + switch (state) { + case PS_MAIN: + integer = (integer * 10)+asc; + if (integer & 0x8000) { + /* Overflow */ + pgc_error(dev, PGC_ERROR_RANGE); + integer = 0x7fff; + } + break; + + case PS_FRACTION: + frac = (frac * 10) + asc; + dp *= 10; + break; + + case PS_EXPONENT: + exponent = (exponent * 10)+asc; + break; + } + + } + + if (! dev->inputbyte(dev, &asc)) return 0; + } while (! is_whitespace(asc)); + + res = (frac << 16) / dp; + pgc_log("PGC: integer=%u frac=%u exponent=%u dp=%i res=0x%08lx\n", + integer, frac, exponent, dp, res); + + res = (res & 0xffff) | (integer << 16); + if (exponent) { + for (n = 0; n < exponent; n++) { + if (esign > 0) + res *= 10; + else + res /= 10; + } + } + *value = sign*res; + + return 1; +} + + +/* + * Add a byte to a command list. + * + * We allow command lists to be arbitrarily large. + */ +int +pgc_cl_append(pgc_cl_t *list, uint8_t v) +{ + uint8_t *buf; + + if (list->listmax == 0 || list->list == NULL) { + list->list = (uint8_t *)malloc(4096); + if (!list->list) { +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: out of memory initializing command list\n"); +#endif + return 0; + } + list->listmax = 4096; + } + + while (list->wrptr >= list->listmax) { + buf = (uint8_t *)realloc(list->list, 2 * list->listmax); + if (!buf) { +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: out of memory growing command list\n"); +#endif + return 0; + } + list->list = buf; + list->listmax *= 2; + } + + list->list[list->wrptr++] = v; + + return 1; +} + + +/* Parse but don't execute a command with a fixed number of byte parameters. */ +int +pgc_parse_bytes(pgc_t *dev, pgc_cl_t *cl, int count) +{ + uint8_t *param = (uint8_t *)malloc(count); + int n; + + if (! param) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + return 0; + } + + for (n = 0; n < count; n++) { + if (! pgc_param_byte(dev, ¶m[n])) { + free(param); + return 0; + } + + if (! pgc_cl_append(cl, param[n])) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + free(param); + return 0; + } + } + + free(param); + + return 1; +} + + +/* Parse but don't execute a command with a fixed number of word parameters. */ +int +pgc_parse_words(pgc_t *dev, pgc_cl_t *cl, int count) +{ + int16_t *param = (int16_t *)malloc(count * sizeof(int16_t)); + int n; + + if (! param) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + return 0; + } + + for (n = 0; n < count; n++) { + if (! pgc_param_word(dev, ¶m[n])) return 0; + + if (!pgc_cl_append(cl, param[n] & 0xff) || + !pgc_cl_append(cl, param[n] >> 8)) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + free(param); + return 0; + } + } + + free(param); + + return 1; +} + + +/* Parse but don't execute a command with a fixed number of coord parameters */ +int +pgc_parse_coords(pgc_t *dev, pgc_cl_t *cl, int count) +{ + int32_t *param = (int32_t *)malloc(count * sizeof(int32_t)); + int n; + + if (! param) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + return 0; + } + + for (n = 0; n < count; n++) + if (! pgc_param_coord(dev, ¶m[n])) return 0; + + /* Here is how the real PGC serializes coords: + * + * 100.5 -> 64 00 00 80 ie 0064.8000 + * 100.3 -> 64 00 CD 4C ie 0064.4CCD + */ + for (n = 0; n < count; n++) { + /* Serialize integer part. */ + if (!pgc_cl_append(cl, (param[n] >> 16) & 0xff) || + !pgc_cl_append(cl, (param[n] >> 24) & 0xff) || + + /* Serialize fraction part. */ + !pgc_cl_append(cl, (param[n] ) & 0xff) || + !pgc_cl_append(cl, (param[n] >> 8) & 0xff)) { + pgc_error(dev, PGC_ERROR_OVERFLOW); + free(param); + return 0; + } + } + + free(param); + + return 1; +} + + +/* Convert coordinates based on the current window / viewport to raster + * coordinates. */ +void +pgc_dto_raster(pgc_t *dev, double *x, double *y) +{ +#ifdef ENABLE_PGC_LOG + double x0 = *x, y0 = *y; +#endif + + *x += (dev->vp_x1 - dev->win_x1); + *y += (dev->vp_y1 - dev->win_y1); + + pgc_log("PGC: coords to raster: (%f, %f) -> (%f, %f)\n", x0, y0, *x, *y); +} + + +/* Overloads that take ints. */ +void +pgc_sto_raster(pgc_t *dev, int16_t *x, int16_t *y) +{ + double xd = *x, yd = *y; + + pgc_dto_raster(dev, &xd, &yd); + *x = (int16_t)xd; + *y = (int16_t)yd; +} + + +void +pgc_ito_raster(pgc_t *dev, int32_t *x, int32_t *y) +{ + double xd = *x, yd = *y; + + pgc_dto_raster(dev, &xd, &yd); + *x = (int32_t)xd; + *y = (int32_t)yd; +} + + +void +pgc_recalctimings(pgc_t *dev) +{ + double disptime, _dispontime, _dispofftime; + double pixel_clock = (cpuclock * (double)(1ull << 32)) / (dev->cga_selected ? 25175000.0 : dev->native_pixel_clock); + + /* Use a fixed 640x400 display. */ + disptime = dev->screenw + 11; + _dispontime = dev->screenw * pixel_clock; + _dispofftime = (disptime - dev->screenw) * pixel_clock; + dev->dispontime = (uint64_t)(_dispontime); + dev->dispofftime = (uint64_t)(_dispofftime); +} + + +/* Write to CGA registers are copied into the transfer memory buffer. */ +void +pgc_out(uint16_t addr, uint8_t val, void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + + pgc_log("PGC: out(%04x, %02x)\n", addr, val); + + switch(addr) { + case 0x03d0: /* CRTC Index register */ + case 0x03d2: + case 0x03d4: + case 0x03d6: + dev->mapram[0x03d0] = val; + break; + + case 0x03d1: /* CRTC Data register */ + case 0x03d3: + case 0x03d5: + case 0x03d7: + if (dev->mapram[0x03d0] < 18) + dev->mapram[0x03e0 + dev->mapram[0x03d0]] = val; + break; + + case 0x03d8: /* CRTC Mode Control register */ + dev->mapram[0x03d8] = val; + break; + + case 0x03d9: /* CRTC Color Select register */ + dev->mapram[0x03d9] = val; + break; + } +} + + +/* Read back the CGA registers. */ +uint8_t +pgc_in(uint16_t addr, void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + uint8_t ret = 0xff; + + switch(addr) { + case 0x03d0: /* CRTC Index register */ + case 0x03d2: + case 0x03d4: + case 0x03d6: + ret = dev->mapram[0x03d0]; + break; + + case 0x03d1: /* CRTC Data register */ + case 0x03d3: + case 0x03d5: + case 0x03d7: + if (dev->mapram[0x03d0] < 18) + ret = dev->mapram[0x03e0 + dev->mapram[0x03d0]]; + break; + + case 0x03d8: /* CRTC Mode Control register */ + ret = dev->mapram[0x03d8]; + break; + + case 0x03d9: /* CRTC Color Select register */ + ret = dev->mapram[0x03d9]; + break; + + case 0x03da: /* CRTC Status register */ + ret = dev->mapram[0x03da]; + break; + } + + pgc_log("PGC: in(%04x) = %02x\n", addr, ret); + + return ret; +} + + +/* Memory write to the transfer buffer. */ +/* TODO: Check the CGA mapping repeat stuff. */ +void +pgc_write(uint32_t addr, uint8_t val, void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + + /* + * It seems variable whether the PGC maps 1K or 2K at 0xc6000. + * + * Map 2K here in case a clone requires it. + */ + if (addr >= 0xc6000 && addr < 0xc6800) { + addr &= 0x7ff; + + /* If one of the FIFOs has been updated, this may cause + * the drawing thread to be woken */ + + if (dev->mapram[addr] != val) { + dev->mapram[addr] = val; + + switch (addr) { + case 0x300: /* input write pointer */ + if (dev->waiting_input_fifo && + dev->mapram[0x300] != dev->mapram[0x301]) { + dev->waiting_input_fifo = 0; + pgc_wake(dev); + } + break; + + case 0x303: /* output read pointer */ + if (dev->waiting_output_fifo && + dev->mapram[0x302] != (uint8_t)(dev->mapram[0x303] - 1)) { + dev->waiting_output_fifo = 0; + pgc_wake(dev); + } + break; + + case 0x305: /* error read pointer */ + if (dev->waiting_error_fifo && + dev->mapram[0x304] != (uint8_t)(dev->mapram[0x305] - 1)) { + dev->waiting_error_fifo = 0; + pgc_wake(dev); + } + break; + + case 0x306: /* cold start flag */ + /* XXX This should be in IM-1024 specific code */ + dev->mapram[0x306] = 0; + break; + + case 0x30c: /* display type */ + pgc_setdisplay(priv, dev->mapram[0x30c]); + dev->mapram[0x30d] = dev->mapram[0x30c]; + break; + + case 0x3ff: /* reboot the PGC */ + pgc_wake(dev); + break; + } + } + } + + if (addr >= 0xb8000 && addr < 0xc0000 && dev->cga_selected) { + addr &= 0x3fff; + dev->cga_vram[addr] = val; + } +} + + +/* TODO: Check the CGA mapping repeat stuff. */ +uint8_t +pgc_read(uint32_t addr, void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + uint8_t ret = 0xff; + + if (addr >= 0xc6000 && addr < 0xc6800) { + addr &= 0x7ff; + ret = dev->mapram[addr]; + } else if (addr >= 0xb8000 && addr < 0xc0000 && dev->cga_selected) { + addr &= 0x3fff; + ret = dev->cga_vram[addr]; + } + + return ret; +} + + +/* Draw the display in CGA (640x400) text mode. */ +void +pgc_cga_text(pgc_t *dev, int w) +{ + int x, c; + uint8_t chr, attr; + int drawcursor = 0; + uint32_t cols[2]; + int pitch = (dev->mapram[0x3e9] + 1) * 2; + uint16_t sc = (dev->displine & 0x0f) % pitch; + uint16_t ma = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; + uint16_t ca = (dev->mapram[0x3ef] | (dev->mapram[0x3ee] << 8)) & 0x3fff; + uint8_t *addr; + uint32_t val; + int cw = (w == 80) ? 8 : 16; + + addr = &dev->cga_vram[(((ma << 1) + ((dev->displine / pitch)*w)) * 2) & 0x3ffe]; + ma += (dev->displine / pitch) * w; + + for (x = 0; x < w; x++) { + chr = *addr++; + attr = *addr++; + + /* Cursor enabled? */ + if (ma == ca && (dev->cgablink & 8) && + (dev->mapram[0x3ea] & 0x60) != 0x20) { + drawcursor = ((dev->mapram[0x3ea] & 0x1f) <= (sc >> 1)) && + ((dev->mapram[0x3eb] & 0x1f) >= (sc >> 1)); + } else + drawcursor = 0; + + if (dev->mapram[0x3d8] & 0x20) { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((dev->cgablink & 8) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + + for (c = 0; c < cw; c++) { + if (drawcursor) + val = cols[(fontdatm[chr + dev->fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f; + else + val = cols[(fontdatm[chr + dev->fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[dev->displine][(x * cw) + c] = val; + } + + ma++; + } +} + + +/* Draw the display in CGA (320x200) graphics mode. */ +void +pgc_cga_gfx40(pgc_t *dev) +{ + int x, c; + uint32_t cols[4]; + int col; + uint16_t ma = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; + uint8_t *addr; + uint16_t dat; + + cols[0] = (dev->mapram[0x3d9] & 15) + 16; + col = ((dev->mapram[0x3d9] & 16) ? 8 : 0) + 16; + + /* From John Elliott's site: + On a real CGA, if bit 2 of port 03D8h and bit 5 of port 03D9h are both set, + the palette used in graphics modes is red/cyan/white. On a PGC, it's + magenta/cyan/white. You still get red/cyan/white if bit 5 of port 03D9h is + not set. This is a firmware issue rather than hardware. */ + if (dev->mapram[0x3d9] & 32) { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } else if (dev->mapram[0x3d8] & 4) { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } else { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + + for (x = 0; x < 40; x++) { + addr = &dev->cga_vram[(ma + 2 * x + 80 * (dev->displine >> 2) + 0x2000 * ((dev->displine >> 1) & 1)) & 0x3fff]; + dat = (addr[0] << 8) | addr[1]; + dev->ma++; + for (c = 0; c < 8; c++) { + buffer32->line[dev->displine][(x << 4) + (c << 1)] = + buffer32->line[dev->displine][(x << 4) + (c << 1) + 1] = cols[dat >> 14]; + dat <<= 2; + } + } +} + + +/* Draw the display in CGA (640x200) graphics mode. */ +void +pgc_cga_gfx80(pgc_t *dev) +{ + int x, c; + uint32_t cols[2]; + uint16_t ma = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; + uint8_t *addr; + uint16_t dat; + + cols[0] = 16; + cols[1] = (dev->mapram[0x3d9] & 15) + 16; + + for (x = 0; x < 40; x++) { + addr = &dev->cga_vram[(ma + 2 * x + 80 * (dev->displine >> 2) + 0x2000 * ((dev->displine >> 1) & 1)) & 0x3fff]; + dat = (addr[0] << 8) | addr[1]; + dev->ma++; + for (c = 0; c < 16; c++) { + buffer32->line[dev->displine][(x << 4) + c] = cols[dat >> 15]; + dat <<= 1; + } + } +} + + +/* Draw the screen in CGA mode. */ +void +pgc_cga_poll(pgc_t *dev) +{ + uint32_t cols[2]; + + if (! dev->linepos) { + timer_advance_u64(&dev->timer, dev->dispofftime); + dev->mapram[0x03da] |= 1; + dev->linepos = 1; + + if (dev->cgadispon) { + if (dev->displine == 0) + video_wait_for_buffer(); + + if ((dev->mapram[0x03d8] & 0x12) == 0x12) + pgc_cga_gfx80(dev); + else if (dev->mapram[0x03d8] & 0x02) + pgc_cga_gfx40(dev); + else if (dev->mapram[0x03d8] & 0x01) + pgc_cga_text(dev, 80); + else + pgc_cga_text(dev, 40); + } else { + cols[0] = ((dev->mapram[0x03d8] & 0x12) == 0x12) ? 0 : ((dev->mapram[0x03d9] & 15) + 16); + hline(buffer32, 0, dev->displine, PGC_CGA_WIDTH, cols[0]); + } + + if (++dev->displine == PGC_CGA_HEIGHT) { + dev->mapram[0x3da] |= 8; + dev->cgadispon = 0; + } + if (dev->displine == PGC_CGA_HEIGHT + 32) { + dev->mapram[0x3da] &= ~8; + dev->cgadispon = 1; + dev->displine = 0; + } + } else { + if (dev->cgadispon) + dev->mapram[0x3da] &= ~1; + timer_advance_u64(&dev->timer, dev->dispontime); + dev->linepos = 0; + + if (dev->displine == PGC_CGA_HEIGHT) { + if (PGC_CGA_WIDTH != xsize || PGC_CGA_HEIGHT != ysize) { + xsize = PGC_CGA_WIDTH; + ysize = PGC_CGA_HEIGHT; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen_8(0, 0, 0, ysize, xsize, ysize); + frames++; + + /* We have a fixed 640x400 screen for CGA modes. */ + video_res_x = PGC_CGA_WIDTH; + video_res_y = PGC_CGA_HEIGHT; + switch (dev->mapram[0x3d8] & 0x12) { + case 0x12: + video_bpp = 1; + break; + + case 0x02: + video_bpp = 2; + break; + + default: + video_bpp = 0; + break; + } + dev->cgablink++; + } + } +} + + +/* Draw the screen in CGA or native mode. */ +void +pgc_poll(void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + uint32_t x, y; + + if (dev->cga_selected) { + pgc_cga_poll(dev); + return; + } + + /* Not CGA, so must be native mode. */ + if (! dev->linepos) { + timer_advance_u64(&dev->timer, dev->dispofftime); + dev->mapram[0x3da] |= 1; + dev->linepos = 1; + if (dev->cgadispon && (uint32_t)dev->displine < dev->maxh) { + if (dev->displine == 0) + video_wait_for_buffer(); + + /* Don't know why pan needs to be multiplied by -2, but + * the IM1024 driver uses PAN -112 for an offset of + * 224. */ + y = dev->displine - 2 * dev->pan_y; + for (x = 0; x < dev->screenw; x++) { + if (x + dev->pan_x < dev->maxw) + buffer32->line[dev->displine][x] = dev->palette[dev->vram[y * dev->maxw + x]]; + else + buffer32->line[dev->displine][x] = dev->palette[0]; + } + } else { + hline(buffer32, 0, dev->displine, dev->screenw, dev->palette[0]); + } + + if (++dev->displine == dev->screenh) { + dev->mapram[0x3da] |= 8; + dev->cgadispon = 0; + } + + if (dev->displine == dev->screenh + 32) { + dev->mapram[0x3da] &= ~8; + dev->cgadispon = 1; + dev->displine = 0; + } + } else { + if (dev->cgadispon) + dev->mapram[0x3da] &= ~1; + timer_advance_u64(&dev->timer, dev->dispontime); + dev->linepos = 0; + + if (dev->displine == dev->screenh) { + if (dev->screenw != xsize || dev->screenh != ysize) { + xsize = dev->screenw; + ysize = dev->screenh; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + frames++; + + video_res_x = dev->screenw; + video_res_y = dev->screenh; + video_bpp = 8; + dev->cgablink++; + } + } +} + + +void +pgc_speed_changed(void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + + pgc_recalctimings(dev); +} + + +void +pgc_close(void *priv) +{ + pgc_t *dev = (pgc_t *)priv; + + /* + * Close down the worker thread by setting a + * flag, and then simulating a reset so it + * stops reading data. + */ +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: telling thread to stop...\n"); +#endif + dev->stopped = 1; + dev->mapram[0x3ff] = 1; + if (dev->waiting_input_fifo || dev->waiting_output_fifo) { + /* Do an immediate wake-up. */ + wake_timer(priv); + } + + /* Wait for thread to stop. */ +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: waiting for thread to stop...\n"); +#endif + // while (dev->stopped); + thread_wait(dev->pgc_thread, -1); +#ifdef ENABLE_PGC_LOG + pgc_log("PGC: thread stopped, closing up.\n"); +#endif + + if (dev->cga_vram) + free(dev->cga_vram); + if (dev->vram) + free(dev->vram); + + free(dev); +} + + +/* + * Initialization code common to the PGC and its subclasses. + * + * Pass the 'input byte' function in since this is overridden in + * the IM-1024, and needs to be set before the drawing thread is + * launched. + */ +void +pgc_init(pgc_t *dev, int maxw, int maxh, int visw, int vish, + int (*inpbyte)(pgc_t *, uint8_t *), double npc) +{ + int i; + + /* Make it a 16k mapping at C4000 (will be C4000-C7FFF), + because of the emulator's granularity - the original + mapping will conflict with hard disk controller BIOS'es. */ + // mem_mapping_add(&dev->mapping, 0xc6000, 2048, + mem_mapping_add(&dev->mapping, 0xc4000, 16384, + pgc_read,NULL,NULL, pgc_write,NULL,NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + mem_mapping_add(&dev->cga_mapping, 0xb8000, 32768, + pgc_read,NULL,NULL, pgc_write,NULL,NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + + io_sethandler(0x03d0, 16, + pgc_in,NULL,NULL, pgc_out,NULL,NULL, dev); + + dev->maxw = maxw; + dev->maxh = maxh; + dev->visw = visw; + dev->vish = vish; + + dev->vram = (uint8_t *)malloc(maxw * maxh); + memset(dev->vram, 0x00, maxw * maxh); + dev->cga_vram = (uint8_t *)malloc(16384); + memset(dev->cga_vram, 0x00, 16384); + + /* Create and initialize command lists. */ + dev->clist = (pgc_cl_t *)malloc(256 * sizeof(pgc_cl_t)); + memset(dev->clist, 0x00, 256 * sizeof(pgc_cl_t)); + for (i = 0; i < 256; i++) { + dev->clist[i].list = NULL; + dev->clist[i].listmax = 0; + dev->clist[i].wrptr = 0; + dev->clist[i].rdptr = 0; + dev->clist[i].repeat = 0; + dev->clist[i].chain = NULL; + } + dev->clcur = NULL; + dev->native_pixel_clock = npc; + + pgc_reset(dev); + + dev->inputbyte = inpbyte; + dev->master = dev->commands = pgc_commands; + dev->pgc_wake_thread = thread_create_event(); + dev->pgc_thread = thread_create(pgc_thread, dev); + + timer_add(&dev->timer, pgc_poll, dev, 1); + + timer_add(&dev->wake_timer, wake_timer, dev, 0); +} + + +static void * +pgc_standalone_init(const device_t *info) +{ + pgc_t *dev; + + dev = (pgc_t *)malloc(sizeof(pgc_t)); + memset(dev, 0x00, sizeof(pgc_t)); + dev->type = info->local; + + /* Framebuffer and screen are both 640x480. */ + pgc_init(dev, 640, 480, 640, 480, input_byte, 25175000.0); + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_pgc); + + return(dev); +} + + +static const device_config_t pgc_config[] = { + { + "", "", -1 + } +}; + + +const device_t pgc_device = { + "PGC", + DEVICE_ISA, 0, + pgc_standalone_init, + pgc_close, + NULL, + NULL, + pgc_speed_changed, + NULL, + pgc_config +}; diff --git a/src/video/vid_pgc.h b/src/video/vid_pgc.h new file mode 100644 index 000000000..82ef899ea --- /dev/null +++ b/src/video/vid_pgc.h @@ -0,0 +1,187 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the PGC driver. + * + * Version: @(#)vid_pgc.h 1.0.2 2019/03/03 + * + * Authors: Fred N. van Kempen, + * John Elliott, + * + * Copyright 2019 Fred N. van Kempen. + * Copyright 2019 John Elliott. + */ +#ifndef VID_PGC_H +# define VID_PGC_H + + +#define PGC_ERROR_RANGE 0x01 +#define PGC_ERROR_INTEGER 0x02 +#define PGC_ERROR_MEMORY 0x03 +#define PGC_ERROR_OVERFLOW 0x04 +#define PGC_ERROR_DIGIT 0x05 +#define PGC_ERROR_OPCODE 0x06 +#define PGC_ERROR_RUNNING 0x07 +#define PGC_ERROR_STACK 0x08 +#define PGC_ERROR_TOOLONG 0x09 +#define PGC_ERROR_AREA 0x0A +#define PGC_ERROR_MISSING 0x0B + + +struct pgc; + +typedef struct pgc_cl { + uint8_t *list; + uint32_t listmax; + uint32_t wrptr; + uint32_t rdptr; + uint32_t repeat; + struct pgc_cl *chain; +} pgc_cl_t; + +typedef struct pgc_cmd { + char ascii[6]; + uint8_t hex; + void (*handler)(struct pgc *); + int (*parser) (struct pgc *, pgc_cl_t *, int); + int p; +} pgc_cmd_t; + +typedef struct pgc { + int8_t type; /* board type */ + int8_t cga_enabled; + int8_t cga_selected; + volatile int8_t stopped; + + mem_mapping_t mapping; + mem_mapping_t cga_mapping; + + pgc_cl_t *clist, + *clcur; + const pgc_cmd_t *master, + *commands; + + uint8_t mapram[2048]; /* host <> PGC communication buffer */ + uint8_t *cga_vram; + uint8_t *vram; + char asc_command[7]; + uint8_t hex_command; + uint32_t palette[256]; + uint32_t userpal[256]; + uint32_t maxw, maxh; /* maximum framebuffer size */ + uint32_t visw, vish; /* maximum screen size */ + uint32_t screenw, screenh; + int16_t pan_x, pan_y; + uint16_t win_x1, win_x2, win_y1, win_y2; + uint16_t vp_x1, vp_x2, vp_y1, vp_y2; + int16_t fill_pattern[16]; + int16_t line_pattern; + uint8_t draw_mode; + uint8_t fill_mode; + uint8_t color; + uint8_t tjust_h; /* hor alignment 1=left 2=ctr 3=right*/ + uint8_t tjust_v; /* vert alignment 1=bottom 2=ctr 3=top*/ + int32_t tsize; /* horizontal spacing */ + + int32_t x, y, z; /* drawing position */ + + thread_t *pgc_thread; + event_t *pgc_wake_thread; + pc_timer_t wake_timer; + + int waiting_input_fifo; + int waiting_output_fifo; + int waiting_error_fifo; + int ascii_mode; + int result_count; + + int fontbase; + int linepos, + displine; + int vc; + int cgadispon; + int con, coff, cursoron, cgablink; + int vsynctime, vadj; + uint16_t ma, maback; + int oddeven; + + uint64_t dispontime, + dispofftime; + pc_timer_t timer; + double native_pixel_clock; + + int drawcursor; + + int (*inputbyte)(struct pgc *, uint8_t *result); +} pgc_t; + + +/* I/O functions and worker thread handlers. */ +extern void pgc_out(uint16_t addr, uint8_t val, void *priv); +extern uint8_t pgc_in(uint16_t addr, void *priv); +extern void pgc_write(uint32_t addr, uint8_t val, void *priv); +extern uint8_t pgc_read(uint32_t addr, void *priv); +extern void pgc_recalctimings(pgc_t *); +extern void pgc_poll(void *priv); +extern void pgc_reset(pgc_t *); +extern void pgc_wake(pgc_t *); +extern void pgc_sleep(pgc_t *); +extern void pgc_setdisplay(pgc_t *, int cga); +extern void pgc_speed_changed(void *priv); +extern void pgc_close(void *priv); +extern void pgc_init(pgc_t *, + int maxw, int maxh, int visw, int vish, + int (*inpbyte)(pgc_t *, uint8_t *), double npc); + +/* Misc support functions. */ +extern void pgc_sto_raster(pgc_t *, int16_t *x, int16_t *y); +extern void pgc_ito_raster(pgc_t *, int32_t *x, int32_t *y); +extern void pgc_dto_raster(pgc_t *, double *x, double *y); +//extern int pgc_input_byte(pgc_t *, uint8_t *val); +//extern int pgc_output_byte(pgc_t *, uint8_t val); +extern int pgc_output_string(pgc_t *, const char *val); +//extern int pgc_error_byte(pgc_t *, uint8_t val); +extern int pgc_error_string(pgc_t *, const char *val); +extern int pgc_error(pgc_t *, int err); + +/* Graphics functions. */ +extern uint8_t *pgc_vram_addr(pgc_t *, int16_t x, int16_t y); +extern void pgc_write_pixel(pgc_t *, uint16_t x, uint16_t y, uint8_t ink); +extern uint8_t pgc_read_pixel(pgc_t *, uint16_t x, uint16_t y); +extern void pgc_plot(pgc_t *, uint16_t x, uint16_t y); +extern uint16_t pgc_draw_line_r(pgc_t *, int32_t x1, int32_t y1, + int32_t x2, int32_t y2, uint16_t linemask); +extern void pgc_fill_line_r(pgc_t *, int32_t x0, int32_t x1, int32_t y); +extern uint16_t pgc_draw_line(pgc_t *, int32_t x1, int32_t y1, + int32_t x2, int32_t y2, uint16_t linemask); +extern void pgc_draw_ellipse(pgc_t *, int32_t x, int32_t y); +extern void pgc_fill_polygon(pgc_t *, + unsigned corners, int32_t *x, int32_t *y); + +/* Command and parameter handling functions. */ +extern int pgc_clist_byte(pgc_t *, uint8_t *val); +extern int pgc_cl_append(pgc_cl_t *, uint8_t v); +extern int pgc_parse_bytes(pgc_t *, pgc_cl_t *, int p); +extern int pgc_parse_words(pgc_t *, pgc_cl_t *, int p); +extern int pgc_parse_coords(pgc_t *, pgc_cl_t *, int p); +extern int pgc_param_byte(pgc_t *, uint8_t *val); +extern int pgc_param_word(pgc_t *, int16_t *val); +extern int pgc_param_coord(pgc_t *, int32_t *val); +extern int pgc_result_byte(pgc_t *, uint8_t val); +extern int pgc_result_word(pgc_t *, int16_t val); +extern int pgc_result_coord(pgc_t *, int32_t val); + +/* Special overload functions for non-IBM implementations. */ +extern void pgc_hndl_lut8(pgc_t *); +extern void pgc_hndl_lut8rd(pgc_t *); + + +extern const device_t pgc_device; + + +#endif /*VID_PGC_H*/ diff --git a/src/video/vid_pgc_palette.h b/src/video/vid_pgc_palette.h new file mode 100644 index 000000000..dd89a58dc --- /dev/null +++ b/src/video/vid_pgc_palette.h @@ -0,0 +1,1579 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Palette definitions for the PGC core. + * + * Version: @(#)vid_pgc_palette.h 1.0.1 2019/03/01 + * + * Authors: Fred N. van Kempen, + * John Elliott, + * + * Copyright 2019 Fred N. van Kempen. + * Copyright 2019 John Elliott. + */ +#ifndef VID_PGC_PALETTE_H +# define VID_PGC_PALETTE_H + + +/* Palette 0: Default */ + { + makecol(0x00,0x00,0x00), + makecol(0x11,0x11,0x11), + makecol(0x22,0x22,0x22), + makecol(0x33,0x33,0x33), + makecol(0x44,0x44,0x44), + makecol(0x55,0x55,0x55), + makecol(0x66,0x66,0x66), + makecol(0x77,0x77,0x77), + makecol(0x88,0x88,0x88), + makecol(0x99,0x99,0x99), + makecol(0xaa,0xaa,0xaa), + makecol(0xbb,0xbb,0xbb), + makecol(0xcc,0xcc,0xcc), + makecol(0xdd,0xdd,0xdd), + makecol(0xee,0xee,0xee), + makecol(0xff,0xff,0xff), + makecol(0x00,0x00,0x00), + makecol(0x00,0x22,0x00), + makecol(0x00,0x44,0x00), + makecol(0x00,0x66,0x00), + makecol(0x00,0x88,0x00), + makecol(0x00,0xaa,0x00), + makecol(0x00,0xcc,0x00), + makecol(0x00,0xee,0x00), + makecol(0x00,0xff,0x00), + makecol(0x22,0xff,0x22), + makecol(0x44,0xff,0x44), + makecol(0x66,0xff,0x66), + makecol(0x88,0xff,0x88), + makecol(0xaa,0xff,0xaa), + makecol(0xcc,0xff,0xcc), + makecol(0xee,0xff,0xee), + makecol(0x00,0x00,0x00), + makecol(0x00,0x22,0x11), + makecol(0x00,0x44,0x22), + makecol(0x00,0x66,0x33), + makecol(0x00,0x88,0x44), + makecol(0x00,0xaa,0x55), + makecol(0x00,0xcc,0x66), + makecol(0x00,0xee,0x77), + makecol(0x00,0xff,0x88), + makecol(0x22,0xff,0x99), + makecol(0x44,0xff,0xaa), + makecol(0x66,0xff,0xbb), + makecol(0x88,0xff,0xcc), + makecol(0xaa,0xff,0xdd), + makecol(0xcc,0xff,0xee), + makecol(0xee,0xff,0xff), + makecol(0x00,0x00,0x00), + makecol(0x00,0x22,0x22), + makecol(0x00,0x44,0x44), + makecol(0x00,0x66,0x66), + makecol(0x00,0x88,0x88), + makecol(0x00,0xaa,0xaa), + makecol(0x00,0xcc,0xcc), + makecol(0x00,0xee,0xee), + makecol(0x00,0xff,0xff), + makecol(0x22,0xff,0xff), + makecol(0x44,0xff,0xff), + makecol(0x66,0xff,0xff), + makecol(0x88,0xff,0xff), + makecol(0xaa,0xff,0xff), + makecol(0xcc,0xff,0xff), + makecol(0xee,0xff,0xff), + makecol(0x00,0x00,0x00), + makecol(0x00,0x11,0x22), + makecol(0x00,0x22,0x44), + makecol(0x00,0x33,0x66), + makecol(0x00,0x44,0x88), + makecol(0x00,0x55,0xaa), + makecol(0x00,0x66,0xcc), + makecol(0x00,0x77,0xee), + makecol(0x00,0x88,0xff), + makecol(0x22,0x99,0xff), + makecol(0x44,0xaa,0xff), + makecol(0x66,0xbb,0xff), + makecol(0x88,0xcc,0xff), + makecol(0xaa,0xdd,0xff), + makecol(0xcc,0xee,0xff), + makecol(0xee,0xff,0xff), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x22), + makecol(0x00,0x00,0x44), + makecol(0x00,0x00,0x66), + makecol(0x00,0x00,0x88), + makecol(0x00,0x00,0xaa), + makecol(0x00,0x00,0xcc), + makecol(0x00,0x00,0xee), + makecol(0x00,0x00,0xff), + makecol(0x22,0x22,0xff), + makecol(0x44,0x44,0xff), + makecol(0x66,0x66,0xff), + makecol(0x88,0x88,0xff), + makecol(0xaa,0xaa,0xff), + makecol(0xcc,0xcc,0xff), + makecol(0xee,0xee,0xff), + makecol(0x00,0x00,0x00), + makecol(0x11,0x00,0x22), + makecol(0x22,0x00,0x44), + makecol(0x33,0x00,0x66), + makecol(0x44,0x00,0x88), + makecol(0x55,0x00,0xaa), + makecol(0x66,0x00,0xcc), + makecol(0x77,0x00,0xee), + makecol(0x88,0x00,0xff), + makecol(0x99,0x22,0xff), + makecol(0xaa,0x44,0xff), + makecol(0xbb,0x66,0xff), + makecol(0xcc,0x88,0xff), + makecol(0xdd,0xaa,0xff), + makecol(0xee,0xcc,0xff), + makecol(0xff,0xee,0xff), + makecol(0x00,0x00,0x00), + makecol(0x22,0x00,0x22), + makecol(0x44,0x00,0x44), + makecol(0x66,0x00,0x66), + makecol(0x88,0x00,0x88), + makecol(0xaa,0x00,0xaa), + makecol(0xcc,0x00,0xcc), + makecol(0xee,0x00,0xee), + makecol(0xff,0x00,0xff), + makecol(0xff,0x22,0xff), + makecol(0xff,0x44,0xff), + makecol(0xff,0x66,0xff), + makecol(0xff,0x88,0xff), + makecol(0xff,0xaa,0xff), + makecol(0xff,0xcc,0xff), + makecol(0xff,0xee,0xff), + makecol(0x00,0x00,0x00), + makecol(0x22,0x00,0x11), + makecol(0x44,0x00,0x22), + makecol(0x66,0x00,0x33), + makecol(0x88,0x00,0x44), + makecol(0xaa,0x00,0x55), + makecol(0xcc,0x00,0x66), + makecol(0xee,0x00,0x77), + makecol(0xff,0x00,0x88), + makecol(0xff,0x22,0x99), + makecol(0xff,0x44,0xaa), + makecol(0xff,0x66,0xbb), + makecol(0xff,0x88,0xcc), + makecol(0xff,0xaa,0xdd), + makecol(0xff,0xcc,0xee), + makecol(0xff,0xee,0xff), + makecol(0x00,0x00,0x00), + makecol(0x22,0x00,0x00), + makecol(0x44,0x00,0x00), + makecol(0x66,0x00,0x00), + makecol(0x88,0x00,0x00), + makecol(0xaa,0x00,0x00), + makecol(0xcc,0x00,0x00), + makecol(0xee,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x22,0x22), + makecol(0xff,0x44,0x44), + makecol(0xff,0x66,0x66), + makecol(0xff,0x88,0x88), + makecol(0xff,0xaa,0xaa), + makecol(0xff,0xcc,0xcc), + makecol(0xff,0xee,0xee), + makecol(0x00,0x00,0x00), + makecol(0x22,0x11,0x00), + makecol(0x44,0x22,0x00), + makecol(0x66,0x33,0x00), + makecol(0x88,0x44,0x00), + makecol(0xaa,0x55,0x00), + makecol(0xcc,0x66,0x00), + makecol(0xee,0x77,0x00), + makecol(0xff,0x88,0x00), + makecol(0xff,0x99,0x22), + makecol(0xff,0xaa,0x44), + makecol(0xff,0xbb,0x66), + makecol(0xff,0xcc,0x88), + makecol(0xff,0xdd,0xaa), + makecol(0xff,0xee,0xcc), + makecol(0xff,0xff,0xee), + makecol(0x00,0x00,0x00), + makecol(0x22,0x22,0x00), + makecol(0x44,0x44,0x00), + makecol(0x66,0x66,0x00), + makecol(0x88,0x88,0x00), + makecol(0xaa,0xaa,0x00), + makecol(0xcc,0xcc,0x00), + makecol(0xee,0xee,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x22), + makecol(0xff,0xff,0x44), + makecol(0xff,0xff,0x66), + makecol(0xff,0xff,0x88), + makecol(0xff,0xff,0xaa), + makecol(0xff,0xff,0xcc), + makecol(0xff,0xff,0xee), + makecol(0x00,0x00,0x00), + makecol(0x11,0x22,0x00), + makecol(0x22,0x44,0x00), + makecol(0x33,0x66,0x00), + makecol(0x44,0x88,0x00), + makecol(0x55,0xaa,0x00), + makecol(0x66,0xcc,0x00), + makecol(0x77,0xee,0x00), + makecol(0x88,0xff,0x00), + makecol(0x99,0xff,0x22), + makecol(0xaa,0xff,0x44), + makecol(0xbb,0xff,0x66), + makecol(0xcc,0xff,0x88), + makecol(0xdd,0xff,0xaa), + makecol(0xee,0xff,0xcc), + makecol(0xff,0xff,0xee), + makecol(0x00,0x00,0x00), + makecol(0x00,0x11,0x00), + makecol(0x11,0x33,0x11), + makecol(0x11,0x44,0x11), + makecol(0x22,0x66,0x22), + makecol(0x22,0x77,0x22), + makecol(0x33,0x99,0x33), + makecol(0x33,0xaa,0x33), + makecol(0x44,0xcc,0x44), + makecol(0x55,0xcc,0x55), + makecol(0x77,0xdd,0x77), + makecol(0x88,0xdd,0x88), + makecol(0xaa,0xee,0xaa), + makecol(0xbb,0xee,0xbb), + makecol(0xdd,0xff,0xdd), + makecol(0xee,0xff,0xee), + makecol(0x00,0x00,0x00), + makecol(0x11,0x00,0x00), + makecol(0x33,0x11,0x11), + makecol(0x44,0x11,0x11), + makecol(0x66,0x22,0x22), + makecol(0x77,0x22,0x22), + makecol(0x99,0x33,0x33), + makecol(0xaa,0x33,0x33), + makecol(0xcc,0x44,0x44), + makecol(0xcc,0x55,0x55), + makecol(0xdd,0x77,0x77), + makecol(0xdd,0x88,0x88), + makecol(0xee,0xaa,0xaa), + makecol(0xee,0xbb,0xbb), + makecol(0xff,0xdd,0xdd), + makecol(0xff,0xee,0xee), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x11), + makecol(0x11,0x11,0x33), + makecol(0x11,0x11,0x44), + makecol(0x22,0x22,0x66), + makecol(0x22,0x22,0x77), + makecol(0x33,0x33,0x99), + makecol(0x33,0x33,0xaa), + makecol(0x44,0x44,0xcc), + makecol(0x55,0x55,0xcc), + makecol(0x77,0x77,0xdd), + makecol(0x88,0x88,0xdd), + makecol(0xaa,0xaa,0xee), + makecol(0xbb,0xbb,0xee), + makecol(0xdd,0xdd,0xff), + makecol(0xee,0xee,0xff), + }, +/* Palette 1: 16-colour palette */ + { + makecol(0x88,0x66,0xdd), + makecol(0x00,0x00,0x00), + makecol(0x44,0x77,0x22), + makecol(0x77,0xaa,0x44), + makecol(0x00,0x77,0x00), + makecol(0x00,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x99,0xee,0x66), + makecol(0x77,0x77,0x77), + makecol(0xff,0xff,0xff), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + }, +/* Palette 2: 2-3-3 truecolour */ + { + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x33), + makecol(0x00,0x00,0x55), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x99), + makecol(0x00,0x00,0xbb), + makecol(0x00,0x00,0xdd), + makecol(0x00,0x00,0xff), + makecol(0x33,0x00,0x00), + makecol(0x33,0x00,0x33), + makecol(0x33,0x00,0x55), + makecol(0x33,0x00,0x77), + makecol(0x33,0x00,0x99), + makecol(0x33,0x00,0xbb), + makecol(0x33,0x00,0xdd), + makecol(0x33,0x00,0xff), + makecol(0x55,0x00,0x00), + makecol(0x55,0x00,0x33), + makecol(0x55,0x00,0x55), + makecol(0x55,0x00,0x77), + makecol(0x55,0x00,0x99), + makecol(0x55,0x00,0xbb), + makecol(0x55,0x00,0xdd), + makecol(0x55,0x00,0xff), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x33), + makecol(0x77,0x00,0x55), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x99), + makecol(0x77,0x00,0xbb), + makecol(0x77,0x00,0xdd), + makecol(0x77,0x00,0xff), + makecol(0x99,0x00,0x00), + makecol(0x99,0x00,0x33), + makecol(0x99,0x00,0x55), + makecol(0x99,0x00,0x77), + makecol(0x99,0x00,0x99), + makecol(0x99,0x00,0xbb), + makecol(0x99,0x00,0xdd), + makecol(0x99,0x00,0xff), + makecol(0xbb,0x00,0x00), + makecol(0xbb,0x00,0x33), + makecol(0xbb,0x00,0x55), + makecol(0xbb,0x00,0x77), + makecol(0xbb,0x00,0x99), + makecol(0xbb,0x00,0xbb), + makecol(0xbb,0x00,0xdd), + makecol(0xbb,0x00,0xff), + makecol(0xdd,0x00,0x00), + makecol(0xdd,0x00,0x33), + makecol(0xdd,0x00,0x55), + makecol(0xdd,0x00,0x77), + makecol(0xdd,0x00,0x99), + makecol(0xdd,0x00,0xbb), + makecol(0xdd,0x00,0xdd), + makecol(0xdd,0x00,0xff), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x33), + makecol(0xff,0x00,0x55), + makecol(0xff,0x00,0x77), + makecol(0xff,0x00,0x99), + makecol(0xff,0x00,0xbb), + makecol(0xff,0x00,0xdd), + makecol(0xff,0x00,0xff), + makecol(0x00,0x55,0x00), + makecol(0x00,0x55,0x33), + makecol(0x00,0x55,0x55), + makecol(0x00,0x55,0x77), + makecol(0x00,0x55,0x99), + makecol(0x00,0x55,0xbb), + makecol(0x00,0x55,0xdd), + makecol(0x00,0x55,0xff), + makecol(0x33,0x55,0x00), + makecol(0x33,0x55,0x33), + makecol(0x33,0x55,0x55), + makecol(0x33,0x55,0x77), + makecol(0x33,0x55,0x99), + makecol(0x33,0x55,0xbb), + makecol(0x33,0x55,0xdd), + makecol(0x33,0x55,0xff), + makecol(0x55,0x55,0x00), + makecol(0x55,0x55,0x33), + makecol(0x55,0x55,0x55), + makecol(0x55,0x55,0x77), + makecol(0x55,0x55,0x99), + makecol(0x55,0x55,0xbb), + makecol(0x55,0x55,0xdd), + makecol(0x55,0x55,0xff), + makecol(0x77,0x55,0x00), + makecol(0x77,0x55,0x33), + makecol(0x77,0x55,0x55), + makecol(0x77,0x55,0x77), + makecol(0x77,0x55,0x99), + makecol(0x77,0x55,0xbb), + makecol(0x77,0x55,0xdd), + makecol(0x77,0x55,0xff), + makecol(0x99,0x55,0x00), + makecol(0x99,0x55,0x33), + makecol(0x99,0x55,0x55), + makecol(0x99,0x55,0x77), + makecol(0x99,0x55,0x99), + makecol(0x99,0x55,0xbb), + makecol(0x99,0x55,0xdd), + makecol(0x99,0x55,0xff), + makecol(0xbb,0x55,0x00), + makecol(0xbb,0x55,0x33), + makecol(0xbb,0x55,0x55), + makecol(0xbb,0x55,0x77), + makecol(0xbb,0x55,0x99), + makecol(0xbb,0x55,0xbb), + makecol(0xbb,0x55,0xdd), + makecol(0xbb,0x55,0xff), + makecol(0xdd,0x55,0x00), + makecol(0xdd,0x55,0x33), + makecol(0xdd,0x55,0x55), + makecol(0xdd,0x55,0x77), + makecol(0xdd,0x55,0x99), + makecol(0xdd,0x55,0xbb), + makecol(0xdd,0x55,0xdd), + makecol(0xdd,0x55,0xff), + makecol(0xff,0x55,0x00), + makecol(0xff,0x55,0x33), + makecol(0xff,0x55,0x55), + makecol(0xff,0x55,0x77), + makecol(0xff,0x55,0x99), + makecol(0xff,0x55,0xbb), + makecol(0xff,0x55,0xdd), + makecol(0xff,0x55,0xff), + makecol(0x00,0xaa,0x00), + makecol(0x00,0xaa,0x33), + makecol(0x00,0xaa,0x55), + makecol(0x00,0xaa,0x77), + makecol(0x00,0xaa,0x99), + makecol(0x00,0xaa,0xbb), + makecol(0x00,0xaa,0xdd), + makecol(0x00,0xaa,0xff), + makecol(0x33,0xaa,0x00), + makecol(0x33,0xaa,0x33), + makecol(0x33,0xaa,0x55), + makecol(0x33,0xaa,0x77), + makecol(0x33,0xaa,0x99), + makecol(0x33,0xaa,0xbb), + makecol(0x33,0xaa,0xdd), + makecol(0x33,0xaa,0xff), + makecol(0x55,0xaa,0x00), + makecol(0x55,0xaa,0x33), + makecol(0x55,0xaa,0x55), + makecol(0x55,0xaa,0x77), + makecol(0x55,0xaa,0x99), + makecol(0x55,0xaa,0xbb), + makecol(0x55,0xaa,0xdd), + makecol(0x55,0xaa,0xff), + makecol(0x77,0xaa,0x00), + makecol(0x77,0xaa,0x33), + makecol(0x77,0xaa,0x55), + makecol(0x77,0xaa,0x77), + makecol(0x77,0xaa,0x99), + makecol(0x77,0xaa,0xbb), + makecol(0x77,0xaa,0xdd), + makecol(0x77,0xaa,0xff), + makecol(0x99,0xaa,0x00), + makecol(0x99,0xaa,0x33), + makecol(0x99,0xaa,0x55), + makecol(0x99,0xaa,0x77), + makecol(0x99,0xaa,0x99), + makecol(0x99,0xaa,0xbb), + makecol(0x99,0xaa,0xdd), + makecol(0x99,0xaa,0xff), + makecol(0xbb,0xaa,0x00), + makecol(0xbb,0xaa,0x33), + makecol(0xbb,0xaa,0x55), + makecol(0xbb,0xaa,0x77), + makecol(0xbb,0xaa,0x99), + makecol(0xbb,0xaa,0xbb), + makecol(0xbb,0xaa,0xdd), + makecol(0xbb,0xaa,0xff), + makecol(0xdd,0xaa,0x00), + makecol(0xdd,0xaa,0x33), + makecol(0xdd,0xaa,0x55), + makecol(0xdd,0xaa,0x77), + makecol(0xdd,0xaa,0x99), + makecol(0xdd,0xaa,0xbb), + makecol(0xdd,0xaa,0xdd), + makecol(0xdd,0xaa,0xff), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x33), + makecol(0xff,0xaa,0x55), + makecol(0xff,0xaa,0x77), + makecol(0xff,0xaa,0x99), + makecol(0xff,0xaa,0xbb), + makecol(0xff,0xaa,0xdd), + makecol(0xff,0xaa,0xee), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x33), + makecol(0x00,0xff,0x55), + makecol(0x00,0xff,0x77), + makecol(0x00,0xff,0x99), + makecol(0x00,0xff,0xbb), + makecol(0x00,0xff,0xdd), + makecol(0x00,0xff,0xff), + makecol(0x33,0xff,0x00), + makecol(0x33,0xff,0x33), + makecol(0x33,0xff,0x55), + makecol(0x33,0xff,0x77), + makecol(0x33,0xff,0x99), + makecol(0x33,0xff,0xbb), + makecol(0x33,0xff,0xdd), + makecol(0x33,0xff,0xff), + makecol(0x55,0xff,0x00), + makecol(0x55,0xff,0x33), + makecol(0x55,0xff,0x55), + makecol(0x55,0xff,0x77), + makecol(0x55,0xff,0x99), + makecol(0x55,0xff,0xbb), + makecol(0x55,0xff,0xdd), + makecol(0x55,0xff,0xff), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x33), + makecol(0x77,0xff,0x55), + makecol(0x77,0xff,0x77), + makecol(0x77,0xff,0x99), + makecol(0x77,0xff,0xbb), + makecol(0x77,0xff,0xdd), + makecol(0x77,0xff,0xff), + makecol(0x99,0xff,0x00), + makecol(0x99,0xff,0x33), + makecol(0x99,0xff,0x55), + makecol(0x99,0xff,0x77), + makecol(0x99,0xff,0x99), + makecol(0x99,0xff,0xbb), + makecol(0x99,0xff,0xdd), + makecol(0x99,0xff,0xff), + makecol(0xbb,0xff,0x00), + makecol(0xbb,0xff,0x33), + makecol(0xbb,0xff,0x55), + makecol(0xbb,0xff,0x77), + makecol(0xbb,0xff,0x99), + makecol(0xbb,0xff,0xbb), + makecol(0xbb,0xff,0xdd), + makecol(0xbb,0xff,0xff), + makecol(0xdd,0xff,0x00), + makecol(0xdd,0xff,0x33), + makecol(0xdd,0xff,0x55), + makecol(0xdd,0xff,0x77), + makecol(0xdd,0xff,0x99), + makecol(0xdd,0xff,0xbb), + makecol(0xdd,0xff,0xdd), + makecol(0xdd,0xff,0xff), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x33), + makecol(0xff,0xff,0x55), + makecol(0xff,0xff,0x77), + makecol(0xff,0xff,0x99), + makecol(0xff,0xff,0xbb), + makecol(0xff,0xff,0xdd), + makecol(0xff,0xff,0xff), + }, +/* Palette 3: 3-2-3 truecolour */ + { + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x33), + makecol(0x00,0x00,0x55), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x99), + makecol(0x00,0x00,0xbb), + makecol(0x00,0x00,0xdd), + makecol(0x00,0x00,0xff), + makecol(0x55,0x00,0x00), + makecol(0x55,0x00,0x33), + makecol(0x55,0x00,0x55), + makecol(0x55,0x00,0x77), + makecol(0x55,0x00,0x99), + makecol(0x55,0x00,0xbb), + makecol(0x55,0x00,0xdd), + makecol(0x55,0x00,0xff), + makecol(0xaa,0x00,0x00), + makecol(0xaa,0x00,0x33), + makecol(0xaa,0x00,0x55), + makecol(0xaa,0x00,0x77), + makecol(0xaa,0x00,0x99), + makecol(0xaa,0x00,0xbb), + makecol(0xaa,0x00,0xdd), + makecol(0xaa,0x00,0xff), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x33), + makecol(0xff,0x00,0x55), + makecol(0xff,0x00,0x77), + makecol(0xff,0x00,0x99), + makecol(0xff,0x00,0xbb), + makecol(0xff,0x00,0xdd), + makecol(0xff,0x00,0xff), + makecol(0x00,0x33,0x00), + makecol(0x00,0x33,0x33), + makecol(0x00,0x33,0x55), + makecol(0x00,0x33,0x77), + makecol(0x00,0x33,0x99), + makecol(0x00,0x33,0xbb), + makecol(0x00,0x33,0xdd), + makecol(0x00,0x33,0xff), + makecol(0x55,0x33,0x00), + makecol(0x55,0x33,0x33), + makecol(0x55,0x33,0x55), + makecol(0x55,0x33,0x77), + makecol(0x55,0x33,0x99), + makecol(0x55,0x33,0xbb), + makecol(0x55,0x33,0xdd), + makecol(0x55,0x33,0xff), + makecol(0xaa,0x33,0x00), + makecol(0xaa,0x33,0x33), + makecol(0xaa,0x33,0x55), + makecol(0xaa,0x33,0x77), + makecol(0xaa,0x33,0x99), + makecol(0xaa,0x33,0xbb), + makecol(0xaa,0x33,0xdd), + makecol(0xaa,0x33,0xff), + makecol(0xff,0x33,0x00), + makecol(0xff,0x33,0x33), + makecol(0xff,0x33,0x55), + makecol(0xff,0x33,0x77), + makecol(0xff,0x33,0x99), + makecol(0xff,0x33,0xbb), + makecol(0xff,0x33,0xdd), + makecol(0xff,0x33,0xff), + makecol(0x00,0x55,0x00), + makecol(0x00,0x55,0x33), + makecol(0x00,0x55,0x55), + makecol(0x00,0x55,0x77), + makecol(0x00,0x55,0x99), + makecol(0x00,0x55,0xbb), + makecol(0x00,0x55,0xdd), + makecol(0x00,0x55,0xff), + makecol(0x55,0x55,0x00), + makecol(0x55,0x55,0x33), + makecol(0x55,0x55,0x55), + makecol(0x55,0x55,0x77), + makecol(0x55,0x55,0x99), + makecol(0x55,0x55,0xbb), + makecol(0x55,0x55,0xdd), + makecol(0x55,0x55,0xff), + makecol(0xaa,0x55,0x00), + makecol(0xaa,0x55,0x33), + makecol(0xaa,0x55,0x55), + makecol(0xaa,0x55,0x77), + makecol(0xaa,0x55,0x99), + makecol(0xaa,0x55,0xbb), + makecol(0xaa,0x55,0xdd), + makecol(0xaa,0x55,0xff), + makecol(0xff,0x55,0x00), + makecol(0xff,0x55,0x33), + makecol(0xff,0x55,0x55), + makecol(0xff,0x55,0x77), + makecol(0xff,0x55,0x99), + makecol(0xff,0x55,0xbb), + makecol(0xff,0x55,0xdd), + makecol(0xff,0x55,0xff), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x33), + makecol(0x00,0x77,0x55), + makecol(0x00,0x77,0x77), + makecol(0x00,0x77,0x99), + makecol(0x00,0x77,0xbb), + makecol(0x00,0x77,0xdd), + makecol(0x00,0x77,0xff), + makecol(0x55,0x77,0x00), + makecol(0x55,0x77,0x33), + makecol(0x55,0x77,0x55), + makecol(0x55,0x77,0x77), + makecol(0x55,0x77,0x99), + makecol(0x55,0x77,0xbb), + makecol(0x55,0x77,0xdd), + makecol(0x55,0x77,0xff), + makecol(0xaa,0x77,0x00), + makecol(0xaa,0x77,0x33), + makecol(0xaa,0x77,0x55), + makecol(0xaa,0x77,0x77), + makecol(0xaa,0x77,0x99), + makecol(0xaa,0x77,0xbb), + makecol(0xaa,0x77,0xdd), + makecol(0xaa,0x77,0xff), + makecol(0xff,0x77,0x00), + makecol(0xff,0x77,0x33), + makecol(0xff,0x77,0x55), + makecol(0xff,0x77,0x77), + makecol(0xff,0x77,0x99), + makecol(0xff,0x77,0xbb), + makecol(0xff,0x77,0xdd), + makecol(0xff,0x77,0xff), + makecol(0x00,0x99,0x00), + makecol(0x00,0x99,0x33), + makecol(0x00,0x99,0x55), + makecol(0x00,0x99,0x77), + makecol(0x00,0x99,0x99), + makecol(0x00,0x99,0xbb), + makecol(0x00,0x99,0xdd), + makecol(0x00,0x99,0xff), + makecol(0x55,0x99,0x00), + makecol(0x55,0x99,0x33), + makecol(0x55,0x99,0x55), + makecol(0x55,0x99,0x77), + makecol(0x55,0x99,0x99), + makecol(0x55,0x99,0xbb), + makecol(0x55,0x99,0xdd), + makecol(0x55,0x99,0xff), + makecol(0xaa,0x99,0x00), + makecol(0xaa,0x99,0x33), + makecol(0xaa,0x99,0x55), + makecol(0xaa,0x99,0x77), + makecol(0xaa,0x99,0x99), + makecol(0xaa,0x99,0xbb), + makecol(0xaa,0x99,0xdd), + makecol(0xaa,0x99,0xff), + makecol(0xff,0x99,0x00), + makecol(0xff,0x99,0x33), + makecol(0xff,0x99,0x55), + makecol(0xff,0x99,0x77), + makecol(0xff,0x99,0x99), + makecol(0xff,0x99,0xbb), + makecol(0xff,0x99,0xdd), + makecol(0xff,0x99,0xff), + makecol(0x00,0xbb,0x00), + makecol(0x00,0xbb,0x33), + makecol(0x00,0xbb,0x55), + makecol(0x00,0xbb,0x77), + makecol(0x00,0xbb,0x99), + makecol(0x00,0xbb,0xbb), + makecol(0x00,0xbb,0xdd), + makecol(0x00,0xbb,0xff), + makecol(0x55,0xbb,0x00), + makecol(0x55,0xbb,0x33), + makecol(0x55,0xbb,0x55), + makecol(0x55,0xbb,0x77), + makecol(0x55,0xbb,0x99), + makecol(0x55,0xbb,0xbb), + makecol(0x55,0xbb,0xdd), + makecol(0x55,0xbb,0xff), + makecol(0xaa,0xbb,0x00), + makecol(0xaa,0xbb,0x33), + makecol(0xaa,0xbb,0x55), + makecol(0xaa,0xbb,0x77), + makecol(0xaa,0xbb,0x99), + makecol(0xaa,0xbb,0xbb), + makecol(0xaa,0xbb,0xdd), + makecol(0xaa,0xbb,0xff), + makecol(0xff,0xbb,0x00), + makecol(0xff,0xbb,0x33), + makecol(0xff,0xbb,0x55), + makecol(0xff,0xbb,0x77), + makecol(0xff,0xbb,0x99), + makecol(0xff,0xbb,0xbb), + makecol(0xff,0xbb,0xdd), + makecol(0xff,0xbb,0xff), + makecol(0x00,0xdd,0x00), + makecol(0x00,0xdd,0x33), + makecol(0x00,0xdd,0x55), + makecol(0x00,0xdd,0x77), + makecol(0x00,0xdd,0x99), + makecol(0x00,0xdd,0xbb), + makecol(0x00,0xdd,0xdd), + makecol(0x00,0xdd,0xff), + makecol(0x55,0xdd,0x00), + makecol(0x55,0xdd,0x33), + makecol(0x55,0xdd,0x55), + makecol(0x55,0xdd,0x77), + makecol(0x55,0xdd,0x99), + makecol(0x55,0xdd,0xbb), + makecol(0x55,0xdd,0xdd), + makecol(0x55,0xdd,0xff), + makecol(0xaa,0xdd,0x00), + makecol(0xaa,0xdd,0x33), + makecol(0xaa,0xdd,0x55), + makecol(0xaa,0xdd,0x77), + makecol(0xaa,0xdd,0x99), + makecol(0xaa,0xdd,0xbb), + makecol(0xaa,0xdd,0xdd), + makecol(0xaa,0xdd,0xff), + makecol(0xff,0xdd,0x00), + makecol(0xff,0xdd,0x33), + makecol(0xff,0xdd,0x55), + makecol(0xff,0xdd,0x77), + makecol(0xff,0xdd,0x99), + makecol(0xff,0xdd,0xbb), + makecol(0xff,0xdd,0xdd), + makecol(0xff,0xdd,0xff), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x33), + makecol(0x00,0xff,0x55), + makecol(0x00,0xff,0x77), + makecol(0x00,0xff,0x99), + makecol(0x00,0xff,0xbb), + makecol(0x00,0xff,0xdd), + makecol(0x00,0xff,0xff), + makecol(0x55,0xff,0x00), + makecol(0x55,0xff,0x33), + makecol(0x55,0xff,0x55), + makecol(0x55,0xff,0x77), + makecol(0x55,0xff,0x99), + makecol(0x55,0xff,0xbb), + makecol(0x55,0xff,0xdd), + makecol(0x55,0xff,0xff), + makecol(0xaa,0xff,0x00), + makecol(0xaa,0xff,0x33), + makecol(0xaa,0xff,0x55), + makecol(0xaa,0xff,0x77), + makecol(0xaa,0xff,0x99), + makecol(0xaa,0xff,0xbb), + makecol(0xaa,0xff,0xdd), + makecol(0xaa,0xff,0xff), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x33), + makecol(0xff,0xff,0x55), + makecol(0xff,0xff,0x77), + makecol(0xff,0xff,0x99), + makecol(0xff,0xff,0xbb), + makecol(0xff,0xff,0xdd), + makecol(0xff,0xff,0xff), + }, +/* Palette 4: 3-3-2 truecolour */ + { + makecol(0x00, 0x00, 0x00), + makecol(0x00, 0x00, 0x55), + makecol(0x00, 0x00, 0xaa), + makecol(0x00, 0x00, 0xff), + makecol(0x00, 0x33, 0x00), + makecol(0x00, 0x33, 0x55), + makecol(0x00, 0x33, 0xaa), + makecol(0x00, 0x33, 0xff), + makecol(0x00, 0x55, 0x00), + makecol(0x00, 0x55, 0x55), + makecol(0x00, 0x55, 0xaa), + makecol(0x00, 0x55, 0xff), + makecol(0x00, 0x77, 0x00), + makecol(0x00, 0x77, 0x55), + makecol(0x00, 0x77, 0xaa), + makecol(0x00, 0x77, 0xff), + makecol(0x00, 0x99, 0x00), + makecol(0x00, 0x99, 0x55), + makecol(0x00, 0x99, 0xaa), + makecol(0x00, 0x99, 0xff), + makecol(0x00, 0xbb, 0x00), + makecol(0x00, 0xbb, 0x55), + makecol(0x00, 0xbb, 0xaa), + makecol(0x00, 0xbb, 0xff), + makecol(0x00, 0xdd, 0x00), + makecol(0x00, 0xdd, 0x55), + makecol(0x00, 0xdd, 0xaa), + makecol(0x00, 0xdd, 0xff), + makecol(0x00, 0xff, 0x00), + makecol(0x00, 0xff, 0x55), + makecol(0x00, 0xff, 0xaa), + makecol(0x00, 0xff, 0xff), + makecol(0x33, 0x00, 0x00), + makecol(0x33, 0x00, 0x55), + makecol(0x33, 0x00, 0xaa), + makecol(0x33, 0x00, 0xff), + makecol(0x33, 0x33, 0x00), + makecol(0x33, 0x33, 0x55), + makecol(0x33, 0x33, 0xaa), + makecol(0x33, 0x33, 0xff), + makecol(0x33, 0x55, 0x00), + makecol(0x33, 0x55, 0x55), + makecol(0x33, 0x55, 0xaa), + makecol(0x33, 0x55, 0xff), + makecol(0x33, 0x77, 0x00), + makecol(0x33, 0x77, 0x55), + makecol(0x33, 0x77, 0xaa), + makecol(0x33, 0x77, 0xff), + makecol(0x33, 0x99, 0x00), + makecol(0x33, 0x99, 0x55), + makecol(0x33, 0x99, 0xaa), + makecol(0x33, 0x99, 0xff), + makecol(0x33, 0xbb, 0x00), + makecol(0x33, 0xbb, 0x55), + makecol(0x33, 0xbb, 0xaa), + makecol(0x33, 0xbb, 0xff), + makecol(0x33, 0xdd, 0x00), + makecol(0x33, 0xdd, 0x55), + makecol(0x33, 0xdd, 0xaa), + makecol(0x33, 0xdd, 0xff), + makecol(0x33, 0xff, 0x00), + makecol(0x33, 0xff, 0x55), + makecol(0x33, 0xff, 0xaa), + makecol(0x33, 0xff, 0xff), + makecol(0x55, 0x00, 0x00), + makecol(0x55, 0x00, 0x55), + makecol(0x55, 0x00, 0xaa), + makecol(0x55, 0x00, 0xff), + makecol(0x55, 0x33, 0x00), + makecol(0x55, 0x33, 0x55), + makecol(0x55, 0x33, 0xaa), + makecol(0x55, 0x33, 0xff), + makecol(0x55, 0x55, 0x00), + makecol(0x55, 0x55, 0x55), + makecol(0x55, 0x55, 0xaa), + makecol(0x55, 0x55, 0xff), + makecol(0x55, 0x77, 0x00), + makecol(0x55, 0x77, 0x55), + makecol(0x55, 0x77, 0xaa), + makecol(0x55, 0x77, 0xff), + makecol(0x55, 0x99, 0x00), + makecol(0x55, 0x99, 0x55), + makecol(0x55, 0x99, 0xaa), + makecol(0x55, 0x99, 0xff), + makecol(0x55, 0xbb, 0x00), + makecol(0x55, 0xbb, 0x55), + makecol(0x55, 0xbb, 0xaa), + makecol(0x55, 0xbb, 0xff), + makecol(0x55, 0xdd, 0x00), + makecol(0x55, 0xdd, 0x55), + makecol(0x55, 0xdd, 0xaa), + makecol(0x55, 0xdd, 0xff), + makecol(0x55, 0xff, 0x00), + makecol(0x55, 0xff, 0x55), + makecol(0x55, 0xff, 0xaa), + makecol(0x55, 0xff, 0xff), + makecol(0x77, 0x00, 0x00), + makecol(0x77, 0x00, 0x55), + makecol(0x77, 0x00, 0xaa), + makecol(0x77, 0x00, 0xff), + makecol(0x77, 0x33, 0x00), + makecol(0x77, 0x33, 0x55), + makecol(0x77, 0x33, 0xaa), + makecol(0x77, 0x33, 0xff), + makecol(0x77, 0x55, 0x00), + makecol(0x77, 0x55, 0x55), + makecol(0x77, 0x55, 0xaa), + makecol(0x77, 0x55, 0xff), + makecol(0x77, 0x77, 0x00), + makecol(0x77, 0x77, 0x55), + makecol(0x77, 0x77, 0xaa), + makecol(0x77, 0x77, 0xff), + makecol(0x77, 0x99, 0x00), + makecol(0x77, 0x99, 0x55), + makecol(0x77, 0x99, 0xaa), + makecol(0x77, 0x99, 0xff), + makecol(0x77, 0xbb, 0x00), + makecol(0x77, 0xbb, 0x55), + makecol(0x77, 0xbb, 0xaa), + makecol(0x77, 0xbb, 0xff), + makecol(0x77, 0xdd, 0x00), + makecol(0x77, 0xdd, 0x55), + makecol(0x77, 0xdd, 0xaa), + makecol(0x77, 0xdd, 0xff), + makecol(0x77, 0xff, 0x00), + makecol(0x77, 0xff, 0x55), + makecol(0x77, 0xff, 0xaa), + makecol(0x77, 0xff, 0xff), + makecol(0x99, 0x00, 0x00), + makecol(0x99, 0x00, 0x55), + makecol(0x99, 0x00, 0xaa), + makecol(0x99, 0x00, 0xff), + makecol(0x99, 0x33, 0x00), + makecol(0x99, 0x33, 0x55), + makecol(0x99, 0x33, 0xaa), + makecol(0x99, 0x33, 0xff), + makecol(0x99, 0x55, 0x00), + makecol(0x99, 0x55, 0x55), + makecol(0x99, 0x55, 0xaa), + makecol(0x99, 0x55, 0xff), + makecol(0x99, 0x77, 0x00), + makecol(0x99, 0x77, 0x55), + makecol(0x99, 0x77, 0xaa), + makecol(0x99, 0x77, 0xff), + makecol(0x99, 0x99, 0x00), + makecol(0x99, 0x99, 0x55), + makecol(0x99, 0x99, 0xaa), + makecol(0x99, 0x99, 0xff), + makecol(0x99, 0xbb, 0x00), + makecol(0x99, 0xbb, 0x55), + makecol(0x99, 0xbb, 0xaa), + makecol(0x99, 0xbb, 0xff), + makecol(0x99, 0xdd, 0x00), + makecol(0x99, 0xdd, 0x55), + makecol(0x99, 0xdd, 0xaa), + makecol(0x99, 0xdd, 0xff), + makecol(0x99, 0xff, 0x00), + makecol(0x99, 0xff, 0x55), + makecol(0x99, 0xff, 0xaa), + makecol(0x99, 0xff, 0xff), + makecol(0xbb, 0x00, 0x00), + makecol(0xbb, 0x00, 0x55), + makecol(0xbb, 0x00, 0xaa), + makecol(0xbb, 0x00, 0xff), + makecol(0xbb, 0x33, 0x00), + makecol(0xbb, 0x33, 0x55), + makecol(0xbb, 0x33, 0xaa), + makecol(0xbb, 0x33, 0xff), + makecol(0xbb, 0x55, 0x00), + makecol(0xbb, 0x55, 0x55), + makecol(0xbb, 0x55, 0xaa), + makecol(0xbb, 0x55, 0xff), + makecol(0xbb, 0x77, 0x00), + makecol(0xbb, 0x77, 0x55), + makecol(0xbb, 0x77, 0xaa), + makecol(0xbb, 0x77, 0xff), + makecol(0xbb, 0x99, 0x00), + makecol(0xbb, 0x99, 0x55), + makecol(0xbb, 0x99, 0xaa), + makecol(0xbb, 0x99, 0xff), + makecol(0xbb, 0xbb, 0x00), + makecol(0xbb, 0xbb, 0x55), + makecol(0xbb, 0xbb, 0xaa), + makecol(0xbb, 0xbb, 0xff), + makecol(0xbb, 0xdd, 0x00), + makecol(0xbb, 0xdd, 0x55), + makecol(0xbb, 0xdd, 0xaa), + makecol(0xbb, 0xdd, 0xff), + makecol(0xbb, 0xff, 0x00), + makecol(0xbb, 0xff, 0x55), + makecol(0xbb, 0xff, 0xaa), + makecol(0xbb, 0xff, 0xff), + makecol(0xdd, 0x00, 0x00), + makecol(0xdd, 0x00, 0x55), + makecol(0xdd, 0x00, 0xaa), + makecol(0xdd, 0x00, 0xff), + makecol(0xdd, 0x33, 0x00), + makecol(0xdd, 0x33, 0x55), + makecol(0xdd, 0x33, 0xaa), + makecol(0xdd, 0x33, 0xff), + makecol(0xdd, 0x55, 0x00), + makecol(0xdd, 0x55, 0x55), + makecol(0xdd, 0x55, 0xaa), + makecol(0xdd, 0x55, 0xff), + makecol(0xdd, 0x77, 0x00), + makecol(0xdd, 0x77, 0x55), + makecol(0xdd, 0x77, 0xaa), + makecol(0xdd, 0x77, 0xff), + makecol(0xdd, 0x99, 0x00), + makecol(0xdd, 0x99, 0x55), + makecol(0xdd, 0x99, 0xaa), + makecol(0xdd, 0x99, 0xff), + makecol(0xdd, 0xbb, 0x00), + makecol(0xdd, 0xbb, 0x55), + makecol(0xdd, 0xbb, 0xaa), + makecol(0xdd, 0xbb, 0xff), + makecol(0xdd, 0xdd, 0x00), + makecol(0xdd, 0xdd, 0x55), + makecol(0xdd, 0xdd, 0xaa), + makecol(0xdd, 0xdd, 0xff), + makecol(0xdd, 0xff, 0x00), + makecol(0xdd, 0xff, 0x55), + makecol(0xdd, 0xff, 0xaa), + makecol(0xdd, 0xff, 0xff), + makecol(0xff, 0x00, 0x00), + makecol(0xff, 0x00, 0x55), + makecol(0xff, 0x00, 0xaa), + makecol(0xff, 0x00, 0xff), + makecol(0xff, 0x33, 0x00), + makecol(0xff, 0x33, 0x55), + makecol(0xff, 0x33, 0xaa), + makecol(0xff, 0x33, 0xff), + makecol(0xff, 0x55, 0x00), + makecol(0xff, 0x55, 0x55), + makecol(0xff, 0x55, 0xaa), + makecol(0xff, 0x55, 0xff), + makecol(0xff, 0x77, 0x00), + makecol(0xff, 0x77, 0x55), + makecol(0xff, 0x77, 0xaa), + makecol(0xff, 0x77, 0xff), + makecol(0xff, 0x99, 0x00), + makecol(0xff, 0x99, 0x55), + makecol(0xff, 0x99, 0xaa), + makecol(0xff, 0x99, 0xff), + makecol(0xff, 0xbb, 0x00), + makecol(0xff, 0xbb, 0x55), + makecol(0xff, 0xbb, 0xaa), + makecol(0xff, 0xbb, 0xff), + makecol(0xff, 0xdd, 0x00), + makecol(0xff, 0xdd, 0x55), + makecol(0xff, 0xdd, 0xaa), + makecol(0xff, 0xdd, 0xff), + makecol(0xff, 0xff, 0x00), + makecol(0xff, 0xff, 0x55), + makecol(0xff, 0xff, 0xaa), + makecol(0xff, 0xff, 0xff), + }, +/* Palette 5: 6x6x6 colour cube */ + { + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x33), + makecol(0x00,0x00,0x66), + makecol(0x00,0x00,0x99), + makecol(0x00,0x00,0xcc), + makecol(0x00,0x00,0xff), + makecol(0x33,0x00,0x00), + makecol(0x33,0x00,0x33), + makecol(0x33,0x00,0x66), + makecol(0x33,0x00,0x99), + makecol(0x33,0x00,0xcc), + makecol(0x33,0x00,0xff), + makecol(0x66,0x00,0x00), + makecol(0x66,0x00,0x33), + makecol(0x66,0x00,0x66), + makecol(0x66,0x00,0x99), + makecol(0x66,0x00,0xcc), + makecol(0x66,0x00,0xff), + makecol(0x99,0x00,0x00), + makecol(0x99,0x00,0x33), + makecol(0x99,0x00,0x66), + makecol(0x99,0x00,0x99), + makecol(0x99,0x00,0xcc), + makecol(0x99,0x00,0xff), + makecol(0xcc,0x00,0x00), + makecol(0xcc,0x00,0x33), + makecol(0xcc,0x00,0x66), + makecol(0xcc,0x00,0x99), + makecol(0xcc,0x00,0xcc), + makecol(0xcc,0x00,0xff), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x33), + makecol(0xff,0x00,0x66), + makecol(0xff,0x00,0x99), + makecol(0xff,0x00,0xcc), + makecol(0xff,0x00,0xff), + makecol(0x00,0x33,0x00), + makecol(0x00,0x33,0x33), + makecol(0x00,0x33,0x66), + makecol(0x00,0x33,0x99), + makecol(0x00,0x33,0xcc), + makecol(0x00,0x33,0xff), + makecol(0x33,0x33,0x00), + makecol(0x33,0x33,0x33), + makecol(0x33,0x33,0x66), + makecol(0x33,0x33,0x99), + makecol(0x33,0x33,0xcc), + makecol(0x33,0x33,0xff), + makecol(0x66,0x33,0x00), + makecol(0x66,0x33,0x33), + makecol(0x66,0x33,0x66), + makecol(0x66,0x33,0x99), + makecol(0x66,0x33,0xcc), + makecol(0x66,0x33,0xff), + makecol(0x99,0x33,0x00), + makecol(0x99,0x33,0x33), + makecol(0x99,0x33,0x66), + makecol(0x99,0x33,0x99), + makecol(0x99,0x33,0xcc), + makecol(0x99,0x33,0xff), + makecol(0xcc,0x33,0x00), + makecol(0xcc,0x33,0x33), + makecol(0xcc,0x33,0x66), + makecol(0xcc,0x33,0x99), + makecol(0xcc,0x33,0xcc), + makecol(0xcc,0x33,0xff), + makecol(0xff,0x33,0x00), + makecol(0xff,0x33,0x33), + makecol(0xff,0x33,0x66), + makecol(0xff,0x33,0x99), + makecol(0xff,0x33,0xcc), + makecol(0xff,0x33,0xff), + makecol(0x00,0x66,0x00), + makecol(0x00,0x66,0x33), + makecol(0x00,0x66,0x66), + makecol(0x00,0x66,0x99), + makecol(0x00,0x66,0xcc), + makecol(0x00,0x66,0xff), + makecol(0x33,0x66,0x00), + makecol(0x33,0x66,0x33), + makecol(0x33,0x66,0x66), + makecol(0x33,0x66,0x99), + makecol(0x33,0x66,0xcc), + makecol(0x33,0x66,0xff), + makecol(0x66,0x66,0x00), + makecol(0x66,0x66,0x33), + makecol(0x66,0x66,0x66), + makecol(0x66,0x66,0x99), + makecol(0x66,0x66,0xcc), + makecol(0x66,0x66,0xff), + makecol(0x99,0x66,0x00), + makecol(0x99,0x66,0x33), + makecol(0x99,0x66,0x66), + makecol(0x99,0x66,0x99), + makecol(0x99,0x66,0xcc), + makecol(0x99,0x66,0xff), + makecol(0xcc,0x66,0x00), + makecol(0xcc,0x66,0x33), + makecol(0xcc,0x66,0x66), + makecol(0xcc,0x66,0x99), + makecol(0xcc,0x66,0xcc), + makecol(0xcc,0x66,0xff), + makecol(0xff,0x66,0x00), + makecol(0xff,0x66,0x33), + makecol(0xff,0x66,0x66), + makecol(0xff,0x66,0x99), + makecol(0xff,0x66,0xcc), + makecol(0xff,0x66,0xff), + makecol(0x00,0x99,0x00), + makecol(0x00,0x99,0x33), + makecol(0x00,0x99,0x66), + makecol(0x00,0x99,0x99), + makecol(0x00,0x99,0xcc), + makecol(0x00,0x99,0xff), + makecol(0x33,0x99,0x00), + makecol(0x33,0x99,0x33), + makecol(0x33,0x99,0x66), + makecol(0x33,0x99,0x99), + makecol(0x33,0x99,0xcc), + makecol(0x33,0x99,0xff), + makecol(0x66,0x99,0x00), + makecol(0x66,0x99,0x33), + makecol(0x66,0x99,0x66), + makecol(0x66,0x99,0x99), + makecol(0x66,0x99,0xcc), + makecol(0x66,0x99,0xff), + makecol(0x99,0x99,0x00), + makecol(0x99,0x99,0x33), + makecol(0x99,0x99,0x66), + makecol(0x99,0x99,0x99), + makecol(0x99,0x99,0xcc), + makecol(0x99,0x99,0xff), + makecol(0xcc,0x99,0x00), + makecol(0xcc,0x99,0x33), + makecol(0xcc,0x99,0x66), + makecol(0xcc,0x99,0x99), + makecol(0xcc,0x99,0xcc), + makecol(0xcc,0x99,0xff), + makecol(0xff,0x99,0x00), + makecol(0xff,0x99,0x33), + makecol(0xff,0x99,0x66), + makecol(0xff,0x99,0x99), + makecol(0xff,0x99,0xcc), + makecol(0xff,0x99,0xff), + makecol(0x00,0xcc,0x00), + makecol(0x00,0xcc,0x33), + makecol(0x00,0xcc,0x66), + makecol(0x00,0xcc,0x99), + makecol(0x00,0xcc,0xcc), + makecol(0x00,0xcc,0xff), + makecol(0x33,0xcc,0x00), + makecol(0x33,0xcc,0x33), + makecol(0x33,0xcc,0x66), + makecol(0x33,0xcc,0x99), + makecol(0x33,0xcc,0xcc), + makecol(0x33,0xcc,0xff), + makecol(0x66,0xcc,0x00), + makecol(0x66,0xcc,0x33), + makecol(0x66,0xcc,0x66), + makecol(0x66,0xcc,0x99), + makecol(0x66,0xcc,0xcc), + makecol(0x66,0xcc,0xff), + makecol(0x99,0xcc,0x00), + makecol(0x99,0xcc,0x33), + makecol(0x99,0xcc,0x66), + makecol(0x99,0xcc,0x99), + makecol(0x99,0xcc,0xcc), + makecol(0x99,0xcc,0xff), + makecol(0xcc,0xcc,0x00), + makecol(0xcc,0xcc,0x33), + makecol(0xcc,0xcc,0x66), + makecol(0xcc,0xcc,0x99), + makecol(0xcc,0xcc,0xcc), + makecol(0xcc,0xcc,0xff), + makecol(0xff,0xcc,0x00), + makecol(0xff,0xcc,0x33), + makecol(0xff,0xcc,0x66), + makecol(0xff,0xcc,0x99), + makecol(0xff,0xcc,0xcc), + makecol(0xff,0xcc,0xff), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x33), + makecol(0x00,0xff,0x66), + makecol(0x00,0xff,0x99), + makecol(0x00,0xff,0xcc), + makecol(0x00,0xff,0xff), + makecol(0x33,0xff,0x00), + makecol(0x33,0xff,0x33), + makecol(0x33,0xff,0x66), + makecol(0x33,0xff,0x99), + makecol(0x33,0xff,0xcc), + makecol(0x33,0xff,0xff), + makecol(0x66,0xff,0x00), + makecol(0x66,0xff,0x33), + makecol(0x66,0xff,0x66), + makecol(0x66,0xff,0x99), + makecol(0x66,0xff,0xcc), + makecol(0x66,0xff,0xff), + makecol(0x99,0xff,0x00), + makecol(0x99,0xff,0x33), + makecol(0x99,0xff,0x66), + makecol(0x99,0xff,0x99), + makecol(0x99,0xff,0xcc), + makecol(0x99,0xff,0xff), + makecol(0xcc,0xff,0x00), + makecol(0xcc,0xff,0x33), + makecol(0xcc,0xff,0x66), + makecol(0xcc,0xff,0x99), + makecol(0xcc,0xff,0xcc), + makecol(0xcc,0xff,0xff), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x33), + makecol(0xff,0xff,0x66), + makecol(0xff,0xff,0x99), + makecol(0xff,0xff,0xcc), + makecol(0xff,0xff,0xff), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + }, + + +#endif /*VID_PGC_PALETTE_H*/ diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 79c122b0f..fb2038768 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -24,6 +24,7 @@ #include "../86box.h" #include "../device.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../pci.h" #include "../rom.h" @@ -39,6 +40,8 @@ #include "vid_icd2061.h" #include "../cpu/cpu.h" +#define ROM_ORCHID_86C911 L"roms/video/s3/BIOS.BIN" +#define ROM_METHEUS_86C928 L"roms/video/s3/928.vbi" #define ROM_V7MIRAGE_86C801 L"roms/video/s3/v7mirage.vbi" #define ROM_PHOENIX_86C805 L"roms/video/s3/805.vbi" #define ROM_PARADISE_BAHAMAS64 L"roms/video/s3/bahamas64.bin" @@ -60,19 +63,24 @@ enum S3_PHOENIX_VISION864, S3_DIAMOND_STEALTH64_764, S3_V7MIRAGE_86C801, - S3_PHOENIX_86C805 + S3_PHOENIX_86C805, + S3_ORCHID_86C911, + S3_METHEUS_86C928 }; enum { S3_86C801, S3_86C805, + S3_86C928, + S3_86C911, S3_VISION864, S3_VISION964, S3_TRIO32, S3_TRIO64 }; +static video_timings_t timing_s3_86c911 = {VIDEO_ISA, 4, 4, 5, 20, 20, 35}; static video_timings_t timing_s3_86c801 = {VIDEO_ISA, 4, 4, 5, 20, 20, 35}; static video_timings_t timing_s3_86c805 = {VIDEO_BUS, 4, 4, 5, 20, 20, 35}; static video_timings_t timing_s3_stealth64 = {VIDEO_BUS, 2, 2, 4, 26, 26, 42}; @@ -130,10 +138,10 @@ typedef struct s3_t uint8_t bank; uint8_t ma_ext; - int width; - int bpp; + int width, bpp; - int chip, pci; + int chip; + int pci, vlb; uint8_t id, id_ext, id_ext_pci; @@ -206,6 +214,8 @@ typedef struct s3_t uint32_t hwc_fg_col, hwc_bg_col; int hwc_col_stack_pos; + + int translate; } s3_t; #define INT_VSY (1 << 0) @@ -220,6 +230,16 @@ void s3_accel_write(uint32_t addr, uint8_t val, void *p); void s3_accel_write_w(uint32_t addr, uint16_t val, void *p); void s3_accel_write_l(uint32_t addr, uint32_t val, void *p); uint8_t s3_accel_read(uint32_t addr, void *p); +uint16_t s3_accel_read_w(uint32_t addr, void *p); +uint32_t s3_accel_read_l(uint32_t addr, void *p); + +void s3_out(uint16_t addr, uint8_t val, void *p); +uint8_t s3_in(uint16_t addr, void *p); + +void s3_accel_out(uint16_t port, uint8_t val, void *p); +void s3_accel_out_w(uint16_t port, uint16_t val, void *p); +void s3_accel_out_l(uint16_t port, uint32_t val, void *p); +uint8_t s3_accel_in(uint16_t port, void *p); static inline void wake_fifo_thread(s3_t *s3) { @@ -258,144 +278,173 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \ } +int s3_cpu_src(s3_t *s3) +{ + if (!(s3->accel.cmd & 0x100)) + return 0; + + if (s3->chip > S3_86C911) + return 1; + + if (s3->accel.cmd & 1) + return 1; + + return 0; +} + +int s3_cpu_dest(s3_t *s3) +{ + if (!(s3->accel.cmd & 0x100)) + return 0; + + if (s3->chip > S3_86C911) + return 0; + + if (s3->accel.cmd & 1) + return 0; + + return 1; +} + static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) { switch (port) { - case 0x82e8: + case 0x8148: case 0x82e8: s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val; s3->accel.poly_cy = s3->accel.cur_y; break; - case 0x82e9: + case 0x8149: case 0x82e9: s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x1f) << 8); s3->accel.poly_cy = s3->accel.cur_y; break; - case 0x82ea: + case 0x814a: case 0x82ea: s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xf00) | val; s3->accel.poly_cy2 = s3->accel.cur_y2; break; - case 0x82eb: + case 0x814b: case 0x82eb: s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xff) | ((val & 0x1f) << 8); s3->accel.poly_cy2 = s3->accel.cur_y2; break; - case 0x86e8: + case 0x8548: case 0x86e8: s3->accel.cur_x = (s3->accel.cur_x & 0xf00) | val; s3->accel.poly_cx = s3->accel.cur_x << 20; s3->accel.poly_x = s3->accel.poly_cx >> 20; break; - case 0x86e9: + case 0x8549: case 0x86e9: s3->accel.cur_x = (s3->accel.cur_x & 0xff) | ((val & 0x1f) << 8); s3->accel.poly_cx = s3->accel.poly_x = s3->accel.cur_x << 20; s3->accel.poly_x = s3->accel.poly_cx >> 20; break; - case 0x86ea: + case 0x854a: case 0x86ea: s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xf00) | val; s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; break; - case 0x86eb: + case 0x854b: case 0x86eb: s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xff) | ((val & 0x1f) << 8); s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; break; - case 0x8ae8: + case 0x8948: case 0x8ae8: s3->accel.desty_axstp = (s3->accel.desty_axstp & 0x3f00) | val; s3->accel.point_1_updated = 1; break; - case 0x8ae9: + case 0x8949: case 0x8ae9: s3->accel.desty_axstp = (s3->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) s3->accel.desty_axstp |= ~0x3fff; s3->accel.point_1_updated = 1; break; - case 0x8aea: + case 0x894a: case 0x8aea: s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0x3f00) | val; s3->accel.point_2_updated = 1; break; - case 0x8aeb: + case 0x849b: case 0x8aeb: s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) s3->accel.desty_axstp2 |= ~0x3fff; s3->accel.point_2_updated = 1; break; - case 0x8ee8: + case 0x8d48: case 0x8ee8: s3->accel.destx_distp = (s3->accel.destx_distp & 0x3f00) | val; s3->accel.point_1_updated = 1; break; - case 0x8ee9: + case 0x8d49: case 0x8ee9: s3->accel.destx_distp = (s3->accel.destx_distp & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) s3->accel.destx_distp |= ~0x3fff; s3->accel.point_1_updated = 1; break; - case 0x8eea: + case 0x8d4a: case 0x8eea: s3->accel.x2 = (s3->accel.x2 & 0xf00) | val; s3->accel.point_2_updated = 1; break; - case 0x8eeb: + case 0x8d4b: case 0x8eeb: s3->accel.x2 = (s3->accel.x2 & 0xff) | ((val & 0xf) << 8); s3->accel.point_2_updated = 1; break; - case 0x92e8: + case 0x9148: case 0x92e8: s3->accel.err_term = (s3->accel.err_term & 0x3f00) | val; break; - case 0x92e9: + case 0x9149: case 0x92e9: s3->accel.err_term = (s3->accel.err_term & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) s3->accel.err_term |= ~0x3fff; break; - case 0x92ea: + case 0x914a: case 0x92ea: s3->accel.err_term2 = (s3->accel.err_term2 & 0x3f00) | val; break; - case 0x92eb: + case 0x914b: case 0x92eb: s3->accel.err_term2 = (s3->accel.err_term2 & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) s3->accel.err_term2 |= ~0x3fff; break; - case 0x96e8: + case 0x9548: case 0x96e8: s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0x3f00) | val; break; - case 0x96e9: + case 0x9459: case 0x96e9: s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0xff) | ((val & 0x0f) << 8); if (val & 0x08) s3->accel.maj_axis_pcnt |= ~0x0fff; break; - case 0x96ea: + case 0x954a: case 0x96ea: s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xf00) | val; break; - case 0x96eb: + case 0x954b: case 0x96eb: s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xff) | ((val & 0x0f) << 8); if (val & 0x08) s3->accel.maj_axis_pcnt2 |= ~0x0fff; break; - case 0x9ae8: + case 0x9948: case 0x9ae8: s3->accel.cmd = (s3->accel.cmd & 0xff00) | val; + s3->data_available = 0; break; - case 0x9ae9: + case 0x9949: case 0x9ae9: s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8); s3_accel_start(-1, 0, 0xffffffff, 0, s3); s3->accel.pix_trans_count = 0; s3->accel.multifunc[0xe] &= ~0x10; /*hack*/ break; - case 0x9ee8: + case 0x9d48: case 0x9ee8: s3->accel.short_stroke = (s3->accel.short_stroke & 0xff00) | val; break; - case 0x9ee9: + case 0x9d49: case 0x9ee9: s3->accel.short_stroke = (s3->accel.short_stroke & 0xff) | (val << 8); break; - case 0xa2e8: + case 0xa148: case 0xa2e8: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); else s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; break; - case 0xa2e9: + case 0xa149: case 0xa2e9: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); else @@ -403,7 +452,7 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; break; - case 0xa2ea: + case 0xa14a: case 0xa2ea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); else if (s3->bpp == 3) @@ -414,7 +463,7 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; } break; - case 0xa2eb: + case 0xa14b: case 0xa2eb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); else if (s3->bpp == 3) @@ -427,13 +476,13 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) } break; - case 0xa6e8: + case 0xa548: case 0xa6e8: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); else s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; break; - case 0xa6e9: + case 0xa549: case 0xa6e9: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); else @@ -441,7 +490,7 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; break; - case 0xa6ea: + case 0xa54a: case 0xa6ea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); else if (s3->bpp == 3) @@ -452,7 +501,7 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; } break; - case 0xa6eb: + case 0xa54b: case 0xa6eb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); else if (s3->bpp == 3) @@ -465,13 +514,13 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) } break; - case 0xaae8: + case 0xa948: case 0xaae8: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); else s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; break; - case 0xaae9: + case 0xa949: case 0xaae9: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); else @@ -479,7 +528,7 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; break; - case 0xaaea: + case 0xa94a: case 0xaaea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); else if (s3->bpp == 3) @@ -490,7 +539,7 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; } break; - case 0xaaeb: + case 0xa94b: case 0xaaeb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); else if (s3->bpp == 3) @@ -503,13 +552,13 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) } break; - case 0xaee8: + case 0xad48: case 0xaee8: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); else s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; break; - case 0xaee9: + case 0xad49: case 0xaee9: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); else @@ -517,7 +566,7 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; break; - case 0xaeea: + case 0xad4a: case 0xaeea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); else if (s3->bpp == 3) @@ -528,7 +577,7 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; } break; - case 0xaeeb: + case 0xad4b: case 0xaeeb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); else if (s3->bpp == 3) @@ -541,13 +590,13 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) } break; - case 0xb2e8: + case 0xb148: case 0xb2e8: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); else s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; break; - case 0xb2e9: + case 0xb149: case 0xb2e9: if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); else @@ -555,7 +604,7 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (!(s3->accel.multifunc[0xe] & 0x200)) s3->accel.multifunc[0xe] ^= 0x10; break; - case 0xb2ea: + case 0xb14a: case 0xb2ea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); else if (s3->bpp == 3) @@ -566,7 +615,7 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; } break; - case 0xb2eb: + case 0xb14b: case 0xb2eb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); else if (s3->bpp == 3) @@ -579,30 +628,34 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) } break; - case 0xb6e8: + case 0xb548: case 0xb6e8: s3->accel.bkgd_mix = val; break; - case 0xbae8: + case 0xb948: case 0xbae8: s3->accel.frgd_mix = val; break; - case 0xbee8: + case 0xbd48: case 0xbee8: s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff00) | val; break; - case 0xbee9: + case 0xbd49: case 0xbee9: s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff) | (val << 8); s3->accel.multifunc[s3->accel.multifunc_cntl >> 12] = s3->accel.multifunc_cntl & 0xfff; break; - case 0xe2e8: + case 0xe148: case 0xe2e8: + if (s3_cpu_dest(s3)) + break; s3->accel.pix_trans[0] = val; if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); break; - case 0xe2e9: + case 0xe149: case 0xe2e9: + if (s3_cpu_dest(s3)) + break; s3->accel.pix_trans[1] = val; if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) { @@ -615,10 +668,14 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) else s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); } break; - case 0xe2ea: + case 0xe14a: case 0xe2ea: + if (s3_cpu_dest(s3)) + break; s3->accel.pix_trans[2] = val; break; - case 0xe2eb: + case 0xe14b: case 0xe2eb: + if (s3_cpu_dest(s3)) + break; s3->accel.pix_trans[3] = val; if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x600 && (s3->accel.cmd & 0x100) && s3->chip == S3_TRIO32) { @@ -1005,11 +1062,218 @@ static void s3_queue(s3_t *s3, uint32_t addr, uint32_t val, uint32_t type) wake_fifo_thread(s3); } +void s3_hwcursor_draw(svga_t *svga, int displine) +{ + s3_t *s3 = (s3_t *)svga->p; + int x; + uint16_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int y_add, x_add; + uint32_t fg, bg; + + y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; + x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + + switch (svga->bpp) + { + case 15: + fg = video_15to32[s3->hwc_fg_col & 0xffff]; + bg = video_15to32[s3->hwc_bg_col & 0xffff]; + break; + + case 16: + fg = video_16to32[s3->hwc_fg_col & 0xffff]; + bg = video_16to32[s3->hwc_bg_col & 0xffff]; + break; + + case 24: case 32: + fg = s3->hwc_fg_col; + bg = s3->hwc_bg_col; + break; + + default: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + { + fg = svga->pallook[s3->hwc_fg_col & 0xff]; + bg = svga->pallook[s3->hwc_bg_col & 0xff]; + } + else + { + fg = svga->pallook[svga->crtc[0xe]]; + bg = svga->pallook[svga->crtc[0xf]]; + } + break; + } + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; + + for (x = 0; x < 64; x += 16) + { + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x8000)) + buffer32->line[displine + y_add][offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; + else if (dat[1] & 0x8000) + buffer32->line[displine + y_add][offset + 32 + x_add] ^= 0xffffff; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr += 4; + } + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; +} + +static void s3_io_remove_alt(s3_t *s3) +{ + if (!s3->translate) + return; + + io_removehandler(0x4148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x4548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x4948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8d48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9d48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xad48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbd48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); +} + +static void s3_io_remove(s3_t *s3) +{ + io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x82e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x86e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8ae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8ee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x92e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x96e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + + s3_io_remove_alt(s3); +} + +void s3_io_set_alt(s3_t *s3) +{ + if (!s3->translate) + return; + + io_sethandler(0x4148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x4548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x4948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip == S3_TRIO64) + { + io_sethandler(0x8148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8d48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + else + { + io_sethandler(0x8148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8d48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9148, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + io_sethandler(0x9948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9d48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa548, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa948, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xad48, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb548, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb948, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbd48, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe148, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); +} + +static void s3_io_set(s3_t *s3) +{ + s3_io_remove(s3); + + io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip == S3_TRIO64) + { + io_sethandler(0x82e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + else + { + io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); + + s3_io_set_alt(s3); +} + void s3_out(uint16_t addr, uint8_t val, void *p) { s3_t *s3 = (s3_t *)p; svga_t *svga = &s3->svga; - uint8_t old; + uint8_t old, mask; int rs2, rs3; if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) @@ -1018,7 +1282,7 @@ void s3_out(uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x3c2: - if (s3->chip == S3_VISION964) { + if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { if (((val >> 2) & 3) != 3) icd2061_write(svga->clock_gen, (val >> 2) & 3); } @@ -1051,13 +1315,13 @@ void s3_out(uint16_t addr, uint8_t val, void *p) rs2 = (svga->crtc[0x55] & 0x01); if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) svga_out(addr, val, svga); - else if (s3->chip == S3_VISION964) { - if (!(svga->crtc[0x45] & 0x20)) + else if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { + if (!(svga->crtc[0x45] & 0x20) || (s3->chip == S3_86C928)) rs3 = !!(svga->crtc[0x55] & 0x02); else - rs3 = 0; + rs3 = 0; bt48x_ramdac_out(addr, rs2, rs3, val, svga->ramdac, svga); - } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805) + } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805 || s3->chip == S3_86C911) att49x_ramdac_out(addr, val, svga->ramdac, svga); else sdac_ramdac_out(addr, rs2, val, svga->ramdac, svga); @@ -1091,7 +1355,10 @@ void s3_out(uint16_t addr, uint8_t val, void *p) break; case 0x50: - switch (svga->crtc[0x50] & 0xc1) + mask = 0xc0; + if (s3->chip > S3_86C805) + mask |= 0x01; + switch (svga->crtc[0x50] & mask) { case 0x00: s3->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break; case 0x01: s3->width = 1152; break; @@ -1103,7 +1370,9 @@ void s3_out(uint16_t addr, uint8_t val, void *p) s3->bpp = (svga->crtc[0x50] >> 4) & 3; break; case 0x69: - s3->ma_ext = val & 0x1f; + if ((s3->chip != S3_86C801) && (s3->chip != S3_86C805) && + (s3->chip != S3_86C911) && (s3->chip != S3_86C928)) + s3->ma_ext = val & 0x1f; break; case 0x35: @@ -1114,19 +1383,28 @@ void s3_out(uint16_t addr, uint8_t val, void *p) svga->write_bank = svga->read_bank = s3->bank << 14; break; case 0x51: - s3->bank = (s3->bank & 0x4f) | ((val & 0xc) << 2); + if ((s3->chip != S3_86C801) && (s3->chip != S3_86C805)) + s3->bank = (s3->bank & 0x6f) | ((val & 0x4) << 2); + else + s3->bank = (s3->bank & 0x4f) | ((val & 0xc) << 2); if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16; else svga->write_bank = svga->read_bank = s3->bank << 14; - s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2); + if ((s3->chip != S3_86C801) && (s3->chip != S3_86C805)) + s3->ma_ext = (s3->ma_ext & ~0x4) | ((val & 1) << 2); + else + s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2); break; case 0x6a: - s3->bank = val; - if (svga->chain4) - svga->write_bank = svga->read_bank = s3->bank << 16; - else - svga->write_bank = svga->read_bank = s3->bank << 14; + if ((s3->chip != S3_86C801) && (s3->chip != S3_86C805) && + (s3->chip != S3_86C911) && (s3->chip != S3_86C928)) { + s3->bank = val; + if (svga->chain4) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + } break; case 0x3a: @@ -1150,7 +1428,7 @@ void s3_out(uint16_t addr, uint8_t val, void *p) svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); if ((s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) && svga->bpp == 32) svga->hwcursor.x <<= 1; - else if ((s3->chip == S3_86C801 || s3->chip == S3_86C805) && (svga->bpp == 15 || svga->bpp == 16)) + else if ((s3->chip == S3_86C801 || s3->chip == S3_86C805 || s3->chip == S3_86C928) && (svga->bpp == 15 || svga->bpp == 16)) svga->hwcursor.x >>= 1; break; @@ -1187,16 +1465,38 @@ void s3_out(uint16_t addr, uint8_t val, void *p) case 0x53: case 0x58: case 0x59: case 0x5a: - s3_updatemapping(s3); + if (s3->chip != S3_86C911) + s3_updatemapping(s3); + break; + + case 0x55: + if (s3->chip == S3_86C928) { + if (val & 0x08) { + svga->hwcursor_draw = NULL; + svga->dac_hwcursor_draw = bt48x_hwcursor_draw; + } else { + svga->hwcursor_draw = s3_hwcursor_draw; + svga->dac_hwcursor_draw = NULL; + } + } break; case 0x42: - if (s3->chip == S3_VISION964) { + if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { if (((svga->miscout >> 2) & 3) == 3) icd2061_write(svga->clock_gen, svga->crtc[0x42] & 0x0f); } break; + case 0x43: + if (s3->chip == S3_86C801 || s3->chip == S3_86C805 || + s3->chip == S3_86C911 || s3->chip == S3_86C928) { + s3_io_remove_alt(s3); + s3->translate = !!(svga->crtc[0x43] & 0x10); + s3_io_set_alt(s3); + } + break; + case 0x67: if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) { @@ -1240,6 +1540,11 @@ uint8_t s3_in(uint16_t addr, void *p) if (svga->attraddr > 0x14) return 0xff; break; + + case 0x3c2: + if (s3->chip == S3_86C911) + return svga_in(addr, svga) | 0x10; + break; case 0x3c5: if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) @@ -1250,10 +1555,10 @@ uint8_t s3_in(uint16_t addr, void *p) rs2 = (svga->crtc[0x55] & 0x01) || !!(svga->crtc[0x43] & 2); if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) return svga_in(addr, svga); - else if (s3->chip == S3_VISION964) { + else if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { rs3 = !!(svga->crtc[0x55] & 0x02); return bt48x_ramdac_in(addr, rs2, rs3, svga->ramdac, svga); - } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805) + } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805 || s3->chip == S3_86C911) return att49x_ramdac_in(addr, svga->ramdac, svga); else return sdac_ramdac_in(addr, rs2, svga->ramdac, svga); @@ -1295,6 +1600,8 @@ void s3_recalctimings(svga_t *svga) { s3_t *s3 = (s3_t *)svga->p; bt48x_ramdac_t *ramdac = (bt48x_ramdac_t *) svga->ramdac; + int clk_sel = (svga->miscout >> 2) & 3; + svga->hdisp = svga->hdisp_old; svga->ma_latch |= (s3->ma_ext << 16); @@ -1313,24 +1620,17 @@ void s3_recalctimings(svga_t *svga) else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; if (!svga->rowoffset) svga->rowoffset = 256; - if (s3->chip == S3_VISION964) { - svga->interlace = ramdac->cr2 & 0x08; - if (ramdac->cr3 & 0x08) + if (s3->chip == S3_VISION964 || s3->chip == S3_86C928) { + svga->interlace = ramdac->cmd_r2 & 0x08; + if (ramdac->cmd_r3 & 0x08) svga->hdisp *= 2; /* x2 clock multiplier */ - if (((svga->miscout >> 2) & 3) == 3) - svga->clock = cpuclock / svga->getclock(svga->crtc[0x42] & 0x0f, svga->clock_gen); - else - svga->clock = cpuclock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); - } else if (s3->chip == S3_86C801 || s3->chip == S3_86C805) { + } else svga->interlace = svga->crtc[0x42] & 0x20; - if (((svga->miscout >> 2) & 3) == 3) - svga->clock = cpuclock / svga->getclock(svga->crtc[0x42] & 0x0f, svga->clock_gen); - else - svga->clock = cpuclock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); - } else { - svga->interlace = svga->crtc[0x42] & 0x20; - svga->clock = cpuclock / svga->getclock((svga->miscout >> 2) & 3, svga->clock_gen); - } + + if ((((svga->miscout >> 2) & 3) == 3) && (s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64)) + clk_sel = svga->crtc[0x42] & 0x0f; + + svga->clock = (cpuclock * (double)(1ull << 32)) / svga->getclock(clk_sel, svga->clock_gen); switch (svga->crtc[0x67] >> 4) { @@ -1349,24 +1649,29 @@ void s3_recalctimings(svga_t *svga) break; case 15: svga->render = svga_render_15bpp_highres; - if (s3->chip != S3_VISION964 && s3->chip != S3_86C801) + if (s3->chip != S3_VISION964 && s3->chip != S3_86C801 && s3->chip != S3_86C928) svga->hdisp /= 2; break; case 16: - svga->render = svga_render_16bpp_highres; + svga->render = svga_render_16bpp_highres; if (s3->chip != S3_VISION964 && s3->chip != S3_86C801) - svga->hdisp /= 2; + { + if (s3->chip == S3_86C928) + svga->hdisp *= 2; + else + svga->hdisp /= 2; + } break; case 24: svga->render = svga_render_24bpp_highres; - if (s3->chip != S3_86C801 && s3->chip != S3_86C805) + if (s3->chip != S3_86C801 && s3->chip != S3_86C805 && s3->chip != S3_86C928) svga->hdisp /= 3; else svga->hdisp = (svga->hdisp * 2) / 3; break; case 32: svga->render = svga_render_32bpp_highres; - if ((s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964)) + if ((s3->chip != S3_TRIO32) && (s3->chip != S3_TRIO64) && (s3->chip != S3_VISION964) && (s3->chip != S3_86C928)) svga->hdisp /= 4; break; } @@ -1416,8 +1721,15 @@ void s3_updatemapping(s3_t *s3) { /*Linear framebuffer*/ mem_mapping_disable(&svga->mapping); - + s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); + if ((s3->chip == S3_86C801) || (s3->chip == S3_86C805) || + (s3->chip == S3_86C911) || (s3->chip == S3_86C928)) { + if (s3->vlb) + s3->linear_base &= 0x03ffffff; + else + s3->linear_base &= 0x00ffffff; + } switch (svga->crtc[0x58] & 3) { case 0: /*64k*/ @@ -1435,6 +1747,7 @@ void s3_updatemapping(s3_t *s3) case S3_TRIO64: case S3_86C801: case S3_86C805: + case S3_86C928: s3->linear_size = 0x400000; break; default: @@ -1460,7 +1773,7 @@ void s3_updatemapping(s3_t *s3) mem_mapping_disable(&s3->linear_mapping); /* Memory mapped I/O. */ - if (svga->crtc[0x53] & 0x10) { + if ((svga->crtc[0x53] & 0x10) || (s3->accel.advfunc_cntl & 0x20)) { /* Old MMIO. */ mem_mapping_disable(&svga->mapping); mem_mapping_enable(&s3->mmio_mapping); @@ -1484,115 +1797,152 @@ static float s3_trio64_getclock(int clock, void *p) } +int s3_enable_fifo(s3_t *s3) +{ +/* FIXME: See why the Windows 3.x drivers break in non-FIFO mode - maybe FIFO is not disablable there? */ +#if 0 + svga_t *svga = &s3->svga; + + if ((s3->chip == S3_TRIO32) || (s3->chip == S3_TRIO64) || + (s3->chip == S3_VISION864) || (s3->chip == S3_VISION964)) + return 1; /* FIFO always enabled on these chips. */ + + return !!((svga->crtc[0x40] & 0x08) || (s3->accel.advfunc_cntl & 0x40)); +#else + return 1; +#endif +} + + void s3_accel_out(uint16_t port, uint8_t val, void *p) { s3_t *s3 = (s3_t *)p; - + if (port >= 0x8000) { - s3_queue(s3, port, val, FIFO_OUT_BYTE); + if (s3_enable_fifo(s3)) + s3_queue(s3, port, val, FIFO_OUT_BYTE); + else + s3_accel_out_fifo(s3, port, val); } - else switch (port) + else { - case 0x42e8: - s3->subsys_stat &= ~val; - s3_update_irqs(s3); - break; - case 0x42e9: - s3->subsys_cntl = val; - s3_update_irqs(s3); - break; - case 0x46e8: - s3->accel.setup_md = val; - break; - case 0x4ae8: - s3->accel.advfunc_cntl = val; - s3_updatemapping(s3); - break; + switch (port) + { + case 0x4148: case 0x42e8: + s3->subsys_stat &= ~val; + s3_update_irqs(s3); + break; + case 0x4149: case 0x42e9: + s3->subsys_cntl = val; + s3_update_irqs(s3); + break; + case 0x4548: case 0x46e8: + s3->accel.setup_md = val; + break; + case 0x4948: case 0x4ae8: + s3->accel.advfunc_cntl = val; + s3_updatemapping(s3); + break; + } } } void s3_accel_out_w(uint16_t port, uint16_t val, void *p) { s3_t *s3 = (s3_t *)p; - s3_queue(s3, port, val, FIFO_OUT_WORD); + + if (s3_enable_fifo(s3)) + s3_queue(s3, port, val, FIFO_OUT_WORD); + else + s3_accel_out_fifo_w(s3, port, val); } void s3_accel_out_l(uint16_t port, uint32_t val, void *p) { s3_t *s3 = (s3_t *)p; - s3_queue(s3, port, val, FIFO_OUT_DWORD); + + if (s3_enable_fifo(s3)) + s3_queue(s3, port, val, FIFO_OUT_DWORD); + else + s3_accel_out_fifo_l(s3, port, val); } uint8_t s3_accel_in(uint16_t port, void *p) { s3_t *s3 = (s3_t *)p; int temp; + switch (port) { - case 0x42e8: + case 0x4148: case 0x42e8: return s3->subsys_stat; - case 0x42e9: + case 0x4149: case 0x42e9: return s3->subsys_cntl; - case 0x82e8: + case 0x8148: case 0x82e8: s3_wait_fifo_idle(s3); return s3->accel.cur_y & 0xff; - case 0x82e9: + case 8149: case 0x82e9: s3_wait_fifo_idle(s3); return s3->accel.cur_y >> 8; - case 0x86e8: + case 0x8548: case 0x86e8: s3_wait_fifo_idle(s3); return s3->accel.cur_x & 0xff; - case 0x86e9: + case 0x8549: case 0x86e9: s3_wait_fifo_idle(s3); return s3->accel.cur_x >> 8; - case 0x8ae8: + case 0x8948: case 0x8ae8: s3_wait_fifo_idle(s3); return s3->accel.desty_axstp & 0xff; - case 0x8ae9: + case 0x8949: case 0x8ae9: s3_wait_fifo_idle(s3); return s3->accel.desty_axstp >> 8; - case 0x8ee8: + case 0x8d48: case 0x8ee8: s3_wait_fifo_idle(s3); return s3->accel.destx_distp & 0xff; - case 0x8ee9: + case 0x8d49: case 0x8ee9: s3_wait_fifo_idle(s3); return s3->accel.destx_distp >> 8; - case 0x92e8: + case 0x9148: case 0x92e8: s3_wait_fifo_idle(s3); return s3->accel.err_term & 0xff; - case 0x92e9: + case 0x9149: case 0x92e9: s3_wait_fifo_idle(s3); return s3->accel.err_term >> 8; - case 0x96e8: + case 0x9548: case 0x96e8: s3_wait_fifo_idle(s3); return s3->accel.maj_axis_pcnt & 0xff; - case 0x96e9: + case 0x9549: case 0x96e9: s3_wait_fifo_idle(s3); return s3->accel.maj_axis_pcnt >> 8; - case 0x9ae8: + case 0x9948: case 0x9ae8: + temp = 0; /* FIFO empty */ if (!s3->blitter_busy) wake_fifo_thread(s3); - if (FIFO_FULL && s3->chip != S3_86C801 && s3->chip != S3_86C805) - return 0xff; /*FIFO full*/ - return 0; /*FIFO empty*/ - case 0x9ae9: + if (FIFO_FULL && s3->chip >= S3_VISION864) + temp = 0xff; /*FIFO full*/ + return temp; /*FIFO empty*/ + case 0x9949: case 0x9ae9: if (!s3->blitter_busy) wake_fifo_thread(s3); temp = 0; - if (s3->chip == S3_86C801 || s3->chip == S3_86C805) + if (s3->chip < S3_VISION864) { if (!FIFO_EMPTY) temp |= 0x02; - if (s3->data_available) + else + temp |= s3->status_9ae8; /*FIFO empty*/ + if (s3->data_available) { temp |= 0x01; + s3->data_available = 0; /* Clear to avoid overblits. */ + } } else { @@ -1605,80 +1955,80 @@ uint8_t s3_accel_in(uint16_t port, void *p) } return temp; - case 0xa2e8: + case 0xa148: case 0xa2e8: s3_wait_fifo_idle(s3); return s3->accel.bkgd_color & 0xff; - case 0xa2e9: + case 0xa149: case 0xa2e9: s3_wait_fifo_idle(s3); return s3->accel.bkgd_color >> 8; - case 0xa2ea: + case 0xa14a: case 0xa2ea: s3_wait_fifo_idle(s3); return s3->accel.bkgd_color >> 16; - case 0xa2eb: + case 0xa14b: case 0xa2eb: s3_wait_fifo_idle(s3); return s3->accel.bkgd_color >> 24; - case 0xa6e8: + case 0xa548: case 0xa6e8: s3_wait_fifo_idle(s3); return s3->accel.frgd_color & 0xff; - case 0xa6e9: + case 0xa549: case 0xa6e9: s3_wait_fifo_idle(s3); return s3->accel.frgd_color >> 8; - case 0xa6ea: + case 0xa54a: case 0xa6ea: s3_wait_fifo_idle(s3); return s3->accel.frgd_color >> 16; - case 0xa6eb: + case 0xa54b: case 0xa6eb: s3_wait_fifo_idle(s3); return s3->accel.frgd_color >> 24; - case 0xaae8: + case 0xa948: case 0xaae8: s3_wait_fifo_idle(s3); return s3->accel.wrt_mask & 0xff; - case 0xaae9: + case 0xa949: case 0xaae9: s3_wait_fifo_idle(s3); return s3->accel.wrt_mask >> 8; - case 0xaaea: + case 0xa94a: case 0xaaea: s3_wait_fifo_idle(s3); return s3->accel.wrt_mask >> 16; - case 0xaaeb: + case 0xa94b: case 0xaaeb: s3_wait_fifo_idle(s3); return s3->accel.wrt_mask >> 24; - case 0xaee8: + case 0xad48: case 0xaee8: s3_wait_fifo_idle(s3); return s3->accel.rd_mask & 0xff; - case 0xaee9: + case 0xad49: case 0xaee9: s3_wait_fifo_idle(s3); return s3->accel.rd_mask >> 8; - case 0xaeea: + case 0xad4a: case 0xaeea: s3_wait_fifo_idle(s3); return s3->accel.rd_mask >> 16; - case 0xaeeb: + case 0xad4b: case 0xaeeb: s3_wait_fifo_idle(s3); return s3->accel.rd_mask >> 24; - case 0xb2e8: + case 0xb148: case 0xb2e8: s3_wait_fifo_idle(s3); return s3->accel.color_cmp & 0xff; - case 0xb2e9: + case 0xb149: case 0xb2e9: s3_wait_fifo_idle(s3); return s3->accel.color_cmp >> 8; - case 0xb2ea: + case 0xb14a: case 0xb2ea: s3_wait_fifo_idle(s3); return s3->accel.color_cmp >> 16; - case 0xb2eb: + case 0xb14b: case 0xb2eb: s3_wait_fifo_idle(s3); return s3->accel.color_cmp >> 24; - case 0xb6e8: + case 0xb548: case 0xb6e8: s3_wait_fifo_idle(s3); return s3->accel.bkgd_mix; - case 0xbae8: + case 0xb948: case 0xbae8: s3_wait_fifo_idle(s3); return s3->accel.frgd_mix; - case 0xbee8: + case 0xbd48: case 0xbee8: s3_wait_fifo_idle(s3); temp = s3->accel.multifunc[0xf] & 0xf; switch (temp) @@ -1696,7 +2046,7 @@ uint8_t s3_accel_in(uint16_t port, void *p) case 0xa: return s3->accel.multifunc[0xd] & 0xff; } return 0xff; - case 0xbee9: + case 0xbd49: case 0xbee9: s3_wait_fifo_idle(s3); temp = s3->accel.multifunc[0xf] & 0xf; s3->accel.multifunc[0xf]++; @@ -1716,8 +2066,44 @@ uint8_t s3_accel_in(uint16_t port, void *p) } return 0xff; - case 0xe2e8: case 0xe2e9: case 0xe2ea: case 0xe2eb: /*PIX_TRANS*/ - break; + case 0xe148: case 0xe2e8: + if (!s3_cpu_dest(s3)) + break; + temp = s3->accel.pix_trans[0]; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(8, 1, 0xffffffff, 0, s3); + else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(1, 1, 0xffffffff, 0xffffffff, s3); + return temp; + case 0xe149: case 0xe2e9: + if (!s3_cpu_dest(s3)) + break; + temp = s3->accel.pix_trans[1]; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(16, 1, 0xffffffff, 0, s3); + else s3_accel_start(16, 1, 0xffffffff, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(2, 1, 0xffffffff, 0xffffffff, s3); + else s3_accel_start(2, 1, 0xffffffff, 0xffffffff, s3); + } + return temp; + case 0xe14a: case 0xe2ea: + if (!s3_cpu_dest(s3)) + break; + temp = s3->accel.pix_trans[2]; + return temp; + case 0xe14b: case 0xe2eb: + if (!s3_cpu_dest(s3)) + break; + temp = s3->accel.pix_trans[3]; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x400) == 0x400 && (s3->accel.cmd & 0x100)) + s3_accel_start(32, 1, 0xffffffff, 0, s3); + else if ((s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100)) + s3_accel_start(4, 1, 0xffffffff, 0xffffffff, s3); + return temp; } return 0; } @@ -1740,9 +2126,135 @@ void s3_accel_write_l(uint32_t addr, uint32_t val, void *p) uint8_t s3_accel_read(uint32_t addr, void *p) { + s3_t *s3 = (s3_t *)p; + uint8_t temp = 0x00; + if (addr & 0x8000) - return s3_accel_in(addr & 0xffff, p); - return 0; + { + temp = s3_accel_in(addr & 0xffff, p); + } + else if (s3_cpu_dest(s3)) + { + temp = s3->accel.pix_trans[addr & 3]; + + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + s3_accel_start(8, 1, 0xffffffff, 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, 0xffffffff, s3); + } + } + + return temp; +} + +uint16_t s3_accel_read_w(uint32_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + uint16_t temp = 0x0000; + + if (addr & 0x8000) + { + temp = s3_accel_read((addr & 0xfffe), p); + temp |= s3_accel_read((addr & 0xfffe) + 1, p) << 8; + } + else if (s3_cpu_dest(s3)) + { + temp = s3->accel.pix_trans[addr & 2]; + temp |= s3->accel.pix_trans[(addr & 2) + 1] << 8; + + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, 0xff, 0, s3); + s3_accel_start(8, 1, 0xff, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(8, 1, 0xffff, 0, s3); + else + s3_accel_start(16, 1, 0xffff, 0, s3); + } + else + { + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(1, 1, 0xffffffff, 0xffffffff, s3); + else + s3_accel_start(2, 1, 0xffffffff, 0xffffffff, s3); + } + } + } + + return temp; +} + +uint32_t s3_accel_read_l(uint32_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + uint32_t temp = 0x00000000; + + if (addr & 0x8000) + { + temp = s3_accel_read((addr & 0xfffc), p); + temp |= s3_accel_read((addr & 0xfffc) + 1, p) << 8; + temp |= s3_accel_read((addr & 0xfffc) + 2, p) << 16; + temp |= s3_accel_read((addr & 0xfffc) + 3, p) << 24; + } + else if (s3_cpu_dest(s3)) + { + temp = s3->accel.pix_trans[0]; + temp |= s3->accel.pix_trans[1] << 8; + temp |= s3->accel.pix_trans[2] << 16; + temp |= s3->accel.pix_trans[3] << 24; + + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, 0xff, 0, s3); + s3_accel_start(8, 1, 0xff, 0, s3); + s3_accel_start(8, 1, 0xff, 0, s3); + s3_accel_start(8, 1, 0xff, 0, s3); + } + else if (s3->accel.cmd & 0x400) + { + s3_accel_start(32, 1, 0xffffffff, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(16, 1, 0xffff, 0, s3); + s3_accel_start(16, 1, 0xffff, 0, s3); + } + else + { + s3_accel_start(8, 1, 0xffff, 0, s3); + s3_accel_start(8, 1, 0xffff, 0, s3); + } + } + else + { + if (s3->accel.cmd & 0x400) + s3_accel_start(4, 1, 0xffffffff, 0xffffffff, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(2, 1, 0xffffffff, 0xffff, s3); + s3_accel_start(2, 1, 0xffffffff, 0xffff, s3); + } + else + { + s3_accel_start(1, 1, 0xffffffff, 0xffff, s3); + s3_accel_start(1, 1, 0xffffffff, 0xffff, s3); + } + } + } + } + + return temp; } static void polygon_setup(s3_t *s3) @@ -1796,8 +2308,7 @@ static void polygon_setup(s3_t *s3) else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; -#define MIX { \ - uint32_t old_dest_dat = dest_dat; \ +#define MIX_READ { \ switch ((mix_dat & mix_mask) ? (s3->accel.frgd_mix & 0xf) : (s3->accel.bkgd_mix & 0xf)) \ { \ case 0x0: dest_dat = ~dest_dat; break; \ @@ -1817,6 +2328,12 @@ static void polygon_setup(s3_t *s3) case 0xe: dest_dat = ~src_dat & dest_dat; break; \ case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ } \ + } + + +#define MIX { \ + uint32_t old_dest_dat = dest_dat; \ + MIX_READ \ dest_dat = (dest_dat & s3->accel.wrt_mask) | (old_dest_dat & ~s3->accel.wrt_mask); \ } @@ -1837,6 +2354,52 @@ static void polygon_setup(s3_t *s3) svga->changedvram[((addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount; \ } +int s3_accel_count(s3_t *s3) +{ + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + return 8; + else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + return 1; + else if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && ((s3->accel.cmd & 0x600) == 0x200) && (s3->accel.cmd & 0x100)) + return 16; + else if (((s3->accel.cmd & 0x600) == 0x200) && (s3->accel.cmd & 0x100)) + return 2; + else if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x100)) + return 32; + else if (s3->accel.cmd & 0x100) + return 4; + else + return -1; +} + +int s3_data_len(s3_t *s3) +{ + if (!(s3->accel.cmd & 0x600)) + return 1; + + if ((s3->accel.cmd & 0x600) == 0x200) + return 2; + + return 4; +} + +void s3_data_swap(s3_t *s3) +{ + uint8_t i, temp_array[4]; + uint8_t c = s3_data_len(s3); + + for (i = 0; i < 4; i++) + temp_array[i] = s3->accel.pix_trans[i]; + + if (s3_data_len(s3) < 2) + return; + + if (s3->accel.cmd & 0x1000) { + for (i = 0; i < c; i++) + s3->accel.pix_trans[i] = temp_array[i ^ (c - 1)]; + } +} + void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3) { svga_t *svga = &s3->svga; @@ -1854,6 +2417,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; uint32_t rd_mask = s3->accel.rd_mask; int cmd = s3->accel.cmd >> 13; + int read = 0, byte_cnt = 0, i; if ((s3->chip == S3_TRIO64) && (s3->accel.cmd & (1 << 11))) cmd |= 8; @@ -1909,16 +2473,18 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - s3->data_available = 0; - - if ((s3->accel.cmd & 0x100) && !cpu_input) + + if (s3_cpu_dest(s3)) + s3->data_available = 0; + + + if (s3_cpu_src(s3) && !cpu_input) { s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ - s3->data_available = 1; return; /*Wait for data from CPU*/ } - if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + if (s3_cpu_src(s3) && !cpu_input) return; /*Wait for data from CPU*/ frgd_mix = (s3->accel.frgd_mix >> 5) & 3; bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; @@ -2047,6 +2613,11 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat break; case 2: /*Rectangle fill*/ + byte_cnt = s3_data_len(s3); + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + s3->data_available = 0; + if (!cpu_input) /*!cpu_input is trigger to start operation*/ { s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; @@ -2057,23 +2628,22 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; s3->accel.dest = s3->accel.cy * s3->width; + + if (s3_cpu_src(s3)) { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } else if (s3_cpu_dest(s3)) + count = s3_accel_count(s3); } - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ - s3->data_available = 0; - - if ((s3->accel.cmd & 0x100) && !cpu_input) - { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ - s3->data_available = 1; - return; /*Wait for data from CPU*/ - } - - if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ - frgd_mix = (s3->accel.frgd_mix >> 5) & 3; bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; - + + s3->accel.pix_trans[0] = 0xff; + s3->accel.pix_trans[1] = 0xff; + s3->accel.pix_trans[2] = 0xff; + s3->accel.pix_trans[3] = 0xff; + while (count-- && s3->accel.sy >= 0) { if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && @@ -2091,14 +2661,28 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - READ_DST(s3->accel.dest + s3->accel.cx, dest_dat); + if (s3_cpu_dest(s3)) { + READ_SRC(s3->accel.dest + s3->accel.cx, src_dat); + dest_dat = 0xffffffff; + } else + READ_DST(s3->accel.dest + s3->accel.cx, dest_dat); MIX - WRITE(s3->accel.dest + s3->accel.cx); + if (s3_cpu_dest(s3)) { + for (i = 0; i <= s3->bpp; i++) + s3->accel.pix_trans[read + i] = (dest_dat >> (i << 3)) & 0xff; + } else + WRITE(s3->accel.dest + s3->accel.cx); } } - + + if (s3_cpu_dest(s3)) { + read += (s3->bpp + 1); + if (read >= byte_cnt) + s3->data_available = 1; /* Read data available. */ + } + mix_dat <<= 1; mix_dat |= 1; if (s3->bpp == 0) cpu_dat >>= 8; @@ -2119,14 +2703,29 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.dest = s3->accel.cy * s3->width; s3->accel.sy--; - if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) { + if (s3_cpu_dest(s3)) { + s3->data_available = 1; + s3_data_swap(s3); + } + return; + } if (s3->accel.sy < 0) { s3->accel.cur_x = s3->accel.cx; - s3->accel.cur_y = s3->accel.cy; + s3->accel.cur_y = s3->accel.cy; + if (s3_cpu_dest(s3)) { + s3->data_available = 1; + s3_data_swap(s3); + } return; } } + + if (s3_cpu_dest(s3) && s3->data_available) { + s3_data_swap(s3); + return; + } } break; @@ -2595,144 +3194,6 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } } -void s3_hwcursor_draw(svga_t *svga, int displine) -{ - s3_t *s3 = (s3_t *)svga->p; - int x; - uint16_t dat[2]; - int xx; - int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - int y_add, x_add; - uint32_t fg, bg; - - y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; - x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; - - switch (svga->bpp) - { - case 15: - fg = video_15to32[s3->hwc_fg_col & 0xffff]; - bg = video_15to32[s3->hwc_bg_col & 0xffff]; - break; - - case 16: - fg = video_16to32[s3->hwc_fg_col & 0xffff]; - bg = video_16to32[s3->hwc_bg_col & 0xffff]; - break; - - case 24: case 32: - fg = s3->hwc_fg_col; - bg = s3->hwc_bg_col; - break; - - default: - if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) - { - fg = svga->pallook[s3->hwc_fg_col & 0xff]; - bg = svga->pallook[s3->hwc_bg_col & 0xff]; - } - else - { - fg = svga->pallook[svga->crtc[0xe]]; - bg = svga->pallook[svga->crtc[0xf]]; - } - break; - } - - if (svga->interlace && svga->hwcursor_oddeven) - svga->hwcursor_latch.addr += 16; - - for (x = 0; x < 64; x += 16) - { - dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; - dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; - for (xx = 0; xx < 16; xx++) - { - if (offset >= svga->hwcursor_latch.x) - { - if (!(dat[0] & 0x8000)) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; - else if (dat[1] & 0x8000) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; - } - - offset++; - dat[0] <<= 1; - dat[1] <<= 1; - } - svga->hwcursor_latch.addr += 4; - } - if (svga->interlace && !svga->hwcursor_oddeven) - svga->hwcursor_latch.addr += 16; -} - -static void s3_io_remove(s3_t *s3) -{ - io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); - - io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - if (s3->chip == S3_TRIO64) - { - io_sethandler(0x82e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x86e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x8ae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x8ee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x92e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x96e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - } - else - { - io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - } - io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); -} - -static void s3_io_set(s3_t *s3) -{ - s3_io_remove(s3); - - io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); - - io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); -} - - uint8_t s3_pci_read(int func, int addr, void *p) { s3_t *s3 = (s3_t *)p; @@ -2848,6 +3309,11 @@ static void *s3_init(const device_t *info) uint32_t vram_size; switch(info->local) { + case S3_ORCHID_86C911: + bios_fn = ROM_ORCHID_86C911; + chip = S3_86C911; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c911); + break; case S3_V7MIRAGE_86C801: bios_fn = ROM_V7MIRAGE_86C801; chip = S3_86C801; @@ -2858,6 +3324,14 @@ static void *s3_init(const device_t *info) chip = S3_86C805; video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c805); break; + case S3_METHEUS_86C928: + bios_fn = ROM_METHEUS_86C928; + chip = S3_86C928; + if (info->flags & DEVICE_VLB) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c805); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_s3_86c801); + break; case S3_PARADISE_BAHAMAS64: bios_fn = ROM_PARADISE_BAHAMAS64; chip = S3_VISION864; @@ -2921,13 +3395,14 @@ static void *s3_init(const device_t *info) } s3->pci = !!(info->flags & DEVICE_PCI); + s3->vlb = !!(info->flags & DEVICE_VLB); mem_mapping_add(&s3->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &s3->svga); mem_mapping_add(&s3->mmio_mapping, 0xa0000, 0x10000, - s3_accel_read, NULL, NULL, + s3_accel_read, s3_accel_read_w, s3_accel_read_l, s3_accel_write, s3_accel_write_w, s3_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, s3); mem_mapping_disable(&s3->mmio_mapping); @@ -2936,7 +3411,7 @@ static void *s3_init(const device_t *info) svga_init(&s3->svga, s3, vram_size, s3_recalctimings, s3_in, s3_out, - bt48x_hwcursor_draw, + NULL, NULL); else svga_init(&s3->svga, s3, vram_size, @@ -2945,7 +3420,10 @@ static void *s3_init(const device_t *info) s3_hwcursor_draw, NULL); - if (s3->chip != S3_86C801 && s3->chip != S3_86C805) { + if (chip == S3_VISION964) + svga->dac_hwcursor_draw = bt48x_hwcursor_draw; + + if (s3->chip >= S3_VISION864) { switch (vram) { case 0: /* 512 kB */ svga->vram_mask = (1 << 19) - 1; @@ -3006,6 +3484,20 @@ static void *s3_init(const device_t *info) s3->int_line = 0; switch(info->local) { + case S3_ORCHID_86C911: + svga->decode_mask = (1 << 20) - 1; + stepping = 0x81; /*86C911*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + s3->width = 1024; + + svga->ramdac = device_add(&att490_ramdac_device); + svga->clock_gen = device_add(&av9194_device); + svga->getclock = av9194_getclock; + break; + case S3_V7MIRAGE_86C801: svga->decode_mask = (2 << 20) - 1; stepping = 0xa0; /*86C801/86C805*/ @@ -3034,6 +3526,20 @@ static void *s3_init(const device_t *info) svga->getclock = av9194_getclock; break; + case S3_METHEUS_86C928: + svga->decode_mask = (4 << 20) - 1; + stepping = 0x90; /*86C928*/ + s3->id = stepping; + s3->id_ext = stepping; + s3->id_ext_pci = 0; + s3->packed_mmio = 0; + svga->crtc[0x5a] = 0x0a; + + svga->ramdac = device_add(&bt485_ramdac_device); + svga->clock_gen = device_add(&icd2061_device); + svga->getclock = icd2061_getclock; + break; + case S3_PARADISE_BAHAMAS64: case S3_PHOENIX_VISION864: svga->decode_mask = (8 << 20) - 1; @@ -3098,6 +3604,11 @@ static void *s3_init(const device_t *info) return s3; } +static int s3_orchid_86c911_available(void) +{ + return rom_present(ROM_ORCHID_86C911); +} + static int s3_v7mirage_86c801_available(void) { return rom_present(ROM_V7MIRAGE_86C801); @@ -3108,6 +3619,11 @@ static int s3_phoenix_86c805_available(void) return rom_present(ROM_PHOENIX_86C805); } +static int s3_metheus_86c928_available(void) +{ + return rom_present(ROM_METHEUS_86C928); +} + static int s3_bahamas64_available(void) { return rom_present(ROM_PARADISE_BAHAMAS64); @@ -3170,6 +3686,27 @@ static void s3_force_redraw(void *p) s3->svga.fullchange = changeframecount; } +static const device_config_t s3_orchid_86c911_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 1, + { + { + "512 KB", 0 + }, + { + "1 MB", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + static const device_config_t s3_9fx_config[] = { { @@ -3264,6 +3801,20 @@ static const device_config_t s3_config[] = } }; +const device_t s3_orchid_86c911_isa_device = +{ + "Orchid Fahrenheit 1280 (S3 86c911) ISA", + DEVICE_AT | DEVICE_ISA, + S3_ORCHID_86C911, + s3_init, + s3_close, + NULL, + s3_orchid_86c911_available, + s3_speed_changed, + s3_force_redraw, + s3_orchid_86c911_config +}; + const device_t s3_v7mirage_86c801_isa_device = { "SPEA V7 Mirage (S3 86c801) ISA", @@ -3292,6 +3843,34 @@ const device_t s3_phoenix_86c805_vlb_device = s3_9fx_config }; +const device_t s3_metheus_86c928_isa_device = +{ + "Metheus Premier 928 (S3 86c928) ISA", + DEVICE_AT | DEVICE_ISA, + S3_METHEUS_86C928, + s3_init, + s3_close, + NULL, + s3_metheus_86c928_available, + s3_speed_changed, + s3_force_redraw, + s3_config +}; + +const device_t s3_metheus_86c928_vlb_device = +{ + "Metheus Premier 928 (S3 86c928) VLB", + DEVICE_VLB, + S3_METHEUS_86C928, + s3_init, + s3_close, + NULL, + s3_metheus_86c928_available, + s3_speed_changed, + s3_force_redraw, + s3_config +}; + const device_t s3_bahamas64_vlb_device = { "Paradise Bahamas 64 (S3 Vision864) VLB", @@ -3303,7 +3882,7 @@ const device_t s3_bahamas64_vlb_device = s3_bahamas64_available, s3_speed_changed, s3_force_redraw, - s3_config + s3_9fx_config }; const device_t s3_bahamas64_pci_device = @@ -3317,7 +3896,7 @@ const device_t s3_bahamas64_pci_device = s3_bahamas64_available, s3_speed_changed, s3_force_redraw, - s3_config + s3_9fx_config }; const device_t s3_diamond_stealth64_964_vlb_device = diff --git a/src/video/vid_s3.h b/src/video/vid_s3.h index 337a7eae5..a44d5cc27 100644 --- a/src/video/vid_s3.h +++ b/src/video/vid_s3.h @@ -17,6 +17,9 @@ * Copyright 2016-2018 Miran Grca. */ +const device_t s3_orchid_86c911_isa_device; +const device_t s3_metheus_premier_86c928_isa_device; +const device_t s3_metheus_premier_86c928_vlb_device; const device_t s3_v7mirage_86c801_isa_device; const device_t s3_phoenix_86c805_vlb_device; const device_t s3_bahamas64_vlb_device; diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 77b929946..65d8e3d1f 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -25,6 +25,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../pci.h" #include "../rom.h" @@ -688,7 +689,7 @@ static void s3_virge_recalctimings(svga_t *svga) int m = svga->seqregs[0x13] & 0x7f; double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0; - svga->clock = cpuclock / freq; + svga->clock = (cpuclock * (float)(1ull << 32)) / freq; } } @@ -3450,7 +3451,7 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) if (offset >= svga->hwcursor_latch.x) { if (dat[0] & 0x8000) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; + buffer32->line[displine + y_add][offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; } offset++; @@ -3466,9 +3467,9 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) if (offset >= svga->hwcursor_latch.x) { if (!(dat[0] & 0x8000)) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; + buffer32->line[displine + y_add][offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; else if (dat[1] & 0x8000) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + buffer32->line[displine + y_add][offset + 32 + x_add] ^= 0xffffff; } offset++; @@ -3722,8 +3723,8 @@ static void s3_virge_overlay_draw(svga_t *svga, int displine) int y_add = enable_overscan ? 16 : 0; int x_add = enable_overscan ? 8 : 0; - p = &((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add]; - + p = &(buffer32->line[displine + y_add][offset + 32 + x_add]); + if ((offset + virge->streams.sec_w) > virge->streams.pri_w) x_size = (virge->streams.pri_w - virge->streams.sec_x) + 1; else @@ -3902,7 +3903,7 @@ static void *s3_virge_init(const device_t *info) s3_virge_mmio_write_w, s3_virge_mmio_write_l, NULL, - 0, + MEM_MAPPING_EXTERNAL, virge); mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, s3_virge_mmio_read_w, @@ -3911,7 +3912,7 @@ static void *s3_virge_init(const device_t *info) s3_virge_mmio_write_w, s3_virge_mmio_write_l, NULL, - 0, + MEM_MAPPING_EXTERNAL, virge); mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, @@ -3920,7 +3921,7 @@ static void *s3_virge_init(const device_t *info) svga_writew_linear, svga_writel_linear, NULL, - 0, + MEM_MAPPING_EXTERNAL, &virge->svga); io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); diff --git a/src/video/vid_sc1502x_ramdac.c b/src/video/vid_sc1502x_ramdac.c index 992ceea6c..75cb01995 100644 --- a/src/video/vid_sc1502x_ramdac.c +++ b/src/video/vid_sc1502x_ramdac.c @@ -26,6 +26,7 @@ #include "../86box.h" #include "../device.h" #include "../mem.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_sc1502x_ramdac.h" diff --git a/src/video/vid_sdac_ramdac.c b/src/video/vid_sdac_ramdac.c index e7ff064a9..44fb8d752 100644 --- a/src/video/vid_sdac_ramdac.c +++ b/src/video/vid_sdac_ramdac.c @@ -8,13 +8,13 @@ * * 87C716 'SDAC' true colour RAMDAC emulation. * - * Version: @(#)vid_sdac_ramdac.c 1.0.5 2018/10/04 + * Version: @(#)vid_sdac_ramdac.c 1.0.6 2019/09/13 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -24,6 +24,7 @@ #include "../86box.h" #include "../device.h" #include "../mem.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_sdac_ramdac.h" @@ -37,9 +38,11 @@ sdac_control_write(sdac_ramdac_t *ramdac, svga_t *svga, uint8_t val) case 0x2: case 0x3: case 0xa: + case 0x8: svga->bpp = 15; break; case 0x4: + case 0x9: case 0xe: svga->bpp = 24; break; @@ -98,7 +101,7 @@ sdac_ramdac_out(uint16_t addr, int rs2, uint8_t val, sdac_ramdac_t *ramdac, svga uint8_t rs = (addr & 0x03); rs |= (!!rs2 << 8); - switch (rs) { + if ((rs >= 0x04) || (ramdac->type == 7)) switch (rs) { case 0x02: if (ramdac->magic_count == 4) sdac_control_write(ramdac, svga, val); @@ -135,7 +138,9 @@ sdac_ramdac_in(uint16_t addr, int rs2, sdac_ramdac_t *ramdac, svga_t *svga) uint8_t rs = (addr & 0x03); rs |= (!!rs2 << 8); - switch (rs) { + if ((rs < 0x04) && (ramdac->type != 7)) + temp = svga_in(addr, svga); + else switch (rs) { case 0x02: if (ramdac->magic_count < 5) ramdac->magic_count++; @@ -150,7 +155,7 @@ sdac_ramdac_in(uint16_t addr, int rs2, sdac_ramdac_t *ramdac, svga_t *svga) case 0x00: case 0x01: case 0x03: - ramdac->magic_count=0; + ramdac->magic_count = 0; temp = svga_in(addr, svga); break; case 0x04: @@ -178,12 +183,16 @@ sdac_getclock(int clock, void *p) float t; int m, n1, n2; + if (ramdac->regs[0xe] & (1 << 5)) + clock = ramdac->regs[0xe] & 7; + + clock &= 7; + if (clock == 0) return 25175000.0; if (clock == 1) return 28322000.0; - clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ m = (ramdac->regs[clock] & 0x7f) + 2; n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; n2 = ((ramdac->regs[clock] >> 13) & 0x07); @@ -200,6 +209,8 @@ sdac_ramdac_init(const device_t *info) sdac_ramdac_t *ramdac = (sdac_ramdac_t *) malloc(sizeof(sdac_ramdac_t)); memset(ramdac, 0, sizeof(sdac_ramdac_t)); + ramdac->type = info->local; + ramdac->regs[0] = 0x6128; ramdac->regs[1] = 0x623d; @@ -217,10 +228,19 @@ sdac_ramdac_close(void *priv) } +const device_t gendac_ramdac_device = +{ + "S3 GENDAC 86c708 RAMDAC", + 0, 0, + sdac_ramdac_init, sdac_ramdac_close, + NULL, NULL, NULL, NULL +}; + + const device_t sdac_ramdac_device = { - "S3 SDAC 86c716 RAMDAC", - 0, 0, - sdac_ramdac_init, sdac_ramdac_close, - NULL, NULL, NULL, NULL + "S3 SDAC 86c716 RAMDAC", + 0, 7, + sdac_ramdac_init, sdac_ramdac_close, + NULL, NULL, NULL, NULL }; diff --git a/src/video/vid_sdac_ramdac.h b/src/video/vid_sdac_ramdac.h index 001b8727f..e57d24519 100644 --- a/src/video/vid_sdac_ramdac.h +++ b/src/video/vid_sdac_ramdac.h @@ -8,13 +8,13 @@ * * 87C716 'SDAC' true colour RAMDAC emulation header. * - * Version: @(#)vid_sdac_ramdac.h 1.0.0 2018/10/04 + * Version: @(#)vid_sdac_ramdac.h 1.0.1 2019/09/13 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ typedef struct sdac_ramdac_t { @@ -22,11 +22,12 @@ typedef struct sdac_ramdac_t int magic_count, windex, rindex, reg_ff, rs2; - uint8_t command; + uint8_t type, command; } sdac_ramdac_t; extern void sdac_ramdac_out(uint16_t addr, int rs2, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga); extern uint8_t sdac_ramdac_in(uint16_t addr, int rs2, sdac_ramdac_t *ramdac, svga_t *svga); extern float sdac_getclock(int clock, void *p); +extern const device_t gendac_ramdac_device; extern const device_t sdac_ramdac_device; diff --git a/src/video/vid_sigma.c b/src/video/vid_sigma.c index 66fe48300..39d314ea8 100644 --- a/src/video/vid_sigma.c +++ b/src/video/vid_sigma.c @@ -8,7 +8,7 @@ * * Sigma Color 400 emulation. * - * Version: @(#)vid_sigma.c 1.0.3 2018/10/23 + * Version: @(#)vid_sigma.c 1.0.4 2019/05/23 * * Authors: John Elliott, * @@ -22,11 +22,11 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" #include "../nmi.h" #include "../rom.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_sigma.h" @@ -149,7 +149,8 @@ typedef struct sigma_t uint8_t crtc_value; /* Value to return from a CRTC register read */ - uint8_t sigmastat; /* Status register [0x2DA] */ + uint8_t sigmastat, /* Status register [0x2DA] */ + fake_stat; /* see sigma_in() for comment */ uint8_t sigmamode; /* Mode control register [0x2D8] */ @@ -164,13 +165,13 @@ typedef struct sigma_t int vsynctime, vadj; int oddeven; - int64_t dispontime, dispofftime; + uint64_t dispontime, dispofftime; int firstline, lastline; int drawcursor; - int64_t vidtime; + pc_timer_t timer; uint8_t *vram; uint8_t bram[2048]; @@ -211,7 +212,8 @@ sigma_out(uint16_t addr, uint8_t val, void *p) } /* For CRTC emulation, the card BIOS sets the value to be * read from port 0x3D1 like this */ - if (addr == 0x3D1) sigma->crtc_value = val; + if (addr == 0x3D1) + sigma->crtc_value = val; } else switch (addr) { case 0x2D0: case 0x2D2: @@ -249,7 +251,7 @@ sigma_out(uint16_t addr, uint8_t val, void *p) case 0x2DD: /* Page in RAM at 0xC1800 */ if (sigma->rom_paged != 0) mmu_invalidate(0xC0000); - sigma->rom_paged = 0; + sigma->rom_paged = 0x00; return; case 0x2DE: @@ -306,8 +308,29 @@ sigma_in(uint16_t addr, void *p) /* For CGA compatibility we have to return something palatable on this port. On a real card this functionality can be turned on or off with SW1/6 */ case 0x3DA: - result = sigma->sigmastat & 7; - if (sigma->sigmastat & STATUS_RETR_V) result |= 8; + if (sigma->sigmamode & MODE_ENABLE) { + result = sigma->sigmastat & 0x07; + if (sigma->sigmastat & STATUS_RETR_V) + result |= 0x08; + } else { + /* + * The card is not running yet, and someone + * (probably the system BIOS) is trying to + * read our status in CGA mode. + * + * One of the systems that do this, is the + * DTK XT (PIM-10TB-Z board) with ERSO 2.42 + * BIOS. If this test fails (i.e. it doesnt + * see valid HS and VS bits alternate) it + * will generate lots of annoying beeps.. + * + * So, the trick here is to just send it + * some alternating bits, making it think + * the CGA circuitry is operational. + */ + sigma->fake_stat ^= (0x08 | 0x01); + result = sigma->fake_stat; + } break; } @@ -322,7 +345,7 @@ sigma_write(uint32_t addr, uint8_t val, void *p) sigma->vram[sigma->plane * 0x8000 + (addr & 0x7fff)] = val; egawrites++; - cycles -= 4; + sub_cycles(4); } @@ -331,7 +354,7 @@ sigma_read(uint32_t addr, void *p) { sigma_t *sigma = (sigma_t *)p; - cycles -= 4; + sub_cycles(4); egareads++; return sigma->vram[sigma->plane * 0x8000 + (addr & 0x7fff)]; } @@ -343,9 +366,6 @@ sigma_bwrite(uint32_t addr, uint8_t val, void *p) sigma_t *sigma = (sigma_t *)p; addr &= 0x3FFF; -#if 0 - if ((addr >= 0x1800) && !sigma->rom_paged && (addr < 0x2000)) -#endif if ((addr < 0x1800) || sigma->rom_paged || (addr >= 0x2000)) ; else @@ -388,8 +408,8 @@ sigma_recalctimings(sigma_t *sigma) _dispofftime = disptime - _dispontime; _dispontime *= CGACONST; _dispofftime *= CGACONST; - sigma->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - sigma->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + sigma->dispontime = (uint64_t)(_dispontime); + sigma->dispofftime = (uint64_t)(_dispofftime); } @@ -399,10 +419,10 @@ static void sigma_text80(sigma_t *sigma) int x, c; uint8_t chr, attr; uint16_t ca = (sigma->crtc[15] | (sigma->crtc[14] << 8)); - uint16_t ma = ((sigma->ma & 0x3FFF) << 1); + uint16_t ma = ((sigma->ma << 1) & 0x3FFF); int drawcursor; uint32_t cols[4]; - uint8_t *vram = sigma->vram + (ma << 1); + uint8_t *vram = sigma->vram + ((ma << 1) % 4000); ca = ca << 1; if (sigma->sigma_ctl & CTL_CURSOR) @@ -429,16 +449,16 @@ static void sigma_text80(sigma_t *sigma) if (drawcursor) { for (c = 0; c < 8; c++) { if (sigma->sigmamode & MODE_FONT16) - buffer->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f; + buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; else - buffer->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdat[chr][sigma->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f; + buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdat[chr][sigma->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; } } else { for (c = 0; c < 8; c++) { if (sigma->sigmamode & MODE_FONT16) - buffer->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; else - buffer->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdat[chr][sigma->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdat[chr][sigma->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } } ++ma; @@ -484,14 +504,14 @@ sigma_text40(sigma_t *sigma) if (drawcursor) { for (c = 0; c < 8; c++) { - buffer->line[sigma->displine][(x << 4) + 2*c + 8] = - buffer->line[sigma->displine][(x << 4) + 2*c + 9] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f; + buffer32->line[sigma->displine][(x << 4) + 2*c + 8] = + buffer32->line[sigma->displine][(x << 4) + 2*c + 9] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; } } else { for (c = 0; c < 8; c++) { - buffer->line[sigma->displine][(x << 4) + 2*c + 8] = - buffer->line[sigma->displine][(x << 4) + 2*c + 9] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; - } + buffer32->line[sigma->displine][(x << 4) + 2*c + 8] = + buffer32->line[sigma->displine][(x << 4) + 2*c + 9] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + } } ma++; } @@ -522,7 +542,7 @@ sigma_gfx400(sigma_t *sigma) ((plane[1] & mask) ? 2 : 0) | ((plane[0] & mask) ? 1 : 0); col |= 16; - buffer->line[sigma->displine][(x << 3) + c + 8] = col; + buffer32->line[sigma->displine][(x << 3) + c + 8] = col; } if (x & 1) ++sigma->ma; @@ -555,7 +575,7 @@ sigma_gfx200(sigma_t *sigma) ((plane[1] & mask) ? 2 : 0) | ((plane[0] & mask) ? 1 : 0); col |= 16; - buffer->line[sigma->displine][(x << 3) + c + 8] = col; + buffer32->line[sigma->displine][(x << 3) + c + 8] = col; } if (x & 1) @@ -590,8 +610,8 @@ sigma_gfx4col(sigma_t *sigma) col |= 16; mask = mask >> 1; - buffer->line[sigma->displine][(x << 3) + (c << 1) + 8] = - buffer->line[sigma->displine][(x << 3) + (c << 1) + 9] = col; + buffer32->line[sigma->displine][(x << 3) + (c << 1) + 8] = + buffer32->line[sigma->displine][(x << 3) + (c << 1) + 9] = col; } if (x & 1) @@ -610,7 +630,7 @@ sigma_poll(void *p) int oldsc; if (!sigma->linepos) { - sigma->vidtime += sigma->dispofftime; + timer_advance_u64(&sigma->timer, sigma->dispofftime); sigma->sigmastat |= STATUS_RETR_H; sigma->linepos = 1; oldsc = sigma->sc; @@ -626,11 +646,11 @@ sigma_poll(void *p) cols[0] = 16; /* Left overscan */ for (c = 0; c < 8; c++) { - buffer->line[sigma->displine][c] = cols[0]; + buffer32->line[sigma->displine][c] = cols[0]; if (sigma->sigmamode & MODE_80COLS) - buffer->line[sigma->displine][c + (sigma->crtc[1] << 4) + 8] = cols[0]; + buffer32->line[sigma->displine][c + (sigma->crtc[1] << 4) + 8] = cols[0]; else - buffer->line[sigma->displine][c + (sigma->crtc[1] << 5) + 8] = cols[0]; + buffer32->line[sigma->displine][c + (sigma->crtc[1] << 5) + 8] = cols[0]; } if (sigma->sigmamode & MODE_GRAPHICS) { if (sigma->sigmamode & MODE_640x400) @@ -648,9 +668,9 @@ sigma_poll(void *p) } else { cols[0] = 16; if (sigma->sigmamode & MODE_80COLS) - hline(buffer, 0, sigma->displine, (sigma->crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, sigma->displine, (sigma->crtc[1] << 4) + 16, cols[0]); else - hline(buffer, 0, sigma->displine, (sigma->crtc[1] << 5) + 16, cols[0]); + hline(buffer32, 0, sigma->displine, (sigma->crtc[1] << 5) + 16, cols[0]); } if (sigma->sigmamode & MODE_80COLS) @@ -659,7 +679,7 @@ sigma_poll(void *p) x = (sigma->crtc[1] << 5) + 16; for (c = 0; c < x; c++) - buffer->line[sigma->displine][c] = sigma->palette[buffer->line[sigma->displine][c] & 0xf] | 16; + buffer32->line[sigma->displine][c] = sigma->palette[buffer32->line[sigma->displine][c] & 0xf] | 16; sigma->sc = oldsc; if (sigma->vc == sigma->crtc[7] && !sigma->sc) @@ -668,7 +688,7 @@ sigma_poll(void *p) if (sigma->displine >= 560) sigma->displine = 0; } else { - sigma->vidtime += sigma->dispontime; + timer_advance_u64(&sigma->timer, sigma->dispontime); sigma->linepos = 0; if (sigma->vsynctime) { sigma->vsynctime--; @@ -706,7 +726,8 @@ sigma_poll(void *p) sigma->vc = 0; sigma->vadj = sigma->crtc[5]; if (!sigma->vadj) sigma->cgadispon = 1; - if (!sigma->vadj) sigma->ma = sigma->maback = (sigma->crtc[13] | (sigma->crtc[12] << 8)) & 0x3fff; + if (!sigma->vadj) + sigma->ma = sigma->maback = (sigma->crtc[13] | (sigma->crtc[12] << 8)) & 0x3fff; if ((sigma->crtc[10] & 0x60) == 0x20) sigma->cursoron = 0; else @@ -786,14 +807,18 @@ sigma_poll(void *p) static void *sigma_init(const device_t *info) { + int bios_addr; sigma_t *sigma = malloc(sizeof(sigma_t)); memset(sigma, 0, sizeof(sigma_t)); + + bios_addr = device_get_config_hex20("bios_addr"); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_sigma); sigma->enable_nmi = device_get_config_int("enable_nmi"); loadfont(ROM_SIGMA_FONT, 7); - rom_init(&sigma->bios_rom, ROM_SIGMA_BIOS, 0xC0000, 0x2000, + rom_init(&sigma->bios_rom, ROM_SIGMA_BIOS, bios_addr, 0x2000, 0x1FFF, 0, MEM_MAPPING_EXTERNAL); /* The BIOS ROM is overlaid by RAM, so remove its default mapping and access it through sigma_bread() / sigma_bwrite() below */ @@ -802,12 +827,12 @@ static void sigma->vram = malloc(0x8000 * 4); - timer_add(sigma_poll, &sigma->vidtime, TIMER_ALWAYS_ENABLED, sigma); + timer_add(&sigma->timer, sigma_poll, sigma, 1); mem_mapping_add(&sigma->mapping, 0xb8000, 0x08000, sigma_read, NULL, NULL, sigma_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, sigma); - mem_mapping_add(&sigma->bios_ram, 0xC1800, 0x0800, + mem_mapping_add(&sigma->bios_ram, bios_addr, 0x2000, sigma_bread, NULL, NULL, sigma_bwrite, NULL, NULL, sigma->bios_rom.rom, MEM_MAPPING_EXTERNAL, sigma); @@ -887,6 +912,47 @@ device_config_t sigma_config[] = { "enable_nmi", "Enable NMI for CGA emulation", CONFIG_BINARY, "", 1 }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xc0000, + { + { + "C000H", 0xc0000 + }, + { + "C800H", 0xc8000 + }, + { + "CC00H", 0xcc000 + }, + { + "D000H", 0xd0000 + }, + { + "D400H", 0xd4000 + }, + { + "D800H", 0xd8000 + }, + { + "DC00H", 0xdc000 + }, + { + "E000H", 0xe0000 + }, + { + "E400H", 0xe4000 + }, + { + "E800H", 0xe8000 + }, + { + "EC00H", 0xec000 + }, + { + "" + } + }, + }, { "", "", -1 } diff --git a/src/video/vid_stg_ramdac.c b/src/video/vid_stg_ramdac.c index 2bbeee85e..75722ef5a 100644 --- a/src/video/vid_stg_ramdac.c +++ b/src/video/vid_stg_ramdac.c @@ -24,6 +24,7 @@ #include "../86box.h" #include "../device.h" #include "../mem.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_stg_ramdac.h" diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 55ac34bb0..a65747122 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -28,11 +28,11 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../machine/machine.h" +#include "../timer.h" #include "../io.h" #include "../pit.h" #include "../mem.h" #include "../rom.h" -#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" @@ -533,8 +533,12 @@ svga_recalctimings(svga_t *svga) _dispontime *= crtcconst; _dispofftime *= crtcconst; - svga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - svga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + svga->dispontime = (uint64_t)(_dispontime); + svga->dispofftime = (uint64_t)(_dispofftime); + if (svga->dispontime < TIMER_USEC) + svga->dispontime = TIMER_USEC; + if (svga->dispofftime < TIMER_USEC) + svga->dispofftime = TIMER_USEC; } @@ -557,6 +561,17 @@ svga_poll(void *p) svga->hwcursor_oddeven = 1; } + if (svga->displine == svga->dac_hwcursor_latch.y && svga->dac_hwcursor_latch.ena) { + svga->dac_hwcursor_on = 64 - svga->dac_hwcursor_latch.yoff; + svga->dac_hwcursor_oddeven = 0; + } + + if (svga->displine == (svga->dac_hwcursor_latch.y + 1) && svga->dac_hwcursor_latch.ena && + svga->interlace) { + svga->dac_hwcursor_on = 64 - (svga->dac_hwcursor_latch.yoff + 1); + svga->dac_hwcursor_oddeven = 1; + } + if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) { svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; svga->overlay_oddeven = 0; @@ -567,7 +582,7 @@ svga_poll(void *p) svga->overlay_oddeven = 1; } - svga->vidtime += svga->dispofftime; + timer_advance_u64(&svga->timer, svga->dispofftime); svga->cgastat |= 1; svga->linepos = 1; @@ -580,7 +595,7 @@ svga_poll(void *p) video_wait_for_buffer(); } - if (svga->hwcursor_on || svga->overlay_on) { + if (svga->hwcursor_on || svga->dac_hwcursor_on || svga->overlay_on) { svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = svga->interlace ? 3 : 2; } @@ -589,15 +604,23 @@ svga_poll(void *p) svga->render(svga); if (svga->overlay_on) { - if (!svga->override) + if (!svga->override && svga->overlay_draw) svga->overlay_draw(svga, svga->displine); svga->overlay_on--; if (svga->overlay_on && svga->interlace) svga->overlay_on--; } + if (svga->dac_hwcursor_on) { + if (!svga->override && svga->dac_hwcursor_draw) + svga->dac_hwcursor_draw(svga, svga->displine); + svga->dac_hwcursor_on--; + if (svga->dac_hwcursor_on && svga->interlace) + svga->dac_hwcursor_on--; + } + if (svga->hwcursor_on) { - if (!svga->override) + if (!svga->override && svga->hwcursor_draw) svga->hwcursor_draw(svga, svga->displine); svga->hwcursor_on--; if (svga->hwcursor_on && svga->interlace) @@ -617,7 +640,7 @@ svga_poll(void *p) if (svga->displine > 1500) svga->displine = 0; } else { - svga->vidtime += svga->dispontime; + timer_advance_u64(&svga->timer, svga->dispontime); if (svga->dispon) svga->cgastat &= ~1; @@ -711,26 +734,6 @@ svga_poll(void *p) svga->ma <<= 2; svga->maback <<= 2; svga->ca <<= 2; - - svga->video_res_x = wx; - svga->video_res_y = wy + 1; - if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ - svga->video_res_x /= (svga->seqregs[1] & 1) ? 8 : 9; - svga->video_res_y /= (svga->crtc[9] & 31) + 1; - svga->video_bpp = 0; - } else { - if (svga->crtc[9] & 0x80) - svga->video_res_y /= 2; - if (!(svga->crtc[0x17] & 2)) - svga->video_res_y *= 4; - else if (!(svga->crtc[0x17] & 1)) - svga->video_res_y *= 2; - svga->video_res_y /= (svga->crtc[9] & 31) + 1; - if (svga->lowres) - svga->video_res_x /= 2; - - svga->video_bpp = svga->bpp; - } } if (svga->vc == svga->vtotal) { svga->vc = 0; @@ -743,6 +746,9 @@ svga_poll(void *p) svga->hwcursor_on = 0; svga->hwcursor_latch = svga->hwcursor; + svga->dac_hwcursor_on = 0; + svga->dac_hwcursor_latch = svga->dac_hwcursor; + svga->overlay_on = 0; svga->overlay_latch = svga->overlay; } @@ -781,14 +787,14 @@ svga_init(svga_t *svga, void *p, int memsize, svga->crtc[0] = 63; svga->crtc[6] = 255; - svga->dispontime = svga->dispofftime = 1000 * (1 << TIMER_SHIFT); + svga->dispontime = 1000ull << 32; + svga->dispofftime = 1000ull << 32; svga->bpp = 8; svga->vram = malloc(memsize); svga->vram_max = memsize; svga->vram_display_mask = svga->vram_mask = memsize - 1; svga->decode_mask = 0x7fffff; svga->changedvram = malloc(memsize >> 12); - svga->changedvram = malloc(0x800000 >> 12); svga->recalctimings_ex = recalctimings_ex; svga->video_in = video_in; svga->video_out = video_out; @@ -798,12 +804,15 @@ svga_init(svga_t *svga, void *p, int memsize, svga->hwcursor.xsize = svga->hwcursor.ysize = 32; svga->hwcursor.yoff = 32; + svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = 32; + svga->dac_hwcursor.yoff = 32; + mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); - timer_add(svga_poll, &svga->vidtime, TIMER_ALWAYS_ENABLED, svga); + timer_add(&svga->timer, svga_poll, svga, 1); svga_pri = svga; @@ -834,7 +843,7 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) egawrites++; - cycles -= video_timing_write_b; + sub_cycles(video_timing_write_b); if (!linear) { memory_map_mode = (svga->gdcreg[6] >> 2) & 3; @@ -906,6 +915,7 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) /* mask data according to sr[2] */ write_mask = mask16[writemask2 & 0x0f]; addr >>= 2; + ((uint32_t *)(svga->vram))[addr] &= ~write_mask; ((uint32_t *)(svga->vram))[addr] |= (val32 & write_mask); return; @@ -920,6 +930,7 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) /* mask data according to sr[2] */ write_mask = mask16[writemask2 & 0x0f]; addr >>= 2; + ((uint32_t *)(svga->vram))[addr] &= ~write_mask; ((uint32_t *)(svga->vram))[addr] |= (val32 & write_mask); return; @@ -976,6 +987,7 @@ svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) /* mask data according to sr[2] */ write_mask = mask16[writemask2 & 0x0f]; addr >>= 2; + ((uint32_t *)(svga->vram))[addr] = (((uint32_t *)(svga->vram))[addr] & ~write_mask) | (val32 & write_mask); } @@ -987,7 +999,7 @@ svga_read_common(uint32_t addr, uint8_t linear, void *p) uint32_t latch_addr = 0, ret; int memory_map_mode, readplane = svga->readplane; - cycles -= video_timing_read_b; + sub_cycles(video_timing_read_b); egareads++; @@ -1112,8 +1124,6 @@ svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) uint32_t *p; int i, j; - svga->frames++; - if ((xsize > 2032) || (ysize > 2032)) { x_add = 0; y_add = 0; @@ -1145,7 +1155,7 @@ svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) if ((wx >= 160) && ((wy + 1) >= 120)) { /* Draw (overscan_size - scroll size) lines of overscan on top. */ for (i = 0; i < (y_add >> 1); i++) { - p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + p = &buffer32->line[i & 0x7ff][32]; for (j = 0; j < (xsize + x_add); j++) p[j] = svga->overscan_color; @@ -1153,17 +1163,17 @@ svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ for (i = 0; i < (y_add >> 1); i++) { - p = &((uint32_t *)buffer32->line[(ysize + (y_add >> 1) + i) & 0x7ff])[32]; + p = &buffer32->line[(ysize + (y_add >> 1) + i) & 0x7ff][32]; for (j = 0; j < (xsize + x_add); j++) p[j] = svga->overscan_color; } for (i = (y_add >> 1); i < (ysize + (y_add >> 1)); i ++) { - p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + p = &buffer32->line[i & 0x7ff][32]; for (j = 0; j < 8; j++) { - p[j] = svga->pallook[svga->overscan_color]; + p[j] = svga->overscan_color; p[xsize + (x_add >> 1) + j] = svga->overscan_color; } } @@ -1208,7 +1218,7 @@ svga_writew_common(uint32_t addr, uint16_t val, uint8_t linear, void *p) egawrites += 2; - cycles -= video_timing_write_w; + sub_cycles(video_timing_write_w); if (!linear) addr = (addr & svga->banked_mask) + svga->write_bank; @@ -1216,6 +1226,7 @@ svga_writew_common(uint32_t addr, uint16_t val, uint8_t linear, void *p) if (addr >= svga->vram_max) return; addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; *(uint16_t *)&svga->vram[addr] = val; } @@ -1241,16 +1252,16 @@ svga_writel_common(uint32_t addr, uint32_t val, uint8_t linear, void *p) svga_t *svga = (svga_t *)p; if (!svga->fast) { - svga_write(addr, val, p); - svga_write(addr + 1, val >> 8, p); - svga_write(addr + 2, val >> 16, p); - svga_write(addr + 3, val >> 24, p); + svga_write_common(addr, val, linear, p); + svga_write_common(addr + 1, val >> 8, linear, p); + svga_write_common(addr + 2, val >> 16, linear, p); + svga_write_common(addr + 3, val >> 24, linear, p); return; } egawrites += 4; - cycles -= video_timing_write_l; + sub_cycles(video_timing_write_l); if (!linear) addr = (addr & svga->banked_mask) + svga->write_bank; @@ -1306,7 +1317,7 @@ svga_readw_common(uint32_t addr, uint8_t linear, void *p) egareads += 2; - cycles -= video_timing_read_w; + sub_cycles(video_timing_read_w); if (!linear) addr = (addr & svga->banked_mask) + svga->read_bank; @@ -1344,7 +1355,7 @@ svga_readl_common(uint32_t addr, uint8_t linear, void *p) egareads += 4; - cycles -= video_timing_read_l; + sub_cycles(video_timing_read_l); if (!linear) addr = (addr & svga->banked_mask) + svga->read_bank; @@ -1368,30 +1379,3 @@ svga_readl_linear(uint32_t addr, void *p) { return svga_readl_common(addr, 1, p); } - - -void -svga_add_status_info(char *s, int max_len, void *p) -{ - svga_t *svga = (svga_t *)p; - char temps[128]; - - if (svga->chain4) - strcpy(temps, "SVGA chained (possibly mode 13h)\n"); - else - strcpy(temps, "SVGA unchained (possibly mode-X)\n"); - strncat(s, temps, max_len); - - if (!svga->video_bpp) - strcpy(temps, "SVGA in text mode\n"); - else - sprintf(temps, "SVGA colour depth : %i bpp\n", svga->video_bpp); - strncat(s, temps, max_len); - - sprintf(temps, "SVGA resolution : %i x %i\n", svga->video_res_x, svga->video_res_y); - strncat(s, temps, max_len); - - sprintf(temps, "SVGA refresh rate : %i Hz\n\n", svga->frames); - svga->frames = 0; - strncat(s, temps, max_len); -} diff --git a/src/video/vid_svga.h b/src/video/vid_svga.h index 4b498cb31..6d941932a 100644 --- a/src/video/vid_svga.h +++ b/src/video/vid_svga.h @@ -28,25 +28,23 @@ typedef struct svga_t { mem_mapping_t mapping; - int enabled, fast, vidclock, fb_only, - dac_addr, dac_pos, dac_r, dac_g, - ramdac_type, ext_overscan, - readmode, writemode, readplane, extvram, - chain4, chain2_write, chain2_read, - oddeven_page, oddeven_chain, - set_reset_disabled, + uint8_t fast, chain4, chain2_write, chain2_read, + ext_overscan, bus_size, + lowres, interlace, linedbl, rowcount, + set_reset_disabled, bpp, ramdac_type, fb_only, + readmode, writemode, readplane, + hwcursor_oddeven, dac_hwcursor_oddeven, overlay_oddeven; + + int dac_addr, dac_pos, dac_r, dac_g, vtotal, dispend, vsyncstart, split, vblankstart, hdisp, hdisp_old, htotal, hdisp_time, rowoffset, - lowres, interlace, linedbl, rowcount, bpp, dispon, hdisp_on, vc, sc, linepos, vslines, linecountff, oddeven, con, cursoron, blink, scrollcache, firstline, lastline, firstline_draw, lastline_draw, displine, fullchange, - video_res_x, video_res_y, video_bpp, frames, fps, - vram_display_mask, - hwcursor_on, overlay_on, - hwcursor_oddeven, overlay_oddeven; + vram_display_mask, vidclock, + hwcursor_on, dac_hwcursor_on, overlay_on; /*The three variables below allow us to implement memory maps like that seen on a 1MB Trio64 : 0MB-1MB - VRAM @@ -69,12 +67,13 @@ typedef struct svga_t PALETTE vgapal; - int64_t dispontime, dispofftime, - vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; double clock; hwcursor_t hwcursor, hwcursor_latch, + dac_hwcursor, dac_hwcursor_latch, overlay, overlay_latch; void (*render)(struct svga_t *svga); @@ -85,6 +84,8 @@ typedef struct svga_t void (*hwcursor_draw)(struct svga_t *svga, int displine); + void (*dac_hwcursor_draw)(struct svga_t *svga, int displine); + void (*overlay_draw)(struct svga_t *svga, int displine); void (*vblank_start)(struct svga_t *svga); diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index fcb7e4486..bd6773e2d 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -8,13 +8,13 @@ * * SVGA renderers. * - * Version: @(#)vid_svga_render.c 1.0.12 2018/08/14 + * Version: @(#)vid_svga_render.c 1.0.13 2019/03/08 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. */ #include #include @@ -22,6 +22,7 @@ #include #include "../86box.h" #include "../mem.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" @@ -42,16 +43,16 @@ void svga_render_blank(svga_t *svga) switch (svga->seqregs[1] & 9) { case 0: - for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 9) + xx + 32 + x_add] = 0; + for (xx = 0; xx < 9; xx++) buffer32->line[svga->displine + y_add][(x * 9) + xx + 32 + x_add] = 0; break; case 1: - for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 8) + xx + 32 + x_add] = 0; + for (xx = 0; xx < 8; xx++) buffer32->line[svga->displine + y_add][(x * 8) + xx + 32 + x_add] = 0; break; case 8: - for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 18) + xx + 32 + x_add] = 0; + for (xx = 0; xx < 18; xx++) buffer32->line[svga->displine + y_add][(x * 18) + xx + 32 + x_add] = 0; break; case 9: - for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 16) + xx + 32 + x_add] = 0; + for (xx = 0; xx < 16; xx++) buffer32->line[svga->displine + y_add][(x * 16) + xx + 32 + x_add] = 0; break; } } @@ -68,7 +69,7 @@ void svga_render_text_40(svga_t *svga) if (svga->fullchange) { - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][32 + x_add]; int x, xx; int drawcursor; uint8_t chr, attr, dat; @@ -134,7 +135,7 @@ void svga_render_text_80(svga_t *svga) if (svga->fullchange) { - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][32 + x_add]; int x, xx; int drawcursor; uint8_t chr, attr, dat; @@ -202,7 +203,7 @@ void svga_render_text_80_ksc5601(svga_t *svga) if (svga->fullchange) { - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][32 + x_add]; int x, xx; int drawcursor; uint8_t chr, attr, dat, nextchr; @@ -332,7 +333,7 @@ void svga_render_2bpp_lowres(svga_t *svga) { int x; int offset = ((8 - svga->scrollcache) << 1) + 16; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -374,7 +375,7 @@ void svga_render_2bpp_highres(svga_t *svga) { int x; int offset = (8 - svga->scrollcache) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -412,7 +413,7 @@ void svga_render_4bpp_lowres(svga_t *svga) { int x; int offset = ((8 - svga->scrollcache) << 1) + 16; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -458,7 +459,7 @@ void svga_render_4bpp_highres(svga_t *svga) { int x; int offset = (8 - svga->scrollcache) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -500,7 +501,7 @@ void svga_render_8bpp_lowres(svga_t *svga) { int x; int offset = (8 - (svga->scrollcache & 6)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -531,7 +532,7 @@ void svga_render_8bpp_highres(svga_t *svga) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -568,7 +569,7 @@ void svga_render_15bpp_lowres(svga_t *svga) { int x; int offset = (8 - (svga->scrollcache & 6)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -583,8 +584,8 @@ void svga_render_15bpp_lowres(svga_t *svga) dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - p[x] = video_15to32[dat & 0xffff]; - p[x + 1] = video_15to32[dat >> 16]; + p[x + 2] = video_15to32[dat & 0xffff]; + p[x + 3] = video_15to32[dat >> 16]; } svga->ma += x << 1; svga->ma &= svga->vram_display_mask; @@ -600,7 +601,7 @@ void svga_render_15bpp_highres(svga_t *svga) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -638,7 +639,7 @@ void svga_render_16bpp_lowres(svga_t *svga) { int x; int offset = (8 - (svga->scrollcache & 6)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -653,8 +654,8 @@ void svga_render_16bpp_lowres(svga_t *svga) dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - p[x] = video_16to32[dat & 0xffff]; - p[x + 1] = video_16to32[dat >> 16]; + p[x + 2] = video_16to32[dat & 0xffff]; + p[x + 3] = video_16to32[dat >> 16]; } svga->ma += x << 1; svga->ma &= svga->vram_display_mask; @@ -670,7 +671,7 @@ void svga_render_16bpp_highres(svga_t *svga) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -720,7 +721,7 @@ void svga_render_24bpp_lowres(svga_t *svga) fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); svga->ma += 3; svga->ma &= svga->vram_display_mask; - ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = fg; + buffer32->line[svga->displine + y_add][(x << 1) + offset + x_add] = buffer32->line[svga->displine + y_add][(x << 1) + 1 + offset + x_add] = fg; } } } @@ -734,7 +735,7 @@ void svga_render_24bpp_highres(svga_t *svga) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -781,7 +782,7 @@ void svga_render_32bpp_lowres(svga_t *svga) fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); svga->ma += 4; svga->ma &= svga->vram_display_mask; - ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = fg; + buffer32->line[svga->displine + y_add][(x << 1) + offset + x_add] = buffer32->line[svga->displine + y_add][(x << 1) + 1 + offset + x_add] = fg; } } } @@ -797,7 +798,7 @@ void svga_render_32bpp_highres(svga_t *svga) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -822,7 +823,7 @@ void svga_render_ABGR8888_highres(svga_t *svga) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; @@ -847,7 +848,7 @@ void svga_render_RGBA8888_highres(svga_t *svga) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + uint32_t *p = &buffer32->line[svga->displine + y_add][offset + x_add]; if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 4f2cd3120..9d7cca6b0 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.42 2018/11/01 + * Version: @(#)vid_table.c 1.0.43 2019/03/03 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -24,6 +24,7 @@ #include #define HAVE_STDARG_H #include "../86box.h" +#include "../timer.h" #include "../machine/machine.h" #include "../mem.h" #include "../device.h" @@ -33,7 +34,6 @@ #include "vid_ati18800.h" #include "vid_ati28800.h" -//#include "vid_ati_mach8.h" #include "vid_ati_mach64.h" #include "vid_cga.h" #include "vid_cl54xx.h" @@ -44,13 +44,15 @@ #include "vid_genius.h" #include "vid_hercules.h" #include "vid_herculesplus.h" +#include "vid_ht216.h" +#include "vid_im1024.h" #include "vid_incolor.h" #include "vid_colorplus.h" #include "vid_mda.h" #include "vid_oak_oti.h" #include "vid_paradise.h" +#include "vid_pgc.h" #include "vid_s3.h" -//#include "vid_s3_911.h" #include "vid_s3_virge.h" #include "vid_sigma.h" #include "vid_tgui9440.h" @@ -70,12 +72,14 @@ typedef struct { static video_timings_t timing_default = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; +static int was_reset = 0; + + static const VIDEO_CARD video_cards[] = { { "None", "none", NULL }, { "Internal", "internal", NULL }, { "[ISA] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_isa", &mach64gx_isa_device }, - //{ "[ISA] ATI Graphics Ultra (Mach8)", "mach8_isa", &mach8_device }, { "[ISA] ATI Korean VGA (ATI-28800-5)", "ati28800k", &ati28800k_device }, { "[ISA] ATI VGA-88 (ATI-18800-1)", "ati18800v", &ati18800_vga88_device }, { "[ISA] ATI VGA Charger (ATI-28800-5)", "ati28800", &ati28800_device }, @@ -101,18 +105,23 @@ video_cards[] = { { "[ISA] Compaq CGA 2", "compaq_cga_2", &compaq_cga_2_device }, { "[ISA] Compaq EGA", "compaq_ega", &cpqega_device }, { "[ISA] EGA", "ega", &ega_device }, + { "[ISA] G2 GC205", "g2_gc205", &g2_gc205_device }, + { "[ISA] Headland HT216-32", "ht216_32", &ht216_32_device }, { "[ISA] Hercules", "hercules", &hercules_device }, { "[ISA] Hercules Plus", "hercules_plus", &herculesplus_device }, { "[ISA] Hercules InColor", "incolor", &incolor_device }, + { "[ISA] Image Manager 1024", "im1024", &im1024_device }, { "[ISA] MDA", "mda", &mda_device }, { "[ISA] MDSI Genius", "genius", &genius_device }, { "[ISA] OAK OTI-037C", "oti037c", &oti037c_device }, { "[ISA] OAK OTI-067", "oti067", &oti067_device }, { "[ISA] OAK OTI-077", "oti077", &oti077_device }, + { "[ISA] Orchid Fahrenheit 1280 (S3 86c911)", "orchid_s3_911", &s3_orchid_86c911_isa_device }, { "[ISA] Paradise PVGA1A", "pvga1a", ¶dise_pvga1a_device }, { "[ISA] Paradise WD90C11-LR", "wd90c11", ¶dise_wd90c11_device }, { "[ISA] Paradise WD90C30-LR", "wd90c30", ¶dise_wd90c30_device }, { "[ISA] Plantronics ColorPlus", "plantronics", &colorplus_device }, + { "[ISA] Professional Graphics Controller", "pgc", &pgc_device }, { "[ISA] Sigma Color 400", "sigma400", &sigma_device }, { "[ISA] SPEA V7 Mirage (S3 86c801)", "px_s3_v7_801_isa", &s3_v7mirage_86c801_isa_device }, #if defined(DEV_BRANCH) && defined(USE_TI) @@ -123,6 +132,7 @@ video_cards[] = { { "[ISA] Trigem Korean VGA (ET4000AX)", "tgkorvga", &et4000k_isa_device }, { "[ISA] Tseng ET4000AX", "et4000ax", &et4000_isa_device }, { "[ISA] VGA", "vga", &vga_device }, + { "[ISA] Video 7 VGA 1024i", "v7_vga_1024i", &v7_vga_1024i_device }, { "[ISA] Wyse 700", "wy700", &wy700_device }, { "[MCA] Tseng ET4000AX", "et4000mca", &et4000_mca_device }, { "[PCI] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_pci", &mach64gx_pci_device }, @@ -197,11 +207,25 @@ vid_table_log(const char *fmt, ...) #endif +void +video_reset_close(void) +{ + video_inform(VIDEO_FLAG_TYPE_NONE, &timing_default); + was_reset = 1; +} + + void video_reset(int card) { - vid_table_log("VIDEO: reset (romset=%d, gfxcard=%d, internal=%d)\n", - romset, card, (machines[machine].flags & MACHINE_VIDEO)?1:0); + /* This is needed to avoid duplicate resets. */ + if ((video_get_type() != VIDEO_FLAG_TYPE_NONE) && was_reset) + return; + + vid_table_log("VIDEO: reset (gfxcard=%d, internal=%d)\n", + card, (machines[machine].flags & MACHINE_VIDEO)?1:0); + + loadfont(L"roms/video/mda/mda.rom", 0); /* Reset (deallocate) the video font arrays. */ if (fontdatksc5601) { @@ -218,7 +242,7 @@ video_reset(int card) /* Do not initialize internal cards here. */ if (!(card == VID_NONE) && \ - !(card == VID_INTERNAL) && !machines[machine].fixed_gfxcard) { + !(card == VID_INTERNAL) && !(machines[machine].flags & MACHINE_VIDEO_FIXED)) { vid_table_log("VIDEO: initializing '%s'\n", video_cards[card].name); /* Do an inform on the default values, so that that there's some sane values initialized @@ -232,6 +256,8 @@ video_reset(int card) /* Enable the Voodoo if configured. */ if (voodoo_enabled) device_add(&voodoo_device); + + was_reset = 1; } diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index 8f6874236..3734ce454 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -62,6 +62,7 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../pci.h" #include "../rom.h" @@ -521,7 +522,7 @@ void tgui_recalctimings(svga_t *svga) if (tgui->type >= TGUI_9440) { if (svga->miscout & 8) - svga->clock = cpuclock / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); + svga->clock = (cpuclock * (double)(1ull << 32)) / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); if (svga->gdcreg[0xf] & 0x08) svga->clock *= 2; @@ -532,20 +533,20 @@ void tgui_recalctimings(svga_t *svga) { switch (((svga->miscout >> 2) & 3) | ((tgui->newctrl2 << 2) & 4) | ((tgui->newctrl2 >> 3) & 8)) { - case 0x02: svga->clock = cpuclock/ 44900000.0; break; - case 0x03: svga->clock = cpuclock/ 36000000.0; break; - case 0x04: svga->clock = cpuclock/ 57272000.0; break; - case 0x05: svga->clock = cpuclock/ 65000000.0; break; - case 0x06: svga->clock = cpuclock/ 50350000.0; break; - case 0x07: svga->clock = cpuclock/ 40000000.0; break; - case 0x08: svga->clock = cpuclock/ 88000000.0; break; - case 0x09: svga->clock = cpuclock/ 98000000.0; break; - case 0x0a: svga->clock = cpuclock/118800000.0; break; - case 0x0b: svga->clock = cpuclock/108000000.0; break; - case 0x0c: svga->clock = cpuclock/ 72000000.0; break; - case 0x0d: svga->clock = cpuclock/ 77000000.0; break; - case 0x0e: svga->clock = cpuclock/ 80000000.0; break; - case 0x0f: svga->clock = cpuclock/ 75000000.0; break; + case 0x02: svga->clock = (cpuclock * (double)(1ull << 32)) / 44900000.0; break; + case 0x03: svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; break; + case 0x04: svga->clock = (cpuclock * (double)(1ull << 32)) / 57272000.0; break; + case 0x05: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; + case 0x06: svga->clock = (cpuclock * (double)(1ull << 32)) / 50350000.0; break; + case 0x07: svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break; + case 0x08: svga->clock = (cpuclock * (double)(1ull << 32)) / 88000000.0; break; + case 0x09: svga->clock = (cpuclock * (double)(1ull << 32)) / 98000000.0; break; + case 0x0a: svga->clock = (cpuclock * (double)(1ull << 32)) /118800000.0; break; + case 0x0b: svga->clock = (cpuclock * (double)(1ull << 32)) /108000000.0; break; + case 0x0c: svga->clock = (cpuclock * (double)(1ull << 32)) / 72000000.0; break; + case 0x0d: svga->clock = (cpuclock * (double)(1ull << 32)) / 77000000.0; break; + case 0x0e: svga->clock = (cpuclock * (double)(1ull << 32)) / 80000000.0; break; + case 0x0f: svga->clock = (cpuclock * (double)(1ull << 32)) / 75000000.0; break; } if (svga->gdcreg[0xf] & 0x08) { @@ -695,9 +696,9 @@ void tgui_hwcursor_draw(svga_t *svga, int displine) if (offset >= svga->hwcursor_latch.x) { if (!(dat[0] & 0x80000000)) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x80000000) ? 0xffffff : 0; + buffer32->line[displine + y_add][offset + 32 + x_add] = (dat[1] & 0x80000000) ? 0xffffff : 0; else if (dat[1] & 0x80000000) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + buffer32->line[displine + y_add][offset + 32 + x_add] ^= 0xffffff; } offset++; @@ -774,8 +775,8 @@ static uint8_t tgui_ext_linear_read(uint32_t addr, void *p) svga_t *svga = (svga_t *)p; tgui_t *tgui = (tgui_t *)svga->p; int c; - - cycles -= video_timing_read_b; + + sub_cycles(video_timing_read_b); addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -806,7 +807,7 @@ static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p) uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]}; uint8_t mask = tgui->ext_gdc_regs[7]; - cycles -= video_timing_write_b; + sub_cycles(video_timing_write_b); addr &= svga->decode_mask; if (addr >= svga->vram_max) @@ -875,7 +876,7 @@ static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p) uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]}; uint16_t mask = (tgui->ext_gdc_regs[7] << 8) | tgui->ext_gdc_regs[8]; - cycles -= video_timing_write_w; + sub_cycles(video_timing_write_w); addr &= svga->decode_mask; if (addr >= svga->vram_max) diff --git a/src/video/vid_ti_cf62011.c b/src/video/vid_ti_cf62011.c index 8210778f1..e77ce27c9 100644 --- a/src/video/vid_ti_cf62011.c +++ b/src/video/vid_ti_cf62011.c @@ -59,6 +59,7 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../rom.h" #include "../device.h" diff --git a/src/video/vid_tkd8001_ramdac.c b/src/video/vid_tkd8001_ramdac.c index 8f0c306fa..e7c381a79 100644 --- a/src/video/vid_tkd8001_ramdac.c +++ b/src/video/vid_tkd8001_ramdac.c @@ -23,6 +23,7 @@ #include #include "../86box.h" #include "../device.h" +#include "../timer.h" #include "../mem.h" #include "video.h" #include "vid_svga.h" diff --git a/src/video/vid_tvga.c b/src/video/vid_tvga.c index cddc0690c..8e2fd3bc3 100644 --- a/src/video/vid_tvga.c +++ b/src/video/vid_tvga.c @@ -23,6 +23,7 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../mem.h" #include "../rom.h" #include "../device.h" @@ -267,12 +268,12 @@ void tvga_recalctimings(svga_t *svga) switch (((svga->miscout >> 2) & 3) | ((tvga->newctrl2 << 2) & 4)) { - case 2: svga->clock = cpuclock/44900000.0; break; - case 3: svga->clock = cpuclock/36000000.0; break; - case 4: svga->clock = cpuclock/57272000.0; break; - case 5: svga->clock = cpuclock/65000000.0; break; - case 6: svga->clock = cpuclock/50350000.0; break; - case 7: svga->clock = cpuclock/40000000.0; break; + case 2: svga->clock = (cpuclock * (double)(1ull << 32))/44900000.0; break; + case 3: svga->clock = (cpuclock * (double)(1ull << 32))/36000000.0; break; + case 4: svga->clock = (cpuclock * (double)(1ull << 32))/57272000.0; break; + case 5: svga->clock = (cpuclock * (double)(1ull << 32))/65000000.0; break; + case 6: svga->clock = (cpuclock * (double)(1ull << 32))/50350000.0; break; + case 7: svga->clock = (cpuclock * (double)(1ull << 32))/40000000.0; break; } if (tvga->oldctrl2 & 0x10) diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index fd86fa4b6..b01e9fa53 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -26,6 +26,7 @@ #include "../mem.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "video.h" #include "vid_svga.h" #include "vid_vga.h" diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index 1b3fa5870..b03ae4f66 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -215,6 +215,15 @@ typedef struct texture_t uint32_t *data; } texture_t; +typedef struct vert_t +{ + float sVx, sVy; + float sRed, sGreen, sBlue, sAlpha; + float sVz, sWb; + float sW0, sS0, sT0; + float sW1, sS1, sT1; +} vert_t; + typedef struct voodoo_t { mem_mapping_t mapping; @@ -227,7 +236,7 @@ typedef struct voodoo_t uint16_t dac_pll_regs[16]; float pixel_clock; - int line_time; + uint64_t line_time; voodoo_params_t params; @@ -261,7 +270,7 @@ typedef struct voodoo_t int swap_count; int disp_buffer, draw_buffer; - int64_t timer_count; + pc_timer_t timer; int line; svga_t *svga; @@ -331,14 +340,7 @@ typedef struct voodoo_t uint32_t cmdfifo_amin, cmdfifo_amax; uint32_t sSetupMode; - struct - { - float sVx, sVy; - float sRed, sGreen, sBlue, sAlpha; - float sVz, sWb; - float sW0, sS0, sT0; - float sW1, sS1, sT1; - } verts[4]; + vert_t verts[4]; int vertex_num; int num_verticies; @@ -386,7 +388,7 @@ typedef struct voodoo_t int dst_stride; } blt; - rgbp_t clutData[33]; + rgbp_t clutData[64]; int clutData_dirty; rgbp_t clutData256[256]; uint32_t video_16to32[0x10000]; @@ -397,9 +399,9 @@ typedef struct voodoo_t int fb_write_buffer, fb_draw_buffer; int buffer_cutoff; - int64_t read_time, write_time, burst_time; + int read_time, write_time, burst_time; - int64_t wake_timer; + pc_timer_t wake_timer; uint8_t thefilter[256][256]; // pixel filter, feeding from one or two uint8_t thefilterg[256][256]; // for green @@ -3747,9 +3749,15 @@ static void triangle_setup(voodoo_t *voodoo) int va = 0, vb = 1, vc = 2; int reverse_cull = 0; - if (voodoo->verts[0].sVy < voodoo->verts[1].sVy) + vert_t verts[3]; + + verts[0] = voodoo->verts[0]; + verts[1] = voodoo->verts[1]; + verts[2] = voodoo->verts[2]; + + if (verts[0].sVy < verts[1].sVy) { - if (voodoo->verts[1].sVy < voodoo->verts[2].sVy) + if (verts[1].sVy < verts[2].sVy) { /* V1>V0, V2>V1, V2>V1>V0*/ va = 0; /*OK*/ @@ -3759,7 +3767,7 @@ static void triangle_setup(voodoo_t *voodoo) else { /* V1>V0, V1>V2*/ - if (voodoo->verts[0].sVy < voodoo->verts[2].sVy) + if (verts[0].sVy < verts[2].sVy) { /* V1>V0, V1>V2, V2>V0, V1>V2>V0*/ va = 0; @@ -3778,10 +3786,10 @@ static void triangle_setup(voodoo_t *voodoo) } else { - if (voodoo->verts[1].sVy < voodoo->verts[2].sVy) + if (verts[1].sVy < verts[2].sVy) { /* V0>V1, V2>V1*/ - if (voodoo->verts[0].sVy < voodoo->verts[2].sVy) + if (verts[0].sVy < verts[2].sVy) { /* V0>V1, V2>V1, V2>V0, V2>V0>V1*/ va = 1; @@ -3807,10 +3815,10 @@ static void triangle_setup(voodoo_t *voodoo) } } - dxAB = voodoo->verts[va].sVx - voodoo->verts[vb].sVx; - dxBC = voodoo->verts[vb].sVx - voodoo->verts[vc].sVx; - dyAB = voodoo->verts[va].sVy - voodoo->verts[vb].sVy; - dyBC = voodoo->verts[vb].sVy - voodoo->verts[vc].sVy; + dxAB = verts[va].sVx - verts[vb].sVx; + dxBC = verts[vb].sVx - verts[vc].sVx; + dyAB = verts[va].sVy - verts[vb].sVy; + dyBC = verts[vb].sVy - verts[vc].sVy; area = dxAB * dyBC - dxBC * dyAB; @@ -3845,66 +3853,66 @@ static void triangle_setup(voodoo_t *voodoo) return; } - voodoo->params.vertexAx = (int32_t)(int16_t)((int32_t)(voodoo->verts[va].sVx * 16.0f) & 0xffff); - voodoo->params.vertexAy = (int32_t)(int16_t)((int32_t)(voodoo->verts[va].sVy * 16.0f) & 0xffff); - voodoo->params.vertexBx = (int32_t)(int16_t)((int32_t)(voodoo->verts[vb].sVx * 16.0f) & 0xffff); - voodoo->params.vertexBy = (int32_t)(int16_t)((int32_t)(voodoo->verts[vb].sVy * 16.0f) & 0xffff); - voodoo->params.vertexCx = (int32_t)(int16_t)((int32_t)(voodoo->verts[vc].sVx * 16.0f) & 0xffff); - voodoo->params.vertexCy = (int32_t)(int16_t)((int32_t)(voodoo->verts[vc].sVy * 16.0f) & 0xffff); + voodoo->params.vertexAx = (int32_t)(int16_t)((int32_t)(verts[va].sVx * 16.0f) & 0xffff); + voodoo->params.vertexAy = (int32_t)(int16_t)((int32_t)(verts[va].sVy * 16.0f) & 0xffff); + voodoo->params.vertexBx = (int32_t)(int16_t)((int32_t)(verts[vb].sVx * 16.0f) & 0xffff); + voodoo->params.vertexBy = (int32_t)(int16_t)((int32_t)(verts[vb].sVy * 16.0f) & 0xffff); + voodoo->params.vertexCx = (int32_t)(int16_t)((int32_t)(verts[vc].sVx * 16.0f) & 0xffff); + voodoo->params.vertexCy = (int32_t)(int16_t)((int32_t)(verts[vc].sVy * 16.0f) & 0xffff); if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy) fatal("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy); if (voodoo->sSetupMode & SETUPMODE_RGB) { - voodoo->params.startR = (int32_t)(voodoo->verts[va].sRed * 4096.0f); - voodoo->params.dRdX = (int32_t)(((voodoo->verts[va].sRed - voodoo->verts[vb].sRed) * dyBC - (voodoo->verts[vb].sRed - voodoo->verts[vc].sRed) * dyAB) * 4096.0f); - voodoo->params.dRdY = (int32_t)(((voodoo->verts[vb].sRed - voodoo->verts[vc].sRed) * dxAB - (voodoo->verts[va].sRed - voodoo->verts[vb].sRed) * dxBC) * 4096.0f); - voodoo->params.startG = (int32_t)(voodoo->verts[va].sGreen * 4096.0f); - voodoo->params.dGdX = (int32_t)(((voodoo->verts[va].sGreen - voodoo->verts[vb].sGreen) * dyBC - (voodoo->verts[vb].sGreen - voodoo->verts[vc].sGreen) * dyAB) * 4096.0f); - voodoo->params.dGdY = (int32_t)(((voodoo->verts[vb].sGreen - voodoo->verts[vc].sGreen) * dxAB - (voodoo->verts[va].sGreen - voodoo->verts[vb].sGreen) * dxBC) * 4096.0f); - voodoo->params.startB = (int32_t)(voodoo->verts[va].sBlue * 4096.0f); - voodoo->params.dBdX = (int32_t)(((voodoo->verts[va].sBlue - voodoo->verts[vb].sBlue) * dyBC - (voodoo->verts[vb].sBlue - voodoo->verts[vc].sBlue) * dyAB) * 4096.0f); - voodoo->params.dBdY = (int32_t)(((voodoo->verts[vb].sBlue - voodoo->verts[vc].sBlue) * dxAB - (voodoo->verts[va].sBlue - voodoo->verts[vb].sBlue) * dxBC) * 4096.0f); + voodoo->params.startR = (int32_t)(verts[va].sRed * 4096.0f); + voodoo->params.dRdX = (int32_t)(((verts[va].sRed - verts[vb].sRed) * dyBC - (verts[vb].sRed - verts[vc].sRed) * dyAB) * 4096.0f); + voodoo->params.dRdY = (int32_t)(((verts[vb].sRed - verts[vc].sRed) * dxAB - (verts[va].sRed - verts[vb].sRed) * dxBC) * 4096.0f); + voodoo->params.startG = (int32_t)(verts[va].sGreen * 4096.0f); + voodoo->params.dGdX = (int32_t)(((verts[va].sGreen - verts[vb].sGreen) * dyBC - (verts[vb].sGreen - verts[vc].sGreen) * dyAB) * 4096.0f); + voodoo->params.dGdY = (int32_t)(((verts[vb].sGreen - verts[vc].sGreen) * dxAB - (verts[va].sGreen - verts[vb].sGreen) * dxBC) * 4096.0f); + voodoo->params.startB = (int32_t)(verts[va].sBlue * 4096.0f); + voodoo->params.dBdX = (int32_t)(((verts[va].sBlue - verts[vb].sBlue) * dyBC - (verts[vb].sBlue - verts[vc].sBlue) * dyAB) * 4096.0f); + voodoo->params.dBdY = (int32_t)(((verts[vb].sBlue - verts[vc].sBlue) * dxAB - (verts[va].sBlue - verts[vb].sBlue) * dxBC) * 4096.0f); } if (voodoo->sSetupMode & SETUPMODE_ALPHA) { - voodoo->params.startA = (int32_t)(voodoo->verts[va].sAlpha * 4096.0f); - voodoo->params.dAdX = (int32_t)(((voodoo->verts[va].sAlpha - voodoo->verts[vb].sAlpha) * dyBC - (voodoo->verts[vb].sAlpha - voodoo->verts[vc].sAlpha) * dyAB) * 4096.0f); - voodoo->params.dAdY = (int32_t)(((voodoo->verts[vb].sAlpha - voodoo->verts[vc].sAlpha) * dxAB - (voodoo->verts[va].sAlpha - voodoo->verts[vb].sAlpha) * dxBC) * 4096.0f); + voodoo->params.startA = (int32_t)(verts[va].sAlpha * 4096.0f); + voodoo->params.dAdX = (int32_t)(((verts[va].sAlpha - verts[vb].sAlpha) * dyBC - (verts[vb].sAlpha - verts[vc].sAlpha) * dyAB) * 4096.0f); + voodoo->params.dAdY = (int32_t)(((verts[vb].sAlpha - verts[vc].sAlpha) * dxAB - (verts[va].sAlpha - verts[vb].sAlpha) * dxBC) * 4096.0f); } if (voodoo->sSetupMode & SETUPMODE_Z) { - voodoo->params.startZ = (int32_t)(voodoo->verts[va].sVz * 4096.0f); - voodoo->params.dZdX = (int32_t)(((voodoo->verts[va].sVz - voodoo->verts[vb].sVz) * dyBC - (voodoo->verts[vb].sVz - voodoo->verts[vc].sVz) * dyAB) * 4096.0f); - voodoo->params.dZdY = (int32_t)(((voodoo->verts[vb].sVz - voodoo->verts[vc].sVz) * dxAB - (voodoo->verts[va].sVz - voodoo->verts[vb].sVz) * dxBC) * 4096.0f); + voodoo->params.startZ = (int32_t)(verts[va].sVz * 4096.0f); + voodoo->params.dZdX = (int32_t)(((verts[va].sVz - verts[vb].sVz) * dyBC - (verts[vb].sVz - verts[vc].sVz) * dyAB) * 4096.0f); + voodoo->params.dZdY = (int32_t)(((verts[vb].sVz - verts[vc].sVz) * dxAB - (verts[va].sVz - verts[vb].sVz) * dxBC) * 4096.0f); } if (voodoo->sSetupMode & SETUPMODE_Wb) { - voodoo->params.startW = (int64_t)(voodoo->verts[va].sWb * 4294967296.0f); - voodoo->params.dWdX = (int64_t)(((voodoo->verts[va].sWb - voodoo->verts[vb].sWb) * dyBC - (voodoo->verts[vb].sWb - voodoo->verts[vc].sWb) * dyAB) * 4294967296.0f); - voodoo->params.dWdY = (int64_t)(((voodoo->verts[vb].sWb - voodoo->verts[vc].sWb) * dxAB - (voodoo->verts[va].sWb - voodoo->verts[vb].sWb) * dxBC) * 4294967296.0f); + voodoo->params.startW = (int64_t)(verts[va].sWb * 4294967296.0f); + voodoo->params.dWdX = (int64_t)(((verts[va].sWb - verts[vb].sWb) * dyBC - (verts[vb].sWb - verts[vc].sWb) * dyAB) * 4294967296.0f); + voodoo->params.dWdY = (int64_t)(((verts[vb].sWb - verts[vc].sWb) * dxAB - (verts[va].sWb - verts[vb].sWb) * dxBC) * 4294967296.0f); voodoo->params.tmu[0].startW = voodoo->params.tmu[1].startW = voodoo->params.startW; voodoo->params.tmu[0].dWdX = voodoo->params.tmu[1].dWdX = voodoo->params.dWdX; voodoo->params.tmu[0].dWdY = voodoo->params.tmu[1].dWdY = voodoo->params.dWdY; } if (voodoo->sSetupMode & SETUPMODE_W0) { - voodoo->params.tmu[0].startW = (int64_t)(voodoo->verts[va].sW0 * 4294967296.0f); - voodoo->params.tmu[0].dWdX = (int64_t)(((voodoo->verts[va].sW0 - voodoo->verts[vb].sW0) * dyBC - (voodoo->verts[vb].sW0 - voodoo->verts[vc].sW0) * dyAB) * 4294967296.0f); - voodoo->params.tmu[0].dWdY = (int64_t)(((voodoo->verts[vb].sW0 - voodoo->verts[vc].sW0) * dxAB - (voodoo->verts[va].sW0 - voodoo->verts[vb].sW0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[0].startW = (int64_t)(verts[va].sW0 * 4294967296.0f); + voodoo->params.tmu[0].dWdX = (int64_t)(((verts[va].sW0 - verts[vb].sW0) * dyBC - (verts[vb].sW0 - verts[vc].sW0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dWdY = (int64_t)(((verts[vb].sW0 - verts[vc].sW0) * dxAB - (verts[va].sW0 - verts[vb].sW0) * dxBC) * 4294967296.0f); voodoo->params.tmu[1].startW = voodoo->params.tmu[0].startW; voodoo->params.tmu[1].dWdX = voodoo->params.tmu[0].dWdX; voodoo->params.tmu[1].dWdY = voodoo->params.tmu[0].dWdY; } if (voodoo->sSetupMode & SETUPMODE_S0_T0) { - voodoo->params.tmu[0].startS = (int64_t)(voodoo->verts[va].sS0 * 4294967296.0f); - voodoo->params.tmu[0].dSdX = (int64_t)(((voodoo->verts[va].sS0 - voodoo->verts[vb].sS0) * dyBC - (voodoo->verts[vb].sS0 - voodoo->verts[vc].sS0) * dyAB) * 4294967296.0f); - voodoo->params.tmu[0].dSdY = (int64_t)(((voodoo->verts[vb].sS0 - voodoo->verts[vc].sS0) * dxAB - (voodoo->verts[va].sS0 - voodoo->verts[vb].sS0) * dxBC) * 4294967296.0f); - voodoo->params.tmu[0].startT = (int64_t)(voodoo->verts[va].sT0 * 4294967296.0f); - voodoo->params.tmu[0].dTdX = (int64_t)(((voodoo->verts[va].sT0 - voodoo->verts[vb].sT0) * dyBC - (voodoo->verts[vb].sT0 - voodoo->verts[vc].sT0) * dyAB) * 4294967296.0f); - voodoo->params.tmu[0].dTdY = (int64_t)(((voodoo->verts[vb].sT0 - voodoo->verts[vc].sT0) * dxAB - (voodoo->verts[va].sT0 - voodoo->verts[vb].sT0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[0].startS = (int64_t)(verts[va].sS0 * 4294967296.0f); + voodoo->params.tmu[0].dSdX = (int64_t)(((verts[va].sS0 - verts[vb].sS0) * dyBC - (verts[vb].sS0 - verts[vc].sS0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dSdY = (int64_t)(((verts[vb].sS0 - verts[vc].sS0) * dxAB - (verts[va].sS0 - verts[vb].sS0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[0].startT = (int64_t)(verts[va].sT0 * 4294967296.0f); + voodoo->params.tmu[0].dTdX = (int64_t)(((verts[va].sT0 - verts[vb].sT0) * dyBC - (verts[vb].sT0 - verts[vc].sT0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dTdY = (int64_t)(((verts[vb].sT0 - verts[vc].sT0) * dxAB - (verts[va].sT0 - verts[vb].sT0) * dxBC) * 4294967296.0f); voodoo->params.tmu[1].startS = voodoo->params.tmu[0].startS; voodoo->params.tmu[1].dSdX = voodoo->params.tmu[0].dSdX; voodoo->params.tmu[1].dSdY = voodoo->params.tmu[0].dSdY; @@ -3914,18 +3922,18 @@ static void triangle_setup(voodoo_t *voodoo) } if (voodoo->sSetupMode & SETUPMODE_W1) { - voodoo->params.tmu[1].startW = (int64_t)(voodoo->verts[va].sW1 * 4294967296.0f); - voodoo->params.tmu[1].dWdX = (int64_t)(((voodoo->verts[va].sW1 - voodoo->verts[vb].sW1) * dyBC - (voodoo->verts[vb].sW1 - voodoo->verts[vc].sW1) * dyAB) * 4294967296.0f); - voodoo->params.tmu[1].dWdY = (int64_t)(((voodoo->verts[vb].sW1 - voodoo->verts[vc].sW1) * dxAB - (voodoo->verts[va].sW1 - voodoo->verts[vb].sW1) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startW = (int64_t)(verts[va].sW1 * 4294967296.0f); + voodoo->params.tmu[1].dWdX = (int64_t)(((verts[va].sW1 - verts[vb].sW1) * dyBC - (verts[vb].sW1 - verts[vc].sW1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dWdY = (int64_t)(((verts[vb].sW1 - verts[vc].sW1) * dxAB - (verts[va].sW1 - verts[vb].sW1) * dxBC) * 4294967296.0f); } if (voodoo->sSetupMode & SETUPMODE_S1_T1) { - voodoo->params.tmu[1].startS = (int64_t)(voodoo->verts[va].sS1 * 4294967296.0f); - voodoo->params.tmu[1].dSdX = (int64_t)(((voodoo->verts[va].sS1 - voodoo->verts[vb].sS1) * dyBC - (voodoo->verts[vb].sS1 - voodoo->verts[vc].sS1) * dyAB) * 4294967296.0f); - voodoo->params.tmu[1].dSdY = (int64_t)(((voodoo->verts[vb].sS1 - voodoo->verts[vc].sS1) * dxAB - (voodoo->verts[va].sS1 - voodoo->verts[vb].sS1) * dxBC) * 4294967296.0f); - voodoo->params.tmu[1].startT = (int64_t)(voodoo->verts[va].sT1 * 4294967296.0f); - voodoo->params.tmu[1].dTdX = (int64_t)(((voodoo->verts[va].sT1 - voodoo->verts[vb].sT1) * dyBC - (voodoo->verts[vb].sT1 - voodoo->verts[vc].sT1) * dyAB) * 4294967296.0f); - voodoo->params.tmu[1].dTdY = (int64_t)(((voodoo->verts[vb].sT1 - voodoo->verts[vc].sT1) * dxAB - (voodoo->verts[va].sT1 - voodoo->verts[vb].sT1) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startS = (int64_t)(verts[va].sS1 * 4294967296.0f); + voodoo->params.tmu[1].dSdX = (int64_t)(((verts[va].sS1 - verts[vb].sS1) * dyBC - (verts[vb].sS1 - verts[vc].sS1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dSdY = (int64_t)(((verts[vb].sS1 - verts[vc].sS1) * dxAB - (verts[va].sS1 - verts[vb].sS1) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startT = (int64_t)(verts[va].sT1 * 4294967296.0f); + voodoo->params.tmu[1].dTdX = (int64_t)(((verts[va].sT1 - verts[vb].sT1) * dyBC - (verts[vb].sT1 - verts[vc].sT1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dTdY = (int64_t)(((verts[vb].sT1 - verts[vc].sT1) * dxAB - (verts[va].sT1 - verts[vb].sT1) * dxBC) * 4294967296.0f); } voodoo->params.sign = (area < 0.0); @@ -4341,7 +4349,7 @@ static void wait_for_swap_complete(voodoo_t *voodoo) { thread_wait_event(voodoo->wake_fifo_thread, -1); thread_reset_event(voodoo->wake_fifo_thread); - if ((voodoo->swap_pending && voodoo->flush) || FIFO_ENTRIES >= 65536) + if ((voodoo->swap_pending && voodoo->flush) || FIFO_FULL) { /*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/ memset(voodoo->dirty_line, 1, 1024); @@ -5903,15 +5911,13 @@ static void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) #define WAKE_DELAY (TIMER_USEC * 100) static inline void wake_fifo_thread(voodoo_t *voodoo) { - if (!voodoo->wake_timer) + if (!timer_is_enabled(&voodoo->wake_timer)) { /*Don't wake FIFO thread immediately - if we do that it will probably process one word and go back to sleep, requiring it to be woken on almost every write. Instead, wait a short while so that the CPU emulation writes more data so we have more batched-up work.*/ - timer_process(); - voodoo->wake_timer = WAKE_DELAY; - timer_update_outstanding(); + timer_set_delay_u64(&voodoo->wake_timer, WAKE_DELAY); } } @@ -5923,8 +5929,6 @@ static inline void wake_fifo_thread_now(voodoo_t *voodoo) static void voodoo_wake_timer(void *p) { voodoo_t *voodoo = (voodoo_t *)p; - - voodoo->wake_timer = 0; thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ } @@ -5959,7 +5963,7 @@ static uint16_t voodoo_readw(uint32_t addr, void *p) addr &= 0xffffff; - cycles -= voodoo->read_time; + sub_cycles(voodoo->read_time); if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ { @@ -6016,7 +6020,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) voodoo->rd_count++; addr &= 0xffffff; - cycles -= voodoo->read_time; + sub_cycles(voodoo->read_time); if (addr & 0x800000) /*Texture*/ { @@ -6169,14 +6173,23 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) break; case SST_vRetrace: - timer_clock(); temp = voodoo->line & 0x1fff; break; case SST_hvRetrace: - timer_clock(); - temp = voodoo->line & 0x1fff; - temp |= ((((voodoo->line_time - voodoo->timer_count) * voodoo->h_total) / voodoo->timer_count) << 16) & 0x7ff0000; - break; + { + uint32_t line_time = (uint32_t)(voodoo->line_time >> 32); + uint32_t diff = (timer_get_ts_int(&voodoo->timer) > (tsc & 0xffffffff)) ? (timer_get_ts_int(&voodoo->timer) - (tsc & 0xffffffff)) : 0; + uint32_t pre_div = diff * voodoo->h_total; + uint32_t post_div = pre_div / line_time; + uint32_t h_pos = (voodoo->h_total - 1) - post_div; + + if (h_pos >= voodoo->h_total) + h_pos = 0; + + temp = voodoo->line & 0x1fff; + temp |= (h_pos << 16); + } + break; case SST_fbiInit5: temp = voodoo->fbiInit5 & ~0x1ff; @@ -6221,9 +6234,9 @@ static void voodoo_writew(uint32_t addr, uint16_t val, void *p) addr &= 0xffffff; if (addr == voodoo->last_write_addr+4) - cycles -= voodoo->burst_time; + sub_cycles(voodoo->burst_time); else - cycles -= voodoo->write_time; + sub_cycles(voodoo->write_time); voodoo->last_write_addr = addr; if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ @@ -6251,7 +6264,7 @@ static void voodoo_pixelclock_update(voodoo_t *voodoo) voodoo->pixel_clock = t; clock_const = cpuclock / t; - voodoo->line_time = (int)((double)line_length * clock_const * (double)(1 << TIMER_SHIFT)); + voodoo->line_time = (uint64_t)((double)line_length * clock_const * (double)(1ULL << 32)); } static void voodoo_writel(uint32_t addr, uint32_t val, void *p) @@ -6263,9 +6276,9 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) addr &= 0xffffff; if (addr == voodoo->last_write_addr+4) - cycles -= voodoo->burst_time; + sub_cycles(voodoo->burst_time); else - cycles -= voodoo->write_time; + sub_cycles(voodoo->write_time); voodoo->last_write_addr = addr; if (addr & 0x800000) /*Texture*/ @@ -7370,7 +7383,7 @@ void voodoo_callback(void *p) if (draw_voodoo->dirty_line[draw_line]) { - uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line + y_add])[32 + x_add]; + uint32_t *p = &buffer32->line[voodoo->line + y_add][32 + x_add]; uint16_t *src = (uint16_t *)&draw_voodoo->fb_mem[draw_voodoo->front_offset + draw_line*draw_voodoo->row_width]; int x; @@ -7485,9 +7498,9 @@ skip_draw: voodoo->v_retrace = 0; } if (voodoo->line_time) - voodoo->timer_count += voodoo->line_time; + timer_advance_u64(&voodoo->timer, voodoo->line_time); else - voodoo->timer_count += TIMER_USEC * 32; + timer_advance_u64(&voodoo->timer, TIMER_USEC * 32); } static void voodoo_speed_changed(void *p) @@ -7568,7 +7581,7 @@ void *voodoo_card_init() } } - timer_add(voodoo_callback, &voodoo->timer_count, TIMER_ALWAYS_ENABLED, voodoo); + timer_add(&voodoo->timer, voodoo_callback, voodoo, 1); voodoo->svga = svga_get_pri(); voodoo->fbiInit0 = 0; @@ -7585,7 +7598,7 @@ void *voodoo_card_init() if (voodoo->render_threads == 2) voodoo->render_thread[1] = thread_create(render_thread_2, voodoo); - timer_add(voodoo_wake_timer, &voodoo->wake_timer, &voodoo->wake_timer, (void *)voodoo); + timer_add(&voodoo->wake_timer, voodoo_wake_timer, (void *)voodoo, 0); for (c = 0; c < 0x100; c++) { diff --git a/src/video/vid_wy700.c b/src/video/vid_wy700.c index c13fd4f78..b490dc4a6 100644 --- a/src/video/vid_wy700.c +++ b/src/video/vid_wy700.c @@ -23,9 +23,9 @@ #include #include "../86box.h" #include "../io.h" +#include "../timer.h" #include "../pit.h" #include "../mem.h" -#include "../timer.h" #include "../device.h" #include "video.h" #include "vid_wy700.h" @@ -212,13 +212,13 @@ typedef struct wy700_t int enabled; /* Display enabled, 0 or 1 */ int detach; /* Detach cursor, 0 or 1 */ - int64_t dispontime, dispofftime; - int64_t vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int linepos, displine; int vc; int dispon, blink; - int64_t vsynctime; + int vsynctime; uint8_t *vram; } wy700_t; @@ -514,8 +514,8 @@ void wy700_recalctimings(wy700_t *wy700) _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; - wy700->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); - wy700->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); + wy700->dispontime = (uint64_t)(_dispontime); + wy700->dispofftime = (uint64_t)(_dispofftime); } @@ -578,7 +578,7 @@ void wy700_textline(wy700_t *wy700) if (sc == 14 && mda && ((attr & 7) == 1)) { for (c = 0; c < cw; c++) - buffer->line[wy700->displine][(x * cw) + c] = + buffer32->line[wy700->displine][(x * cw) + c] = mdacols[attr][blink][1]; } else /* Draw 16 pixels of character */ @@ -595,16 +595,16 @@ void wy700_textline(wy700_t *wy700) col = mdacols[0][0][0]; if (w == 40) { - buffer->line[wy700->displine][(x * cw) + 2*c] = col; - buffer->line[wy700->displine][(x * cw) + 2*c + 1] = col; + buffer32->line[wy700->displine][(x * cw) + 2*c] = col; + buffer32->line[wy700->displine][(x * cw) + 2*c + 1] = col; } - else buffer->line[wy700->displine][(x * cw) + c] = col; + else buffer32->line[wy700->displine][(x * cw) + c] = col; } if (drawcursor) { for (c = 0; c < cw; c++) - buffer->line[wy700->displine][(x * cw) + c] ^= (mda ? mdacols : cgacols)[attr][0][1]; + buffer32->line[wy700->displine][(x * cw) + c] ^= (mda ? mdacols : cgacols)[attr][0][1]; } ++ma; } @@ -642,8 +642,8 @@ void wy700_cgaline(wy700_t *wy700) ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) ink = 16; - buffer->line[wy700->displine][x*64 + 2*c] = - buffer->line[wy700->displine][x*64 + 2*c+1] = + buffer32->line[wy700->displine][x*64 + 2*c] = + buffer32->line[wy700->displine][x*64 + 2*c+1] = ink; dat = dat << 1; } @@ -661,10 +661,10 @@ void wy700_cgaline(wy700_t *wy700) } if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) ink = 16; - buffer->line[wy700->displine][x*64 + 4*c] = - buffer->line[wy700->displine][x*64 + 4*c+1] = - buffer->line[wy700->displine][x*64 + 4*c+2] = - buffer->line[wy700->displine][x*64 + 4*c+3] = + buffer32->line[wy700->displine][x*64 + 4*c] = + buffer32->line[wy700->displine][x*64 + 4*c+1] = + buffer32->line[wy700->displine][x*64 + 4*c+2] = + buffer32->line[wy700->displine][x*64 + 4*c+3] = ink; dat = dat << 2; } @@ -703,10 +703,10 @@ void wy700_medresline(wy700_t *wy700) } /* Display disabled? */ if (!(wy700->wy700_mode & 8)) ink = 16; - buffer->line[wy700->displine][x*64 + 4*c] = - buffer->line[wy700->displine][x*64 + 4*c+1] = - buffer->line[wy700->displine][x*64 + 4*c+2] = - buffer->line[wy700->displine][x*64 + 4*c+3] = + buffer32->line[wy700->displine][x*64 + 4*c] = + buffer32->line[wy700->displine][x*64 + 4*c+1] = + buffer32->line[wy700->displine][x*64 + 4*c+2] = + buffer32->line[wy700->displine][x*64 + 4*c+3] = ink; dat = dat << 2; } @@ -718,8 +718,8 @@ void wy700_medresline(wy700_t *wy700) ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; /* Display disabled? */ if (!(wy700->wy700_mode & 8)) ink = 16; - buffer->line[wy700->displine][x*64 + 2*c] = - buffer->line[wy700->displine][x*64 + 2*c+1] = + buffer32->line[wy700->displine][x*64 + 2*c] = + buffer32->line[wy700->displine][x*64 + 2*c+1] = ink; dat = dat << 1; } @@ -765,8 +765,8 @@ void wy700_hiresline(wy700_t *wy700) } /* Display disabled? */ if (!(wy700->wy700_mode & 8)) ink = 16; - buffer->line[wy700->displine][x*32 + 2*c] = - buffer->line[wy700->displine][x*32 + 2*c+1] = + buffer32->line[wy700->displine][x*32 + 2*c] = + buffer32->line[wy700->displine][x*32 + 2*c+1] = ink; dat = dat << 2; } @@ -778,7 +778,7 @@ void wy700_hiresline(wy700_t *wy700) ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; /* Display disabled? */ if (!(wy700->wy700_mode & 8)) ink = 16; - buffer->line[wy700->displine][x*32 + c] = ink; + buffer32->line[wy700->displine][x*32 + c] = ink; dat = dat << 1; } } @@ -795,7 +795,7 @@ void wy700_poll(void *p) if (!wy700->linepos) { - wy700->vidtime += wy700->dispofftime; + timer_advance_u64(&wy700->timer, wy700->dispofftime); wy700->cga_stat |= 1; wy700->mda_stat |= 1; wy700->linepos = 1; @@ -856,7 +856,7 @@ void wy700_poll(void *p) wy700->cga_stat &= ~1; wy700->mda_stat &= ~1; } - wy700->vidtime += wy700->dispontime; + timer_advance_u64(&wy700->timer, wy700->dispontime); wy700->linepos = 0; if (wy700->displine == 800) @@ -911,7 +911,7 @@ void *wy700_init(const device_t *info) loadfont(L"roms/video/wyse700/wy700.rom", 3); - timer_add(wy700_poll, &wy700->vidtime, TIMER_ALWAYS_ENABLED, wy700); + timer_add(&wy700->timer, wy700_poll, wy700, 1); /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in * high-resolution modes) */ diff --git a/src/video/video.c b/src/video/video.c index ba5cb4ebf..aeb4cf7c1 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -66,13 +66,12 @@ #include "vid_svga.h" -bitmap_t *screen = NULL, - *buffer = NULL, - *buffer32 = NULL; +bitmap_t *buffer32 = NULL; uint8_t fontdat[2048][8]; /* IBM CGA font */ uint8_t fontdatm[2048][16]; /* IBM MDA font */ uint8_t fontdatw[512][32]; /* Wyse700 font */ uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ +uint8_t fontdat12x18[256][36]; /* IM1024 font */ dbcs_font_t *fontdatksc5601 = NULL; /* Korean KSC-5601 font */ dbcs_font_t *fontdatksc5601_user = NULL; /* Korean KSC-5601 user defined font */ uint32_t pal_lookup[256]; @@ -325,7 +324,7 @@ video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) } -uint8_t pixels8(uint8_t *pixels) +uint8_t pixels8(uint32_t *pixels) { int i; uint8_t temp = 0; @@ -367,14 +366,14 @@ video_blend(int x, int y) if (!x) carry = 0; - val1 = pixels8(&(buffer->line[y][x])); + val1 = pixels8(&(buffer32->line[y][x])); val2 = (val1 >> 1) + carry; carry = (val1 & 1) << 7; pixels32_1 = cga_2_table[val1 >> 4] + cga_2_table[val2 >> 4]; pixels32_2 = cga_2_table[val1 & 0xf] + cga_2_table[val2 & 0xf]; for (xx = 0; xx < 4; xx++) { - buffer->line[y][x + xx] = pixel_to_color((uint8_t *) &pixels32_1, xx); - buffer->line[y][x + (xx | 4)] = pixel_to_color((uint8_t *) &pixels32_2, xx); + buffer32->line[y][x + xx] = pixel_to_color((uint8_t *) &pixels32_1, xx); + buffer32->line[y][x + (xx | 4)] = pixel_to_color((uint8_t *) &pixels32_2, xx); } } @@ -388,10 +387,14 @@ video_blit_memtoscreen_8(int x, int y, int y1, int y2, int w, int h) for (yy = 0; yy < h; yy++) { - if ((y + yy) >= 0 && (y + yy) < buffer->h) + if ((y + yy) >= 0 && (y + yy) < buffer32->h) { - for (xx = 0; xx < w; xx++) - *(uint32_t *) &(buffer32->line[y + yy][(x + xx) << 2]) = pal_lookup[buffer->line[y + yy][x + xx]]; + for (xx = 0; xx < w; xx++) { + if (buffer32->line[y + yy][x + xx] <= 0xff) + buffer32->line[y + yy][x + xx] = pal_lookup[buffer32->line[y + yy][x + xx]]; + else + buffer32->line[y + yy][x + xx] = 0x00000000; + } } } @@ -557,13 +560,13 @@ calc_16to32(int c) void hline(bitmap_t *b, int x1, int y, int x2, uint32_t col) { - if (y < 0 || y >= buffer->h) + int x; + + if (y < 0 || y >= buffer32->h) return; - if (b == buffer) - memset(&b->line[y][x1], col, x2 - x1); - else - memset(&((uint32_t *)b->line[y])[x1], col, (x2 - x1) * 4); + for (x = x1; x < x2; x++) + b->line[y][x] = col; } @@ -603,12 +606,12 @@ destroy_bitmap(bitmap_t *b) bitmap_t * create_bitmap(int x, int y) { - bitmap_t *b = malloc(sizeof(bitmap_t) + (y * sizeof(uint8_t *))); + bitmap_t *b = malloc(sizeof(bitmap_t) + (y * sizeof(uint32_t *))); int c; b->dat = malloc(x * y * 4); for (c = 0; c < y; c++) - b->line[c] = b->dat + (c * x * 4); + b->line[c] = &(b->dat[c * x]); b->w = x; b->h = y; @@ -630,7 +633,6 @@ video_init(void) /* Account for overscan. */ buffer32 = create_bitmap(2048, 2048); - buffer = create_bitmap(2048, 2048); for (c = 0; c < 64; c++) { cgapal[c + 64].r = (((c & 4) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; cgapal[c + 64].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; @@ -699,7 +701,6 @@ video_close(void) free(video_15to32); free(video_16to32); - destroy_bitmap(buffer); destroy_bitmap(buffer32); if (fontdatksc5601) { @@ -753,17 +754,14 @@ loadfont(wchar_t *s, int format) break; case 1: /* PC200 */ - for (c=0; c<256; c++) - for (d=0; d<8; d++) - fontdatm[c][d] = fgetc(f); - for (c=0; c<256; c++) - for (d=0; d<8; d++) - fontdatm[c][d+8] = fgetc(f); - (void)fseek(f, 4096, SEEK_SET); - for (c=0; c<256; c++) { - for (d=0; d<8; d++) - fontdat[c][d] = fgetc(f); - for (d=0; d<8; d++) (void)fgetc(f); + for (d = 0; d < 4; d++) { + /* There are 4 fonts in the ROM */ + for (c = 0; c < 256; c++) /* 8x14 MDA in 8x16 cell */ + fread(&fontdatm[256*d + c][0], 1, 16, f); + for (c = 0; c < 256; c++) { /* 8x8 CGA in 8x16 cell */ + fread(&fontdat[256*d + c][0], 1, 8, f); + fseek(f, 8, SEEK_CUR); + } } break; @@ -841,6 +839,17 @@ loadfont(wchar_t *s, int format) for (c = 0; c < 256; c++) fread(&fontdatm[c][0], 1, 16, f); break; + + case 8: /* Amstrad PC1512 */ + for (c = 0; c < 2048; c++) /* Allow up to 2048 chars */ + for (d=0; d<8; d++) + fontdat[c][d] = fgetc(f); + break; + + case 9: /* Image Manager 1024 native font */ + for (c = 0; c < 256; c++) + fread(&fontdat12x18[c][0], 1, 36, f); + break; } (void)fclose(f); diff --git a/src/video/video.h b/src/video/video.h index e42c122cc..3d66bf58e 100644 --- a/src/video/video.h +++ b/src/video/video.h @@ -34,9 +34,8 @@ enum { enum { FULLSCR_SCALE_FULL = 0, FULLSCR_SCALE_43, - FULLSCR_SCALE_SQ, - FULLSCR_SCALE_INT, - FULLSCR_SCALE_KEEPRATIO + FULLSCR_SCALE_KEEPRATIO, + FULLSCR_SCALE_INT }; @@ -54,6 +53,7 @@ enum { #define VIDEO_FLAG_TYPE_CGA 0 #define VIDEO_FLAG_TYPE_MDA 1 #define VIDEO_FLAG_TYPE_SPECIAL 2 +#define VIDEO_FLAG_TYPE_NONE 3 #define VIDEO_FLAG_TYPE_MASK 3 typedef struct { @@ -64,8 +64,8 @@ typedef struct { typedef struct { int w, h; - uint8_t *dat; - uint8_t *line[2048]; + uint32_t *dat; + uint32_t *line[2048]; } bitmap_t; typedef struct { @@ -83,9 +83,7 @@ extern int egareads, egawrites; extern int changeframecount; -extern bitmap_t *screen, - *buffer, - *buffer32; +extern bitmap_t *buffer32; extern PALETTE cgapal, cgapal_mono[6]; extern uint32_t pal_lookup[256]; @@ -95,6 +93,9 @@ extern int video_fullscreen, extern int fullchange; extern uint8_t fontdat[2048][8]; extern uint8_t fontdatm[2048][16]; +extern uint8_t fontdatw[512][32]; +extern uint8_t fontdat8x12[256][16]; +extern uint8_t fontdat12x18[256][36]; extern dbcs_font_t *fontdatksc5601; extern dbcs_font_t *fontdatksc5601_user; extern uint32_t *video_6to8, @@ -121,7 +122,7 @@ extern int vid_cga_contrast; extern int video_grayscale; extern int video_graytype; -extern float cpuclock; +extern double cpuclock; extern int emu_fps, frames; extern int readflash; @@ -164,6 +165,7 @@ extern void updatewindowsize(int x, int y); extern void video_init(void); extern void video_close(void); +extern void video_reset_close(void); extern void video_reset(int card); extern uint8_t video_force_resize_get(void); extern void video_force_resize_set(uint8_t res); diff --git a/src/vnc.c b/src/vnc.c index 9b28438fe..4f895cc60 100644 --- a/src/vnc.c +++ b/src/vnc.c @@ -177,9 +177,9 @@ vnc_blit(int x, int y, int y1, int y2, int w, int h) if ((y+yy) >= 0 && (y+yy) < VNC_MAX_Y) { if (video_grayscale || invert_display) - video_transform_copy(p, &(((uint32_t *)buffer32->line[y+yy])[x]), w); + video_transform_copy(p, &(buffer32->line[y+yy][x]), w); else - memcpy(p, &(((uint32_t *)buffer32->line[y+yy])[x]), w*4); + memcpy(p, &(buffer32->line[y+yy][x]), w*4); } } diff --git a/src/vnc_keymap.c b/src/vnc_keymap.c index 20a9126aa..d8b453066 100644 --- a/src/vnc_keymap.c +++ b/src/vnc_keymap.c @@ -22,12 +22,12 @@ * NOTE: The values are as defined in the Microsoft document named * "Keyboard Scan Code Specification", version 1.3a of 2000/03/16. * - * Version: @(#)vnc_keymap.c 1.0.3 2018/04/29 + * Version: @(#)vnc_keymap.c 1.0.4 2019/03/24 * * Authors: Fred N. van Kempen, * Based on raw code by RichardG, * - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -668,5 +668,30 @@ vnc_kbinput(int down, int k) } /* Send this scancode sequence to the PC keyboard. */ - keyboard_input(down, scan); + switch (scan >> 8) { + case 0x00: + default: + if (scan & 0xff) + keyboard_input(down, scan & 0xff); + break; + case 0x2a: + if (scan & 0xff) { + if (down) { + keyboard_input(down, 0x2a); + keyboard_input(down, scan & 0xff); + } else { + keyboard_input(down, scan & 0xff); + keyboard_input(down, 0x2a); + } + } + break; + case 0xe0: + if (scan & 0xff) + keyboard_input(down, (scan & 0xff) | 0x100); + break; + case 0xe1: + if (scan == 0x1d) + keyboard_input(down, 0x100); + break; + } } diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 5dfe8edc5..f595ec879 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -88,11 +88,10 @@ BEGIN MENUITEM "&Fullscreen\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN POPUP "Fullscreen &stretch mode" BEGIN - MENUITEM "&Full screen stretch", IDM_VID_FS_FULL - MENUITEM "&4:3", IDM_VID_FS_43 - MENUITEM "&Square pixels", IDM_VID_FS_SQ - MENUITEM "&Integer scale", IDM_VID_FS_INT - MENUITEM "&Keep size", IDM_VID_FS_KEEPRATIO + MENUITEM "&Full screen stretch", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Square pixels (Keep ratio)", IDM_VID_FS_KEEPRATIO + MENUITEM "&Integer scale", IDM_VID_FS_INT END POPUP "E&GA/(S)VGA settings" BEGIN @@ -409,7 +408,7 @@ BEGIN PUSHBUTTON "Configure",IDC_CONFIGURE_NET,214,43,46,12 END -DLG_CFG_PORTS DIALOG DISCARDABLE 97, 0, 267, 99 +DLG_CFG_PORTS DIALOG DISCARDABLE 97, 0, 267, 117 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -430,8 +429,12 @@ BEGIN CONTROL "Serial port 2",IDC_CHECK_SERIAL2,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,147,64,94,10 - CONTROL "Parallel port",IDC_CHECK_PARALLEL,"Button", + CONTROL "Parallel port 1",IDC_CHECK_PARALLEL1,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,82,94,10 + CONTROL "Parallel port 2",IDC_CHECK_PARALLEL2,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,82,94,10 + CONTROL "Parallel port 3",IDC_CHECK_PARALLEL3,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,100,94,10 END DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 97, 0, 267, 200 @@ -931,10 +934,12 @@ BEGIN IDS_5376 "Disabled" IDS_5380 "ATAPI" IDS_5381 "SCSI" + IDS_5382 "SCSI (Chinon)" IDS_5632 "Disabled" IDS_5636 "ATAPI (%01i:%01i)" IDS_5637 "SCSI (ID %02i)" + IDS_5638 "SCSI (ID %02i)" IDS_5888 "160 kB" IDS_5889 "180 kB" @@ -982,7 +987,7 @@ VS_VERSION_INFO VERSIONINFO BEGIN BLOCK "StringFileInfo" BEGIN - BLOCK "0409fde9" + BLOCK "040904b0" BEGIN VALUE "Comments", "\0" VALUE "CompanyName", "IRC #SoftHistory\0" diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 53251dce4..0ce65f2ce 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.136 2019/01/13 +# Version: @(#)Makefile.mingw 1.0.137 2019/03/03 # # Authors: Miran Grca, # Fred N. van Kempen, @@ -53,6 +53,9 @@ ifeq ($(DEV_BUILD), y) ifndef LASERXT LASERXT := y endif + ifndef MR495 + MR495 := y + endif ifndef MRTHOR MRTHOR := y endif @@ -62,9 +65,24 @@ ifeq ($(DEV_BUILD), y) ifndef PORTABLE3 PORTABLE3 := y endif + ifndef PS1M2133 + PS1M2133 := y + endif ifndef PS2M70T4 PS2M70T4 := y endif + ifndef RIVA128 + RIVA128 := y + endif + ifndef TC430HX + TC430HX := y + endif + ifndef VECTRA54 + VECTRA54 := y + endif + ifndef VGAWONDER + VGAWONDER := y + endif ifndef VNC VNC := y endif @@ -93,6 +111,9 @@ else ifndef LASERXT LASERXT := n endif + ifndef MR495 + MR495 := n + endif ifndef MRTHOR MRTHOR := n endif @@ -102,9 +123,21 @@ else ifndef PORTABLE3 PORTABLE3 := n endif + ifndef PS1M2133 + PS1M2133 := n + endif ifndef PS2M70T4 PS2M70T4 := n endif + ifndef RIVA128 + RIVA128 := n + endif + ifndef TC430HX + TC430HX := n + endif + ifndef VECTRA54 + VECTRA54 := n + endif ifndef VGAWONDER VGAWONDER := n endif @@ -145,10 +178,7 @@ ifndef RDP RDP := n endif ifndef DINPUT - DINPUT := y - ifeq ($(ARM), y) - DINPUT := n - endif + DINPUT := n endif ifndef D3DX D3DX := y @@ -225,7 +255,7 @@ endif # Nothing should need changing from here on.. # ######################################################################### VPATH := $(EXPATH) . cpu \ - cdrom disk floppy game machine \ + cdrom chipset disk floppy game machine \ printer \ sound \ sound/munt sound/munt/c_interface sound/munt/sha1 \ @@ -240,7 +270,7 @@ endif CPP := ${TOOL_PREFIX}g++ CC := ${TOOL_PREFIX}gcc WINDRES := windres -STRIP := strip +STRIP := strip ifeq ($(ARM64), y) CPP := aarch64-w64-mingw32-g++ CC := aarch64-w64-mingw32-gcc @@ -316,19 +346,16 @@ ifeq ($(VRAMDUMP), y) OPTS += -DENABLE_VRAM_DUMP RFLAGS += -DENABLE_VRAM_DUMP endif -ifeq ($(X64), y) -PLATCG := codegen_x86-64.o -CGOPS := codegen_ops_x86-64.h -VCG := vid_voodoo_codegen_x86-64.h -else -PLATCG := codegen_x86.o -CGOPS := codegen_ops_x86.h -VCG := vid_voodoo_codegen_x86.h -endif # Optional modules. ifeq ($(DYNAREC), y) +ifeq ($(X64), y) +PLATCG := codegen_x86-64.o +else +PLATCG := codegen_x86.o +endif + OPTS += -DUSE_DYNAREC RFLAGS += -DUSE_DYNAREC DYNARECOBJ := 386_dynarec_ops.o \ @@ -422,6 +449,7 @@ endif ifeq ($(I686), y) OPTS += -DUSE_I686 +DEVBROBJ += m_at_socket8.o endif ifeq ($(LASERXT), y) @@ -429,6 +457,10 @@ OPTS += -DUSE_LASERXT DEVBROBJ += m_xt_laserxt.o endif +ifeq ($(MR495), y) +OPTS += -DUSE_MR495 +endif + ifeq ($(MRTHOR), y) OPTS += -DUSE_MRTHOR endif @@ -442,10 +474,27 @@ ifeq ($(PORTABLE3), y) OPTS += -DUSE_PORTABLE3 endif +ifeq ($(PS1M2133), y) +OPTS += -DUSE_PS1M2133 +endif + ifeq ($(PS2M70T4), y) OPTS += -DUSE_PS2M70T4 endif +ifeq ($(RIVA128), y) +OPTS += -DUSE_RIVA128 +DEVBROBJ += vid_riva128.o +endif + +ifeq ($(TC430HX), y) +OPTS += -DUSE_TC430HX +endif + +ifeq ($(VECTRA54), y) +OPTS += -DUSE_VECTRA54 +endif + ifeq ($(VGAWONDER), y) OPTS += -DUSE_VGAWONDER endif @@ -477,42 +526,45 @@ CXXFLAGS := $(CFLAGS) ######################################################################### # Create the (final) list of objects to build. # ######################################################################### -MAINOBJ := pc.o config.o random.o timer.o io.o dma.o nmi.o pic.o \ - pit.o ppi.o pci.o mca.o mcr.o mem.o memregs.o rom.o \ - device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ) +MAINOBJ := pc.o config.o random.o timer.o io.o apm.o dma.o nmi.o \ + pic.o pit.o port_92.o ppi.o pci.o mca.o mcr.o mem.o \ + rom.o device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ) -INTELOBJ := intel.o \ - intel_flash.o \ +INTELOBJ := intel_flash.o \ intel_sio.o intel_piix.o CPUOBJ := cpu.o cpu_table.o \ - 808x.o 386.o 386_dynarec.o \ + 808x.o 386.o \ + 386_dynarec.o \ x86seg.o x87.o \ $(DYNARECOBJ) +CHIPSETOBJ := acc2168.o acer_m3a.o ali1429.o headland.o \ + intel_4x0.o neat.o opti495.o scat.o \ + sis_85c471.o sis_85c496.o \ + wd76c10.o + MCHOBJ := machine.o machine_table.o \ m_xt.o m_xt_compaq.o \ m_xt_t1000.o m_xt_t1000_vid.o \ - m_xt_xi8088.o \ - m_xt_zenith.o \ + m_xt_xi8088.o m_xt_zenith.o \ m_pcjr.o \ - m_amstrad.o \ - m_europc.o \ + m_amstrad.o m_europc.o \ m_olivetti_m24.o m_tandy.o \ - m_at.o \ - m_at_ali1429.o m_at_commodore.o \ - m_at_neat.o m_at_headland.o \ + m_at.o m_at_commodore.o \ m_at_t3100e.o m_at_t3100e_vid.o \ m_ps1.o m_ps1_hdc.o \ m_ps2_isa.o m_ps2_mca.o \ - m_at_opti495.o m_at_scat.o \ - m_at_compaq.o m_at_wd76c10.o \ - m_at_sis_85c471.o m_at_sis_85c496.o \ - m_at_4x0.o + m_at_compaq.o \ + m_at_286_386sx.o m_at_386dx_486.o \ + m_at_socket4_5.o m_at_socket7_s7.o -DEVOBJ := bugger.o isamem.o isartc.o lpt.o $(SERIAL) \ - sio_fdc37c66x.o sio_fdc37c669.o sio_fdc37c93x.o \ - sio_pc87306.o sio_w83877f.o sio_um8669f.o \ +DEVOBJ := bugger.o ibm_5161.o isamem.o isartc.o lpt.o $(SERIAL) \ + sio_acc3221.o \ + sio_fdc37c66x.o sio_fdc37c669.o \ + sio_fdc37c93x.o \ + sio_pc87306.o sio_w83877f.o \ + sio_um8669f.o \ keyboard.o \ keyboard_xt.o keyboard_at.o \ gameport.o \ @@ -530,11 +582,12 @@ FDDOBJ := fdd.o fdc.o fdi2raw.o \ HDDOBJ := hdd.o \ hdd_image.o hdd_table.o \ hdc.o \ - hdc_mfm_xt.o hdc_mfm_at.o \ + hdc_st506_xt.o hdc_st506_at.o \ hdc_xta.o \ hdc_esdi_at.o hdc_esdi_mca.o \ - hdc_xtide.o hdc_ide.o - + hdc_xtide.o hdc_ide.o \ + hdc_ide_sff8038i.o + CDROMOBJ := cdrom.o \ cdrom_dosbox.o cdrom_image.o @@ -594,6 +647,7 @@ VIDOBJ := video.o \ vid_hercules.o vid_herculesplus.o vid_incolor.o \ vid_colorplus.o \ vid_genius.o \ + vid_pgc.o vid_im1024.o \ vid_sigma.o \ vid_wy700.o \ vid_ega.o vid_ega_render.o \ @@ -608,6 +662,7 @@ VIDOBJ := video.o \ vid_cl54xx.o \ vid_et4000.o vid_sc1502x_ramdac.o \ vid_et4000w32.o vid_stg_ramdac.o \ + vid_ht216.o \ vid_oak_oti.o \ vid_paradise.o \ vid_ti_cf62011.o \ @@ -628,8 +683,8 @@ else PLATOBJ += win_mouse_rawinput.o win_joystick_xinput.o endif -OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(MCHOBJ) $(DEVOBJ) \ - $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ +OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(CHIPSETOBJ) $(MCHOBJ) \ + $(DEVOBJ) $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ $(USBOBJ) $(NETOBJ) $(PRINTOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) \ $(PLATOBJ) $(UIOBJ) $(D2DOBJ) $(FSYNTHOBJ) $(MUNTOBJ) \ $(DEVBROBJ) @@ -639,12 +694,12 @@ endif LIBS := -mwindows \ -lddraw -ldxguid -ld3d9 \ - -lcomctl32 -lwinmm + -lcomctl32 ifeq ($(STATIC), y) -LIBS += -lopenal -lole32 +LIBS += -lopenal -lole32 -lwinmm else -LIBS += -lopenal.dll +LIBS += -lwinmm -lopenal.dll endif ifeq ($(D2D), y) diff --git a/src/win/Makefile_ndr.mingw b/src/win/Makefile_ndr.mingw new file mode 100644 index 000000000..81c4c9e7b --- /dev/null +++ b/src/win/Makefile_ndr.mingw @@ -0,0 +1,848 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# Makefile for Win32 (MinGW32) environment. +# +# Version: @(#)Makefile.mingw 1.0.137 2019/03/03 +# +# Authors: Miran Grca, +# Fred N. van Kempen, +# + +# Various compile-time options. +ifndef STUFF +STUFF := +endif + +# Add feature selections here. +ifndef EXTRAS +EXTRAS := +endif + +ifndef DEV_BUILD +DEV_BUILD := n +endif +ifndef FLTO +FLTO := full +endif + +ifeq ($(DEV_BUILD), y) + ifndef DEBUG + DEBUG := y + endif + ifndef DEV_BRANCH + DEV_BRANCH := y + endif + ifndef AMD_K + AMD_K := y + endif + ifndef CRASHDUMP + CRASHDUMP := y + endif + ifndef D2D + D2D := y + endif + ifndef I686 + I686 := y + endif + ifndef LASERXT + LASERXT := y + endif + ifndef MR495 + MR495 := y + endif + ifndef MRTHOR + MRTHOR := y + endif + ifndef PAS16 + PAS16 := y + endif + ifndef PORTABLE3 + PORTABLE3 := y + endif + ifndef PS1M2133 + PS1M2133 := y + endif + ifndef PS2M70T4 + PS2M70T4 := y + endif + ifndef RIVA128 + RIVA128 := y + endif + ifndef TC430HX + TC430HX := y + endif + ifndef VECTRA54 + VECTRA54 := y + endif + ifndef VGAWONDER + VGAWONDER := y + endif + ifndef VNC + VNC := y + endif + ifndef XL24 + XL24 := y + endif +else + ifndef DEBUG + DEBUG := n + endif + ifndef DEV_BRANCH + DEV_BRANCH := n + endif + ifndef AMD_K + AMD_K := n + endif + ifndef CRASHDUMP + CRASHDUMP := n + endif + ifndef D2D + D2D := n + endif + ifndef I686 + I686 := n + endif + ifndef LASERXT + LASERXT := n + endif + ifndef MR495 + MR495 := n + endif + ifndef MRTHOR + MRTHOR := n + endif + ifndef PAS16 + PAS16 := n + endif + ifndef PORTABLE3 + PORTABLE3 := n + endif + ifndef PS1M2133 + PS1M2133 := n + endif + ifndef PS2M70T4 + PS2M70T4 := n + endif + ifndef RIVA128 + RIVA128 := n + endif + ifndef TC430HX + TC430HX := n + endif + ifndef VECTRA54 + VECTRA54 := n + endif + ifndef VGAWONDER + VGAWONDER := n + endif + ifndef VNC + VNC := n + endif + ifndef XL24 + XL24 := n + endif +endif + +# Defaults for several build options (possibly defined in a chained file.) +ifndef AUTODEP +AUTODEP := n +endif +ifndef OPTIM +OPTIM := n +endif +ifndef RELEASE +RELEASE := n +endif +ifndef X64 +X64 := n +endif +ifndef ARM +ARM := n +endif +ifndef ARM64 +ARM64 := n +endif +ifndef WX +WX := n +endif +ifndef USB +USB := n +endif +ifndef RDP +RDP := n +endif +ifndef DINPUT + DINPUT := n +endif +ifndef D3DX + D3DX := y + ifeq ($(ARM), y) + D3DX := n + endif + ifeq ($(ARM64), y) + D3DX := n + endif +endif +ifndef OPENAL +OPENAL := y +endif +ifndef FLUIDSYNTH +FLUIDSYNTH := y +endif +ifndef MUNT +MUNT := y +endif +ifndef DYNAREC + DYNAREC := y + ifeq ($(ARM), y) + DYNAREC := n + endif + ifeq ($(ARM64), y) + DYNAREC := n + endif +endif + + +# Name of the executable. +ifndef PROG + ifneq ($(WX), n) + PROG := Wx86Box + else + PROG := 86Box + endif +endif + +# WxWidgets basic info. Extract using the config program. +ifneq ($(WX), n) + EXPATH += wx + WX_CONFIG := wx-config.exe + ifeq ($(WX), y) + WX_PATH := C:/MinGW32/WxWidgets + WX_FLAGS := -I$(WX_PATH)/lib/wx/include/msw-unicode-3.0 \ + -I$(WX_PATH)/include/wx-3.0 \ + -D__WXMSW__ -DWX_PRECOMP -D_FILE_OFFSET_BITS=64 -pthread +# -lwx_mswu_gl-3.0 -lwxtiff-3.0 -llzma + WX_LIBS := -mwindows -mthreads -L$(WX_PATH)/lib \ + -lwx_mswu-3.0.dll \ + -lrpcrt4 -loleaut32 -lole32 -luuid \ + -lwinspool -lwinmm -lshell32 -lcomctl32 \ + -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 + endif + ifeq ($(WX), static) + WX_PATH := C:/MinGW32/WxWidgets + WX_FLAGS := -I$(WX_PATH)/lib/wx/include/msw-unicode-3.0 \ + -I$(WX_PATH)/include/wx-3.0 \ + -D__WXMSW__ -DWX_PRECOMP -D_FILE_OFFSET_BITS=64 -pthread +# -lwx_mswu_gl-3.0 -lwxtiff-3.0 -llzma + WX_LIBS := -mwindows -mthreads -L$(WX_PATH)/lib \ + -lwx_mswu-3.0 -lwxscintilla-3.0 \ + -lwxjpeg-3.0 -lwxpng-3.0 -lwxzlib-3.0 \ + -lwxregexu-3.0 -lwxexpat-3.0 \ + -lrpcrt4 -loleaut32 -lole32 -luuid \ + -lwinspool -lwinmm -lshell32 -lcomctl32 \ + -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 + endif +endif + + +######################################################################### +# Nothing should need changing from here on.. # +######################################################################### +VPATH := $(EXPATH) . cpu_new \ + cdrom chipset disk floppy game machine \ + printer \ + sound \ + sound/munt sound/munt/c_interface sound/munt/sha1 \ + sound/munt/srchelper \ + sound/resid-fp \ + scsi video network network/slirp win +ifeq ($(X64), y) +TOOL_PREFIX := x86_64-w64-mingw32- +else +TOOL_PREFIX := i686-w64-mingw32- +endif +CPP := ${TOOL_PREFIX}g++ +CC := ${TOOL_PREFIX}gcc +WINDRES := windres +STRIP := strip +ifeq ($(ARM64), y) +CPP := aarch64-w64-mingw32-g++ +CC := aarch64-w64-mingw32-gcc +WINDRES := aarch64-w64-mingw32-windres +STRIP := aarch64-w64-mingw32-strip +endif +ifeq ($(ARM), y) +CPP := armv7-w64-mingw32-g++ +CC := armv7-w64-mingw32-gcc +WINDRES := armv7-w64-mingw32-windres +STRIP := armv7-w64-mingw32-strip +endif +DEPS = -MMD -MF $*.d -c $< +DEPFILE := win/.depends + +# Set up the correct toolchain flags. +OPTS := $(EXTRAS) $(STUFF) +ifdef EXFLAGS +OPTS += $(EXFLAGS) +endif +ifdef EXINC +OPTS += -I$(EXINC) +endif +ifeq ($(X64), y) + ifeq ($(OPTIM), y) + DFLAGS := -march=native + else + DFLAGS := + endif +else + ifeq ($(OPTIM), y) + DFLAGS := -march=native + else + DFLAGS := -march=i686 + endif +endif +ifeq ($(DEBUG), y) + DFLAGS += -ggdb -DDEBUG + AOPTIM := + ifndef COPTIM + COPTIM := -Og + endif +else + DFLAGS += -g0 + ifeq ($(OPTIM), y) + AOPTIM := -mtune=native + ifndef COPTIM + COPTIM := -O3 -flto=$(FLTO) + endif + else + ifndef COPTIM + COPTIM := -O3 + endif + endif +endif +AFLAGS := -msse2 -mfpmath=sse +ifeq ($(ARM), y) + DFLAGS := -march=armv7-a + AOPTIM := + AFLAGS := -mfloat-abi=hard +endif +ifeq ($(ARM64), y) + DFLAGS := -march=armv8-a + AOPTIM := + AFLAGS := -mfloat-abi=hard +endif +RFLAGS := --input-format=rc -O coff +OPTS += -DUSE_NEW_DYNAREC +ifeq ($(RELEASE), y) +OPTS += -DRELEASE_BUILD +RFLAGS += -DRELEASE_BUILD +endif +ifeq ($(VRAMDUMP), y) +OPTS += -DENABLE_VRAM_DUMP +RFLAGS += -DENABLE_VRAM_DUMP +endif + + +# Optional modules. +ifeq ($(DYNAREC), y) +ifeq ($(X64), y) +PLATCG := codegen_backend_x86-64.o codegen_backend_x86-64_ops.o codegen_backend_x86-64_ops_sse.o \ + codegen_backend_x86-64_uops.o +else +PLATCG := codegen_backend_x86.o codegen_backend_x86_ops.o codegen_backend_x86_ops_fpu.o codegen_backend_x86_ops_sse.o \ + codegen_backend_x86_uops.o +endif + +OPTS += -DUSE_DYNAREC +RFLAGS += -DUSE_DYNAREC +DYNARECOBJ := 386_dynarec_ops.o \ + codegen.o codegen_accumulate.o codegen_allocator.o codegen_block.o codegen_ir.o codegen_ops.o \ + codegen_ops_3dnow.o codegen_ops_branch.o codegen_ops_arith.o codegen_ops_fpu_arith.o \ + codegen_ops_fpu_constant.o codegen_ops_fpu_loadstore.o codegen_ops_fpu_misc.o codegen_ops_helpers.o codegen_ops_jump.o \ + codegen_ops_logic.o codegen_ops_misc.o codegen_ops_mmx_arith.o codegen_ops_mmx_cmp.o \ + codegen_ops_mmx_loadstore.o codegen_ops_mmx_logic.o codegen_ops_mmx_pack.o codegen_ops_mmx_shift.o \ + codegen_ops_mov.o codegen_ops_shift.o codegen_ops_stack.o codegen_reg.o codegen_timing_486.o \ + codegen_timing_686.o codegen_timing_common.o codegen_timing_k6.o codegen_timing_pentium.o \ + codegen_timing_winchip.o codegen_timing_winchip2.o $(PLATCG) +endif + +ifneq ($(WX), n) + OPTS += -DUSE_WX $(WX_FLAGS) + LIBS += $(WX_LIBS) + UIOBJ := wx_main.o wx_ui.o wx_stbar.o wx_render.o +else + UIOBJ := win_ui.o win_stbar.o \ + win_ddraw.o win_d3d.o win_sdl.o \ + win_dialog.o win_about.o \ + win_settings.o win_devconf.o win_snd_gain.o \ + win_new_floppy.o win_jsconf.o +endif + +ifeq ($(OPENAL), y) +OPTS += -DUSE_OPENAL +endif +ifeq ($(FLUIDSYNTH), y) +OPTS += -DUSE_FLUIDSYNTH +FSYNTHOBJ := midi_fluidsynth.o +endif + +ifeq ($(MUNT), y) +OPTS += -DUSE_MUNT +MUNTOBJ := midi_mt32.o \ + Analog.o BReverbModel.o File.o FileStream.o LA32Ramp.o \ + LA32FloatWaveGenerator.o LA32WaveGenerator.o \ + MidiStreamParser.o Part.o Partial.o PartialManager.o \ + Poly.o ROMInfo.o SampleRateConverter_dummy.o Synth.o \ + Tables.o TVA.o TVF.o TVP.o sha1.o c_interface.o +endif + +ifeq ($(D2D), y) +OPTS += -DUSE_D2D +RFLAGS += -DUSE_D2D +D2DLIB := -ld2d1 +D2DOBJ := win_d2d.o +endif + +ifeq ($(VNC), y) +OPTS += -DUSE_VNC +RFLAGS += -DUSE_VNC + ifneq ($(VNC_PATH), ) + OPTS += -I$(VNC_PATH)\INCLUDE + VNCLIB := -L$(VNC_PATH)\LIB + endif +VNCLIB += -lvncserver +VNCOBJ := vnc.o vnc_keymap.o +endif + +ifeq ($(RDP), y) +OPTS += -DUSE_RDP +RFLAGS += -DUSE_RDP + ifneq ($(RDP_PATH), ) + OPTS += -I$(RDP_PATH)\INCLUDE + RDPLIB := -L$(RDP_PATH)\LIB + endif +RDPLIB += -lrdp +RDPOBJ := rdp.o +endif + +ifeq ($(DINPUT), y) +OPTS += -DUSE_DINPUT +endif + +ifeq ($(D3DX), y) +OPTS += -DUSE_D3DX +endif + +# Options for the DEV branch. +ifeq ($(DEV_BRANCH), y) +OPTS += -DDEV_BRANCH +DEVBROBJ := + +ifeq ($(AMD_K), y) +OPTS += -DUSE_AMD_K +endif + +ifeq ($(CRASHDUMPOBJ), y) +OPTS += -DUSE_CRASHDUMP +DEVBROBJ += win_crashdump.o +endif + +ifeq ($(I686), y) +OPTS += -DUSE_I686 +DEVBROBJ += m_at_socket8.o +endif + +ifeq ($(LASERXT), y) +OPTS += -DUSE_LASERXT +DEVBROBJ += m_xt_laserxt.o +endif + +ifeq ($(MR495), y) +OPTS += -DUSE_MR495 +endif + +ifeq ($(MRTHOR), y) +OPTS += -DUSE_MRTHOR +endif + +ifeq ($(PAS16), y) +OPTS += -DUSE_PAS16 +DEVBROBJ += snd_pas16.o +endif + +ifeq ($(PORTABLE3), y) +OPTS += -DUSE_PORTABLE3 +endif + +ifeq ($(PS1M2133), y) +OPTS += -DUSE_PS1M2133 +endif + +ifeq ($(PS2M70T4), y) +OPTS += -DUSE_PS2M70T4 +endif + +ifeq ($(RIVA128), y) +OPTS += -DUSE_RIVA128 +DEVBROBJ += vid_riva128.o +endif + +ifeq ($(TC430HX), y) +OPTS += -DUSE_TC430HX +endif + +ifeq ($(VECTRA54), y) +OPTS += -DUSE_VECTRA54 +endif + +ifeq ($(VGAWONDER), y) +OPTS += -DUSE_VGAWONDER +endif + +ifeq ($(XL24), y) +OPTS += -DUSE_XL24 +endif + +endif + + +# Options for works-in-progress. +ifndef SERIAL +SERIAL := serial.o +endif + + +# Final versions of the toolchain flags. +CFLAGS := $(WX_FLAGS) $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \ + $(AFLAGS) -fomit-frame-pointer -mstackrealign -Wall \ + -fno-strict-aliasing + +# Add freetyp2 references through pkgconfig +CFLAGS := $(CFLAGS) `pkg-config.exe --cflags freetype2` + +CXXFLAGS := $(CFLAGS) + + +######################################################################### +# Create the (final) list of objects to build. # +######################################################################### +MAINOBJ := pc.o config.o random.o timer.o io.o apm.o dma.o nmi.o \ + pic.o pit.o port_92.o ppi.o pci.o mca.o mcr.o mem_new.o \ + rom.o device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ) + +INTELOBJ := intel_flash.o \ + intel_sio.o intel_piix.o + +CPUOBJ := cpu.o cpu_table.o \ + 808x.o 386.o 386_common.o \ + 386_dynarec.o \ + x86seg.o x87.o \ + $(DYNARECOBJ) + +CHIPSETOBJ := acc2168.o acer_m3a.o ali1429.o headland.o \ + intel_4x0.o neat.o opti495.o scat.o \ + sis_85c471.o sis_85c496.o \ + wd76c10.o + +MCHOBJ := machine.o machine_table_new.o \ + m_xt.o m_xt_compaq.o \ + m_xt_t1000.o m_xt_t1000_vid.o \ + m_xt_xi8088.o m_xt_zenith.o \ + m_pcjr.o \ + m_amstrad.o m_europc.o \ + m_olivetti_m24.o m_tandy.o \ + m_at.o m_at_commodore.o \ + m_at_t3100e.o m_at_t3100e_vid.o \ + m_ps1.o m_ps1_hdc.o \ + m_ps2_isa.o m_ps2_mca.o \ + m_at_compaq.o \ + m_at_286_386sx.o m_at_386dx_486.o \ + m_at_socket4_5.o m_at_socket7_s7.o + +DEVOBJ := bugger.o ibm_5161.o isamem.o isartc.o lpt.o $(SERIAL) \ + sio_acc3221.o \ + sio_fdc37c66x.o sio_fdc37c669.o \ + sio_fdc37c93x.o \ + sio_pc87306.o sio_w83877f.o \ + sio_um8669f.o \ + keyboard.o \ + keyboard_xt.o keyboard_at.o \ + gameport.o \ + joystick_standard.o joystick_ch_flightstick_pro.o \ + joystick_sw_pad.o joystick_tm_fcs.o \ + mouse.o \ + mouse_bus.o \ + mouse_serial.o mouse_ps2.o + +FDDOBJ := fdd.o fdc.o fdi2raw.o \ + fdd_common.o fdd_86f.o \ + fdd_fdi.o fdd_imd.o fdd_img.o fdd_json.o \ + fdd_mfm.o fdd_td0.o + +HDDOBJ := hdd.o \ + hdd_image.o hdd_table.o \ + hdc.o \ + hdc_st506_xt.o hdc_st506_at.o \ + hdc_xta.o \ + hdc_esdi_at.o hdc_esdi_mca.o \ + hdc_xtide.o hdc_ide.o \ + hdc_ide_sff8038i.o + +CDROMOBJ := cdrom.o \ + cdrom_dosbox.o cdrom_image.o + +ZIPOBJ := zip.o + +ifeq ($(USB), y) +USBOBJ := usb.o +endif + +SCSIOBJ := scsi.o scsi_device.o \ + scsi_cdrom.o scsi_disk.o \ + scsi_x54x.o \ + scsi_aha154x.o scsi_buslogic.o \ + scsi_ncr5380.o scsi_ncr53c8xx.o + +NETOBJ := network.o \ + net_pcap.o \ + net_slirp.o \ + bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o \ + ip_input.o queue.o tcp_input.o debug.o ip_output.o \ + sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o \ + net_dp8390.o \ + net_3c503.o net_ne2000.o \ + net_wd8003.o + +PRINTOBJ := png.o prt_cpmap.o \ + prt_escp.o prt_text.o + +SNDOBJ := sound.o \ + openal.o \ + snd_opl.o snd_dbopl.o \ + dbopl.o nukedopl.o \ + snd_resid.o \ + convolve.o convolve-sse.o envelope.o extfilt.o \ + filter.o pot.o sid.o voice.o wave6581__ST.o \ + wave6581_P_T.o wave6581_PS_.o wave6581_PST.o \ + wave8580__ST.o wave8580_P_T.o wave8580_PS_.o \ + wave8580_PST.o wave.o \ + midi.o midi_system.o \ + snd_speaker.o \ + snd_pssj.o \ + snd_lpt_dac.o snd_lpt_dss.o \ + snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \ + snd_cms.o \ + snd_gus.o \ + snd_sb.o snd_sb_dsp.o \ + snd_emu8k.o snd_mpu401.o \ + snd_sn76489.o snd_ssi2001.o \ + snd_wss.o \ + snd_ym7128.o + +VIDOBJ := video.o \ + vid_table.o \ + vid_cga.o vid_cga_comp.o \ + vid_compaq_cga.o \ + vid_mda.o \ + vid_hercules.o vid_herculesplus.o vid_incolor.o \ + vid_colorplus.o \ + vid_genius.o \ + vid_pgc.o vid_im1024.o \ + vid_sigma.o \ + vid_wy700.o \ + vid_ega.o vid_ega_render.o \ + vid_svga.o vid_svga_render.o \ + vid_vga.o \ + vid_ati_eeprom.o \ + vid_ati18800.o vid_ati28800.o \ + vid_ati_mach64.o vid_ati68860_ramdac.o \ + vid_bt48x_ramdac.o \ + vid_av9194.o \ + vid_icd2061.o vid_ics2595.o \ + vid_cl54xx.o \ + vid_et4000.o vid_sc1502x_ramdac.o \ + vid_et4000w32.o vid_stg_ramdac.o \ + vid_ht216.o \ + vid_oak_oti.o \ + vid_paradise.o \ + vid_ti_cf62011.o \ + vid_tvga.o \ + vid_tgui9440.o vid_tkd8001_ramdac.o \ + vid_att20c49x_ramdac.o \ + vid_s3.o vid_s3_virge.o \ + vid_sdac_ramdac.o \ + vid_voodoo.o + +PLATOBJ := win.o \ + win_dynld.o win_thread.o \ + win_cdrom.o win_keyboard.o \ + win_midi.o +ifeq ($(DINPUT), y) + PLATOBJ += win_mouse.o win_joystick.o +else + PLATOBJ += win_mouse_rawinput.o win_joystick_xinput.o +endif + +OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(CHIPSETOBJ) $(MCHOBJ) \ + $(DEVOBJ) $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ + $(USBOBJ) $(NETOBJ) $(PRINTOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) \ + $(PLATOBJ) $(UIOBJ) $(D2DOBJ) $(FSYNTHOBJ) $(MUNTOBJ) \ + $(DEVBROBJ) +ifdef EXOBJ +OBJ += $(EXOBJ) +endif + +LIBS := -mwindows \ + -lddraw -ldxguid -ld3d9 \ + -lcomctl32 + +ifeq ($(STATIC), y) +LIBS += -lopenal -lole32 -lwinmm +else +LIBS += -lwinmm -lopenal.dll +endif + +ifeq ($(D2D), y) +LIBS += $(D2DLIB) +endif +ifeq ($(VNC), y) +LIBS += $(VNCLIB) -lws2_32 +endif +ifeq ($(RDP), y) +LIBS += $(RDPLIB) +endif +ifneq ($(WX), n) +LIBS += $(WX_LIBS) -lm +endif +LIBS += -lpng -lz -lwsock32 -liphlpapi +LIBS += -static -lstdc++ +ifneq ($(X64), y) +LIBS += -Wl,--large-address-aware +endif +ifeq ($(DINPUT), y) + LIBS += -ldinput8 +else + LIBS += -lxinput +endif +ifeq ($(D3DX), y) +LIBS += -ld3dx9 +endif + +ifeq ($(STATIC), y) +LIBS += -static +endif + +# Build module rules. +ifeq ($(AUTODEP), y) +%.o: %.c + @echo $< + @$(CC) $(CFLAGS) $(DEPS) -c $< + +%.o: %.cc + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -c $< + +%.o: %.cpp + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -c $< +else +%.o: %.c + @echo $< + @$(CC) $(CFLAGS) -c $< + +%.o: %.cc + @echo $< + @$(CPP) $(CXXFLAGS) -c $< + +%.o: %.cpp + @echo $< + @$(CPP) $(CXXFLAGS) -c $< + +%.d: %.c $(wildcard $*.d) + @echo $< + @$(CC) $(CFLAGS) $(DEPS) -E $< >NUL + +%.d: %.cc $(wildcard $*.d) + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >NUL + +%.d: %.cpp $(wildcard $*.d) + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >NUL +endif + + +all: $(PROG).exe pcap_if.exe + + +86Box.res: 86Box.rc + @echo Processing $< + @$(WINDRES) $(RFLAGS) $(EXTRAS) -i $< -o 86Box.res + +$(PROG).exe: $(OBJ) 86Box.res + @echo Linking $(PROG).exe .. + @$(CC) -o $(PROG).exe $(OBJ) 86Box.res $(LIBS) +ifneq ($(DEBUG), y) + @$(STRIP) $(PROG).exe +endif + +pcap_if.res: pcap_if.rc + @echo Processing $< + @$(WINDRES) $(RFLAGS) -i $< -o pcap_if.res + +pcap_if.exe: pcap_if.o win_dynld.o pcap_if.res + @echo Linking pcap_if.exe .. + @$(CC) -o pcap_if.exe pcap_if.o win_dynld.o pcap_if.res +ifneq ($(DEBUG), y) + @$(STRIP) pcap_if.exe +endif + +hello.exe: hello.o + $(CXX) $(LDFLAGS) -o hello.exe hello.o $(WXLIBS) $(LIBS) +ifneq ($(DEBUG), y) + @$(STRIP) hello.exe +endif + + +clean: + @echo Cleaning objects.. + @-rm -f *.o 2>NUL + @-rm -f *.res 2>NUL + +clobber: clean + @echo Cleaning executables.. + @-rm -f *.d 2>NUL + @-rm -f *.exe 2>NUL +# @-rm -f $(DEPFILE) 2>NUL + +ifneq ($(AUTODEP), y) +depclean: + @-rm -f $(DEPFILE) 2>NUL + @echo Creating dependencies.. + @echo # Run "make depends" to re-create this file. >$(DEPFILE) + +depends: DEPOBJ=$(OBJ:%.o=%.d) +depends: depclean $(OBJ:%.o=%.d) + @-cat $(DEPOBJ) >>$(DEPFILE) + @-rm -f $(DEPOBJ) + +$(DEPFILE): +endif + + +# Module dependencies. +ifeq ($(AUTODEP), y) +#-include $(OBJ:%.o=%.d) (better, but sloooowwwww) +-include *.d +else +include $(wildcard $(DEPFILE)) +endif + + +# End of Makefile.mingw. diff --git a/src/win/icons/cdrom.ico b/src/win/icons/cdrom.ico index a3fb90a8b..bfb69e438 100644 Binary files a/src/win/icons/cdrom.ico and b/src/win/icons/cdrom.ico differ diff --git a/src/win/icons/cdrom_active.ico b/src/win/icons/cdrom_active.ico index 91f4f3ec7..95d39b84d 100644 Binary files a/src/win/icons/cdrom_active.ico and b/src/win/icons/cdrom_active.ico differ diff --git a/src/win/icons/cdrom_disabled.ico b/src/win/icons/cdrom_disabled.ico index 02220893c..b755e789a 100644 Binary files a/src/win/icons/cdrom_disabled.ico and b/src/win/icons/cdrom_disabled.ico differ diff --git a/src/win/icons/cdrom_empty.ico b/src/win/icons/cdrom_empty.ico index 647ebeae6..78e6d15b1 100644 Binary files a/src/win/icons/cdrom_empty.ico and b/src/win/icons/cdrom_empty.ico differ diff --git a/src/win/icons/cdrom_empty_active.ico b/src/win/icons/cdrom_empty_active.ico index f14b71145..b3b27574c 100644 Binary files a/src/win/icons/cdrom_empty_active.ico and b/src/win/icons/cdrom_empty_active.ico differ diff --git a/src/win/icons/floppy_525.ico b/src/win/icons/floppy_525.ico index 81fc78571..7ea15d84d 100644 Binary files a/src/win/icons/floppy_525.ico and b/src/win/icons/floppy_525.ico differ diff --git a/src/win/icons/floppy_525_active.ico b/src/win/icons/floppy_525_active.ico index 204053b3a..3bedb572a 100644 Binary files a/src/win/icons/floppy_525_active.ico and b/src/win/icons/floppy_525_active.ico differ diff --git a/src/win/icons/floppy_525_empty.ico b/src/win/icons/floppy_525_empty.ico index 2b20861a3..017c9dc0e 100644 Binary files a/src/win/icons/floppy_525_empty.ico and b/src/win/icons/floppy_525_empty.ico differ diff --git a/src/win/icons/floppy_525_empty_active.ico b/src/win/icons/floppy_525_empty_active.ico index 71a2ef751..2224ae502 100644 Binary files a/src/win/icons/floppy_525_empty_active.ico and b/src/win/icons/floppy_525_empty_active.ico differ diff --git a/src/win/icons/floppy_disabled.ico b/src/win/icons/floppy_disabled.ico index 7a0e1bb7c..8b20f4f51 100644 Binary files a/src/win/icons/floppy_disabled.ico and b/src/win/icons/floppy_disabled.ico differ diff --git a/src/win/icons/floppy_drives.ico b/src/win/icons/floppy_drives.ico index 4c11a9966..58c96091f 100644 Binary files a/src/win/icons/floppy_drives.ico and b/src/win/icons/floppy_drives.ico differ diff --git a/src/win/icons/hard_disk.ico b/src/win/icons/hard_disk.ico index 9b4a5fd7f..36439eb31 100644 Binary files a/src/win/icons/hard_disk.ico and b/src/win/icons/hard_disk.ico differ diff --git a/src/win/icons/hard_disk_active.ico b/src/win/icons/hard_disk_active.ico index 1adee78a9..52be00623 100644 Binary files a/src/win/icons/hard_disk_active.ico and b/src/win/icons/hard_disk_active.ico differ diff --git a/src/win/resource.h b/src/win/resource.h index d27f9b3c8..c2b58ed69 100644 --- a/src/win/resource.h +++ b/src/win/resource.h @@ -160,7 +160,9 @@ #define IDC_COMBO_LPT3 1112 #define IDC_CHECK_SERIAL1 1113 #define IDC_CHECK_SERIAL2 1114 -#define IDC_CHECK_PARALLEL 1115 +#define IDC_CHECK_PARALLEL1 1115 +#define IDC_CHECK_PARALLEL2 1116 +#define IDC_CHECK_PARALLEL3 1117 #define IDC_OTHER_PERIPH 1120 /* other periph config */ #define IDC_COMBO_SCSI 1121 @@ -284,9 +286,8 @@ #define IDM_VID_FULLSCREEN 40060 #define IDM_VID_FS_FULL 40061 #define IDM_VID_FS_43 40062 -#define IDM_VID_FS_SQ 40063 +#define IDM_VID_FS_KEEPRATIO 40063 #define IDM_VID_FS_INT 40064 -#define IDM_VID_FS_KEEPRATIO 40065 #define IDM_VID_FORCE43 40066 #define IDM_VID_OVERSCAN 40067 #define IDM_VID_INVERT 40069 diff --git a/src/win/win.c b/src/win/win.c index 51e2292dc..d0097f79a 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -8,15 +8,15 @@ * * Platform main support module for Windows. * - * Version: @(#)win.c 1.0.55 2018/11/19 + * Version: @(#)win.c 1.0.57 2019/03/06 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #define UNICODE #include @@ -76,34 +76,36 @@ static rc_str_t *lpRCstr2048, static int vid_api_inited = 0; -static struct { - char *name; +static const struct { + const char *name; int local; int (*init)(void *); void (*close)(void); void (*resize)(int x, int y); int (*pause)(void); + void (*enable)(int enable); + void (*screenshot)(const wchar_t *fn); } vid_apis[2][RENDERERS_NUM] = { { - { "DDraw", 1, (int(*)(void*))ddraw_init, ddraw_close, NULL, ddraw_pause }, + { "DDraw", 1, (int(*)(void*))ddraw_init, ddraw_close, NULL, ddraw_pause, ddraw_enable, ddraw_take_screenshot }, #ifdef USE_D2D - { "D2D", 1, (int(*)(void*))d2d_init, d2d_close, NULL, d2d_pause }, + { "D2D", 1, (int(*)(void*))d2d_init, d2d_close, NULL, d2d_pause, d2d_enable, d2d_take_screenshot }, #endif - { "D3D", 1, (int(*)(void*))d3d_init, d3d_close, d3d_resize, d3d_pause }, - { "SDL", 1, (int(*)(void*))sdl_init, sdl_close, NULL, sdl_pause } + { "D3D", 1, (int(*)(void*))d3d_init, d3d_close, d3d_resize, d3d_pause, d3d_enable, d3d_take_screenshot }, + { "SDL", 1, (int(*)(void*))sdl_init, sdl_close, NULL, sdl_pause, sdl_enable, sdl_take_screenshot } #ifdef USE_VNC - ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause } + ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL, vnc_take_screenshot } #endif }, { - { "DDraw", 1, (int(*)(void*))ddraw_init_fs, ddraw_close, NULL, ddraw_pause }, + { "DDraw", 1, (int(*)(void*))ddraw_init_fs, ddraw_close, NULL, ddraw_pause, ddraw_enable, ddraw_take_screenshot }, #ifdef USE_D2D - { "D2D", 1, (int(*)(void*))d2d_init_fs, d2d_close, NULL, d2d_pause }, + { "D2D", 1, (int(*)(void*))d2d_init_fs, d2d_close, NULL, d2d_pause, d2d_enable, d2d_take_screenshot }, #endif - { "D3D", 1, (int(*)(void*))d3d_init_fs, d3d_close, NULL, d3d_pause }, - { "SDL", 1, (int(*)(void*))sdl_init_fs, sdl_close, sdl_resize, sdl_pause } + { "D3D", 1, (int(*)(void*))d3d_init_fs, d3d_close, NULL, d3d_pause, d3d_enable, d3d_take_screenshot }, + { "SDL", 1, (int(*)(void*))sdl_init_fs, sdl_close, sdl_resize, sdl_pause, sdl_enable, sdl_take_screenshot } #ifdef USE_VNC - ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause } + ,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL, vnc_take_screenshot } #endif }, }; @@ -348,6 +350,9 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) { wchar_t **argw = NULL; int argc, i; + wchar_t * AppID = L"86Box.86Box\0"; + + SetCurrentProcessExplicitAppUserModelID(AppID); /* Set this to the default value (windowed mode). */ video_fullscreen = 0; @@ -435,6 +440,7 @@ plat_get_exe_name(wchar_t *s, int size) GetModuleFileName(hinstance, s, size); } + void plat_tempfile(wchar_t *bufp, wchar_t *prefix, wchar_t *suffix) { @@ -455,6 +461,7 @@ plat_tempfile(wchar_t *bufp, wchar_t *prefix, wchar_t *suffix) mbstowcs(bufp, temp, strlen(temp)+1); } + int plat_getcwd(wchar_t *bufp, int max) { @@ -478,6 +485,14 @@ plat_fopen(wchar_t *path, wchar_t *mode) } +/* Open a file, using Unicode pathname, with 64bit pointers. */ +FILE * +plat_fopen64(const wchar_t *path, const wchar_t *mode) +{ + return(_wfopen(path, mode)); +} + + void plat_remove(wchar_t *path) { @@ -507,6 +522,46 @@ plat_path_abs(wchar_t *path) } +/* Return the last element of a pathname. */ +wchar_t * +plat_get_basename(const wchar_t *path) +{ + int c = (int)wcslen(path); + + while (c > 0) { + if (path[c] == L'/' || path[c] == L'\\') + return((wchar_t *)&path[c]); + c--; + } + + return((wchar_t *)path); +} + + +/* Return the 'directory' element of a pathname. */ +void +plat_get_dirname(wchar_t *dest, const wchar_t *path) +{ + int c = (int)wcslen(path); + wchar_t *ptr; + + ptr = (wchar_t *)path; + + while (c > 0) { + if (path[c] == L'/' || path[c] == L'\\') { + ptr = (wchar_t *)&path[c]; + break; + } + c--; + } + + /* Copy to destination. */ + while (path < ptr) + *dest++ = *path++; + *dest = L'\0'; +} + + wchar_t * plat_get_filename(wchar_t *s) { @@ -544,6 +599,7 @@ void plat_append_filename(wchar_t *dest, wchar_t *s1, wchar_t *s2) { wcscat(dest, s1); + plat_path_slash(dest); wcscat(dest, s2); } @@ -607,7 +663,11 @@ plat_vidapi(char *name) { int i; - if (!strcasecmp(name, "default") || !strcasecmp(name, "system")) return(0); +#ifdef USE_D2D + if (!strcasecmp(name, "default") || !strcasecmp(name, "system")) return(2); +#else + if (!strcasecmp(name, "default") || !strcasecmp(name, "system")) return(1); +#endif for (i = 0; i < RENDERERS_NUM; i++) { if (vid_apis[0][i].name && @@ -627,10 +687,7 @@ plat_vidapi_name(int api) switch(api) { case 0: -#if 0 - /* DirectDraw is default. */ name = "ddraw"; -#endif break; #ifdef USE_D2D @@ -639,7 +696,10 @@ plat_vidapi_name(int api) break; case 2: +#if 0 + /* Direct3D is default. */ name = "d3d"; +#endif break; case 3: @@ -647,7 +707,10 @@ plat_vidapi_name(int api) break; #else case 1: +#if 0 + /* Direct3D is default. */ name = "d3d"; +#endif break; case 2: @@ -714,6 +777,17 @@ plat_vidsize(int x, int y) } +void +plat_vidapi_enable(int enable) +{ + if (!vid_api_inited || !vid_apis[video_fullscreen][vid_api].enable) return; + + startblit(); + video_wait_for_blit(); + vid_apis[video_fullscreen][vid_api].enable(enable); + endblit(); +} + int get_vidpause(void) { @@ -768,6 +842,7 @@ take_screenshot(void) struct tm *info; time_t now; + if (!vid_api_inited || !vid_apis[video_fullscreen][vid_api].screenshot) return; win_log("Screenshot: video API is: %i\n", vid_api); if ((vid_api < 0) || (vid_api >= RENDERERS_NUM)) return; @@ -786,44 +861,7 @@ take_screenshot(void) wcsftime(fn, 128, L"%Y%m%d_%H%M%S.png", info); wcscat(path, fn); - - switch(vid_api) { - case 0: /* ddraw */ - ddraw_take_screenshot(path); - break; - -#ifdef USE_D2D - case 1: /* d2d */ - d2d_take_screenshot(path); - break; - - case 2: /* d3d9 */ - d3d_take_screenshot(path); - break; - - case 3: /* sdl */ - sdl_take_screenshot(path); - break; -#else - case 1: /* d3d9 */ - d3d_take_screenshot(path); - break; - - case 2: /* sdl */ - sdl_take_screenshot(path); - break; -#endif - -#ifdef USE_VNC -#ifdef USE_D2D - case 4: /* vnc */ -#else - case 3: /* vnc */ -#endif - vnc_take_screenshot(path); - break; -#endif - } + vid_apis[video_fullscreen][vid_api].screenshot((const wchar_t *) path); } diff --git a/src/win/win_d2d.cpp b/src/win/win_d2d.cpp index bea716d3b..3a5ed202b 100644 --- a/src/win/win_d2d.cpp +++ b/src/win/win_d2d.cpp @@ -8,11 +8,11 @@ * * Rendering module for Microsoft Direct2D. * - * Version: @(#)win_d2d.cpp 1.0.2 2018/10/18 + * Version: @(#)win_d2d.cpp 1.0.3 2019/03/09 * * Authors: David Hrdlička, * - * Copyright 2018 David Hrdlička. + * Copyright 2018,2019 David Hrdlička. */ #include #include @@ -35,6 +35,7 @@ #include "../device.h" #include "../video/video.h" #include "../plat.h" +#include "../plat_dynld.h" #include "../ui.h" #include "win.h" #include "win_d2d.h" @@ -47,9 +48,24 @@ static ID2D1HwndRenderTarget *d2d_hwndRT; static ID2D1BitmapRenderTarget *d2d_btmpRT; static ID2D1Bitmap *d2d_bitmap; static int d2d_width, d2d_height, d2d_screen_width, d2d_screen_height, d2d_fs; +static volatile int d2d_enabled = 0; #endif +/* Pointers to the real functions. */ +static HRESULT (*D2D1_CreateFactory)(D2D1_FACTORY_TYPE facType, + REFIID riid, + CONST D2D1_FACTORY_OPTIONS *pFacOptions, + void **ppIFactory); +static dllimp_t d2d_imports[] = { + { "D2D1CreateFactory", &D2D1_CreateFactory }, + { NULL, NULL } +}; + + +static volatile void *d2d_handle; /* handle to WinPcap DLL */ + + #ifdef ENABLE_D2D_LOG int d2d_do_log = ENABLE_D2D_LOG; @@ -76,7 +92,7 @@ d2d_stretch(float *w, float *h, float *x, float *y) { double dw, dh, dx, dy, temp, temp2, ratio_w, ratio_h, gsr, hsr; - switch (video_fullscreen_scale) + switch (video_fullscreen_scale) { case FULLSCR_SCALE_FULL: *w = d2d_screen_width; @@ -86,35 +102,34 @@ d2d_stretch(float *w, float *h, float *x, float *y) break; case FULLSCR_SCALE_43: + case FULLSCR_SCALE_KEEPRATIO: dw = (double) d2d_screen_width; dh = (double) d2d_screen_height; - temp = (dh / 3.0) * 4.0; - dx = (dw - temp) / 2.0; - dw = temp; - *w = (float) dw; - *h = (float) dh; - *x = (float) dx; - *y = 0; - break; - - case FULLSCR_SCALE_SQ: - dw = (double) d2d_screen_width; - dh = (double) d2d_screen_height; - temp = ((double) *w); - temp2 = ((double) *h); - dx = (dw / 2.0) - ((dh * temp) / (temp2 * 2.0)); - dy = 0.0; - if (dx < 0.0) + hsr = dw / dh; + if (video_fullscreen_scale == FULLSCR_SCALE_43) + gsr = 4.0 / 3.0; + else + gsr = ((double) *w) / ((double) *h); + if (gsr <= hsr) { - dx = 0.0; - dy = (dw / 2.0) - ((dh * temp2) / (temp * 2.0)); + temp = dh * gsr; + dx = (dw - temp) / 2.0; + dw = temp; + *w = (float) dw; + *h = (float) dh; + *x = (float) dx; + *y = 0; + } + else + { + temp = dw / gsr; + dy = (dh - temp) / 2.0; + dh = temp; + *w = (float) dw; + *h = (float) dh; + *x = 0; + *y = (float) dy; } - dw -= (dx * 2.0); - dh -= (dy * 2.0); - *w = (float) dw; - *h = (float) dh; - *x = (float) dx; - *y = (float) dy; break; case FULLSCR_SCALE_INT: @@ -137,33 +152,6 @@ d2d_stretch(float *w, float *h, float *x, float *y) *x = (float) dx; *y = (float) dy; break; - - case FULLSCR_SCALE_KEEPRATIO: - dw = (double) d2d_screen_width; - dh = (double) d2d_screen_height; - hsr = dw / dh; - gsr = ((double) *w) / ((double) *h); - if (gsr <= hsr) - { - temp = dh * gsr; - dx = (dw - temp) / 2.0; - dw = temp; - *w = (float) dw; - *h = (float) dh; - *x = (float) dx; - *y = 0; - } - else - { - temp = dw / gsr; - dy = (dh - temp) / 2.0; - dh = temp; - *w = (float) dw; - *h = (float) dh; - *x = 0; - *y = (float) dy; - } - break; } } #endif @@ -179,7 +167,7 @@ d2d_blit(int x, int y, int y1, int y2, int w, int h) int yy; D2D1_RECT_U rectU; - ID2D1Bitmap *fs_bitmap; + ID2D1Bitmap *fs_bitmap = 0; ID2D1RenderTarget *RT; float fs_x, fs_y; @@ -188,6 +176,11 @@ d2d_blit(int x, int y, int y1, int y2, int w, int h) d2d_log("Direct2D: d2d_blit(x=%d, y=%d, y1=%d, y2=%d, w=%d, h=%d)\n", x, y, y1, y2, w, h); + if (!d2d_enabled) { + video_blit_complete(); + return; + } + // TODO: Detect double scanned mode and resize render target // appropriately for more clear picture @@ -244,12 +237,12 @@ d2d_blit(int x, int y, int y1, int y2, int w, int h) if (video_grayscale || invert_display) video_transform_copy( (uint32_t *) &(((uint8_t *)srcdata)[yy * w * 4]), - &(((uint32_t *)buffer32->line[y + yy])[x]), + &(buffer32->line[y + yy][x]), w); else memcpy( (uint32_t *) &(((uint8_t *)srcdata)[yy * w * 4]), - &(((uint32_t *)buffer32->line[y + yy])[x]), + &(buffer32->line[y + yy][x]), w * 4); } } @@ -325,6 +318,12 @@ d2d_close(void) { d2d_log("Direct2D: d2d_close()\n"); + /* Unregister our renderer! */ + video_setblit(NULL); + + if (d2d_enabled) + d2d_enabled = 0; + #ifdef USE_D2D if (d2d_bitmap) { @@ -358,6 +357,12 @@ d2d_close(void) d2d_hwnd = NULL; old_hwndMain = NULL; } + + /* Unload the DLL if possible. */ + if (d2d_handle != NULL) { + dynld_close((void *)d2d_handle); + d2d_handle = NULL; + } #endif } @@ -372,7 +377,7 @@ d2d_init_common(int fs) d2d_log("Direct2D: d2d_init_common(fs=%d)\n", fs); - cgapal_rebuild(); + d2d_handle = dynld_module("d2d1.dll", d2d_imports); if (fs) { @@ -404,10 +409,8 @@ d2d_init_common(int fs) SetWindowPos(d2d_hwnd, HWND_TOPMOST, 0, 0, d2d_screen_width, d2d_screen_height, SWP_SHOWWINDOW); } - if (SUCCEEDED(hr)) - { - hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &d2d_factory); - } + hr = D2D1_CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, __uuidof(ID2D1Factory), + NULL, reinterpret_cast (&d2d_factory)); if (fs) { @@ -459,6 +462,8 @@ d2d_init_common(int fs) return(0); } + d2d_enabled = 1; + return(1); } #endif @@ -501,7 +506,7 @@ d2d_pause(void) void -d2d_take_screenshot(wchar_t *fn) +d2d_take_screenshot(const wchar_t *fn) { // Saving a screenshot of a Direct2D render target is harder than // one would think. Keeping this stubbed for the moment @@ -509,4 +514,11 @@ d2d_take_screenshot(wchar_t *fn) d2d_log("Direct2D: d2d_take_screenshot(%s)\n", fn); return; -} \ No newline at end of file +} + + +void +d2d_enable(int enable) +{ + d2d_enabled = enable; +} diff --git a/src/win/win_d2d.h b/src/win/win_d2d.h index 00bfe0887..d76c4bdd0 100644 --- a/src/win/win_d2d.h +++ b/src/win/win_d2d.h @@ -1,4 +1,4 @@ -/* +/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent @@ -25,7 +25,8 @@ extern void d2d_close(void); extern int d2d_init(HWND h); extern int d2d_init_fs(HWND h); extern int d2d_pause(void); -extern void d2d_take_screenshot(wchar_t *fn); +extern void d2d_take_screenshot(const wchar_t *fn); +extern void d2d_enable(int enable); #ifdef __cplusplus } diff --git a/src/win/win_d3d.cpp b/src/win/win_d3d.cpp index 0815470a4..6e5a6f8ef 100644 --- a/src/win/win_d3d.cpp +++ b/src/win/win_d3d.cpp @@ -8,15 +8,15 @@ * * Rendering module for Microsoft Direct3D 9. * - * Version: @(#)win_d3d.cpp 1.0.11 2018/05/26 + * Version: @(#)win_d3d.cpp 1.0.12 2019/03/09 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -45,6 +45,7 @@ static HWND d3d_hwnd; static HWND d3d_device_window; static int d3d_w, d3d_h; +static volatile int d3d_enabled = 0; static CUSTOMVERTEX d3d_verts[] = { { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, @@ -79,7 +80,12 @@ static void d3d_size(RECT w_rect, double *l, double *t, double *r, double *b, int w, int h) { int ratio_w, ratio_h; - double hsr, gsr, ra, d; + double hsr, gsr, d, sh, sw, wh, ww, mh, mw; + + sh = (double) (w_rect.bottom - w_rect.top); + sw = (double) (w_rect.right - w_rect.left); + wh = (double) h; + ww = (double) w; switch (video_fullscreen_scale) { case FULLSCR_SCALE_FULL: @@ -87,28 +93,37 @@ d3d_size(RECT w_rect, double *l, double *t, double *r, double *b, int w, int h) break; case FULLSCR_SCALE_43: - *t = -0.5; - *b = (w_rect.bottom - w_rect.top) - 0.5; - *l = ((w_rect.right - w_rect.left) / 2) - (((w_rect.bottom - w_rect.top) * 4) / (3 * 2)) - 0.5; - *r = ((w_rect.right - w_rect.left) / 2) + (((w_rect.bottom - w_rect.top) * 4) / (3 * 2)) - 0.5; - if (*l < -0.5) { - *l = -0.5; - *r = (w_rect.right - w_rect.left) - 0.5; - *t = ((w_rect.bottom - w_rect.top) / 2) - (((w_rect.right - w_rect.left) * 3) / (4 * 2)) - 0.5; - *b = ((w_rect.bottom - w_rect.top) / 2) + (((w_rect.right - w_rect.left) * 3) / (4 * 2)) - 0.5; + case FULLSCR_SCALE_KEEPRATIO: + if (video_fullscreen_scale == FULLSCR_SCALE_43) { + mw = 4.0; + mh = 3.0; + } else { + mw = ww; + mh = wh; } - break; - case FULLSCR_SCALE_SQ: - *t = -0.5; - *b = (w_rect.bottom - w_rect.top) - 0.5; - *l = ((w_rect.right - w_rect.left) / 2) - (((w_rect.bottom - w_rect.top) * w) / (h * 2)) - 0.5; - *r = ((w_rect.right - w_rect.left) / 2) + (((w_rect.bottom - w_rect.top) * w) / (h * 2)) - 0.5; - if (*l < -0.5) { + hsr = sw / sh; + gsr = mw / mh; + + if (hsr > gsr) { + /* Host ratio is bigger than guest ratio. */ + d = (sw - (mw * (sh / mh))) / 2.0; + + *l = ((int) d) - 0.5; + *r = ((int) (sw - d)) - 0.5; + *t = -0.5; + *b = ((int) sh) - 0.5; + } else if (hsr < gsr) { + /* Host ratio is smaller or rqual than guest ratio. */ + d = (sh - (mh * (sw / mw))) / 2.0; + *l = -0.5; - *r = (w_rect.right - w_rect.left) - 0.5; - *t = ((w_rect.bottom - w_rect.top) / 2) - (((w_rect.right - w_rect.left) * h) / (w * 2)) - 0.5; - *b = ((w_rect.bottom - w_rect.top) / 2) + (((w_rect.right - w_rect.left) * h) / (w * 2)) - 0.5; + *r = ((int) sw) - 0.5; + *t = ((int) d) - 0.5; + *b = ((int) (sh - d)) - 0.5; + } else { + /* Host ratio is equal to guest ratio. */ + d3d_size_default(w_rect, l, t, r, b); } break; @@ -123,37 +138,6 @@ d3d_size(RECT w_rect, double *l, double *t, double *r, double *b, int w, int h) *b = ((w_rect.bottom - w_rect.top) / 2) + ((h * ratio_w) / 2) - 0.5; break; - case FULLSCR_SCALE_KEEPRATIO: - hsr = ((double) (w_rect.right - w_rect.left)) / ((double) (w_rect.bottom - w_rect.top)); - gsr = ((double) w) / ((double) h); - - if (hsr > gsr) { - /* Host ratio is bigger than guest ratio. */ - ra = ((double) (w_rect.bottom - w_rect.top)) / ((double) h); - - d = ((double) w) * ra; - d = (((double) (w_rect.right - w_rect.left)) - d) / 2.0; - - *l = ((int) d) - 0.5; - *r = (w_rect.right - w_rect.left) - ((int) d) - 0.5; - *t = -0.5; - *b = (w_rect.bottom - w_rect.top) - 0.5; - } else if (hsr < gsr) { - /* Host ratio is smaller or rqual than guest ratio. */ - ra = ((double) (w_rect.right - w_rect.left)) / ((double) w); - - d = ((double) h) * ra; - d = (((double) (w_rect.bottom - w_rect.top)) - d) / 2.0; - - *l = -0.5; - *r = (w_rect.right - w_rect.left) - 0.5; - *t = ((int) d) - 0.5; - *b = (w_rect.bottom - w_rect.top) - ((int) d) - 0.5; - } else { - /* Host ratio is equal to guest ratio. */ - d3d_size_default(w_rect, l, t, r, b); - } - break; } } @@ -169,6 +153,11 @@ d3d_blit_fs(int x, int y, int y1, int y2, int w, int h) int yy; double l = 0, t = 0, r = 0, b = 0; + if (!d3d_enabled) { + video_blit_complete(); + return; + } + if ((y1 == y2) || (h <= 0)) { video_blit_complete(); return; /*Nothing to do*/ @@ -187,9 +176,9 @@ d3d_blit_fs(int x, int y, int y1, int y2, int w, int h) for (yy = y1; yy < y2; yy++) { if (buffer32) { if (video_grayscale || invert_display) - video_transform_copy((uint32_t *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w); + video_transform_copy((uint32_t *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(buffer32->line[yy + y][x]), w); else - memcpy((void *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); + memcpy((void *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(buffer32->line[yy + y][x]), w * 4); } } @@ -282,6 +271,11 @@ d3d_blit(int x, int y, int y1, int y2, int w, int h) RECT r; int yy; + if (!d3d_enabled) { + video_blit_complete(); + return; + } + if ((y1 == y2) || (h <= 0)) { video_blit_complete(); return; /*Nothing to do*/ @@ -298,9 +292,9 @@ d3d_blit(int x, int y, int y1, int y2, int w, int h) if (buffer32) { if ((y + yy) >= 0 && (y + yy) < buffer32->h) { if (video_grayscale || invert_display) - video_transform_copy((uint32_t *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w); + video_transform_copy((uint32_t *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(buffer32->line[yy + y][x]), w); else - memcpy((void *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); + memcpy((void *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(buffer32->line[yy + y][x]), w * 4); } } } @@ -415,8 +409,6 @@ d3d_init(HWND h) { d3d_hwnd = h; - cgapal_rebuild(); - d3d = Direct3DCreate9(D3D_SDK_VERSION); memset(&d3dpp, 0, sizeof(d3dpp)); @@ -444,6 +436,8 @@ d3d_init(HWND h) video_setblit(d3d_blit); + d3d_enabled = 1; + return(1); } @@ -453,8 +447,6 @@ d3d_init_fs(HWND h) { WCHAR title[200]; - cgapal_rebuild(); - d3d_w = GetSystemMetrics(SM_CXSCREEN); d3d_h = GetSystemMetrics(SM_CYSCREEN); @@ -504,6 +496,8 @@ d3d_init_fs(HWND h) video_setblit(d3d_blit_fs); + d3d_enabled = 1; + return(1); } @@ -527,6 +521,9 @@ d3d_close(void) { video_setblit(NULL); + if (d3d_enabled) + d3d_enabled = 0; + d3d_close_objects(); if (d3ddev) { @@ -634,8 +631,130 @@ d3d_pause(void) } +#ifndef USE_D3DX +static void +SavePNG(wchar_t *szFilename, D3DSURFACE_DESC *surfaceDesc, D3DLOCKED_RECT *d3dlr) +{ + BITMAPINFO bmpInfo; + HDC hdc; + LPVOID pBuf = NULL; + LPVOID pBuf2 = NULL; + png_bytep *b_rgb = NULL; + int i; + + /* create file */ + FILE *fp = plat_fopen(szFilename, (wchar_t *) L"wb"); + if (!fp) { + ddraw_log("[SavePNG] File %ls could not be opened for writing", szFilename); + return; + } + + /* initialize stuff */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!png_ptr) { + ddraw_log("[SavePNG] png_create_write_struct failed"); + fclose(fp); + return; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + ddraw_log("[SavePNG] png_create_info_struct failed"); + fclose(fp); + return; + } + + png_init_io(png_ptr, fp); + + hdc = GetDC(NULL); + + ZeroMemory(&bmpInfo, sizeof(BITMAPINFO)); + bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + + GetDIBits(hdc, hBitmap, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS); + + if (bmpInfo.bmiHeader.biSizeImage <= 0) + bmpInfo.bmiHeader.biSizeImage = + bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8; + + pBuf = malloc(bmpInfo.bmiHeader.biSizeImage); + if (pBuf == NULL) { + ddraw_log("[SavePNG] Unable to Allocate Bitmap Memory"); + fclose(fp); + return; + } + + if (ys2 <= 250) { + pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage << 1); + if (pBuf2 == NULL) { + ddraw_log("[SavePNG] Unable to Allocate Secondary Bitmap Memory"); + free(pBuf); + fclose(fp); + return; + } + + } + + ddraw_log("save png w=%i h=%i\n", bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); + + bmpInfo.bmiHeader.biCompression = BI_RGB; + + GetDIBits(hdc, hBitmap, 0, bmpInfo.bmiHeader.biHeight, pBuf, &bmpInfo, DIB_RGB_COLORS); + + if (pBuf2) { + bmpInfo.bmiHeader.biSizeImage <<= 1; + bmpInfo.bmiHeader.biHeight <<= 1; + } + + png_set_IHDR(png_ptr, info_ptr, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight, + 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * bmpInfo.bmiHeader.biHeight); + if (b_rgb == NULL) { + ddraw_log("[SavePNG] Unable to Allocate RGB Bitmap Memory"); + free(pBuf2); + free(pBuf); + fclose(fp); + return; + } + + for (i = 0; i < bmpInfo.bmiHeader.biHeight; i++) { + b_rgb[i] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr)); + } + + if (pBuf2) { + DoubleLines((uint8_t *) pBuf2, (uint8_t *) pBuf); + bgra_to_rgb(b_rgb, (uint8_t *) pBuf2, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); + } else + bgra_to_rgb(b_rgb, (uint8_t *) pBuf, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); + + png_write_info(png_ptr, info_ptr); + + png_write_image(png_ptr, b_rgb); + + png_write_end(png_ptr, NULL); + + /* cleanup heap allocation */ + if (hdc) ReleaseDC(NULL,hdc); + + for (i = 0; i < bmpInfo.bmiHeader.biHeight; i++) + if (b_rgb[i]) free(b_rgb[i]); + + if (b_rgb) free(b_rgb); + + if (pBuf2) free(pBuf2); + + if (pBuf) free(pBuf); + + if (fp) fclose(fp); +} +#endif + + void -d3d_take_screenshot(wchar_t *fn) +d3d_take_screenshot(const wchar_t *fn) { #ifdef USE_D3DX LPDIRECT3DSURFACE9 d3dSurface = NULL; @@ -650,6 +769,28 @@ d3d_take_screenshot(wchar_t *fn) #else /* TODO: how to take screenshot without d3dx? just a stub for now */ - pclog("Direct3D: d3d_take_screenshot(%s)\n", fn); + LPDIRECT3DSURFACE9 d3dSurface = NULL; + D3DSURFACE_DESC surfaceDesc; + D3DLOCKED_RECT d3dlr; + BYTE *pSurfaceBuffer; + + if (! d3dTexture) return; + + d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); + d3dSurface->GetDesc(&surfaceDesc); + d3dSurface->LockRect(&d3dlr, 0, D3DLOCK_DONOTWAIT); + pSurfaceBuffer = (BYTE *) d3dlr.pBits + d3dlr.Pitch * (surfaceDesc.Height - 1); + + D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); + + d3dSurface->Release(); + d3dSurface = NULL; #endif } + + +void +d3d_enable(int enable) +{ + d3d_enabled = enable; +} diff --git a/src/win/win_d3d.h b/src/win/win_d3d.h index 18c7c9161..8a869ab31 100644 --- a/src/win/win_d3d.h +++ b/src/win/win_d3d.h @@ -36,7 +36,8 @@ extern void d3d_reset(void); extern void d3d_reset_fs(void); extern int d3d_pause(void); extern void d3d_resize(int x, int y); -extern void d3d_take_screenshot(wchar_t *fn); +extern void d3d_take_screenshot(const wchar_t *fn); +extern void d3d_enable(int enable); #ifdef __cplusplus } diff --git a/src/win/win_ddraw.cpp b/src/win/win_ddraw.cpp index 4e7c144e6..1f4ac469d 100644 --- a/src/win/win_ddraw.cpp +++ b/src/win/win_ddraw.cpp @@ -11,15 +11,15 @@ * NOTES: This code should be re-merged into a single init() with a * 'fullscreen' argument, indicating FS mode is requested. * - * Version: @(#)win_ddraw.cpp 1.0.13 2018/11/18 + * Version: @(#)win_ddraw.cpp 1.0.14 2019/03/09 * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -53,6 +53,7 @@ static HWND ddraw_hwnd; static HBITMAP hbitmap; static int ddraw_w, ddraw_h, xs, ys, ys2; +static volatile int ddraw_enabled = 0; static png_structp png_ptr; static png_infop info_ptr; @@ -133,7 +134,7 @@ DoubleLines(uint8_t *dst, uint8_t *src) static void -SavePNG(wchar_t *szFilename, HBITMAP hBitmap) +SavePNG(const wchar_t *szFilename, HBITMAP hBitmap) { BITMAPINFO bmpInfo; HDC hdc; @@ -143,7 +144,7 @@ SavePNG(wchar_t *szFilename, HBITMAP hBitmap) int i; /* create file */ - FILE *fp = plat_fopen(szFilename, (wchar_t *) L"wb"); + FILE *fp = plat_fopen((wchar_t *) szFilename, (wchar_t *) L"wb"); if (!fp) { ddraw_log("[SavePNG] File %ls could not be opened for writing", szFilename); return; @@ -266,38 +267,52 @@ static void ddraw_fs_size(RECT w_rect, RECT *r_dest, int w, int h) { int ratio_w, ratio_h; - double hsr, gsr, ra, d; + double hsr, gsr, d, sh, sw, wh, ww, mh, mw; ddraw_log("video_fullscreen_scale = %i\n", video_fullscreen_scale); + sh = (double) (w_rect.bottom - w_rect.top); + sw = (double) (w_rect.right - w_rect.left); + wh = (double) h; + ww = (double) w; + switch (video_fullscreen_scale) { case FULLSCR_SCALE_FULL: ddraw_fs_size_default(w_rect, r_dest); break; case FULLSCR_SCALE_43: - r_dest->top = 0; - r_dest->bottom = (w_rect.bottom - w_rect.top) - 1; - r_dest->left = ((w_rect.right - w_rect.left) / 2) - (((w_rect.bottom - w_rect.top) * 4) / (3 * 2)); - r_dest->right = ((w_rect.right - w_rect.left) / 2) + (((w_rect.bottom - w_rect.top) * 4) / (3 * 2)) - 1; - if (r_dest->left < 0) { - r_dest->left = 0; - r_dest->right = (w_rect.right - w_rect.left) - 1; - r_dest->top = ((w_rect.bottom - w_rect.top) / 2) - (((w_rect.right - w_rect.left) * 3) / (4 * 2)); - r_dest->bottom = ((w_rect.bottom - w_rect.top) / 2) + (((w_rect.right - w_rect.left) * 3) / (4 * 2)) - 1; + case FULLSCR_SCALE_KEEPRATIO: + if (video_fullscreen_scale == FULLSCR_SCALE_43) { + mw = 4.0; + mh = 3.0; + } else { + mw = ww; + mh = wh; } - break; - case FULLSCR_SCALE_SQ: - r_dest->top = 0; - r_dest->bottom = (w_rect.bottom - w_rect.top) - 1; - r_dest->left = ((w_rect.right - w_rect.left) / 2) - (((w_rect.bottom - w_rect.top) * w) / (h * 2)); - r_dest->right = ((w_rect.right - w_rect.left) / 2) + (((w_rect.bottom - w_rect.top) * w) / (h * 2)) - 1; - if (r_dest->left < 0) { + hsr = sw / sh; + gsr = mw / mh; + + if (hsr > gsr) { + /* Host ratio is bigger than guest ratio. */ + d = (sw - (mw * (sh / mh))) / 2.0; + + r_dest->left = (int) d; + r_dest->right = (int) (sw - d - 1.0); + r_dest->top = 0; + r_dest->bottom = (int) (sh - 1.0); + } else if (hsr < gsr) { + /* Host ratio is smaller or rqual than guest ratio. */ + d = (sh - (mh * (sw / mw))) / 2.0; + r_dest->left = 0; - r_dest->right = (w_rect.right - w_rect.left) - 1; - r_dest->top = ((w_rect.bottom - w_rect.top) / 2) - (((w_rect.right - w_rect.left) * h) / (w * 2)); - r_dest->bottom = ((w_rect.bottom - w_rect.top) / 2) + (((w_rect.right - w_rect.left) * h) / (w * 2)) - 1; + r_dest->right = (int) (sw - 1.0); + r_dest->top = (int) d; + r_dest->bottom = (int) (sh - d - 1.0); + } else { + /* Host ratio is equal to guest ratio. */ + ddraw_fs_size_default(w_rect, r_dest); } break; @@ -311,38 +326,6 @@ ddraw_fs_size(RECT w_rect, RECT *r_dest, int w, int h) r_dest->top = ((w_rect.bottom - w_rect.top) / 2) - ((h * ratio_w) / 2); r_dest->bottom = ((w_rect.bottom - w_rect.top) / 2) + ((h * ratio_w) / 2) - 1; break; - - case FULLSCR_SCALE_KEEPRATIO: - hsr = ((double) (w_rect.right - w_rect.left)) / ((double) (w_rect.bottom - w_rect.top)); - gsr = ((double) w) / ((double) h); - - if (hsr > gsr) { - /* Host ratio is bigger than guest ratio. */ - ra = ((double) (w_rect.bottom - w_rect.top)) / ((double) h); - - d = ((double) w) * ra; - d = (((double) (w_rect.right - w_rect.left)) - d) / 2.0; - - r_dest->left = ((int) d); - r_dest->right = (w_rect.right - w_rect.left) - ((int) d) - 1; - r_dest->top = 0; - r_dest->bottom = (w_rect.bottom - w_rect.top) - 1; - } else if (hsr < gsr) { - /* Host ratio is smaller or rqual than guest ratio. */ - ra = ((double) (w_rect.right - w_rect.left)) / ((double) w); - - d = ((double) h) * ra; - d = (((double) (w_rect.bottom - w_rect.top)) - d) / 2.0; - - r_dest->left = 0; - r_dest->right = (w_rect.right - w_rect.left) - 1; - r_dest->top = ((int) d); - r_dest->bottom = (w_rect.bottom - w_rect.top) - ((int) d) - 1; - } else { - /* Host ratio is equal to guest ratio. */ - ddraw_fs_size_default(w_rect, r_dest); - } - break; } } @@ -357,6 +340,11 @@ ddraw_blit_fs(int x, int y, int y1, int y2, int w, int h) HRESULT hr; DDBLTFX ddbltfx; + if (!ddraw_enabled) { + video_blit_complete(); + return; + } + if (lpdds_back == NULL) { video_blit_complete(); return; /*Nothing to do*/ @@ -386,9 +374,9 @@ ddraw_blit_fs(int x, int y, int y1, int y2, int w, int h) for (yy = y1; yy < y2; yy++) { if (buffer32) { if (video_grayscale || invert_display) - video_transform_copy((uint32_t *)((uintptr_t)ddsd.lpSurface + (yy * ddsd.lPitch)), &(((uint32_t *)buffer32->line[y + yy])[x]), w); + video_transform_copy((uint32_t *)((uintptr_t)ddsd.lpSurface + (yy * ddsd.lPitch)), &(buffer32->line[y + yy][x]), w); else - memcpy((void *)((uintptr_t)ddsd.lpSurface + (yy * ddsd.lPitch)), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + memcpy((void *)((uintptr_t)ddsd.lpSurface + (yy * ddsd.lPitch)), &(buffer32->line[y + yy][x]), w * 4); } } video_blit_complete(); @@ -434,6 +422,11 @@ ddraw_blit(int x, int y, int y1, int y2, int w, int h) HRESULT hr; int yy; + if (!ddraw_enabled) { + video_blit_complete(); + return; + } + if (lpdds_back == NULL) { video_blit_complete(); return; /*Nothing to do*/ @@ -465,9 +458,9 @@ ddraw_blit(int x, int y, int y1, int y2, int w, int h) if (buffer32) { if ((y + yy) >= 0 && (y + yy) < buffer32->h) { if (video_grayscale || invert_display) - video_transform_copy((uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w); + video_transform_copy((uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]), &(buffer32->line[y + yy][x]), w); else - memcpy((uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + memcpy((uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]), &(buffer32->line[y + yy][x]), w * 4); } } } @@ -503,7 +496,7 @@ ddraw_blit(int x, int y, int y1, int y2, int w, int h) void -ddraw_take_screenshot(wchar_t *fn) +ddraw_take_screenshot(const wchar_t *fn) { #if 0 xs = xsize; @@ -541,8 +534,6 @@ ddraw_take_screenshot(wchar_t *fn) int ddraw_init(HWND h) { - cgapal_rebuild(); - if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) return(0); if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) @@ -600,6 +591,8 @@ ddraw_init(HWND h) video_setblit(ddraw_blit); + ddraw_enabled = 1; + return(1); } @@ -610,8 +603,6 @@ ddraw_init_fs(HWND h) ddraw_w = GetSystemMetrics(SM_CXSCREEN); ddraw_h = GetSystemMetrics(SM_CYSCREEN); - cgapal_rebuild(); - if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) return 0; if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) return 0; @@ -658,6 +649,8 @@ ddraw_init_fs(HWND h) video_setblit(ddraw_blit_fs); + ddraw_enabled = 1; + return(1); } @@ -667,6 +660,9 @@ ddraw_close(void) { video_setblit(NULL); + if (ddraw_enabled) + ddraw_enabled = 0; + if (lpdds_back2) { lpdds_back2->Release(); lpdds_back2 = NULL; @@ -695,3 +691,10 @@ ddraw_pause(void) { return(0); } + + +void +ddraw_enable(int enable) +{ + ddraw_enabled = enable; +} diff --git a/src/win/win_ddraw.h b/src/win/win_ddraw.h index 357ba4906..155cb3d24 100644 --- a/src/win/win_ddraw.h +++ b/src/win/win_ddraw.h @@ -32,7 +32,8 @@ extern int ddraw_init(HWND h); extern int ddraw_init_fs(HWND h); extern void ddraw_close(void); extern int ddraw_pause(void); -extern void ddraw_take_screenshot(wchar_t *fn); +extern void ddraw_take_screenshot(const wchar_t *fn); +extern void ddraw_enable(int enable); #ifdef __cplusplus } diff --git a/src/win/win_joystick_xinput.cpp b/src/win/win_joystick_xinput.cpp index ad3e3ffd2..6be292c13 100644 --- a/src/win/win_joystick_xinput.cpp +++ b/src/win/win_joystick_xinput.cpp @@ -126,8 +126,8 @@ void joystick_init() memcpy(plat_joystick_state[c].button[7].name, XINPUT_NAME_RT, sizeof(XINPUT_NAME_RT)); memcpy(plat_joystick_state[c].button[8].name, XINPUT_NAME_BACK, sizeof(XINPUT_NAME_BACK)); memcpy(plat_joystick_state[c].button[9].name, XINPUT_NAME_START, sizeof(XINPUT_NAME_START)); - memcpy(plat_joystick_state[c].button[10].name, XINPUT_NAME_LS, sizeof(XINPUT_NAME_RS)); - memcpy(plat_joystick_state[c].button[11].name, XINPUT_NAME_RS, sizeof(XINPUT_NAME_LS)); + memcpy(plat_joystick_state[c].button[10].name, XINPUT_NAME_LS, sizeof(XINPUT_NAME_LS)); + memcpy(plat_joystick_state[c].button[11].name, XINPUT_NAME_RS, sizeof(XINPUT_NAME_RS)); plat_joystick_state[c].nr_povs = 0; diff --git a/src/win/win_keyboard.c b/src/win/win_keyboard.c index 7c08f6ca9..eaf4ddac4 100644 --- a/src/win/win_keyboard.c +++ b/src/win/win_keyboard.c @@ -39,17 +39,16 @@ static uint16_t scancode_map[768]; static UINT16 convert_scan_code(UINT16 scan_code) { - if ((scan_code & 0xFF00) == 0xE000) { - scan_code &= 0x00FF; - scan_code |= 0x0100; - } else if (scan_code == 0xE11D) - scan_code = 0xE000; + if ((scan_code & 0xff00) == 0xe000) + scan_code = (scan_code & 0xff) | 0x0100; + + if (scan_code == 0xE11D) + scan_code = 0x0100; /* E0 00 is sent by some USB keyboards for their special keys, as it is an invalid scan code (it has no untranslated set 2 equivalent), we mark it appropriately so it does not get passed through. */ - else if ((scan_code > 0x00FF) || (scan_code == 0xE000)) { + else if ((scan_code > 0x01FF) || (scan_code == 0x0100)) scan_code = 0xFFFF; - } return scan_code; } @@ -138,12 +137,14 @@ keyboard_handle(LPARAM lParam, int infocus) /* If it's not a scan code that starts with 0xE1 */ if (!(rawKB.Flags & RI_KEY_E1)) { if (rawKB.Flags & RI_KEY_E0) - scancode |= (0xE0 << 8); + scancode |= 0x100; /* Translate the scan code to 9-bit */ scancode = convert_scan_code(scancode); /* Remap it according to the list from the Registry */ + if (scancode != scancode_map[scancode]) + pclog("Scan code remap: %03X -> %03X\n", scancode, scancode); scancode = scancode_map[scancode]; /* If it's not 0xFFFF, send it to the emulated diff --git a/src/win/win_sdl.c b/src/win/win_sdl.c index cd2bdc93f..e0ebf7382 100644 --- a/src/win/win_sdl.c +++ b/src/win/win_sdl.c @@ -12,13 +12,13 @@ * we will not use that, but, instead, use a new window which * coverrs the entire desktop. * - * Version: @(#)win_sdl.c 1.0.5 2019/02/08 + * Version: @(#)win_sdl.c 1.0.6 2019/03/09 * * Authors: Fred N. van Kempen, * Michael Dring, * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2018 Michael Dring. + * Copyright 2018,2019 Fred N. van Kempen. + * Copyright 2018,2019 Michael Dring. * * Redistribution and use in source and binary forms, with * or without modification, are permitted provided that the @@ -87,9 +87,11 @@ static HWND sdl_hwnd = NULL; static int sdl_w, sdl_h; static int sdl_fs; static int cur_w, cur_h; +static volatile int sdl_enabled = 0; +static SDL_mutex* sdl_mutex = NULL; -static png_structp png_ptr; -static png_infop info_ptr; +static png_structp png_ptr; +static png_infop info_ptr; /* Pointers to the real functions. */ @@ -125,6 +127,11 @@ static int (*sdl_RenderReadPixels)(SDL_Renderer* renderer, int pitch); static SDL_bool (*sdl_SetHint)(const char* name, const char* value); +static SDL_mutex* (*sdl_CreateMutex)(void); +static void (*sdl_DestroyMutex)(SDL_mutex* mutex); +static int (*sdl_LockMutex)(SDL_mutex* mutex); +static int (*sdl_UnlockMutex)(SDL_mutex* mutex); + static dllimp_t sdl_imports[] = { { "SDL_GetVersion", &sdl_GetVersion }, @@ -144,6 +151,10 @@ static dllimp_t sdl_imports[] = { { "SDL_GetWindowSize", &sdl_GetWindowSize }, { "SDL_RenderReadPixels", &sdl_RenderReadPixels }, { "SDL_SetHint", &sdl_SetHint }, + { "SDL_CreateMutex", &sdl_CreateMutex }, + { "SDL_DestroyMutex", &sdl_DestroyMutex }, + { "SDL_LockMutex", &sdl_LockMutex }, + { "SDL_UnlockMutex", &sdl_UnlockMutex }, { NULL, NULL } }; @@ -181,33 +192,31 @@ sdl_stretch(int *w, int *h, int *x, int *y) *y = 0; break; case FULLSCR_SCALE_43: + case FULLSCR_SCALE_KEEPRATIO: dw = (double) sdl_w; dh = (double) sdl_h; - temp = (dh / 3.0) * 4.0; - dx = (dw - temp) / 2.0; - dw = temp; - *w = (int) dw; - *h = (int) dh; - *x = (int) dx; - *y = 0; - break; - case FULLSCR_SCALE_SQ: - dw = (double) sdl_w; - dh = (double) sdl_h; - temp = ((double) *w); - temp2 = ((double) *h); - dx = (dw / 2.0) - ((dh * temp) / (temp2 * 2.0)); - dy = 0.0; - if (dx < 0.0) { - dx = 0.0; - dy = (dw / 2.0) - ((dh * temp2) / (temp * 2.0)); + hsr = dw / dh; + if (video_fullscreen_scale == FULLSCR_SCALE_43) + gsr = 4.0 / 3.0; + else + gsr = ((double) *w) / ((double) *h); + if (gsr <= hsr) { + temp = dh * gsr; + dx = (dw - temp) / 2.0; + dw = temp; + *w = (int) dw; + *h = (int) dh; + *x = (int) dx; + *y = 0; + } else { + temp = dw / gsr; + dy = (dh - temp) / 2.0; + dh = temp; + *w = (int) dw; + *h = (int) dh; + *x = 0; + *y = (int) dy; } - dw -= (dx * 2.0); - dh -= (dy * 2.0); - *w = (int) dw; - *h = (int) dh; - *x = (int) dx; - *y = (int) dy; break; case FULLSCR_SCALE_INT: dw = (double) sdl_w; @@ -227,29 +236,6 @@ sdl_stretch(int *w, int *h, int *x, int *y) *x = (int) dx; *y = (int) dy; break; - case FULLSCR_SCALE_KEEPRATIO: - dw = (double) sdl_w; - dh = (double) sdl_h; - hsr = dw / dh; - gsr = ((double) *w) / ((double) *h); - if (gsr <= hsr) { - temp = dh * gsr; - dx = (dw - temp) / 2.0; - dw = temp; - *w = (int) dw; - *h = (int) dh; - *x = (int) dx; - *y = 0; - } else { - temp = dw / gsr; - dy = (dh - temp) / 2.0; - dh = temp; - *w = (int) dw; - *h = (int) dh; - *x = 0; - *y = (int) dy; - } - break; } } @@ -262,7 +248,12 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) int pitch; int yy, ret; - if (y1 == y2) { + if (!sdl_enabled) { + video_blit_complete(); + return; + } + + if ((y1 == y2) || (h <= 0)) { video_blit_complete(); return; } @@ -272,6 +263,8 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) return; } + sdl_LockMutex(sdl_mutex); + /* * TODO: * SDL_UpdateTexture() might be better here, as it is @@ -282,9 +275,9 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) for (yy = y1; yy < y2; yy++) { if ((y + yy) >= 0 && (y + yy) < buffer32->h) { if (video_grayscale || invert_display) - video_transform_copy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w); + video_transform_copy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(buffer32->line[y + yy][x]), w); else - memcpy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + memcpy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(buffer32->line[y + yy][x]), w * 4); } } @@ -309,6 +302,8 @@ sdl_blit(int x, int y, int y1, int y2, int w, int h) sdl_log("SDL: unable to copy texture to renderer (%s)\n", sdl_GetError()); sdl_RenderPresent(sdl_render); + + sdl_UnlockMutex(sdl_mutex); } @@ -318,6 +313,14 @@ sdl_close(void) /* Unregister our renderer! */ video_setblit(NULL); + if (sdl_enabled) + sdl_enabled = 0; + + if (sdl_mutex != NULL) { + sdl_DestroyMutex(sdl_mutex); + sdl_mutex = NULL; + } + if (sdl_tex != NULL) { sdl_DestroyTexture(sdl_tex); sdl_tex = NULL; @@ -340,7 +343,8 @@ sdl_close(void) SetFocus(hwndMain); - DestroyWindow(sdl_hwnd); + if (sdl_fs) + DestroyWindow(sdl_hwnd); sdl_hwnd = NULL; } @@ -372,8 +376,6 @@ sdl_init_common(int fs) sdl_log("SDL: init (fs=%d)\n", fs); - cgapal_rebuild(); - /* Try loading the DLL. */ sdl_handle = dynld_module(PATH_SDL_DLL, sdl_imports); if (sdl_handle == NULL) { @@ -498,6 +500,10 @@ sdl_init_common(int fs) sdl_fs = fs; + sdl_enabled = 1; + + sdl_mutex = sdl_CreateMutex(); + return(1); } @@ -619,13 +625,20 @@ sdl_resize(int x, int y) if ((x == cur_w) && (y == cur_h)) return; - sdl_log("sdl_resize(%i, %i)\n", x, y); ww = x; wh = y; sdl_stretch(&ww, &wh, &wx, &wy); - MoveWindow(sdl_hwnd, wx, wy, ww, wh, TRUE); + if (sdl_fs) + MoveWindow(sdl_hwnd, wx, wy, ww, wh, TRUE); cur_w = x; cur_h = y; } + + +void +sdl_enable(int enable) +{ + sdl_enabled = enable; +} diff --git a/src/win/win_sdl.h b/src/win/win_sdl.h index 23ba344be..c0e10ea93 100644 --- a/src/win/win_sdl.h +++ b/src/win/win_sdl.h @@ -55,6 +55,7 @@ extern int sdl_init(HWND h); extern int sdl_init_fs(HWND h); extern int sdl_pause(void); extern void sdl_resize(int x, int y); +extern void sdl_enable(int enable); extern void sdl_take_screenshot(const wchar_t *fn); diff --git a/src/win/win_serial.c b/src/win/win_serial.c deleted file mode 100644 index 21dc7443d..000000000 --- a/src/win/win_serial.c +++ /dev/null @@ -1,571 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of host serial port services for Win32. - * - * This code is based on a universal serial port driver for - * Windows and UNIX systems, with support for FTDI and Prolific - * USB ports. Support for these has been removed. - * - * Version: @(#)win_serial.c 1.0.6 2017/10/16 - * - * Author: Fred N. van Kempen, - * - * Copyright 2017 Fred N. van Kempen. - */ -#include -#include -#include -#include -#define PLAT_SERIAL_C -#include "../86box.h" -#include "../plat.h" -#include "../plat_serial.h" - - -/* Handle the receiving of data from the host port. */ -static void -bhtty_reader(void *arg) -{ - BHTTY *pp = (BHTTY *)arg; - unsigned char b; - DWORD n; - - pclog("%s: thread started\n", pp->name); - - /* As long as the channel is open.. */ - while (pp->tid != NULL) { - /* Post a READ on the device. */ - n = 0; - if (ReadFile(pp->handle, &b, (DWORD)1, &n, &pp->rov) == FALSE) { - n = GetLastError(); - if (n != ERROR_IO_PENDING) { - /* Not good, we got an error. */ - pclog("%s: I/O error %d in read!\n", pp->name, n); - break; - } - - /* The read is pending, wait for it.. */ - if (GetOverlappedResult(pp->handle, &pp->rov, &n, TRUE) == FALSE) { - n = GetLastError(); - pclog("%s: I/O error %d in read!\n", pp->name, n); - break; - } - } - -pclog("%s: got %d bytes of data\n", pp->name, n); - if (n == 1) { - /* We got data, update stuff. */ - if (pp->icnt < sizeof(pp->buff)) { -pclog("%s: queued byte %02x (%d)\n", pp->name, b, pp->icnt+1); - pp->buff[pp->ihead++] = b; - pp->ihead &= (sizeof(pp->buff)-1); - pp->icnt++; - - /* Do a callback to let them know. */ - if (pp->rd_done != NULL) - pp->rd_done(pp->rd_arg, n); - } else { - pclog("%s: RX buffer overrun!\n", pp->name); - } - } - } - - /* Error or done, clean up. */ - pp->tid = NULL; - pclog("%s: thread stopped.\n", pp->name); -} - - -/* Set the state of a port. */ -int -bhtty_sstate(BHTTY *pp, void *arg) -{ - /* Make sure we can do this. */ - if (arg == NULL) { - pclog("%s: invalid argument\n", pp->name); - return(-1); - } - - if (SetCommState(pp->handle, (DCB *)arg) == FALSE) { - /* Mark an error. */ - pclog("%s: set state: %d\n", pp->name, GetLastError()); - return(-1); - } - - return(0); -} - - -/* Fetch the state of a port. */ -int -bhtty_gstate(BHTTY *pp, void *arg) -{ - /* Make sure we can do this. */ - if (arg == NULL) { - pclog("%s: invalid argument\n", pp->name); - return(-1); - } - - if (GetCommState(pp->handle, (DCB *)arg) == FALSE) { - /* Mark an error. */ - pclog("%s: get state: %d\n", pp->name, GetLastError()); - return(-1); - } - - return(0); -} - - -/* Enable or disable RTS/CTS mode (hardware handshaking.) */ -int -bhtty_crtscts(BHTTY *pp, char yesno) -{ - /* Get the current mode. */ - if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); - - switch(yesno) { - case 0: /* disable CRTSCTS */ - pp->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */ - pp->dcb.fDsrSensitivity = 0; - - pp->dcb.fOutxCtsFlow = 0; /* disable RTS/CTS mode */ - - pp->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */ - pp->dcb.fOutX = 0; - pp->dcb.fInX = 0; - break; - - case 1: /* enable CRTSCTS */ - pp->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */ - pp->dcb.fDsrSensitivity = 0; - - pp->dcb.fOutxCtsFlow = 1; /* enable RTS/CTS mode */ - - pp->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */ - pp->dcb.fOutX = 0; - pp->dcb.fInX = 0; - break; - - default: - pclog("%s: invalid parameter '%d'!\n", pp->name, yesno); - return(-1); - } - - /* Set new mode. */ - if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); - - return(0); -} - - -/* Set the port parameters. */ -int -bhtty_params(BHTTY *pp, char dbit, char par, char sbit) -{ - /* Get the current mode. */ - if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); - - /* Set the desired word length. */ - switch((int)dbit) { - case -1: /* no change */ - break; - - case 5: /* FTDI doesnt like these */ - case 6: - case 9: - break; - - case 7: - case 8: - pp->dcb.ByteSize = dbit; - break; - - default: - pclog("%s: invalid parameter '%d'!\n", pp->name, dbit); - return(-1); - } - - /* Set the type of parity encoding. */ - switch((int)par) { - case -1: /* no change */ - case ' ': - break; - - case 0: - case 'N': - pp->dcb.fParity = FALSE; - pp->dcb.Parity = NOPARITY; - break; - - case 1: - case 'O': - pp->dcb.fParity = TRUE; - pp->dcb.Parity = ODDPARITY; - break; - - case 2: - case 'E': - pp->dcb.fParity = TRUE; - pp->dcb.Parity = EVENPARITY; - break; - - case 3: - case 'M': - case 4: - case 'S': - break; - - default: - pclog("%s: invalid parameter '%c'!\n", pp->name, par); - return(-1); - } - - /* Set the number of stop bits. */ - switch((int)sbit) { - case -1: /* no change */ - break; - - case 1: - pp->dcb.StopBits = ONESTOPBIT; - break; - - case 2: - pp->dcb.StopBits = TWOSTOPBITS; - break; - - default: - pclog("%s: invalid parameter '%d'!\n", pp->name, sbit); - return(-1); - } - - /* Set new mode. */ - if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); - - return(0); -} - - -/* Put a port in transparent ("raw") state. */ -void -bhtty_raw(BHTTY *pp, void *arg) -{ - DCB *dcb = (DCB *)arg; - - /* Make sure we can do this. */ - if (arg == NULL) { - pclog("%s: invalid parameter\n", pp->name); - return; - } - - /* Enable BINARY transparent mode. */ - dcb->fBinary = 1; - dcb->fErrorChar = 0; /* disable Error Replacement */ - dcb->fNull = 0; /* disable NUL stripping */ - - /* Disable the DTR and RTS lines. */ - dcb->fDtrControl = DTR_CONTROL_DISABLE; /* DTR line */ - dcb->fRtsControl = RTS_CONTROL_DISABLE; /* RTS line */ - - /* Disable DSR/DCD handshaking. */ - dcb->fOutxDsrFlow = 0; /* DSR handshaking */ - dcb->fDsrSensitivity = 0; /* DSR Sensitivity */ - - /* Disable RTS/CTS handshaking. */ - dcb->fOutxCtsFlow = 0; /* CTS handshaking */ - - /* Disable XON/XOFF handshaking. */ - dcb->fTXContinueOnXoff = 0; /* continue TX after Xoff */ - dcb->fOutX = 0; /* enable output X-ON/X-OFF */ - dcb->fInX = 0; /* enable input X-ON/X-OFF */ - dcb->XonChar = 0x11; /* ASCII XON */ - dcb->XoffChar = 0x13; /* ASCII XOFF */ - dcb->XonLim = 100; - dcb->XoffLim = 100; - - dcb->fParity = FALSE; - dcb->Parity = NOPARITY; - dcb->StopBits = ONESTOPBIT; - dcb->BaudRate = CBR_1200; -} - - -/* Set the port speed. */ -int -bhtty_speed(BHTTY *pp, long speed) -{ - /* Get the current mode and speed. */ - if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); - - /* - * Set speed. - * - * This is not entirely correct, we should use a table - * with DCB_xxx speed values here, but we removed that - * and just hardcode the speed value into DCB. --FvK - */ - pp->dcb.BaudRate = speed; - - /* Set new speed. */ - if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); - - return(0); -} - - -/* Clean up and flush. */ -int -bhtty_flush(BHTTY *pp) -{ - DWORD dwErrs; - COMSTAT cst; - - /* First, clear any errors. */ - (void)ClearCommError(pp->handle, &dwErrs, &cst); - - /* Now flush all buffers. */ - if (PurgeComm(pp->handle, - (PURGE_RXABORT | PURGE_TXABORT | \ - PURGE_RXCLEAR | PURGE_TXCLEAR)) == FALSE) { - pclog("%s: flush: %d\n", pp->name, GetLastError()); - return(-1); - } - - /* Re-clear any errors. */ - if (ClearCommError(pp->handle, &dwErrs, &cst) == FALSE) { - pclog("%s: clear errors: %d\n", pp->name, GetLastError()); - return(-1); - } - - return(0); -} - - -/* Close an open serial port. */ -void -bhtty_close(BHTTY *pp) -{ - /* If the polling thread is running, stop it. */ - (void)bhtty_active(pp, 0); - - /* Close the event handles. */ - if (pp->rov.hEvent != INVALID_HANDLE_VALUE) - CloseHandle(pp->rov.hEvent); - if (pp->wov.hEvent != INVALID_HANDLE_VALUE) - CloseHandle(pp->wov.hEvent); - - if (pp->handle != INVALID_HANDLE_VALUE) { - pclog("%s: closing host port\n", pp->name); - - /* Restore the previous port state, if any. */ - (void)bhtty_sstate(pp, &pp->odcb); - - /* Close the port. */ - CloseHandle(pp->handle); - pp->handle = INVALID_HANDLE_VALUE; - } - - /* Release the control block. */ - free(pp); -} - - -/* Open a host serial port for I/O. */ -BHTTY * -bhtty_open(char *port, int tmo) -{ - char temp[84]; - COMMTIMEOUTS to; - COMMCONFIG conf; - BHTTY *pp; - DWORD d; - - /* First things first... create a control block. */ - if ((pp = (BHTTY *)malloc(sizeof(BHTTY))) == NULL) { - pclog("%s: out of memory!\n", port); - return(NULL); - } - memset(pp, 0x00, sizeof(BHTTY)); - strncpy(pp->name, port, sizeof(pp->name)-1); - - /* Try a regular Win32 serial port. */ - sprintf(temp, "\\\\.\\%s", pp->name); - if ((pp->handle = CreateFile(temp, - (GENERIC_READ|GENERIC_WRITE), - 0, - NULL, - OPEN_EXISTING, - FILE_FLAG_OVERLAPPED, - 0)) == INVALID_HANDLE_VALUE) { - pclog("%s: open port: %d\n", pp->name, GetLastError()); - free(pp); - return(NULL); - } - - /* Create event handles. */ - pp->rov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - pp->wov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - - /* Set up buffer size of the port. */ - if (SetupComm(pp->handle, 32768L, 32768L) == FALSE) { - /* This fails on FTDI-based devices. */ - pclog("%s: set buffers: %d\n", pp->name, GetLastError()); -#if 0 - CloseHandle(pp->handle); - free(pp); - return(NULL); -#endif - } - - /* Grab default config for the driver and set it. */ - d = sizeof(COMMCONFIG); - memset(&conf, 0x00, d); - conf.dwSize = d; - if (GetDefaultCommConfig(temp, &conf, &d) == TRUE) { - /* Change config here... */ - - /* Set new configuration. */ - if (SetCommConfig(pp->handle, &conf, d) == FALSE) { - /* This fails on FTDI-based devices. */ - pclog("%s: set configuration: %d\n", pp->name, GetLastError()); -#if 0 - CloseHandle(pp->handle); - free(pp); - return(NULL); -#endif - } - } - pclog("%s: host port '%s' open\n", pp->name, temp); - - /* - * We now have an open port. To allow for clean exit - * of the application, we first retrieve the port's - * current settings, and save these for later. - */ - if (bhtty_gstate(pp, &pp->odcb) < 0) { - (void)bhtty_close(pp); - return(NULL); - } - memcpy(&pp->dcb, &pp->odcb, sizeof(DCB)); - - /* Force the port to BINARY mode. */ - bhtty_raw(pp, &pp->dcb); - - /* Set new state of this port. */ - if (bhtty_sstate(pp, &pp->dcb) < 0) { - (void)bhtty_close(pp); - return(NULL); - } - - /* Just to make sure.. disable RTS/CTS mode. */ - (void)bhtty_crtscts(pp, 0); - - /* Set new timeout values. */ - if (GetCommTimeouts(pp->handle, &to) == FALSE) { - pclog("%s: error %d while getting current TO\n", - pp->name, GetLastError()); - (void)bhtty_close(pp); - return(NULL); - } - if (tmo < 0) { - /* No timeout, immediate return. */ - to.ReadIntervalTimeout = MAXDWORD; - to.ReadTotalTimeoutMultiplier = 0; - to.ReadTotalTimeoutConstant = 0; - } else if (tmo == 0) { - /* No timeout, wait for data. */ - memset(&to, 0x00, sizeof(to)); - } else { - /* Timeout specified. */ - to.ReadIntervalTimeout = MAXDWORD; - to.ReadTotalTimeoutMultiplier = MAXDWORD; - to.ReadTotalTimeoutConstant = tmo; - } - if (SetCommTimeouts(pp->handle, &to) == FALSE) { - pclog("%s: error %d while setting TO\n", pp->name, GetLastError()); - (void)bhtty_close(pp); - return(NULL); - } - - /* Clear all errors and flush all buffers. */ - if (bhtty_flush(pp) < 0) { - (void)bhtty_close(pp); - return(NULL); - } - - return(pp); -} - - -/* Activate the I/O for this port. */ -int -bhtty_active(BHTTY *pp, int flg) -{ - if (flg) { - pclog("%s: starting thread..\n", pp->name); - pp->tid = thread_create(bhtty_reader, pp); - } else { - if (pp->tid != NULL) { - pclog("%s: stopping thread..\n", pp->name); - thread_kill(pp->tid); - pp->tid = NULL; - } - } - - return(0); -} - - -/* Try to write data to an open port. */ -int -bhtty_write(BHTTY *pp, unsigned char val) -{ - DWORD n = 0; - -pclog("%s: writing byte %02x\n", pp->name, val); - if (WriteFile(pp->handle, &val, 1, &n, &pp->wov) == FALSE) { - n = GetLastError(); - if (n != ERROR_IO_PENDING) { - /* Not good, we got an error. */ - pclog("%s: I/O error %d in write!\n", pp->name, n); - return(-1); - } - - /* The write is pending, wait for it.. */ - if (GetOverlappedResult(pp->handle, &pp->wov, &n, TRUE) == FALSE) { - n = GetLastError(); - pclog("%s: I/O error %d in write!\n", pp->name, n); - return(-1); - } - } - - return((int)n); -} - - -/* - * Try to read data from an open port. - * - * For now, we will use one byte per call. Eventually, - * we should go back to loading a buffer full of data, - * just to speed things up a bit. --FvK - */ -int -bhtty_read(BHTTY *pp, unsigned char *bufp, int max) -{ - if (pp->icnt == 0) return(0); - - while (max-- > 0) { - *bufp++ = pp->buff[pp->itail++]; -pclog("%s: dequeued byte %02x (%d)\n", pp->name, *(bufp-1), pp->icnt); - pp->itail &= (sizeof(pp->buff)-1); - if (--pp->icnt == 0) break; - } - - return(max); -} diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 7a642fc69..d19daa2f7 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -8,13 +8,13 @@ * * Windows 86Box Settings dialog handler. * - * Version: @(#)win_settings.c 1.0.54 2019/02/11 + * Version: @(#)win_settings.c 1.0.55 2019/03/03 * * Authors: Miran Grca, * David Hrdlička, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2018 David Hrdlička. + * Copyright 2016-2019 Miran Grca. + * Copyright 2018,2019 David Hrdlička. */ #define UNICODE #define BITMAP WINDOWS_BITMAP @@ -36,6 +36,7 @@ #include "../mem.h" #include "../rom.h" #include "../device.h" +#include "../timer.h" #include "../nvr.h" #include "../machine/machine.h" #include "../game/gameport.h" @@ -92,8 +93,8 @@ static int temp_net_type, temp_net_card; static char temp_pcap_dev[522]; /* Ports category */ -static char temp_lpt_device_names[3][16]; -static int temp_serial[2], temp_lpt; +static int temp_lpt_devices[3]; +static int temp_serial[2], temp_lpt[3]; /* Other peripherals category */ static int temp_hdc, temp_scsi_card, temp_ide_ter, temp_ide_qua; @@ -120,7 +121,7 @@ static HWND hwndParentDialog, hwndChildDialog; static uint32_t displayed_category = 0; extern int is486; -static int romstolist[ROM_MAX], listtomachine[ROM_MAX], romstomachine[ROM_MAX], machinetolist[ROM_MAX]; +static int 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]; @@ -235,18 +236,12 @@ win_settings_init(void) temp_net_card = network_card; /* Ports category */ -#ifdef ENABLE_SETTINGS_LOG - assert(sizeof(temp_lpt_device_names) == sizeof(lpt_device_names)); -#endif for (i = 0; i < 3; i++) { -#ifdef ENABLE_SETTINGS_LOG - assert(sizeof(temp_lpt_device_names[i]) == sizeof(lpt_device_names[i])); -#endif - memcpy(temp_lpt_device_names[i], lpt_device_names[i], sizeof(lpt_device_names[i])); + temp_lpt_devices[i] = lpt_ports[i].device; + temp_lpt[i] = lpt_ports[i].enabled; } - temp_serial[0] = serial_enabled[0]; - temp_serial[1] = serial_enabled[1]; - temp_lpt = lpt_enabled; + for (i = 0; i < 2; i++) + temp_serial[i] = serial_enabled[i]; /* Other peripherals category */ temp_scsi_card = scsi_card_current; @@ -291,7 +286,7 @@ win_settings_init(void) for (i = 0; i < CDROM_NUM; i++) { if (cdrom[i].bus_type == CDROM_BUS_ATAPI) ide_tracking |= (2 << (cdrom[i].ide_channel << 3)); - else if (cdrom[i].bus_type == CDROM_BUS_SCSI) + else if (cdrom[i].bus_type == CDROM_BUS_SCSI || cdrom[i].bus_type == CDROM_BUS_SCSI_CHINON) scsi_tracking[cdrom[i].scsi_device_id >> 3] |= (1 << ((cdrom[i].scsi_device_id & 0x07) << 3)); } memcpy(temp_zip_drives, zip_drives, ZIP_NUM * sizeof(zip_drive_t)); @@ -349,11 +344,12 @@ win_settings_changed(void) i = i || (network_card != temp_net_card); /* Ports category */ - for (j = 0; j < 3; j++) - i = i || strncmp(temp_lpt_device_names[j], lpt_device_names[j], sizeof(temp_lpt_device_names[j]) - 1); - i = i || (temp_serial[0] != serial_enabled[0]); - i = i || (temp_serial[1] != serial_enabled[1]); - i = i || (temp_lpt != lpt_enabled); + for (j = 0; j < 3; j++) { + i = i || (temp_lpt_devices[j] != lpt_ports[j].device); + i = i || (temp_lpt[j] != lpt_ports[j].enabled); + } + for (j = 0; j < 2; j++) + i = i || (temp_serial[j] != serial_enabled[j]); /* Peripherals category */ i = i || (scsi_card_current != temp_scsi_card); @@ -417,7 +413,6 @@ win_settings_save(void) /* Machine category */ machine = temp_machine; - romset = machine_getromset(); cpu_manufacturer = temp_cpu_m; cpu_waitstates = temp_wait_states; cpu = temp_cpu; @@ -453,11 +448,12 @@ win_settings_save(void) network_card = temp_net_card; /* Ports category */ - for (i = 0; i < 3; i++) - memcpy(lpt_device_names[i], temp_lpt_device_names[i], sizeof(temp_lpt_device_names[i])); - serial_enabled[0] = temp_serial[0]; - serial_enabled[1] = temp_serial[1]; - lpt_enabled = temp_lpt; + for (i = 0; i < 3; i++) { + lpt_ports[i].device = temp_lpt_devices[i]; + lpt_ports[i].enabled = temp_lpt[i]; + } + for (i = 0; i < 2; i++) + serial_enabled[i] = temp_serial[i]; /* Peripherals category */ scsi_card_current = temp_scsi_card; @@ -512,15 +508,13 @@ static void win_settings_machine_recalc_cpu(HWND hdlg) { HWND h; - int cpu_type, temp_romset; + int cpu_type; #ifdef USE_DYNAREC int cpu_flags; #endif - temp_romset = machine_getromset_ex(temp_machine); - h = GetDlgItem(hdlg, IDC_COMBO_WS); - cpu_type = machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + cpu_type = machines[temp_machine].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; if ((cpu_type >= CPU_286) && (cpu_type <= CPU_386DX)) EnableWindow(h, TRUE); else @@ -528,7 +522,7 @@ win_settings_machine_recalc_cpu(HWND hdlg) #ifdef USE_DYNAREC h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); - cpu_flags = machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + cpu_flags = machines[temp_machine].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) && (cpu_flags & CPU_REQUIRES_DYNAREC)) fatal("Attempting to select a CPU that requires the recompiler and does not support it at the same time\n"); if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) { @@ -543,8 +537,9 @@ win_settings_machine_recalc_cpu(HWND hdlg) #endif h = GetDlgItem(hdlg, IDC_CHECK_FPU); - cpu_type = machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; - if ((cpu_type < CPU_i486DX) && (cpu_type >= CPU_286)) + cpu_type = machines[temp_machine].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + // if ((cpu_type < CPU_i486DX) && (cpu_type >= CPU_286)) + if (cpu_type < CPU_i486DX) EnableWindow(h, TRUE); else if (cpu_type < CPU_286) { temp_fpu = 0; @@ -561,18 +556,17 @@ static void win_settings_machine_recalc_cpu_m(HWND hdlg) { HWND h; - int c, temp_romset; + int c; LPTSTR lptsTemp; char *stransi; - temp_romset = machine_getromset_ex(temp_machine); lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_CPU); SendMessage(h, CB_RESETCONTENT, 0, 0); c = 0; - while (machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[c].cpu_type != -1) { - stransi = (char *) machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[c].name; + while (machines[temp_machine].cpu[temp_cpu_m].cpus[c].cpu_type != -1) { + stransi = (char *) machines[temp_machine].cpu[temp_cpu_m].cpus[c].name; mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); c++; @@ -592,13 +586,12 @@ static void win_settings_machine_recalc_machine(HWND hdlg) { HWND h; - int c, temp_romset; + int c; LPTSTR lptsTemp; const char *stransi; UDACCEL accel; device_t *d; - temp_romset = machine_getromset_ex(temp_machine); lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_CONFIGURE_MACHINE); @@ -611,8 +604,8 @@ win_settings_machine_recalc_machine(HWND hdlg) h = GetDlgItem(hdlg, IDC_COMBO_CPU_TYPE); SendMessage(h, CB_RESETCONTENT, 0, 0); c = 0; - while (machines[romstomachine[temp_romset]].cpu[c].cpus != NULL && c < 4) { - stransi = machines[romstomachine[temp_romset]].cpu[c].name; + while (machines[temp_machine].cpu[c].cpus != NULL && c < 4) { + stransi = machines[temp_machine].cpu[c].name; mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); c++; @@ -626,11 +619,11 @@ win_settings_machine_recalc_machine(HWND hdlg) win_settings_machine_recalc_cpu_m(hdlg); h = GetDlgItem(hdlg, IDC_MEMSPIN); - SendMessage(h, UDM_SETRANGE, 0, (machines[romstomachine[temp_romset]].min_ram << 16) | machines[romstomachine[temp_romset]].max_ram); + SendMessage(h, UDM_SETRANGE, 0, (machines[temp_machine].min_ram << 16) | machines[temp_machine].max_ram); accel.nSec = 0; - accel.nInc = machines[romstomachine[temp_romset]].ram_granularity; + accel.nInc = machines[temp_machine].ram_granularity; SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); - if (!(machines[romstomachine[temp_romset]].flags & MACHINE_AT) || (machines[romstomachine[temp_romset]].ram_granularity >= 128)) { + if (!(machines[temp_machine].flags & MACHINE_AT) || (machines[temp_machine].ram_granularity >= 128)) { SendMessage(h, UDM_SETPOS, 0, temp_mem_size); h = GetDlgItem(hdlg, IDC_TEXT_MB); SendMessage(h, WM_SETTEXT, 0, win_get_string(IDS_2094)); @@ -661,18 +654,14 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); - for (c = 0; c < ROM_MAX; c++) - romstolist[c] = 0; c = d = 0; - while (machines[c].id != -1) { - if (romspresent[machines[c].id]) { + while (machine_get_internal_name_ex(c) != NULL) { + if (machine_available(c)) { stransi = (char *)machines[c].name; mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); machinetolist[c] = d; listtomachine[d] = c; - romstolist[machines[c].id] = d; - romstomachine[machines[c].id] = c; d++; } c++; @@ -848,7 +837,7 @@ recalc_vid_list(HWND hdlg) } if (!found_card) SendMessage(h, CB_SETCURSEL, 0, 0); - EnableWindow(h, machines[temp_machine].fixed_gfxcard ? FALSE : TRUE); + EnableWindow(h, (machines[temp_machine].flags & MACHINE_VIDEO_FIXED) ? FALSE : TRUE); h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); EnableWindow(h, (machines[temp_machine].flags & MACHINE_PCI) ? TRUE : FALSE); @@ -1343,7 +1332,7 @@ static BOOL CALLBACK win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND h; - int c, d, i; + int c, i; char *s; LPTSTR lptsTemp; @@ -1353,7 +1342,7 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) for (i = 0; i < 3; i++) { h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); - c = d = 0; + c = 0; while (1) { s = lpt_device_get_name(c); @@ -1367,22 +1356,18 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); } - if (!strcmp(temp_lpt_device_names[i], lpt_device_get_internal_name(c))) - d = c; - c++; } - SendMessage(h, CB_SETCURSEL, d, 0); + SendMessage(h, CB_SETCURSEL, temp_lpt_devices[i], 0); + + h=GetDlgItem(hdlg, IDC_CHECK_PARALLEL1 + i); + SendMessage(h, BM_SETCHECK, temp_lpt[i], 0); } - h=GetDlgItem(hdlg, IDC_CHECK_SERIAL1); - SendMessage(h, BM_SETCHECK, temp_serial[0], 0); - - h=GetDlgItem(hdlg, IDC_CHECK_SERIAL2); - SendMessage(h, BM_SETCHECK, temp_serial[1], 0); - - h=GetDlgItem(hdlg, IDC_CHECK_PARALLEL); - SendMessage(h, BM_SETCHECK, temp_lpt, 0); + for (i = 0; i < 2; i++) { + h=GetDlgItem(hdlg, IDC_CHECK_SERIAL1 + i); + SendMessage(h, BM_SETCHECK, temp_serial[i], 0); + } free(lptsTemp); @@ -1391,18 +1376,16 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) case WM_SAVESETTINGS: for (i = 0; i < 3; i++) { h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); - c = SendMessage(h, CB_GETCURSEL, 0, 0); - strcpy(temp_lpt_device_names[i], lpt_device_get_internal_name(c)); + temp_lpt_devices[i] = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_PARALLEL1 + i); + temp_lpt[i] = SendMessage(h, BM_GETCHECK, 0, 0); } - h = GetDlgItem(hdlg, IDC_CHECK_SERIAL1); - temp_serial[0] = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECK_SERIAL2); - temp_serial[1] = SendMessage(h, BM_GETCHECK, 0, 0); - - h = GetDlgItem(hdlg, IDC_CHECK_PARALLEL); - temp_lpt = SendMessage(h, BM_GETCHECK, 0, 0); + for (i = 0; i < 2; i++) { + h = GetDlgItem(hdlg, IDC_CHECK_SERIAL1 + i); + temp_serial[i] = SendMessage(h, BM_GETCHECK, 0, 0); + } default: return FALSE; @@ -3068,11 +3051,15 @@ hdd_add_file_open_error: max_spt = max_hpc = max_tracks = 0; break; case HDD_BUS_MFM: - max_spt = 17; + max_spt = 26; /* 17 for MFM, 26 for RLL. */ max_hpc = 15; max_tracks = 1023; break; case HDD_BUS_ESDI: + max_spt = 43; /* ESDI drives usually had 32 to 43 sectors per track. */ + max_hpc = 16; + max_tracks = 1023; + break; case HDD_BUS_XTA: max_spt = 63; max_hpc = 16; @@ -3470,6 +3457,7 @@ win_settings_cdrom_drives_recalc_list(HWND hwndList) lvI.iImage = 1; break; case CDROM_BUS_SCSI: + case CDROM_BUS_SCSI_CHINON: wsprintf(szText, plat_get_string(fsid), temp_cdrom[i].scsi_device_id); lvI.pszText = szText; lvI.iImage = 1; @@ -3732,6 +3720,7 @@ win_settings_cdrom_drives_update_item(HWND hwndList, int i) lvI.iImage = 1; break; case CDROM_BUS_SCSI: + case CDROM_BUS_SCSI_CHINON: wsprintf(szText, plat_get_string(fsid), temp_cdrom[i].scsi_device_id); lvI.pszText = szText; lvI.iImage = 1; @@ -3812,7 +3801,7 @@ cdrom_add_locations(HWND hdlg) lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); - for (i = CDROM_BUS_DISABLED; i <= CDROM_BUS_SCSI; i++) { + for (i = CDROM_BUS_DISABLED; i <= CDROM_BUS_SCSI_CHINON; i++) { if ((i == CDROM_BUS_DISABLED) || (i >= CDROM_BUS_ATAPI)) SendMessage(h, CB_ADDSTRING, 0, win_get_string(combo_id_to_string_id(i))); } @@ -3894,6 +3883,7 @@ static void cdrom_recalc_location_controls(HWND hdlg, int assign_id) SendMessage(h, CB_SETCURSEL, temp_cdrom[lv1_current_sel].ide_channel, 0); break; case CDROM_BUS_SCSI: /* SCSI */ + case CDROM_BUS_SCSI_CHINON: h = GetDlgItem(hdlg, IDT_1741); ShowWindow(h, SW_SHOW); EnableWindow(h, TRUE); @@ -4009,7 +3999,7 @@ cdrom_track(uint8_t id) { if (temp_cdrom[id].bus_type == CDROM_BUS_ATAPI) ide_tracking |= (2 << (temp_cdrom[id].ide_channel << 3)); - else if (temp_cdrom[id].bus_type == CDROM_BUS_SCSI) + else if (temp_cdrom[id].bus_type == CDROM_BUS_SCSI || temp_cdrom[id].bus_type == CDROM_BUS_SCSI_CHINON) scsi_tracking[temp_cdrom[id].scsi_device_id >> 3] |= (1 << (temp_cdrom[id].scsi_device_id & 0x07)); } @@ -4019,7 +4009,7 @@ cdrom_untrack(uint8_t id) { if (temp_cdrom[id].bus_type == CDROM_BUS_ATAPI) ide_tracking &= ~(2 << (temp_cdrom[id].ide_channel << 3)); - else if (temp_cdrom[id].bus_type == CDROM_BUS_SCSI) + else if (temp_cdrom[id].bus_type == CDROM_BUS_SCSI || temp_cdrom[id].bus_type == CDROM_BUS_SCSI_CHINON) scsi_tracking[temp_cdrom[id].scsi_device_id >> 3] &= ~(1 << (temp_cdrom[id].scsi_device_id & 0x07)); } @@ -4188,6 +4178,9 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam case CDROM_BUS_SCSI: b = 2; break; + case CDROM_BUS_SCSI_CHINON: + b = 3; + break; } SendMessage(h, CB_SETCURSEL, b, 0); @@ -4255,6 +4248,9 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam case CDROM_BUS_SCSI: b = 2; break; + case CDROM_BUS_SCSI_CHINON: + b = 3; + break; } SendMessage(h, CB_SETCURSEL, b, 0); @@ -4317,6 +4313,9 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam case 2: b2 = CDROM_BUS_SCSI; break; + case 3: + b2 = CDROM_BUS_SCSI_CHINON; + break; } if (b2 == temp_cdrom[lv1_current_sel].bus_type) break; diff --git a/src/win/win_stbar.c b/src/win/win_stbar.c index d2fbb2d00..f3a8b15e4 100644 --- a/src/win/win_stbar.c +++ b/src/win/win_stbar.c @@ -8,13 +8,13 @@ * * Implement the application's Status Bar. * - * Version: @(#)win_stbar.c 1.0.24 2018/10/28 + * Version: @(#)win_stbar.c 1.0.25 2019/03/15 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. */ #define UNICODE #define BITMAP WINDOWS_BITMAP @@ -33,6 +33,7 @@ #include "../cpu/cpu.h" #include "../device.h" #include "../machine/machine.h" +#include "../timer.h" #include "../disk/hdd.h" #include "../disk/hdc.h" #include "../floppy/fdd.h" @@ -190,6 +191,19 @@ StatusBarCreateZIPSubmenu(HMENU m, int id) } +void +ui_sb_timer_callback(int pane) +{ + sb_part_icons[pane] &= ~1; + + if (sb_part_icons && sb_part_icons[pane]) { + SendMessage(hwndSBAR, SB_SETICON, pane, + (LPARAM)hIcon[sb_part_icons[pane]]); + } +} + + + /* API */ /* API: update one of the icons after activity. */ void @@ -204,12 +218,13 @@ ui_sb_update_icon(int tag, int active) return; found = sb_map[tag]; - if (found != 0xff) { - sb_part_icons[found] &= ~1; - sb_part_icons[found] |= (uint8_t) active; + if ((found != 0xff) && ((sb_part_icons[found] ^ active) & 1) && active) { + sb_part_icons[found] |= 1; SendMessage(hwndSBAR, SB_SETICON, found, (LPARAM)hIcon[sb_part_icons[found]]); + + SetTimer(hwndMain, 0x8000 | found, 75, NULL); } } @@ -487,6 +502,9 @@ ui_sb_update_panes(void) int do_net; char *hdc_name; + if (!config_changed) + return; + if (sb_ready) { sb_ready = 0; } @@ -534,7 +552,7 @@ ui_sb_update_panes(void) !(hdint || !memcmp(hdc_name, "ide", 3))) continue; - if ((cdrom[i].bus_type == CDROM_BUS_SCSI) && + if ((cdrom[i].bus_type == CDROM_BUS_SCSI || cdrom[i].bus_type == CDROM_BUS_SCSI_CHINON) && (scsi_card_current == 0)) continue; if (cdrom[i].bus_type != 0) @@ -552,7 +570,7 @@ ui_sb_update_panes(void) if (zip_drives[i].bus_type != 0) sb_parts++; } - if (c_mfm && (hdint || !memcmp(hdc_name, "mfm", 3))) { + if (c_mfm && (hdint || !memcmp(hdc_name, "st506", 5))) { /* MFM drives, and MFM or Internal controller. */ sb_parts++; } @@ -597,7 +615,7 @@ ui_sb_update_panes(void) !(hdint || !memcmp(hdc_name, "ide", 3))) { continue; } - if ((cdrom[i].bus_type == CDROM_BUS_SCSI) && (scsi_card_current == 0)) + if ((cdrom[i].bus_type == CDROM_BUS_SCSI || cdrom[i].bus_type == CDROM_BUS_SCSI_CHINON) && (scsi_card_current == 0)) continue; if (cdrom[i].bus_type != 0) { edge += SB_ICON_WIDTH; @@ -622,7 +640,7 @@ ui_sb_update_panes(void) sb_parts++; } } - if (c_mfm && (hdint || !memcmp(hdc_name, "mfm", 3))) { + if (c_mfm && (hdint || !memcmp(hdc_name, "st506", 5))) { edge += SB_ICON_WIDTH; iStatusWidths[sb_parts] = edge; sb_part_meanings[sb_parts] = SB_HDD | HDD_BUS_MFM; diff --git a/src/win/win_ui.c b/src/win/win_ui.c index dd1dfc43c..910865b7c 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -8,7 +8,7 @@ * * user Interface module for WinAPI on Windows. * - * Version: @(#)win_ui.c 1.0.40 2019/7/28 + * Version: @(#)win_ui.c 1.0.39 2019/3/20 * * Authors: Sarah Walker, * Miran Grca, @@ -51,7 +51,8 @@ HWND hwndMain, /* application main window */ HMENU menuMain; /* application main menu */ HICON hIcon[256]; /* icon data loaded from resources */ RECT oldclip; /* mouse rect */ -int sbar_height = 23; /* statusbar height */ +int sbar_height = 23; /* statusbar height */ +int minimized = 0; int infocus = 1; int rctrl_is_lalt = 0; int user_resize = 0; @@ -348,6 +349,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); GetWindowRect(hwnd, &rect); + /* Main Window. */ if (GetSystemMetrics(SM_CXPADDEDBORDER) == 0) { /* For platforms that subsystem version < 6.0 (default on mingw/msys2) */ @@ -428,9 +430,8 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_VID_FS_FULL: case IDM_VID_FS_43: - case IDM_VID_FS_SQ: + case IDM_VID_FS_KEEPRATIO: case IDM_VID_FS_INT: - case IDM_VID_FS_KEEPRATIO: CheckMenuItem(hmenu, IDM_VID_FS_FULL+video_fullscreen_scale, MF_UNCHECKED); video_fullscreen_scale = LOWORD(wParam) - IDM_VID_FS_FULL; CheckMenuItem(hmenu, IDM_VID_FS_FULL+video_fullscreen_scale, MF_CHECKED); @@ -569,7 +570,18 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); temp_x = (lParam & 0xFFFF); - temp_y = (lParam >> 16) - sbar_height; + temp_y = (lParam >> 16); + + if ((temp_x <= 0) || (temp_y <= 0)) { + minimized = 1; + break; + } else if (minimized == 1) { + minimized = 0; + video_force_resize_set(1); + } + + plat_vidapi_enable(0); + temp_y -= sbar_height; if (temp_x < 1) temp_x = 1; if (temp_y < 1) @@ -606,6 +618,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) window_h = rect.bottom - rect.top; save_window_pos = 1; } + plat_vidapi_enable(1); config_save(); break; @@ -622,9 +635,10 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_TIMER: - if (wParam == TIMER_1SEC) { + if (wParam == TIMER_1SEC) pc_onesec(); - } + else if ((wParam >= 0x8000) && (wParam <= 0x80ff)) + ui_sb_timer_callback(wParam & 0xff); break; case WM_RESETD3D: @@ -852,11 +866,11 @@ ui_init(int nCmdShow) /* Create the status bar window. */ StatusBarCreate(hwndMain, IDC_STATUS, hinstance); - /* Get the actual height of the statusbar, - * since that is not something we can change. - */ - GetWindowRect(hwndSBAR, &sbar_rect); - sbar_height = sbar_rect.bottom - sbar_rect.top; + /* Get the actual height of the statusbar, + * since that is not something we can change. + */ + GetWindowRect(hwndSBAR, &sbar_rect); + sbar_height = sbar_rect.bottom - sbar_rect.top; /* * Before we can create the Render window, we first have @@ -1031,7 +1045,7 @@ plat_resize(int x, int y) SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); GetWindowRect(hwndMain, &r); - + if (GetSystemMetrics(SM_CXPADDEDBORDER) == 0) { /* For platforms that subsystem version < 6.0 (gcc on mingw/msys2) */ /* In this case, border sizes are different between resizable and non-resizable window */