--- /dev/null
+/*
+ * 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.
+ */
+
+
+#include "dosbox.h"
+
+#if (C_DYNAMIC_X86)
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#if defined (WIN32)
+#include <windows.h>
+#include <winbase.h>
+#endif
+
+#if (C_HAVE_MPROTECT)
+#include <sys/mman.h>
+
+#include <limits.h>
+#ifndef PAGESIZE
+#define PAGESIZE 4096
+#endif
+#endif /* C_HAVE_MPROTECT */
+
+#include "callback.h"
+#include "regs.h"
+#include "mem.h"
+#include "cpu.h"
+#include "debug.h"
+#include "paging.h"
+#include "inout.h"
+#include "fpu.h"
+
+#define CACHE_MAXSIZE (4096*3)
+#define CACHE_TOTAL (1024*1024*8)
+#define CACHE_PAGES (512)
+#define CACHE_BLOCKS (64*1024)
+#define CACHE_ALIGN (16)
+#define DYN_HASH_SHIFT (4)
+#define DYN_PAGE_HASH (4096>>DYN_HASH_SHIFT)
+#define DYN_LINKS (16)
+
+//#define DYN_LOG 1 //Turn logging on
+
+
+#if C_FPU
+#define CPU_FPU 1 //Enable FPU escape instructions
+#endif
+
+enum {
+ G_EAX,G_ECX,G_EDX,G_EBX,
+ G_ESP,G_EBP,G_ESI,G_EDI,
+ G_ES,G_CS,G_SS,G_DS,G_FS,G_GS,
+ G_FLAGS,G_NEWESP,G_EIP,
+ G_EA,G_STACK,G_CYCLES,
+ G_TMPB,G_TMPW,G_SHIFT,
+ G_EXIT,
+ G_MAX,
+};
+
+enum SingleOps {
+ SOP_INC,SOP_DEC,
+ SOP_NOT,SOP_NEG,
+};
+
+enum DualOps {
+ DOP_ADD,DOP_ADC,
+ DOP_SUB,DOP_SBB,
+ DOP_CMP,DOP_XOR,
+ DOP_AND,DOP_OR,
+ DOP_TEST,
+ DOP_MOV,
+ DOP_XCHG,
+};
+
+enum ShiftOps {
+ SHIFT_ROL,SHIFT_ROR,
+ SHIFT_RCL,SHIFT_RCR,
+ SHIFT_SHL,SHIFT_SHR,
+ SHIFT_SAL,SHIFT_SAR,
+};
+
+enum BranchTypes {
+ BR_O,BR_NO,BR_B,BR_NB,
+ BR_Z,BR_NZ,BR_BE,BR_NBE,
+ BR_S,BR_NS,BR_P,BR_NP,
+ BR_L,BR_NL,BR_LE,BR_NLE
+};
+
+
+enum BlockReturn {
+ BR_Normal=0,
+ BR_Cycles,
+ BR_Link1,BR_Link2,
+ BR_Opcode,
+#if (C_DEBUG)
+ BR_OpcodeFull,
+#endif
+ BR_Iret,
+ BR_CallBack,
+ BR_SMCBlock
+};
+
+#define SMC_CURRENT_BLOCK 0xffff
+
+
+#define DYNFLG_HAS16 0x1 //Would like 8-bit host reg support
+#define DYNFLG_HAS8 0x2 //Would like 16-bit host reg support
+#define DYNFLG_LOAD 0x4 //Load value when accessed
+#define DYNFLG_SAVE 0x8 //Needs to be saved back at the end of block
+#define DYNFLG_CHANGED 0x10 //Value is in a register and changed from load
+#define DYNFLG_ACTIVE 0x20 //Register has an active value
+
+class GenReg;
+class CodePageHandler;
+
+struct DynReg {
+ Bitu flags;
+ GenReg * genreg;
+ void * data;
+};
+
+enum DynAccess {
+ DA_d,DA_w,
+ DA_bh,DA_bl
+};
+
+enum ByteCombo {
+ BC_ll,BC_lh,
+ BC_hl,BC_hh,
+};
+
+static DynReg DynRegs[G_MAX];
+#define DREG(_WHICH_) &DynRegs[G_ ## _WHICH_ ]
+
+static struct {
+ Bitu ea,tmpb,tmpd,stack,shift,newesp;
+} extra_regs;
+
+static void IllegalOption(const char* msg) {
+ E_Exit("DynCore: illegal option in %s",msg);
+}
+
+#include "core_dyn_x86/cache.h"
+
+static struct {
+ Bitu callback;
+ Bit32u readdata;
+} core_dyn;
+
+static struct {
+ Bit32u state[32];
+ FPU_P_Reg temp,temp2;
+ Bit32u dh_fpu_enabled;
+ Bit32u state_used;
+ Bit32u cw,host_cw;
+ Bit8u temp_state[128];
+} dyn_dh_fpu;
+
+
+#include "core_dyn_x86/risc_x86.h"
+
+struct DynState {
+ DynReg regs[G_MAX];
+};
+
+static void dyn_flags_host_to_gen(void) {
+ gen_dop_word(DOP_MOV,true,DREG(EXIT),DREG(FLAGS));
+ gen_dop_word_imm(DOP_AND,true,DREG(EXIT),FMASK_TEST);
+ gen_load_flags(DREG(EXIT));
+ gen_releasereg(DREG(EXIT));
+ gen_releasereg(DREG(FLAGS));
+}
+
+static void dyn_flags_gen_to_host(void) {
+ gen_save_flags(DREG(EXIT));
+ gen_dop_word_imm(DOP_AND,true,DREG(EXIT),FMASK_TEST);
+ gen_dop_word_imm(DOP_AND,true,DREG(FLAGS),~FMASK_TEST);
+ gen_dop_word(DOP_OR,true,DREG(FLAGS),DREG(EXIT)); //flags are marked for save
+ gen_releasereg(DREG(EXIT));
+ gen_releasereg(DREG(FLAGS));
+}
+
+static void dyn_savestate(DynState * state) {
+ for (Bitu i=0;i<G_MAX;i++) {
+ state->regs[i].flags=DynRegs[i].flags;
+ state->regs[i].genreg=DynRegs[i].genreg;
+ }
+}
+
+static void dyn_loadstate(DynState * state) {
+ for (Bitu i=0;i<G_MAX;i++) {
+ gen_setupreg(&DynRegs[i],&state->regs[i]);
+ }
+}
+
+static void dyn_synchstate(DynState * state) {
+ for (Bitu i=0;i<G_MAX;i++) {
+ gen_synchreg(&DynRegs[i],&state->regs[i]);
+ }
+}
+
+static void dyn_saveregister(DynReg * src_reg, DynReg * dst_reg) {
+ dst_reg->flags=src_reg->flags;
+ dst_reg->genreg=src_reg->genreg;
+}
+
+static void dyn_restoreregister(DynReg * src_reg, DynReg * dst_reg) {
+ dst_reg->flags=src_reg->flags;
+ dst_reg->genreg=src_reg->genreg;
+ dst_reg->genreg->dynreg=dst_reg; // necessary when register has been released
+}
+
+#include "core_dyn_x86/decoder.h"
+
+#if defined (_MSC_VER)
+#define DH_FPU_SAVE_REINIT \
+{ \
+ __asm { \
+ __asm fnsave dyn_dh_fpu.state[0] \
+ } \
+ dyn_dh_fpu.state_used=false; \
+ dyn_dh_fpu.state[0]|=0x3f; \
+}
+#else
+#define DH_FPU_SAVE_REINIT \
+{ \
+ __asm__ volatile ( \
+ "fnsave %0 \n" \
+ : "=m" (dyn_dh_fpu.state[0]) \
+ : \
+ : "memory" \
+ ); \
+ dyn_dh_fpu.state_used=false; \
+ dyn_dh_fpu.state[0]|=0x3f; \
+}
+#endif
+
+
+Bits CPU_Core_Dyn_X86_Run(void) {
+ /* Determine the linear address of CS:EIP */
+restart_core:
+ PhysPt ip_point=SegPhys(cs)+reg_eip;
+#if C_DEBUG
+#if C_HEAVY_DEBUG
+ if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+#endif
+#endif
+ CodePageHandler * chandler=0;
+ if (GCC_UNLIKELY(MakeCodePage(ip_point,chandler))) {
+ CPU_Exception(cpu.exception.which,cpu.exception.error);
+ goto restart_core;
+ }
+ if (!chandler) {
+ if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
+ return CPU_Core_Normal_Run();
+ }
+ /* Find correct Dynamic Block to run */
+ CacheBlock * block=chandler->FindCacheBlock(ip_point&4095);
+ if (!block) {
+ if (!chandler->invalidation_map || (chandler->invalidation_map[ip_point&4095]<4)) {
+ block=CreateCacheBlock(chandler,ip_point,32);
+ } else {
+ Bitu old_cycles=CPU_Cycles;
+ CPU_Cycles=1;
+ Bits nc_retcode=CPU_Core_Normal_Run();
+ if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
+ if (!nc_retcode) {
+ CPU_Cycles=old_cycles-1;
+ goto restart_core;
+ }
+ CPU_CycleLeft+=old_cycles;
+ return nc_retcode;
+ }
+ }
+run_block:
+ cache.block.running=0;
+ BlockReturn ret=gen_runcode(block->cache.start);
+ switch (ret) {
+ case BR_Iret:
+#if C_DEBUG
+#if C_HEAVY_DEBUG
+ if (DEBUG_HeavyIsBreakpoint()) {
+ if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
+ return debugCallback;
+ }
+#endif
+#endif
+ if (!GETFLAG(TF)) {
+ if (GETFLAG(IF) && PIC_IRQCheck) {
+ if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
+ return CBRET_NONE;
+ }
+ goto restart_core;
+ }
+ cpudecoder=CPU_Core_Dyn_X86_Trap_Run;
+ if (!dyn_dh_fpu.state_used) return CBRET_NONE;
+ DH_FPU_SAVE_REINIT
+ return CBRET_NONE;
+ case BR_Normal:
+ /* Maybe check if we staying in the same page? */
+#if C_DEBUG
+#if C_HEAVY_DEBUG
+ if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+#endif
+#endif
+ goto restart_core;
+ case BR_Cycles:
+#if C_DEBUG
+#if C_HEAVY_DEBUG
+ if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+#endif
+#endif
+ if (!dyn_dh_fpu.state_used) return CBRET_NONE;
+ DH_FPU_SAVE_REINIT
+ return CBRET_NONE;
+ case BR_CallBack:
+ if (!dyn_dh_fpu.state_used) return core_dyn.callback;
+ DH_FPU_SAVE_REINIT
+ return core_dyn.callback;
+ case BR_SMCBlock:
+// LOG_MSG("selfmodification of running block at %x:%x",SegValue(cs),reg_eip);
+ cpu.exception.which=0;
+ // fallthrough, let the normal core handle the block-modifying instruction
+ case BR_Opcode:
+ CPU_CycleLeft+=CPU_Cycles;
+ CPU_Cycles=1;
+ if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
+ return CPU_Core_Normal_Run();
+#if (C_DEBUG)
+ case BR_OpcodeFull:
+ CPU_CycleLeft+=CPU_Cycles;
+ CPU_Cycles=1;
+ if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
+ return CPU_Core_Full_Run();
+#endif
+ case BR_Link1:
+ case BR_Link2:
+ {
+ Bitu temp_ip=SegPhys(cs)+reg_eip;
+ CodePageHandler * temp_handler=(CodePageHandler *)get_tlb_readhandler(temp_ip);
+ if (temp_handler->flags & PFLAG_HASCODE) {
+ block=temp_handler->FindCacheBlock(temp_ip & 4095);
+ if (!block) goto restart_core;
+ cache.block.running->LinkTo(ret==BR_Link2,block);
+ goto run_block;
+ }
+ }
+ goto restart_core;
+ }
+ if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
+ return CBRET_NONE;
+}
+
+Bits CPU_Core_Dyn_X86_Trap_Run(void) {
+ Bits oldCycles = CPU_Cycles;
+ CPU_Cycles = 1;
+ cpu.trap_skip = false;
+
+ Bits ret=CPU_Core_Normal_Run();
+ if (!cpu.trap_skip) CPU_HW_Interrupt(1);
+ CPU_Cycles = oldCycles-1;
+ cpudecoder = &CPU_Core_Dyn_X86_Run;
+
+ return ret;
+}
+
+void CPU_Core_Dyn_X86_Init(void) {
+ Bits i;
+ /* Setup the global registers and their flags */
+ for (i=0;i<G_MAX;i++) DynRegs[i].genreg=0;
+ DynRegs[G_EAX].data=®_eax;
+ DynRegs[G_EAX].flags=DYNFLG_HAS8|DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
+ DynRegs[G_ECX].data=®_ecx;
+ DynRegs[G_ECX].flags=DYNFLG_HAS8|DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
+ DynRegs[G_EDX].data=®_edx;
+ DynRegs[G_EDX].flags=DYNFLG_HAS8|DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
+ DynRegs[G_EBX].data=®_ebx;
+ DynRegs[G_EBX].flags=DYNFLG_HAS8|DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
+
+ DynRegs[G_EBP].data=®_ebp;
+ DynRegs[G_EBP].flags=DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
+ DynRegs[G_ESP].data=®_esp;
+ DynRegs[G_ESP].flags=DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
+ DynRegs[G_EDI].data=®_edi;
+ DynRegs[G_EDI].flags=DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
+ DynRegs[G_ESI].data=®_esi;
+ DynRegs[G_ESI].flags=DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
+
+ DynRegs[G_ES].data=&Segs.phys[es];
+ DynRegs[G_ES].flags=DYNFLG_LOAD|DYNFLG_SAVE;
+ DynRegs[G_CS].data=&Segs.phys[cs];
+ DynRegs[G_CS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
+ DynRegs[G_SS].data=&Segs.phys[ss];
+ DynRegs[G_SS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
+ DynRegs[G_DS].data=&Segs.phys[ds];
+ DynRegs[G_DS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
+ DynRegs[G_FS].data=&Segs.phys[fs];
+ DynRegs[G_FS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
+ DynRegs[G_GS].data=&Segs.phys[gs];
+ DynRegs[G_GS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
+
+ DynRegs[G_FLAGS].data=®_flags;
+ DynRegs[G_FLAGS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
+
+ DynRegs[G_NEWESP].data=&extra_regs.newesp;
+ DynRegs[G_NEWESP].flags=0;
+
+ DynRegs[G_EIP].data=®_eip;
+ DynRegs[G_EIP].flags=DYNFLG_LOAD|DYNFLG_SAVE;
+
+ DynRegs[G_EA].data=&extra_regs.ea;
+ DynRegs[G_EA].flags=0;
+ DynRegs[G_STACK].data=&extra_regs.stack;
+ DynRegs[G_STACK].flags=0;
+ DynRegs[G_CYCLES].data=&CPU_Cycles;
+ DynRegs[G_CYCLES].flags=DYNFLG_LOAD|DYNFLG_SAVE;
+ DynRegs[G_TMPB].data=&extra_regs.tmpb;
+ DynRegs[G_TMPB].flags=DYNFLG_HAS8|DYNFLG_HAS16;
+ DynRegs[G_TMPW].data=&extra_regs.tmpd;
+ DynRegs[G_TMPW].flags=DYNFLG_HAS16;
+ DynRegs[G_SHIFT].data=&extra_regs.shift;
+ DynRegs[G_SHIFT].flags=DYNFLG_HAS8|DYNFLG_HAS16;
+ DynRegs[G_EXIT].data=0;
+ DynRegs[G_EXIT].flags=DYNFLG_HAS16;
+ /* Init the generator */
+ gen_init();
+
+ /* Init the fpu state */
+ dyn_dh_fpu.dh_fpu_enabled=true;
+ dyn_dh_fpu.state_used=false;
+ dyn_dh_fpu.cw=0x37f;
+#if defined (_MSC_VER)
+ __asm {
+ __asm finit
+ __asm fsave dyn_dh_fpu.state[0]
+ __asm fstcw dyn_dh_fpu.host_cw
+ }
+#else
+ __asm__ volatile (
+ "finit \n"
+ "fsave %0 \n"
+ "fstcw %1 \n"
+ : "=m" (dyn_dh_fpu.state[0]), "=m" (dyn_dh_fpu.host_cw)
+ :
+ : "memory"
+ );
+#endif
+
+ return;
+}
+
+void CPU_Core_Dyn_X86_Cache_Init(bool enable_cache) {
+ /* Initialize code cache and dynamic blocks */
+ cache_init(enable_cache);
+}
+
+void CPU_Core_Dyn_X86_Cache_Close(void) {
+ cache_close();
+}
+
+void CPU_Core_Dyn_X86_Cache_Reset(void) {
+ cache_reset();
+}
+
+void CPU_Core_Dyn_X86_SetFPUMode(bool dh_fpu) {
+ dyn_dh_fpu.dh_fpu_enabled=dh_fpu;
+}
+
+Bit32u fpu_state[32];
+
+void CPU_Core_Dyn_X86_SaveDHFPUState(void) {
+ if (dyn_dh_fpu.dh_fpu_enabled) {
+ if (dyn_dh_fpu.state_used!=0) {
+#if defined (_MSC_VER)
+ __asm {
+ __asm fsave fpu_state[0]
+ __asm finit
+ }
+#else
+ __asm__ volatile (
+ "fsave %0 \n"
+ "finit \n"
+ : "=m" (fpu_state[0])
+ :
+ : "memory"
+ );
+#endif
+ }
+ }
+}
+
+void CPU_Core_Dyn_X86_RestoreDHFPUState(void) {
+ if (dyn_dh_fpu.dh_fpu_enabled) {
+ if (dyn_dh_fpu.state_used!=0) {
+#if defined (_MSC_VER)
+ __asm {
+ __asm frstor fpu_state[0]
+ }
+#else
+ __asm__ volatile (
+ "frstor %0 \n"
+ :
+ : "m" (fpu_state[0])
+ :
+ );
+#endif
+ }
+ }
+}
+
+#else
+
+void CPU_Core_Dyn_X86_SaveDHFPUState(void) {
+}
+
+void CPU_Core_Dyn_X86_RestoreDHFPUState(void) {
+}
+
+#endif
--- /dev/null
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# src/cpu/core_dyn_x86/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/dosbox
+pkgincludedir = $(includedir)/dosbox
+pkglibdir = $(libdir)/dosbox
+pkglibexecdir = $(libexecdir)/dosbox
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = src/cpu/core_dyn_x86
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = aclocal-1.16
+ALSA_CFLAGS =
+ALSA_LIBS = -lasound -lm -ldl -lpthread
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+AUTOCONF = autoconf
+AUTOHEADER = autoheader
+AUTOMAKE = automake-1.16
+AWK = gawk
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS = -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
+CXX = g++
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+ECHO_C =
+ECHO_N = -n
+ECHO_T =
+EGREP = /bin/grep -E
+EXEEXT =
+GREP = /bin/grep
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LDFLAGS =
+LIBOBJS =
+LIBS = -lasound -lm -ldl -lpthread -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL -lXfont2 -lXi -lpng -lz -lX11 -lGL
+LTLIBOBJS =
+MAKEINFO = makeinfo
+MKDIR_P = /bin/mkdir -p
+OBJEXT = o
+PACKAGE = dosbox
+PACKAGE_BUGREPORT =
+PACKAGE_NAME = dosbox
+PACKAGE_STRING = dosbox 0.74
+PACKAGE_TARNAME = dosbox
+PACKAGE_URL =
+PACKAGE_VERSION = 0.74
+PATH_SEPARATOR = :
+RANLIB = ranlib
+SDL_CFLAGS = -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
+SDL_CONFIG = /usr/local/bin/sdl-config
+SDL_LIBS = -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL -lXfont2 -lXi -lpthread
+SET_MAKE =
+SHELL = /bin/bash
+STRIP =
+VERSION = 0.74
+WINDRES = :
+abs_builddir = /home/whatisthis/src/DOSVAXJ3/src/cpu/core_dyn_x86
+abs_srcdir = /home/whatisthis/src/DOSVAXJ3/src/cpu/core_dyn_x86
+abs_top_builddir = /home/whatisthis/src/DOSVAXJ3
+abs_top_srcdir = /home/whatisthis/src/DOSVAXJ3
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = $${TAR-tar} chof - "$$tardir"
+am__untar = $${TAR-tar} xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias =
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = x86_64-pc-linux-gnu
+host_alias =
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/whatisthis/src/DOSVAXJ3/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+runstatedir = ${localstatedir}/run
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target_alias =
+top_build_prefix = ../../../
+top_builddir = ../../..
+top_srcdir = ../../..
+noinst_HEADERS = cache.h helpers.h decoder.h risc_x86.h string.h \
+ dyn_fpu.h dyn_fpu_dh.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/cpu/core_dyn_x86/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/cpu/core_dyn_x86/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+noinst_HEADERS = cache.h helpers.h decoder.h risc_x86.h string.h \
+ dyn_fpu.h dyn_fpu_dh.h
\ No newline at end of file
--- /dev/null
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/cpu/core_dyn_x86
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WINDRES = @WINDRES@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = cache.h helpers.h decoder.h risc_x86.h string.h \
+ dyn_fpu.h dyn_fpu_dh.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/cpu/core_dyn_x86/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/cpu/core_dyn_x86/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+/*
+ * 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.
+ */
+
+
+class CacheBlock {
+public:
+ void Clear(void);
+ void LinkTo(Bitu index,CacheBlock * toblock) {
+ assert(toblock);
+ link[index].to=toblock;
+ link[index].next=toblock->link[index].from;
+ toblock->link[index].from=this;
+ }
+ struct {
+ Bit16u start,end; //Where the page is the original code
+ CodePageHandler * handler; //Page containing this code
+ } page;
+ struct {
+ Bit8u * start; //Where in the cache are we
+ Bitu size;
+ CacheBlock * next;
+ Bit8u * wmapmask;
+ Bit16u maskstart;
+ Bit16u masklen;
+ } cache;
+ struct {
+ Bitu index;
+ CacheBlock * next;
+ } hash;
+ struct {
+ CacheBlock * to;
+ CacheBlock * next;
+ CacheBlock * from;
+ } link[2];
+ CacheBlock * crossblock;
+};
+
+static struct {
+ struct {
+ CacheBlock * first;
+ CacheBlock * active;
+ CacheBlock * free;
+ CacheBlock * running;
+ } block;
+ Bit8u * pos;
+ CodePageHandler * free_pages;
+ CodePageHandler * used_pages;
+ CodePageHandler * last_page;
+} cache;
+
+static CacheBlock link_blocks[2];
+
+class CodePageHandler : public PageHandler {
+public:
+ CodePageHandler() {
+ invalidation_map=NULL;
+ }
+ void SetupAt(Bitu _phys_page,PageHandler * _old_pagehandler) {
+ phys_page=_phys_page;
+ old_pagehandler=_old_pagehandler;
+ flags=old_pagehandler->flags|PFLAG_HASCODE;
+ flags&=~PFLAG_WRITEABLE;
+ active_blocks=0;
+ active_count=16;
+ memset(&hash_map,0,sizeof(hash_map));
+ memset(&write_map,0,sizeof(write_map));
+ if (invalidation_map!=NULL) {
+ free(invalidation_map);
+ invalidation_map=NULL;
+ }
+ }
+ bool InvalidateRange(Bitu start,Bitu end) {
+ Bits index=1+(end>>DYN_HASH_SHIFT);
+ bool is_current_block=false;
+ Bit32u ip_point=SegPhys(cs)+reg_eip;
+ ip_point=(PAGING_GetPhysicalPage(ip_point)-(phys_page<<12))+(ip_point&0xfff);
+ while (index>=0) {
+ Bitu map=0;
+ for (Bitu count=start;count<=end;count++) map+=write_map[count];
+ if (!map) return is_current_block;
+ CacheBlock * block=hash_map[index];
+ while (block) {
+ CacheBlock * nextblock=block->hash.next;
+ if (start<=block->page.end && end>=block->page.start) {
+ if (ip_point<=block->page.end && ip_point>=block->page.start) is_current_block=true;
+ block->Clear();
+ }
+ block=nextblock;
+ }
+ index--;
+ }
+ return is_current_block;
+ }
+ void writeb(PhysPt addr,Bitu val){
+ if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return;
+ if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) {
+ E_Exit("wb:non-readable code page found that is no ROM page");
+ }
+ addr&=4095;
+ if (host_readb(hostmem+addr)==(Bit8u)val) return;
+ host_writeb(hostmem+addr,val);
+ if (!*(Bit8u*)&write_map[addr]) {
+ if (active_blocks) return;
+ active_count--;
+ if (!active_count) Release();
+ return;
+ } else if (!invalidation_map) {
+ invalidation_map=(Bit8u*)malloc(4096);
+ memset(invalidation_map,0,4096);
+ }
+ invalidation_map[addr]++;
+ InvalidateRange(addr,addr);
+ }
+ void writew(PhysPt addr,Bitu val){
+ if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return;
+ if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) {
+ E_Exit("ww:non-readable code page found that is no ROM page");
+ }
+ addr&=4095;
+ if (host_readw(hostmem+addr)==(Bit16u)val) return;
+ host_writew(hostmem+addr,val);
+ if (!*(Bit16u*)&write_map[addr]) {
+ if (active_blocks) return;
+ active_count--;
+ if (!active_count) Release();
+ return;
+ } else if (!invalidation_map) {
+ invalidation_map=(Bit8u*)malloc(4096);
+ memset(invalidation_map,0,4096);
+ }
+ (*(Bit16u*)&invalidation_map[addr])+=0x101;
+ InvalidateRange(addr,addr+1);
+ }
+ void writed(PhysPt addr,Bitu val){
+ if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return;
+ if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) {
+ E_Exit("wd:non-readable code page found that is no ROM page");
+ }
+ addr&=4095;
+ if (host_readd(hostmem+addr)==(Bit32u)val) return;
+ host_writed(hostmem+addr,val);
+ if (!*(Bit32u*)&write_map[addr]) {
+ if (active_blocks) return;
+ active_count--;
+ if (!active_count) Release();
+ return;
+ } else if (!invalidation_map) {
+ invalidation_map=(Bit8u*)malloc(4096);
+ memset(invalidation_map,0,4096);
+ }
+ (*(Bit32u*)&invalidation_map[addr])+=0x1010101;
+ InvalidateRange(addr,addr+3);
+ }
+ bool writeb_checked(PhysPt addr,Bitu val) {
+ if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return false;
+ if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) {
+ E_Exit("cb:non-readable code page found that is no ROM page");
+ }
+ addr&=4095;
+ if (host_readb(hostmem+addr)==(Bit8u)val) return false;
+ if (!*(Bit8u*)&write_map[addr]) {
+ if (!active_blocks) {
+ active_count--;
+ if (!active_count) Release();
+ }
+ } else {
+ if (!invalidation_map) {
+ invalidation_map=(Bit8u*)malloc(4096);
+ memset(invalidation_map,0,4096);
+ }
+ invalidation_map[addr]++;
+ if (InvalidateRange(addr,addr)) {
+ cpu.exception.which=SMC_CURRENT_BLOCK;
+ return true;
+ }
+ }
+ host_writeb(hostmem+addr,val);
+ return false;
+ }
+ bool writew_checked(PhysPt addr,Bitu val) {
+ if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return false;
+ if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) {
+ E_Exit("cw:non-readable code page found that is no ROM page");
+ }
+ addr&=4095;
+ if (host_readw(hostmem+addr)==(Bit16u)val) return false;
+ if (!*(Bit16u*)&write_map[addr]) {
+ if (!active_blocks) {
+ active_count--;
+ if (!active_count) Release();
+ }
+ } else {
+ if (!invalidation_map) {
+ invalidation_map=(Bit8u*)malloc(4096);
+ memset(invalidation_map,0,4096);
+ }
+ (*(Bit16u*)&invalidation_map[addr])+=0x101;
+ if (InvalidateRange(addr,addr+1)) {
+ cpu.exception.which=SMC_CURRENT_BLOCK;
+ return true;
+ }
+ }
+ host_writew(hostmem+addr,val);
+ return false;
+ }
+ bool writed_checked(PhysPt addr,Bitu val) {
+ if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return false;
+ if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) {
+ E_Exit("cd:non-readable code page found that is no ROM page");
+ }
+ addr&=4095;
+ if (host_readd(hostmem+addr)==(Bit32u)val) return false;
+ if (!*(Bit32u*)&write_map[addr]) {
+ if (!active_blocks) {
+ active_count--;
+ if (!active_count) Release();
+ }
+ } else {
+ if (!invalidation_map) {
+ invalidation_map=(Bit8u*)malloc(4096);
+ memset(invalidation_map,0,4096);
+ }
+ (*(Bit32u*)&invalidation_map[addr])+=0x1010101;
+ if (InvalidateRange(addr,addr+3)) {
+ cpu.exception.which=SMC_CURRENT_BLOCK;
+ return true;
+ }
+ }
+ host_writed(hostmem+addr,val);
+ return false;
+ }
+ void AddCacheBlock(CacheBlock * block) {
+ Bitu index=1+(block->page.start>>DYN_HASH_SHIFT);
+ block->hash.next=hash_map[index];
+ block->hash.index=index;
+ hash_map[index]=block;
+ block->page.handler=this;
+ active_blocks++;
+ }
+ void AddCrossBlock(CacheBlock * block) {
+ block->hash.next=hash_map[0];
+ block->hash.index=0;
+ hash_map[0]=block;
+ block->page.handler=this;
+ active_blocks++;
+ }
+ void DelCacheBlock(CacheBlock * block) {
+ active_blocks--;
+ active_count=16;
+ CacheBlock * * where=&hash_map[block->hash.index];
+ while (*where!=block) {
+ where=&((*where)->hash.next);
+ //Will crash if a block isn't found, which should never happen.
+ }
+ *where=block->hash.next;
+ if (GCC_UNLIKELY(block->cache.wmapmask!=NULL)) {
+ for (Bitu i=block->page.start;i<block->cache.maskstart;i++) {
+ if (write_map[i]) write_map[i]--;
+ }
+ Bitu maskct=0;
+ for (Bitu i=block->cache.maskstart;i<=block->page.end;i++,maskct++) {
+ if (write_map[i]) {
+ if ((maskct>=block->cache.masklen) || (!block->cache.wmapmask[maskct])) write_map[i]--;
+ }
+ }
+ free(block->cache.wmapmask);
+ block->cache.wmapmask=NULL;
+ } else {
+ for (Bitu i=block->page.start;i<=block->page.end;i++) {
+ if (write_map[i]) write_map[i]--;
+ }
+ }
+ }
+ void Release(void) {
+ MEM_SetPageHandler(phys_page,1,old_pagehandler);
+ PAGING_ClearTLB();
+ if (prev) prev->next=next;
+ else cache.used_pages=next;
+ if (next) next->prev=prev;
+ else cache.last_page=prev;
+ next=cache.free_pages;
+ cache.free_pages=this;
+ prev=0;
+ }
+ void ClearRelease(void) {
+ for (Bitu index=0;index<(1+DYN_PAGE_HASH);index++) {
+ CacheBlock * block=hash_map[index];
+ while (block) {
+ CacheBlock * nextblock=block->hash.next;
+ block->page.handler=0; //No need, full clear
+ block->Clear();
+ block=nextblock;
+ }
+ }
+ Release();
+ }
+ CacheBlock * FindCacheBlock(Bitu start) {
+ CacheBlock * block=hash_map[1+(start>>DYN_HASH_SHIFT)];
+ while (block) {
+ if (block->page.start==start) return block;
+ block=block->hash.next;
+ }
+ return 0;
+ }
+ HostPt GetHostReadPt(Bitu phys_page) {
+ hostmem=old_pagehandler->GetHostReadPt(phys_page);
+ return hostmem;
+ }
+ HostPt GetHostWritePt(Bitu phys_page) {
+ return GetHostReadPt( phys_page );
+ }
+public:
+ Bit8u write_map[4096];
+ Bit8u * invalidation_map;
+ CodePageHandler * next, * prev;
+private:
+ PageHandler * old_pagehandler;
+ CacheBlock * hash_map[1+DYN_PAGE_HASH];
+ Bitu active_blocks;
+ Bitu active_count;
+ HostPt hostmem;
+ Bitu phys_page;
+};
+
+
+static INLINE void cache_addunsedblock(CacheBlock * block) {
+ block->cache.next=cache.block.free;
+ cache.block.free=block;
+}
+
+static CacheBlock * cache_getblock(void) {
+ CacheBlock * ret=cache.block.free;
+ if (!ret) E_Exit("Ran out of CacheBlocks" );
+ cache.block.free=ret->cache.next;
+ ret->cache.next=0;
+ return ret;
+}
+
+void CacheBlock::Clear(void) {
+ Bitu ind;
+ /* Check if this is not a cross page block */
+ if (hash.index) for (ind=0;ind<2;ind++) {
+ CacheBlock * fromlink=link[ind].from;
+ link[ind].from=0;
+ while (fromlink) {
+ CacheBlock * nextlink=fromlink->link[ind].next;
+ fromlink->link[ind].next=0;
+ fromlink->link[ind].to=&link_blocks[ind];
+ fromlink=nextlink;
+ }
+ if (link[ind].to!=&link_blocks[ind]) {
+ CacheBlock * * wherelink=&link[ind].to->link[ind].from;
+ while (*wherelink != this && *wherelink) {
+ wherelink = &(*wherelink)->link[ind].next;
+ }
+ if(*wherelink)
+ *wherelink = (*wherelink)->link[ind].next;
+ else
+ LOG(LOG_CPU,LOG_ERROR)("Cache anomaly. please investigate");
+ }
+ } else
+ cache_addunsedblock(this);
+ if (crossblock) {
+ crossblock->crossblock=0;
+ crossblock->Clear();
+ crossblock=0;
+ }
+ if (page.handler) {
+ page.handler->DelCacheBlock(this);
+ page.handler=0;
+ }
+ if (cache.wmapmask){
+ free(cache.wmapmask);
+ cache.wmapmask=NULL;
+ }
+}
+
+
+static CacheBlock * cache_openblock(void) {
+ CacheBlock * block=cache.block.active;
+ /* check for enough space in this block */
+ Bitu size=block->cache.size;
+ CacheBlock * nextblock=block->cache.next;
+ if (block->page.handler)
+ block->Clear();
+ while (size<CACHE_MAXSIZE) {
+ if (!nextblock)
+ goto skipresize;
+ size+=nextblock->cache.size;
+ CacheBlock * tempblock=nextblock->cache.next;
+ if (nextblock->page.handler)
+ nextblock->Clear();
+ cache_addunsedblock(nextblock);
+ nextblock=tempblock;
+ }
+skipresize:
+ block->cache.size=size;
+ block->cache.next=nextblock;
+ cache.pos=block->cache.start;
+ return block;
+}
+
+static void cache_closeblock(void) {
+ CacheBlock * block=cache.block.active;
+ block->link[0].to=&link_blocks[0];
+ block->link[1].to=&link_blocks[1];
+ block->link[0].from=0;
+ block->link[1].from=0;
+ block->link[0].next=0;
+ block->link[1].next=0;
+ /* Close the block with correct alignments */
+ Bitu written=cache.pos-block->cache.start;
+ if (written>block->cache.size) {
+ if (!block->cache.next) {
+ if (written>block->cache.size+CACHE_MAXSIZE) E_Exit("CacheBlock overrun 1 %d",written-block->cache.size);
+ } else E_Exit("CacheBlock overrun 2 written %d size %d",written,block->cache.size);
+ } else {
+ Bitu new_size;
+ Bitu left=block->cache.size-written;
+ /* Smaller than cache align then don't bother to resize */
+ if (left>CACHE_ALIGN) {
+ new_size=((written-1)|(CACHE_ALIGN-1))+1;
+ CacheBlock * newblock=cache_getblock();
+ newblock->cache.start=block->cache.start+new_size;
+ newblock->cache.size=block->cache.size-new_size;
+ newblock->cache.next=block->cache.next;
+ block->cache.next=newblock;
+ block->cache.size=new_size;
+ }
+ }
+ /* Advance the active block pointer */
+ if (!block->cache.next) {
+// LOG_MSG("Cache full restarting");
+ cache.block.active=cache.block.first;
+ } else {
+ cache.block.active=block->cache.next;
+ }
+}
+
+static INLINE void cache_addb(Bit8u val) {
+ *cache.pos++=val;
+}
+
+static INLINE void cache_addw(Bit16u val) {
+ *(Bit16u*)cache.pos=val;
+ cache.pos+=2;
+}
+
+static INLINE void cache_addd(Bit32u val) {
+ *(Bit32u*)cache.pos=val;
+ cache.pos+=4;
+}
+
+
+static void gen_return(BlockReturn retcode);
+
+static Bit8u * cache_code_start_ptr=NULL;
+static Bit8u * cache_code=NULL;
+static Bit8u * cache_code_link_blocks=NULL;
+static CacheBlock * cache_blocks=NULL;
+
+/* Define temporary pagesize so the MPROTECT case and the regular case share as much code as possible */
+#if (C_HAVE_MPROTECT)
+#define PAGESIZE_TEMP PAGESIZE
+#else
+#define PAGESIZE_TEMP 4096
+#endif
+
+static bool cache_initialized = false;
+
+static void cache_init(bool enable) {
+ Bits i;
+ if (enable) {
+ if (cache_initialized) return;
+ cache_initialized = true;
+ if (cache_blocks == NULL) {
+ cache_blocks=(CacheBlock*)malloc(CACHE_BLOCKS*sizeof(CacheBlock));
+ if(!cache_blocks) E_Exit("Allocating cache_blocks has failed");
+ memset(cache_blocks,0,sizeof(CacheBlock)*CACHE_BLOCKS);
+ cache.block.free=&cache_blocks[0];
+ for (i=0;i<CACHE_BLOCKS-1;i++) {
+ cache_blocks[i].link[0].to=(CacheBlock *)1;
+ cache_blocks[i].link[1].to=(CacheBlock *)1;
+ cache_blocks[i].cache.next=&cache_blocks[i+1];
+ }
+ }
+ if (cache_code_start_ptr==NULL) {
+#if defined (WIN32)
+ cache_code_start_ptr=(Bit8u*)VirtualAlloc(0,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP,
+ MEM_COMMIT,PAGE_EXECUTE_READWRITE);
+ if (!cache_code_start_ptr)
+ cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
+#else
+ cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
+#endif
+ if(!cache_code_start_ptr) E_Exit("Allocating dynamic core cache memory failed");
+
+ cache_code=(Bit8u*)(((Bitu)cache_code_start_ptr + PAGESIZE_TEMP-1) & ~(PAGESIZE_TEMP-1)); //Bitu is same size as a pointer.
+
+ cache_code_link_blocks=cache_code;
+ cache_code+=PAGESIZE_TEMP;
+
+#if (C_HAVE_MPROTECT)
+ if(mprotect(cache_code_link_blocks,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP,PROT_WRITE|PROT_READ|PROT_EXEC))
+ LOG_MSG("Setting excute permission on the code cache has failed!");
+#endif
+ CacheBlock * block=cache_getblock();
+ cache.block.first=block;
+ cache.block.active=block;
+ block->cache.start=&cache_code[0];
+ block->cache.size=CACHE_TOTAL;
+ block->cache.next=0; //Last block in the list
+ }
+ /* Setup the default blocks for block linkage returns */
+ cache.pos=&cache_code_link_blocks[0];
+ link_blocks[0].cache.start=cache.pos;
+ gen_return(BR_Link1);
+ cache.pos=&cache_code_link_blocks[32];
+ link_blocks[1].cache.start=cache.pos;
+ gen_return(BR_Link2);
+ cache.free_pages=0;
+ cache.last_page=0;
+ cache.used_pages=0;
+ /* Setup the code pages */
+ for (i=0;i<CACHE_PAGES;i++) {
+ CodePageHandler * newpage=new CodePageHandler();
+ newpage->next=cache.free_pages;
+ cache.free_pages=newpage;
+ }
+ }
+}
+
+static void cache_close(void) {
+/* for (;;) {
+ if (cache.used_pages) {
+ CodePageHandler * cpage=cache.used_pages;
+ CodePageHandler * npage=cache.used_pages->next;
+ cpage->ClearRelease();
+ delete cpage;
+ cache.used_pages=npage;
+ } else break;
+ }
+ if (cache_blocks != NULL) {
+ free(cache_blocks);
+ cache_blocks = NULL;
+ }
+ if (cache_code_start_ptr != NULL) {
+ ### care: under windows VirtualFree() has to be used if
+ ### VirtualAlloc was used for memory allocation
+ free(cache_code_start_ptr);
+ cache_code_start_ptr = NULL;
+ }
+ cache_code = NULL;
+ cache_code_link_blocks = NULL;
+ cache_initialized = false; */
+}
+
+static void cache_reset(void) {
+ if (cache_initialized) {
+ for (;;) {
+ if (cache.used_pages) {
+ CodePageHandler * cpage=cache.used_pages;
+ CodePageHandler * npage=cache.used_pages->next;
+ cpage->ClearRelease();
+ delete cpage;
+ cache.used_pages=npage;
+ } else break;
+ }
+
+ if (cache_blocks == NULL) {
+ cache_blocks=(CacheBlock*)malloc(CACHE_BLOCKS*sizeof(CacheBlock));
+ if(!cache_blocks) E_Exit("Allocating cache_blocks has failed");
+ }
+ memset(cache_blocks,0,sizeof(CacheBlock)*CACHE_BLOCKS);
+ cache.block.free=&cache_blocks[0];
+ for (Bits i=0;i<CACHE_BLOCKS-1;i++) {
+ cache_blocks[i].link[0].to=(CacheBlock *)1;
+ cache_blocks[i].link[1].to=(CacheBlock *)1;
+ cache_blocks[i].cache.next=&cache_blocks[i+1];
+ }
+
+ if (cache_code_start_ptr==NULL) {
+#if defined (WIN32)
+ cache_code_start_ptr=(Bit8u*)VirtualAlloc(0,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP,
+ MEM_COMMIT,PAGE_EXECUTE_READWRITE);
+ if (!cache_code_start_ptr)
+ cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
+#else
+ cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
+#endif
+ if (!cache_code_start_ptr) E_Exit("Allocating dynamic core cache memory failed");
+
+ cache_code=(Bit8u*)(((Bitu)cache_code_start_ptr + PAGESIZE_TEMP-1) & ~(PAGESIZE_TEMP-1)); //Bitu is same size as a pointer.
+
+ cache_code_link_blocks=cache_code;
+ cache_code+=PAGESIZE_TEMP;
+
+#if (C_HAVE_MPROTECT)
+ if(mprotect(cache_code_link_blocks,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP,PROT_WRITE|PROT_READ|PROT_EXEC))
+ LOG_MSG("Setting excute permission on the code cache has failed!");
+#endif
+ }
+
+ CacheBlock * block=cache_getblock();
+ cache.block.first=block;
+ cache.block.active=block;
+ block->cache.start=&cache_code[0];
+ block->cache.size=CACHE_TOTAL;
+ block->cache.next=0; //Last block in the list
+
+ /* Setup the default blocks for block linkage returns */
+ cache.pos=&cache_code_link_blocks[0];
+ link_blocks[0].cache.start=cache.pos;
+ gen_return(BR_Link1);
+ cache.pos=&cache_code_link_blocks[32];
+ link_blocks[1].cache.start=cache.pos;
+ gen_return(BR_Link2);
+ cache.free_pages=0;
+ cache.last_page=0;
+ cache.used_pages=0;
+ /* Setup the code pages */
+ for (Bitu i=0;i<CACHE_PAGES;i++) {
+ CodePageHandler * newpage=new CodePageHandler();
+ newpage->next=cache.free_pages;
+ cache.free_pages=newpage;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#define X86_DYNFPU_DH_ENABLED
+#define X86_INLINED_MEMACCESS
+
+
+enum REP_Type {
+ REP_NONE=0,REP_NZ,REP_Z
+};
+
+static struct DynDecode {
+ PhysPt code;
+ PhysPt code_start;
+ PhysPt op_start;
+ bool big_op;
+ bool big_addr;
+ REP_Type rep;
+ Bitu cycles;
+ CacheBlock * block;
+ CacheBlock * active_block;
+ struct {
+ CodePageHandler * code;
+ Bitu index;
+ Bit8u * wmap;
+ Bit8u * invmap;
+ Bitu first;
+ } page;
+ struct {
+ Bitu val;
+ Bitu mod;
+ Bitu rm;
+ Bitu reg;
+ } modrm;
+ DynReg * segprefix;
+} decode;
+
+static bool MakeCodePage(Bitu lin_addr,CodePageHandler * &cph) {
+ Bit8u rdval;
+ //Ensure page contains memory:
+ if (GCC_UNLIKELY(mem_readb_checked(lin_addr,&rdval))) return true;
+ PageHandler * handler=get_tlb_readhandler(lin_addr);
+ if (handler->flags & PFLAG_HASCODE) {
+ cph=( CodePageHandler *)handler;
+ return false;
+ }
+ if (handler->flags & PFLAG_NOCODE) {
+ if (PAGING_ForcePageInit(lin_addr)) {
+ handler=get_tlb_readhandler(lin_addr);
+ if (handler->flags & PFLAG_HASCODE) {
+ cph=( CodePageHandler *)handler;
+ return false;
+ }
+ }
+ if (handler->flags & PFLAG_NOCODE) {
+ LOG_MSG("DYNX86:Can't run code in this page!");
+ cph=0; return false;
+ }
+ }
+ Bitu lin_page=lin_addr >> 12;
+ Bitu phys_page=lin_page;
+ if (!PAGING_MakePhysPage(phys_page)) {
+ LOG_MSG("DYNX86:Can't find physpage");
+ cph=0; return false;
+ }
+ /* Find a free CodePage */
+ if (!cache.free_pages) {
+ if (cache.used_pages!=decode.page.code) cache.used_pages->ClearRelease();
+ else {
+ if ((cache.used_pages->next) && (cache.used_pages->next!=decode.page.code))
+ cache.used_pages->next->ClearRelease();
+ else {
+ LOG_MSG("DYNX86:Invalid cache links");
+ cache.used_pages->ClearRelease();
+ }
+ }
+ }
+ CodePageHandler * cpagehandler=cache.free_pages;
+ cache.free_pages=cache.free_pages->next;
+ cpagehandler->prev=cache.last_page;
+ cpagehandler->next=0;
+ if (cache.last_page) cache.last_page->next=cpagehandler;
+ cache.last_page=cpagehandler;
+ if (!cache.used_pages) cache.used_pages=cpagehandler;
+ cpagehandler->SetupAt(phys_page,handler);
+ MEM_SetPageHandler(phys_page,1,cpagehandler);
+ PAGING_UnlinkPages(lin_page,1);
+ cph=cpagehandler;
+ return false;
+}
+
+static Bit8u decode_fetchb(void) {
+ if (GCC_UNLIKELY(decode.page.index>=4096)) {
+ /* Advance to the next page */
+ decode.active_block->page.end=4095;
+ /* trigger possible page fault here */
+ decode.page.first++;
+ Bitu fetchaddr=decode.page.first << 12;
+ mem_readb(fetchaddr);
+ MakeCodePage(fetchaddr,decode.page.code);
+ CacheBlock * newblock=cache_getblock();
+ decode.active_block->crossblock=newblock;
+ newblock->crossblock=decode.active_block;
+ decode.active_block=newblock;
+ decode.active_block->page.start=0;
+ decode.page.code->AddCrossBlock(decode.active_block);
+ decode.page.wmap=decode.page.code->write_map;
+ decode.page.invmap=decode.page.code->invalidation_map;
+ decode.page.index=0;
+ }
+ decode.page.wmap[decode.page.index]+=0x01;
+ decode.page.index++;
+ decode.code+=1;
+ return mem_readb(decode.code-1);
+}
+static Bit16u decode_fetchw(void) {
+ if (GCC_UNLIKELY(decode.page.index>=4095)) {
+ Bit16u val=decode_fetchb();
+ val|=decode_fetchb() << 8;
+ return val;
+ }
+ *(Bit16u *)&decode.page.wmap[decode.page.index]+=0x0101;
+ decode.code+=2;decode.page.index+=2;
+ return mem_readw(decode.code-2);
+}
+static Bit32u decode_fetchd(void) {
+ if (GCC_UNLIKELY(decode.page.index>=4093)) {
+ Bit32u val=decode_fetchb();
+ val|=decode_fetchb() << 8;
+ val|=decode_fetchb() << 16;
+ val|=decode_fetchb() << 24;
+ return val;
+ /* Advance to the next page */
+ }
+ *(Bit32u *)&decode.page.wmap[decode.page.index]+=0x01010101;
+ decode.code+=4;decode.page.index+=4;
+ return mem_readd(decode.code-4);
+}
+
+#define START_WMMEM 64
+
+static INLINE void decode_increase_wmapmask(Bitu size) {
+ Bitu mapidx;
+ CacheBlock* activecb=decode.active_block;
+ if (GCC_UNLIKELY(!activecb->cache.wmapmask)) {
+ activecb->cache.wmapmask=(Bit8u*)malloc(START_WMMEM);
+ memset(activecb->cache.wmapmask,0,START_WMMEM);
+ activecb->cache.maskstart=decode.page.index;
+ activecb->cache.masklen=START_WMMEM;
+ mapidx=0;
+ } else {
+ mapidx=decode.page.index-activecb->cache.maskstart;
+ if (GCC_UNLIKELY(mapidx+size>=activecb->cache.masklen)) {
+ Bitu newmasklen=activecb->cache.masklen*4;
+ if (newmasklen<mapidx+size) newmasklen=((mapidx+size)&~3)*2;
+ Bit8u* tempmem=(Bit8u*)malloc(newmasklen);
+ memset(tempmem,0,newmasklen);
+ memcpy(tempmem,activecb->cache.wmapmask,activecb->cache.masklen);
+ free(activecb->cache.wmapmask);
+ activecb->cache.wmapmask=tempmem;
+ activecb->cache.masklen=newmasklen;
+ }
+ }
+ switch (size) {
+ case 1 : activecb->cache.wmapmask[mapidx]+=0x01; break;
+ case 2 : (*(Bit16u*)&activecb->cache.wmapmask[mapidx])+=0x0101; break;
+ case 4 : (*(Bit32u*)&activecb->cache.wmapmask[mapidx])+=0x01010101; break;
+ }
+}
+
+static bool decode_fetchb_imm(Bitu & val) {
+ if (decode.page.index<4096) {
+ if (decode.page.invmap != NULL) {
+ if (decode.page.invmap[decode.page.index] == 0) {
+ val=(Bit32u)decode_fetchb();
+ return false;
+ }
+ HostPt tlb_addr=get_tlb_read(decode.code);
+ if (tlb_addr) {
+ val=(Bitu)(tlb_addr+decode.code);
+ decode_increase_wmapmask(1);
+ decode.code++;
+ decode.page.index++;
+ return true;
+ }
+ }
+ }
+ val=(Bit32u)decode_fetchb();
+ return false;
+}
+static bool decode_fetchw_imm(Bitu & val) {
+ if (decode.page.index<4095) {
+ if (decode.page.invmap != NULL) {
+ if ((decode.page.invmap[decode.page.index] == 0) &&
+ (decode.page.invmap[decode.page.index + 1] == 0)
+ ) {
+ val=decode_fetchw();
+ return false;
+ }
+ HostPt tlb_addr=get_tlb_read(decode.code);
+ if (tlb_addr) {
+ val=(Bitu)(tlb_addr+decode.code);
+ decode_increase_wmapmask(2);
+ decode.code+=2;
+ decode.page.index+=2;
+ return true;
+ }
+ }
+ }
+ val=decode_fetchw();
+ return false;
+}
+static bool decode_fetchd_imm(Bitu & val) {
+ if (decode.page.index<4093) {
+ if (decode.page.invmap != NULL) {
+ if ((decode.page.invmap[decode.page.index] == 0) &&
+ (decode.page.invmap[decode.page.index + 1] == 0) &&
+ (decode.page.invmap[decode.page.index + 2] == 0) &&
+ (decode.page.invmap[decode.page.index + 3] == 0)
+ ) {
+ val=decode_fetchd();
+ return false;
+ }
+ HostPt tlb_addr=get_tlb_read(decode.code);
+ if (tlb_addr) {
+ val=(Bitu)(tlb_addr+decode.code);
+ decode_increase_wmapmask(4);
+ decode.code+=4;
+ decode.page.index+=4;
+ return true;
+ }
+ }
+ }
+ val=decode_fetchd();
+ return false;
+}
+
+
+static void dyn_reduce_cycles(void) {
+ gen_protectflags();
+ if (!decode.cycles) decode.cycles++;
+ gen_dop_word_imm(DOP_SUB,true,DREG(CYCLES),decode.cycles);
+}
+
+static void dyn_save_noncritical_regs(void) {
+ gen_releasereg(DREG(EAX));
+ gen_releasereg(DREG(ECX));
+ gen_releasereg(DREG(EDX));
+ gen_releasereg(DREG(EBX));
+ gen_releasereg(DREG(ESP));
+ gen_releasereg(DREG(EBP));
+ gen_releasereg(DREG(ESI));
+ gen_releasereg(DREG(EDI));
+}
+
+static void dyn_save_critical_regs(void) {
+ dyn_save_noncritical_regs();
+ gen_releasereg(DREG(FLAGS));
+ gen_releasereg(DREG(EIP));
+ gen_releasereg(DREG(CYCLES));
+}
+
+static void dyn_set_eip_last_end(DynReg * endreg) {
+ gen_protectflags();
+ gen_lea(endreg,DREG(EIP),0,0,decode.code-decode.code_start);
+ gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),decode.op_start-decode.code_start);
+}
+
+static INLINE void dyn_set_eip_end(void) {
+ gen_protectflags();
+ gen_dop_word_imm(DOP_ADD,cpu.code.big,DREG(EIP),decode.code-decode.code_start);
+}
+
+static INLINE void dyn_set_eip_end(DynReg * endreg) {
+ gen_protectflags();
+ if (cpu.code.big) gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(EIP));
+ else gen_extend_word(false,DREG(TMPW),DREG(EIP));
+ gen_dop_word_imm(DOP_ADD,cpu.code.big,DREG(TMPW),decode.code-decode.code_start);
+}
+
+static INLINE void dyn_set_eip_last(void) {
+ gen_protectflags();
+ gen_dop_word_imm(DOP_ADD,cpu.code.big,DREG(EIP),decode.op_start-decode.code_start);
+}
+
+
+enum save_info_type {db_exception, cycle_check, normal, fpu_restore};
+
+
+static struct {
+ save_info_type type;
+ DynState state;
+ Bit8u * branch_pos;
+ Bit32u eip_change;
+ Bitu cycles;
+ Bit8u * return_pos;
+} save_info[512];
+
+Bitu used_save_info=0;
+
+
+static BlockReturn DynRunException(Bit32u eip_add,Bit32u cycle_sub,Bit32u dflags) {
+ reg_flags=(dflags&FMASK_TEST) | (reg_flags&(~FMASK_TEST));
+ reg_eip+=eip_add;
+ CPU_Cycles-=cycle_sub;
+ if (cpu.exception.which==SMC_CURRENT_BLOCK) return BR_SMCBlock;
+ CPU_Exception(cpu.exception.which,cpu.exception.error);
+ return BR_Normal;
+}
+
+static void dyn_check_bool_exception(DynReg * check) {
+ gen_dop_byte(DOP_OR,check,0,check,0);
+ save_info[used_save_info].branch_pos=gen_create_branch_long(BR_NZ);
+ dyn_savestate(&save_info[used_save_info].state);
+ if (!decode.cycles) decode.cycles++;
+ save_info[used_save_info].cycles=decode.cycles;
+ save_info[used_save_info].eip_change=decode.op_start-decode.code_start;
+ if (!cpu.code.big) save_info[used_save_info].eip_change&=0xffff;
+ save_info[used_save_info].type=db_exception;
+ used_save_info++;
+}
+
+static void dyn_check_bool_exception_al(void) {
+ cache_addw(0xc00a); // or al, al
+ save_info[used_save_info].branch_pos=gen_create_branch_long(BR_NZ);
+ dyn_savestate(&save_info[used_save_info].state);
+ if (!decode.cycles) decode.cycles++;
+ save_info[used_save_info].cycles=decode.cycles;
+ save_info[used_save_info].eip_change=decode.op_start-decode.code_start;
+ if (!cpu.code.big) save_info[used_save_info].eip_change&=0xffff;
+ save_info[used_save_info].type=db_exception;
+ used_save_info++;
+}
+
+#include "pic.h"
+
+static void dyn_check_irqrequest(void) {
+ gen_load_host(&PIC_IRQCheck,DREG(TMPB),4);
+ gen_dop_word(DOP_OR,true,DREG(TMPB),DREG(TMPB));
+ save_info[used_save_info].branch_pos=gen_create_branch_long(BR_NZ);
+ gen_releasereg(DREG(TMPB));
+ dyn_savestate(&save_info[used_save_info].state);
+ if (!decode.cycles) decode.cycles++;
+ save_info[used_save_info].cycles=decode.cycles;
+ save_info[used_save_info].eip_change=decode.code-decode.code_start;
+ if (!cpu.code.big) save_info[used_save_info].eip_change&=0xffff;
+ save_info[used_save_info].type=normal;
+ used_save_info++;
+}
+
+static void dyn_check_bool_exception_ne(void) {
+ save_info[used_save_info].branch_pos=gen_create_branch_long(BR_Z);
+ dyn_savestate(&save_info[used_save_info].state);
+ if (!decode.cycles) decode.cycles++;
+ save_info[used_save_info].cycles=decode.cycles;
+ save_info[used_save_info].eip_change=decode.op_start-decode.code_start;
+ if (!cpu.code.big) save_info[used_save_info].eip_change&=0xffff;
+ save_info[used_save_info].type=db_exception;
+ used_save_info++;
+}
+
+static void dyn_fill_blocks(void) {
+ for (Bitu sct=0; sct<used_save_info; sct++) {
+ gen_fill_branch_long(save_info[sct].branch_pos);
+ switch (save_info[sct].type) {
+ case db_exception:
+ dyn_loadstate(&save_info[sct].state);
+ decode.cycles=save_info[sct].cycles;
+ dyn_save_critical_regs();
+ if (cpu.code.big) gen_call_function((void *)&DynRunException,"%Id%Id%F",save_info[sct].eip_change,save_info[sct].cycles);
+ else gen_call_function((void *)&DynRunException,"%Iw%Id%F",save_info[sct].eip_change,save_info[sct].cycles);
+ gen_return_fast(BR_Normal,true);
+ break;
+ case cycle_check:
+ gen_return(BR_Cycles);
+ break;
+ case normal:
+ dyn_loadstate(&save_info[sct].state);
+ gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),save_info[sct].eip_change);
+ dyn_save_critical_regs();
+ gen_return(BR_Cycles);
+ break;
+ case fpu_restore:
+ dyn_loadstate(&save_info[sct].state);
+ gen_load_host(&dyn_dh_fpu.state_used,DREG(TMPB),4);
+ gen_sop_word(SOP_INC,true,DREG(TMPB));
+ GenReg * gr1=FindDynReg(DREG(TMPB));
+ cache_addb(0xdd); // FRSTOR fpu.state (fpu_restore)
+ cache_addb(0x25);
+ cache_addd((Bit32u)(&(dyn_dh_fpu.state[0])));
+ cache_addb(0x89); // mov fpu.state_used,1
+ cache_addb(0x05|(gr1->index<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.state_used)));
+ gen_releasereg(DREG(TMPB));
+ dyn_synchstate(&save_info[sct].state);
+ gen_create_jump(save_info[sct].return_pos);
+ break;
+ }
+ }
+ used_save_info=0;
+}
+
+
+#if !defined(X86_INLINED_MEMACCESS)
+static void dyn_read_byte(DynReg * addr,DynReg * dst,Bitu high) {
+ gen_protectflags();
+ gen_call_function((void *)&mem_readb_checked,"%Dd%Id",addr,&core_dyn.readdata);
+ dyn_check_bool_exception_al();
+ gen_mov_host(&core_dyn.readdata,dst,1,high);
+}
+static void dyn_write_byte(DynReg * addr,DynReg * val,Bitu high) {
+ gen_protectflags();
+ if (high) gen_call_function((void *)&mem_writeb_checked,"%Dd%Dh",addr,val);
+ else gen_call_function((void *)&mem_writeb_checked,"%Dd%Dd",addr,val);
+ dyn_check_bool_exception_al();
+}
+static void dyn_read_word(DynReg * addr,DynReg * dst,bool dword) {
+ gen_protectflags();
+ if (dword) gen_call_function((void *)&mem_readd_checked,"%Dd%Id",addr,&core_dyn.readdata);
+ else gen_call_function((void *)&mem_readw_checked,"%Dd%Id",addr,&core_dyn.readdata);
+ dyn_check_bool_exception_al();
+ gen_mov_host(&core_dyn.readdata,dst,dword?4:2);
+}
+static void dyn_write_word(DynReg * addr,DynReg * val,bool dword) {
+ gen_protectflags();
+ if (dword) gen_call_function((void *)&mem_writed_checked,"%Dd%Dd",addr,val);
+ else gen_call_function((void *)&mem_writew_checked,"%Dd%Dd",addr,val);
+ dyn_check_bool_exception_al();
+}
+static void dyn_read_byte_release(DynReg * addr,DynReg * dst,Bitu high) {
+ gen_protectflags();
+ gen_call_function((void *)&mem_readb_checked,"%Ddr%Id",addr,&core_dyn.readdata);
+ dyn_check_bool_exception_al();
+ gen_mov_host(&core_dyn.readdata,dst,1,high);
+}
+static void dyn_write_byte_release(DynReg * addr,DynReg * val,Bitu high) {
+ gen_protectflags();
+ if (high) gen_call_function((void *)&mem_writeb_checked,"%Ddr%Dh",addr,val);
+ else gen_call_function((void *)&mem_writeb_checked,"%Ddr%Dd",addr,val);
+ dyn_check_bool_exception_al();
+}
+static void dyn_read_word_release(DynReg * addr,DynReg * dst,bool dword) {
+ gen_protectflags();
+ if (dword) gen_call_function((void *)&mem_readd_checked,"%Ddr%Id",addr,&core_dyn.readdata);
+ else gen_call_function((void *)&mem_readw_checked,"%Ddr%Id",addr,&core_dyn.readdata);
+ dyn_check_bool_exception_al();
+ gen_mov_host(&core_dyn.readdata,dst,dword?4:2);
+}
+static void dyn_write_word_release(DynReg * addr,DynReg * val,bool dword) {
+ gen_protectflags();
+ if (dword) gen_call_function((void *)&mem_writed_checked,"%Ddr%Dd",addr,val);
+ else gen_call_function((void *)&mem_writew_checked,"%Ddr%Dd",addr,val);
+ dyn_check_bool_exception_al();
+}
+
+#else
+
+static void dyn_read_intro(DynReg * addr,bool release_addr=true) {
+ gen_protectflags();
+
+ if (addr->genreg) {
+ // addr already in a register
+ Bit8u reg_idx=(Bit8u)addr->genreg->index;
+ x86gen.regs[X86_REG_ECX]->Clear();
+ if (reg_idx!=1) {
+ cache_addw(0xc88b+(reg_idx<<8)); //Mov ecx,reg
+ }
+ x86gen.regs[X86_REG_EAX]->Clear();
+ if (release_addr) gen_releasereg(addr);
+ } else {
+ // addr still in memory, directly move into ecx
+ x86gen.regs[X86_REG_EAX]->Clear();
+ x86gen.regs[X86_REG_ECX]->Clear();
+ cache_addw(0x0d8b); //Mov ecx,[data]
+ cache_addd((Bit32u)addr->data);
+ }
+ x86gen.regs[X86_REG_EDX]->Clear();
+
+ cache_addw(0xc18b); // mov eax,ecx
+}
+
+bool mem_readb_checked_dcx86(PhysPt address) {
+ return get_tlb_readhandler(address)->readb_checked(address, (Bit8u*)(&core_dyn.readdata));
+}
+
+static void dyn_read_byte(DynReg * addr,DynReg * dst,Bitu high) {
+ dyn_read_intro(addr,false);
+
+ cache_addw(0xe8c1); // shr eax,0x0c
+ cache_addb(0x0c);
+ cache_addw(0x048b); // mov eax,paging.tlb.read[eax*TYPE Bit32u]
+ cache_addb(0x85);
+ cache_addd((Bit32u)(&paging.tlb.read[0]));
+ cache_addw(0xc085); // test eax,eax
+ Bit8u* je_loc=gen_create_branch(BR_Z);
+
+
+ cache_addw(0x048a); // mov al,[eax+ecx]
+ cache_addb(0x08);
+
+ Bit8u* jmp_loc=gen_create_jump();
+ gen_fill_branch(je_loc);
+ cache_addb(0x51); // push ecx
+ cache_addb(0xe8);
+ cache_addd(((Bit32u)&mem_readb_checked_dcx86) - (Bit32u)cache.pos-4);
+ cache_addw(0xc483); // add esp,4
+ cache_addb(0x04);
+ cache_addw(0x012c); // sub al,1
+
+ dyn_check_bool_exception_ne();
+
+ cache_addw(0x058a); //mov al,[]
+ cache_addd((Bit32u)(&core_dyn.readdata));
+
+ gen_fill_jump(jmp_loc);
+
+ x86gen.regs[X86_REG_EAX]->notusable=true;
+ GenReg * genreg=FindDynReg(dst);
+ x86gen.regs[X86_REG_EAX]->notusable=false;
+ cache_addw(0xc08a+(genreg->index<<11)+(high?0x2000:0));
+ dst->flags|=DYNFLG_CHANGED;
+}
+
+static void dyn_read_byte_release(DynReg * addr,DynReg * dst,Bitu high) {
+ dyn_read_intro(addr);
+
+ cache_addw(0xe8c1); // shr eax,0x0c
+ cache_addb(0x0c);
+ cache_addw(0x048b); // mov eax,paging.tlb.read[eax*TYPE Bit32u]
+ cache_addb(0x85);
+ cache_addd((Bit32u)(&paging.tlb.read[0]));
+ cache_addw(0xc085); // test eax,eax
+ Bit8u* je_loc=gen_create_branch(BR_Z);
+
+
+ cache_addw(0x048a); // mov al,[eax+ecx]
+ cache_addb(0x08);
+
+ Bit8u* jmp_loc=gen_create_jump();
+ gen_fill_branch(je_loc);
+ cache_addb(0x51); // push ecx
+ cache_addb(0xe8);
+ cache_addd(((Bit32u)&mem_readb_checked_dcx86) - (Bit32u)cache.pos-4);
+ cache_addw(0xc483); // add esp,4
+ cache_addb(0x04);
+ cache_addw(0x012c); // sub al,1
+
+ dyn_check_bool_exception_ne();
+
+ cache_addw(0x058a); //mov al,[]
+ cache_addd((Bit32u)(&core_dyn.readdata));
+
+ gen_fill_jump(jmp_loc);
+
+ x86gen.regs[X86_REG_EAX]->notusable=true;
+ GenReg * genreg=FindDynReg(dst);
+ x86gen.regs[X86_REG_EAX]->notusable=false;
+ cache_addw(0xc08a+(genreg->index<<11)+(high?0x2000:0));
+ dst->flags|=DYNFLG_CHANGED;
+}
+
+bool mem_readd_checked_dcx86(PhysPt address) {
+ if ((address & 0xfff)<0xffd) {
+ HostPt tlb_addr=get_tlb_read(address);
+ if (tlb_addr) {
+ core_dyn.readdata=host_readd(tlb_addr+address);
+ return false;
+ } else {
+ return get_tlb_readhandler(address)->readd_checked(address, &core_dyn.readdata);
+ }
+ } else return mem_unalignedreadd_checked(address, &core_dyn.readdata);
+}
+
+static void dyn_read_word(DynReg * addr,DynReg * dst,bool dword) {
+ if (dword) {
+ dyn_read_intro(addr,false);
+
+ cache_addw(0xe8d1); // shr eax,0x1
+ Bit8u* jb_loc1=gen_create_branch(BR_B);
+ cache_addw(0xe8d1); // shr eax,0x1
+ Bit8u* jb_loc2=gen_create_branch(BR_B);
+ cache_addw(0xe8c1); // shr eax,0x0a
+ cache_addb(0x0a);
+ cache_addw(0x048b); // mov eax,paging.tlb.read[eax*TYPE Bit32u]
+ cache_addb(0x85);
+ cache_addd((Bit32u)(&paging.tlb.read[0]));
+ cache_addw(0xc085); // test eax,eax
+ Bit8u* je_loc=gen_create_branch(BR_Z);
+
+ GenReg * genreg=FindDynReg(dst,true);
+
+ cache_addw(0x048b+(genreg->index <<(8+3))); // mov dest,[eax+ecx]
+ cache_addb(0x08);
+
+ Bit8u* jmp_loc=gen_create_jump();
+ gen_fill_branch(jb_loc1);
+ gen_fill_branch(jb_loc2);
+ gen_fill_branch(je_loc);
+ cache_addb(0x51); // push ecx
+ cache_addb(0xe8);
+ cache_addd(((Bit32u)&mem_readd_checked_dcx86) - (Bit32u)cache.pos-4);
+ cache_addw(0xc483); // add esp,4
+ cache_addb(0x04);
+ cache_addw(0x012c); // sub al,1
+
+ dyn_check_bool_exception_ne();
+
+ gen_mov_host(&core_dyn.readdata,dst,4);
+ dst->flags|=DYNFLG_CHANGED;
+
+ gen_fill_jump(jmp_loc);
+ } else {
+ gen_protectflags();
+ gen_call_function((void *)&mem_readw_checked,"%Dd%Id",addr,&core_dyn.readdata);
+ dyn_check_bool_exception_al();
+ gen_mov_host(&core_dyn.readdata,dst,2);
+ }
+}
+
+static void dyn_read_word_release(DynReg * addr,DynReg * dst,bool dword) {
+ if (dword) {
+ dyn_read_intro(addr);
+
+ cache_addw(0xe8d1); // shr eax,0x1
+ Bit8u* jb_loc1=gen_create_branch(BR_B);
+ cache_addw(0xe8d1); // shr eax,0x1
+ Bit8u* jb_loc2=gen_create_branch(BR_B);
+ cache_addw(0xe8c1); // shr eax,0x0a
+ cache_addb(0x0a);
+ cache_addw(0x048b); // mov eax,paging.tlb.read[eax*TYPE Bit32u]
+ cache_addb(0x85);
+ cache_addd((Bit32u)(&paging.tlb.read[0]));
+ cache_addw(0xc085); // test eax,eax
+ Bit8u* je_loc=gen_create_branch(BR_Z);
+
+ GenReg * genreg=FindDynReg(dst,true);
+
+ cache_addw(0x048b+(genreg->index <<(8+3))); // mov dest,[eax+ecx]
+ cache_addb(0x08);
+
+ Bit8u* jmp_loc=gen_create_jump();
+ gen_fill_branch(jb_loc1);
+ gen_fill_branch(jb_loc2);
+ gen_fill_branch(je_loc);
+ cache_addb(0x51); // push ecx
+ cache_addb(0xe8);
+ cache_addd(((Bit32u)&mem_readd_checked_dcx86) - (Bit32u)cache.pos-4);
+ cache_addw(0xc483); // add esp,4
+ cache_addb(0x04);
+ cache_addw(0x012c); // sub al,1
+
+ dyn_check_bool_exception_ne();
+
+ gen_mov_host(&core_dyn.readdata,dst,4);
+ dst->flags|=DYNFLG_CHANGED;
+
+ gen_fill_jump(jmp_loc);
+ } else {
+ gen_protectflags();
+ gen_call_function((void *)&mem_readw_checked,"%Ddr%Id",addr,&core_dyn.readdata);
+ dyn_check_bool_exception_al();
+ gen_mov_host(&core_dyn.readdata,dst,2);
+ }
+}
+
+static void dyn_write_intro(DynReg * addr,bool release_addr=true) {
+ gen_protectflags();
+
+ if (addr->genreg) {
+ // addr in a register
+ Bit8u reg_idx_addr=(Bit8u)addr->genreg->index;
+
+ x86gen.regs[X86_REG_EAX]->Clear();
+ x86gen.regs[X86_REG_EAX]->notusable=true;
+ x86gen.regs[X86_REG_ECX]->Clear();
+ x86gen.regs[X86_REG_ECX]->notusable=true;
+
+ if (reg_idx_addr) {
+ // addr!=eax
+ cache_addb(0x8b); //Mov eax,reg
+ cache_addb(0xc0+reg_idx_addr);
+ }
+ if (release_addr) gen_releasereg(addr);
+ } else {
+ // addr still in memory, directly move into eax
+ x86gen.regs[X86_REG_EAX]->Clear();
+ x86gen.regs[X86_REG_EAX]->notusable=true;
+ x86gen.regs[X86_REG_ECX]->Clear();
+ x86gen.regs[X86_REG_ECX]->notusable=true;
+ cache_addb(0xa1); //Mov eax,[data]
+ cache_addd((Bit32u)addr->data);
+ }
+
+ cache_addw(0xc88b); // mov ecx,eax
+}
+
+static void dyn_write_byte(DynReg * addr,DynReg * val,bool high) {
+ dyn_write_intro(addr,false);
+
+ GenReg * genreg=FindDynReg(val);
+ cache_addw(0xe9c1); // shr ecx,0x0c
+ cache_addb(0x0c);
+ cache_addw(0x0c8b); // mov ecx,paging.tlb.read[ecx*TYPE Bit32u]
+ cache_addb(0x8d);
+ cache_addd((Bit32u)(&paging.tlb.write[0]));
+ cache_addw(0xc985); // test ecx,ecx
+ Bit8u* je_loc=gen_create_branch(BR_Z);
+
+ cache_addw(0x0488+(genreg->index<<11)+(high?0x2000:0)); // mov [eax+ecx],reg
+ cache_addb(0x08);
+
+ Bit8u* jmp_loc=gen_create_jump();
+ gen_fill_branch(je_loc);
+
+ if (GCC_UNLIKELY(high)) cache_addw(0xe086+((genreg->index+(genreg->index<<3))<<8));
+ cache_addb(0x52); // push edx
+ cache_addb(0x50+genreg->index);
+ cache_addb(0x50); // push eax
+ if (GCC_UNLIKELY(high)) cache_addw(0xe086+((genreg->index+(genreg->index<<3))<<8));
+ cache_addb(0xe8);
+ cache_addd(((Bit32u)&mem_writeb_checked) - (Bit32u)cache.pos-4);
+ cache_addw(0xc483); // add esp,8
+ cache_addb(0x08);
+ cache_addw(0x012c); // sub al,1
+ cache_addb(0x5a); // pop edx
+
+ // Restore registers to be used again
+ x86gen.regs[X86_REG_EAX]->notusable=false;
+ x86gen.regs[X86_REG_ECX]->notusable=false;
+
+ dyn_check_bool_exception_ne();
+
+ gen_fill_jump(jmp_loc);
+}
+
+static void dyn_write_byte_release(DynReg * addr,DynReg * val,bool high) {
+ dyn_write_intro(addr);
+
+ GenReg * genreg=FindDynReg(val);
+ cache_addw(0xe9c1); // shr ecx,0x0c
+ cache_addb(0x0c);
+ cache_addw(0x0c8b); // mov ecx,paging.tlb.read[ecx*TYPE Bit32u]
+ cache_addb(0x8d);
+ cache_addd((Bit32u)(&paging.tlb.write[0]));
+ cache_addw(0xc985); // test ecx,ecx
+ Bit8u* je_loc=gen_create_branch(BR_Z);
+
+ cache_addw(0x0488+(genreg->index<<11)+(high?0x2000:0)); // mov [eax+ecx],reg
+ cache_addb(0x08);
+
+ Bit8u* jmp_loc=gen_create_jump();
+ gen_fill_branch(je_loc);
+
+ cache_addb(0x52); // push edx
+ if (GCC_UNLIKELY(high)) cache_addw(0xe086+((genreg->index+(genreg->index<<3))<<8));
+ cache_addb(0x50+genreg->index);
+ cache_addb(0x50); // push eax
+ if (GCC_UNLIKELY(high)) cache_addw(0xe086+((genreg->index+(genreg->index<<3))<<8));
+ cache_addb(0xe8);
+ cache_addd(((Bit32u)&mem_writeb_checked) - (Bit32u)cache.pos-4);
+ cache_addw(0xc483); // add esp,8
+ cache_addb(0x08);
+ cache_addw(0x012c); // sub al,1
+ cache_addb(0x5a); // pop edx
+
+ // Restore registers to be used again
+ x86gen.regs[X86_REG_EAX]->notusable=false;
+ x86gen.regs[X86_REG_ECX]->notusable=false;
+
+ dyn_check_bool_exception_ne();
+
+ gen_fill_jump(jmp_loc);
+}
+
+static void dyn_write_word(DynReg * addr,DynReg * val,bool dword) {
+ if (dword) {
+ dyn_write_intro(addr,false);
+
+ GenReg * genreg=FindDynReg(val);
+ cache_addw(0xe9d1); // shr ecx,0x1
+ Bit8u* jb_loc1=gen_create_branch(BR_B);
+ cache_addw(0xe9d1); // shr ecx,0x1
+ Bit8u* jb_loc2=gen_create_branch(BR_B);
+ cache_addw(0xe9c1); // shr ecx,0x0a
+ cache_addb(0x0a);
+ cache_addw(0x0c8b); // mov ecx,paging.tlb.read[ecx*TYPE Bit32u]
+ cache_addb(0x8d);
+ cache_addd((Bit32u)(&paging.tlb.write[0]));
+ cache_addw(0xc985); // test ecx,ecx
+ Bit8u* je_loc=gen_create_branch(BR_Z);
+
+ cache_addw(0x0489+(genreg->index <<(8+3))); // mov [eax+ecx],reg
+ cache_addb(0x08);
+
+ Bit8u* jmp_loc=gen_create_jump();
+ gen_fill_branch(jb_loc1);
+ gen_fill_branch(jb_loc2);
+ gen_fill_branch(je_loc);
+
+ cache_addb(0x52); // push edx
+ cache_addb(0x50+genreg->index);
+ cache_addb(0x50); // push eax
+ cache_addb(0xe8);
+ cache_addd(((Bit32u)&mem_writed_checked) - (Bit32u)cache.pos-4);
+ cache_addw(0xc483); // add esp,8
+ cache_addb(0x08);
+ cache_addw(0x012c); // sub al,1
+ cache_addb(0x5a); // pop edx
+
+ // Restore registers to be used again
+ x86gen.regs[X86_REG_EAX]->notusable=false;
+ x86gen.regs[X86_REG_ECX]->notusable=false;
+
+ dyn_check_bool_exception_ne();
+
+ gen_fill_jump(jmp_loc);
+ } else {
+ gen_protectflags();
+ gen_call_function((void *)&mem_writew_checked,"%Dd%Dd",addr,val);
+ dyn_check_bool_exception_al();
+ }
+}
+
+static void dyn_write_word_release(DynReg * addr,DynReg * val,bool dword) {
+ if (dword) {
+ dyn_write_intro(addr);
+
+ GenReg * genreg=FindDynReg(val);
+ cache_addw(0xe9d1); // shr ecx,0x1
+ Bit8u* jb_loc1=gen_create_branch(BR_B);
+ cache_addw(0xe9d1); // shr ecx,0x1
+ Bit8u* jb_loc2=gen_create_branch(BR_B);
+ cache_addw(0xe9c1); // shr ecx,0x0a
+ cache_addb(0x0a);
+ cache_addw(0x0c8b); // mov ecx,paging.tlb.read[ecx*TYPE Bit32u]
+ cache_addb(0x8d);
+ cache_addd((Bit32u)(&paging.tlb.write[0]));
+ cache_addw(0xc985); // test ecx,ecx
+ Bit8u* je_loc=gen_create_branch(BR_Z);
+
+ cache_addw(0x0489+(genreg->index <<(8+3))); // mov [eax+ecx],reg
+ cache_addb(0x08);
+
+ Bit8u* jmp_loc=gen_create_jump();
+ gen_fill_branch(jb_loc1);
+ gen_fill_branch(jb_loc2);
+ gen_fill_branch(je_loc);
+
+ cache_addb(0x52); // push edx
+ cache_addb(0x50+genreg->index);
+ cache_addb(0x50); // push eax
+ cache_addb(0xe8);
+ cache_addd(((Bit32u)&mem_writed_checked) - (Bit32u)cache.pos-4);
+ cache_addw(0xc483); // add esp,8
+ cache_addb(0x08);
+ cache_addw(0x012c); // sub al,1
+ cache_addb(0x5a); // pop edx
+
+ // Restore registers to be used again
+ x86gen.regs[X86_REG_EAX]->notusable=false;
+ x86gen.regs[X86_REG_ECX]->notusable=false;
+
+ dyn_check_bool_exception_ne();
+
+ gen_fill_jump(jmp_loc);
+ } else {
+ gen_protectflags();
+ gen_call_function((void *)&mem_writew_checked,"%Ddr%Dd",addr,val);
+ dyn_check_bool_exception_al();
+ }
+}
+
+#endif
+
+
+static void dyn_push_unchecked(DynReg * dynreg) {
+ gen_protectflags();
+ gen_lea(DREG(STACK),DREG(ESP),0,0,decode.big_op?(-4):(-2));
+ gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask);
+ gen_dop_word_var(DOP_AND,true,DREG(ESP),&cpu.stack.notmask);
+ gen_dop_word(DOP_OR,true,DREG(ESP),DREG(STACK));
+ gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS));
+ if (decode.big_op) {
+ gen_call_function((void *)&mem_writed,"%Drd%Dd",DREG(STACK),dynreg);
+ } else {
+ //Can just push the whole 32-bit word as operand
+ gen_call_function((void *)&mem_writew,"%Drd%Dd",DREG(STACK),dynreg);
+ }
+}
+
+static void dyn_push(DynReg * dynreg) {
+ gen_protectflags();
+ gen_lea(DREG(STACK),DREG(ESP),0,0,decode.big_op?(-4):(-2));
+ gen_dop_word(DOP_MOV,true,DREG(NEWESP),DREG(ESP));
+ gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask);
+ gen_dop_word_var(DOP_AND,true,DREG(NEWESP),&cpu.stack.notmask);
+ gen_dop_word(DOP_OR,true,DREG(NEWESP),DREG(STACK));
+ gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS));
+ if (decode.big_op) {
+ gen_call_function((void *)&mem_writed_checked,"%Drd%Dd",DREG(STACK),dynreg);
+ } else {
+ //Can just push the whole 32-bit word as operand
+ gen_call_function((void *)&mem_writew_checked,"%Drd%Dd",DREG(STACK),dynreg);
+ }
+ dyn_check_bool_exception_al();
+ /* everything was ok, change register now */
+ gen_dop_word(DOP_MOV,true,DREG(ESP),DREG(NEWESP));
+ gen_releasereg(DREG(NEWESP));
+}
+
+static void dyn_pop(DynReg * dynreg,bool checked=true) {
+ gen_protectflags();
+ gen_dop_word(DOP_MOV,true,DREG(STACK),DREG(ESP));
+ gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask);
+ gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS));
+ if (checked) {
+ if (decode.big_op) {
+ gen_call_function((void *)&mem_readd_checked,"%Drd%Id",DREG(STACK),&core_dyn.readdata);
+ } else {
+ gen_call_function((void *)&mem_readw_checked,"%Drd%Id",DREG(STACK),&core_dyn.readdata);
+ }
+ dyn_check_bool_exception_al();
+ gen_mov_host(&core_dyn.readdata,dynreg,decode.big_op?4:2);
+ } else {
+ if (decode.big_op) {
+ gen_call_function((void *)&mem_readd,"%Rd%Drd",dynreg,DREG(STACK));
+ } else {
+ gen_call_function((void *)&mem_readw,"%Rw%Drd",dynreg,DREG(STACK));
+ }
+ }
+ if (dynreg!=DREG(ESP)) {
+ gen_lea(DREG(STACK),DREG(ESP),0,0,decode.big_op?4:2);
+ gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask);
+ gen_dop_word_var(DOP_AND,true,DREG(ESP),&cpu.stack.notmask);
+ gen_dop_word(DOP_OR,true,DREG(ESP),DREG(STACK));
+ }
+}
+
+static INLINE void dyn_get_modrm(void) {
+ decode.modrm.val=decode_fetchb();
+ decode.modrm.mod=(decode.modrm.val >> 6) & 3;
+ decode.modrm.reg=(decode.modrm.val >> 3) & 7;
+ decode.modrm.rm=(decode.modrm.val & 7);
+}
+
+static void dyn_fill_ea(bool addseg=true, DynReg * reg_ea=DREG(EA)) {
+ DynReg * segbase;
+ if (!decode.big_addr) {
+ Bits imm;
+ switch (decode.modrm.mod) {
+ case 0:imm=0;break;
+ case 1:imm=(Bit8s)decode_fetchb();break;
+ case 2:imm=(Bit16s)decode_fetchw();break;
+ }
+ DynReg * extend_src=reg_ea;
+ switch (decode.modrm.rm) {
+ case 0:/* BX+SI */
+ gen_lea(reg_ea,DREG(EBX),DREG(ESI),0,imm);
+ segbase=DREG(DS);
+ break;
+ case 1:/* BX+DI */
+ gen_lea(reg_ea,DREG(EBX),DREG(EDI),0,imm);
+ segbase=DREG(DS);
+ break;
+ case 2:/* BP+SI */
+ gen_lea(reg_ea,DREG(EBP),DREG(ESI),0,imm);
+ segbase=DREG(SS);
+ break;
+ case 3:/* BP+DI */
+ gen_lea(reg_ea,DREG(EBP),DREG(EDI),0,imm);
+ segbase=DREG(SS);
+ break;
+ case 4:/* SI */
+ if (imm) gen_lea(reg_ea,DREG(ESI),0,0,imm);
+ else extend_src=DREG(ESI);
+ segbase=DREG(DS);
+ break;
+ case 5:/* DI */
+ if (imm) gen_lea(reg_ea,DREG(EDI),0,0,imm);
+ else extend_src=DREG(EDI);
+ segbase=DREG(DS);
+ break;
+ case 6:/* imm/BP */
+ if (!decode.modrm.mod) {
+ imm=decode_fetchw();
+ gen_dop_word_imm(DOP_MOV,true,reg_ea,imm);
+ segbase=DREG(DS);
+ goto skip_extend_word;
+ } else {
+ gen_lea(reg_ea,DREG(EBP),0,0,imm);
+ segbase=DREG(SS);
+ }
+ break;
+ case 7: /* BX */
+ if (imm) gen_lea(reg_ea,DREG(EBX),0,0,imm);
+ else extend_src=DREG(EBX);
+ segbase=DREG(DS);
+ break;
+ }
+ gen_extend_word(false,reg_ea,extend_src);
+skip_extend_word:
+ if (addseg) {
+ gen_lea(reg_ea,reg_ea,decode.segprefix ? decode.segprefix : segbase,0,0);
+ }
+ } else {
+ Bits imm=0;
+ DynReg * base=0;DynReg * scaled=0;Bitu scale=0;
+ switch (decode.modrm.rm) {
+ case 0:base=DREG(EAX);segbase=DREG(DS);break;
+ case 1:base=DREG(ECX);segbase=DREG(DS);break;
+ case 2:base=DREG(EDX);segbase=DREG(DS);break;
+ case 3:base=DREG(EBX);segbase=DREG(DS);break;
+ case 4: /* SIB */
+ {
+ Bitu sib=decode_fetchb();
+ static DynReg * scaledtable[8]={
+ DREG(EAX),DREG(ECX),DREG(EDX),DREG(EBX),
+ 0,DREG(EBP),DREG(ESI),DREG(EDI),
+ };
+ scaled=scaledtable[(sib >> 3) &7];
+ scale=(sib >> 6);
+ switch (sib & 7) {
+ case 0:base=DREG(EAX);segbase=DREG(DS);break;
+ case 1:base=DREG(ECX);segbase=DREG(DS);break;
+ case 2:base=DREG(EDX);segbase=DREG(DS);break;
+ case 3:base=DREG(EBX);segbase=DREG(DS);break;
+ case 4:base=DREG(ESP);segbase=DREG(SS);break;
+ case 5:
+ if (decode.modrm.mod) {
+ base=DREG(EBP);segbase=DREG(SS);
+ } else {
+ segbase=DREG(DS);
+ Bitu val;
+ if (decode_fetchd_imm(val)) {
+ gen_mov_host((void*)val,DREG(EA),4);
+ if (!addseg) {
+ gen_lea(reg_ea,DREG(EA),scaled,scale,0);
+ } else {
+ DynReg** seg = decode.segprefix ? &decode.segprefix : &segbase;
+ gen_lea(DREG(EA),DREG(EA),scaled,scale,0);
+ gen_lea(reg_ea,DREG(EA),*seg,0,0);
+ }
+ return;
+ }
+ imm=(Bit32s)val;
+ }
+ break;
+ case 6:base=DREG(ESI);segbase=DREG(DS);break;
+ case 7:base=DREG(EDI);segbase=DREG(DS);break;
+ }
+ }
+ break; /* SIB Break */
+ case 5:
+ if (decode.modrm.mod) {
+ base=DREG(EBP);segbase=DREG(SS);
+ } else {
+ imm=(Bit32s)decode_fetchd();segbase=DREG(DS);
+ }
+ break;
+ case 6:base=DREG(ESI);segbase=DREG(DS);break;
+ case 7:base=DREG(EDI);segbase=DREG(DS);break;
+ }
+ switch (decode.modrm.mod) {
+ case 1:imm=(Bit8s)decode_fetchb();break;
+ case 2: {
+ Bitu val;
+ if (decode_fetchd_imm(val)) {
+ gen_mov_host((void*)val,DREG(EA),4);
+ if (!addseg) {
+ gen_lea(DREG(EA),DREG(EA),scaled,scale,0);
+ gen_lea(reg_ea,DREG(EA),base,0,0);
+ } else {
+ DynReg** seg = decode.segprefix ? &decode.segprefix : &segbase;
+ if (!base) {
+ gen_lea(DREG(EA),DREG(EA),scaled,scale,0);
+ gen_lea(reg_ea,DREG(EA),*seg,0,0);
+ } else if (!scaled) {
+ gen_lea(DREG(EA),DREG(EA),*seg,0,0);
+ gen_lea(reg_ea,DREG(EA),base,0,0);
+ } else {
+ gen_lea(DREG(EA),DREG(EA),scaled,scale,0);
+ gen_lea(DREG(EA),DREG(EA),base,0,0);
+ gen_lea(reg_ea,DREG(EA),decode.segprefix ? decode.segprefix : segbase,0,0);
+ }
+ }
+ return;
+ }
+
+ imm=(Bit32s)val;
+ break;
+ }
+ }
+ if (!addseg) {
+ gen_lea(reg_ea,base,scaled,scale,imm);
+ } else {
+ DynReg** seg = decode.segprefix ? &decode.segprefix : &segbase;
+ if (!base) gen_lea(reg_ea,*seg,scaled,scale,imm);
+ else if (!scaled) gen_lea(reg_ea,base,*seg,0,imm);
+ else {
+ gen_lea(DREG(EA),base,scaled,scale,imm);
+ gen_lea(reg_ea,DREG(EA),decode.segprefix ? decode.segprefix : segbase,0,0);
+ }
+ }
+ }
+}
+
+
+static void dyn_dop_word_imm(DualOps op,bool dword,DynReg * dr1) {
+ Bitu val;
+ if (dword) {
+ if (decode_fetchd_imm(val)) {
+ gen_dop_word_imm_mem(op,true,dr1,(void*)val);
+ return;
+ }
+ } else {
+ if (decode_fetchw_imm(val)) {
+ gen_dop_word_imm_mem(op,false,dr1,(void*)val);
+ return;
+ }
+ }
+ gen_dop_word_imm(op,dword,dr1,val);
+}
+
+static void dyn_dop_byte_imm(DualOps op,DynReg * dr1,Bit8u di1) {
+ Bitu val;
+ if (decode_fetchb_imm(val)) {
+ gen_dop_byte_imm_mem(op,dr1,di1,(void*)val);
+ } else {
+ gen_dop_byte_imm(op,dr1,di1,(Bit8u)val);
+ }
+}
+
+
+#include "helpers.h"
+#include "string.h"
+
+
+static void dyn_dop_ebgb(DualOps op) {
+ dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg&3];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true);
+ dyn_read_byte(DREG(EA),DREG(TMPB),false);
+ if (op<=DOP_TEST) {
+ if (op==DOP_ADC || op==DOP_SBB) gen_needcarry();
+ else set_skipflags(false);
+ }
+ gen_dop_byte(op,DREG(TMPB),0,rm_reg,decode.modrm.reg&4);
+ if (op!=DOP_CMP) dyn_write_byte_release(DREG(EA),DREG(TMPB),false);
+ else gen_releasereg(DREG(EA));
+ gen_releasereg(DREG(TMPB));
+ } else {
+ if (op<=DOP_TEST) {
+ if (op==DOP_ADC || op==DOP_SBB) gen_needcarry();
+ else gen_discardflags();
+ }
+ gen_dop_byte(op,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,rm_reg,decode.modrm.reg&4);
+ }
+}
+
+
+static void dyn_dop_gbeb(DualOps op) {
+ dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg&3];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true);
+ dyn_read_byte_release(DREG(EA),DREG(TMPB),false);
+ if (op<=DOP_TEST) {
+ if (op==DOP_ADC || op==DOP_SBB) gen_needcarry();
+ else set_skipflags(false);
+ }
+ gen_dop_byte(op,rm_reg,decode.modrm.reg&4,DREG(TMPB),0);
+ gen_releasereg(DREG(TMPB));
+ } else {
+ if (op<=DOP_TEST) {
+ if (op==DOP_ADC || op==DOP_SBB) gen_needcarry();
+ else gen_discardflags();
+ }
+ gen_dop_byte(op,rm_reg,decode.modrm.reg&4,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4);
+ }
+}
+
+static void dyn_mov_ebib(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ gen_call_write(DREG(EA),decode_fetchb(),1);
+ dyn_check_bool_exception_al();
+ } else {
+ gen_dop_byte_imm(DOP_MOV,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,decode_fetchb());
+ }
+}
+
+static void dyn_mov_ebgb(void) {
+ dyn_get_modrm();
+ DynReg * rm_reg=&DynRegs[decode.modrm.reg&3];Bitu rm_regi=decode.modrm.reg&4;
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ dyn_write_byte_release(DREG(EA),rm_reg,rm_regi==4);
+ } else {
+ gen_dop_byte(DOP_MOV,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,rm_reg,rm_regi);
+ }
+}
+
+static void dyn_mov_gbeb(void) {
+ dyn_get_modrm();
+ DynReg * rm_reg=&DynRegs[decode.modrm.reg&3];Bitu rm_regi=decode.modrm.reg&4;
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ dyn_read_byte_release(DREG(EA),rm_reg,rm_regi);
+ } else {
+ gen_dop_byte(DOP_MOV,rm_reg,rm_regi,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4);
+ }
+}
+
+static void dyn_dop_evgv(DualOps op) {
+ dyn_get_modrm();
+ DynReg * rm_reg=&DynRegs[decode.modrm.reg];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true);
+ dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op);
+ if (op<=DOP_TEST) {
+ if (op==DOP_ADC || op==DOP_SBB) gen_needcarry();
+ else set_skipflags(false);
+ }
+ gen_dop_word(op,decode.big_op,DREG(TMPW),rm_reg);
+ if (op!=DOP_CMP) dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op);
+ else gen_releasereg(DREG(EA));
+ gen_releasereg(DREG(TMPW));
+ } else {
+ if (op<=DOP_TEST) {
+ if (op==DOP_ADC || op==DOP_SBB) gen_needcarry();
+ else gen_discardflags();
+ }
+ gen_dop_word(op,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg);
+ }
+}
+
+static void dyn_imul_gvev(Bitu immsize) {
+ dyn_get_modrm();DynReg * src;
+ DynReg * rm_reg=&DynRegs[decode.modrm.reg];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();dyn_read_word_release(DREG(EA),DREG(TMPW),decode.big_op);
+ src=DREG(TMPW);
+ } else {
+ src=&DynRegs[decode.modrm.rm];
+ }
+ gen_needflags();
+ switch (immsize) {
+ case 0:gen_imul_word(decode.big_op,rm_reg,src);break;
+ case 1:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit8s)decode_fetchb());break;
+ case 2:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit16s)decode_fetchw());break;
+ case 4:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit32s)decode_fetchd());break;
+ }
+ gen_releasereg(DREG(TMPW));
+}
+
+static void dyn_dop_gvev(DualOps op) {
+ dyn_get_modrm();
+ DynReg * rm_reg=&DynRegs[decode.modrm.reg];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true);
+ dyn_read_word_release(DREG(EA),DREG(TMPW),decode.big_op);
+ if (op<=DOP_TEST) {
+ if (op==DOP_ADC || op==DOP_SBB) gen_needcarry();
+ else set_skipflags(false);
+ }
+ gen_dop_word(op,decode.big_op,rm_reg,DREG(TMPW));
+ gen_releasereg(DREG(TMPW));
+ } else {
+ if (op<=DOP_TEST) {
+ if (op==DOP_ADC || op==DOP_SBB) gen_needcarry();
+ else gen_discardflags();
+ }
+ gen_dop_word(op,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm]);
+ }
+}
+
+static void dyn_mov_evgv(void) {
+ dyn_get_modrm();
+ DynReg * rm_reg=&DynRegs[decode.modrm.reg];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ dyn_write_word_release(DREG(EA),rm_reg,decode.big_op);
+ } else {
+ gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg);
+ }
+}
+
+static void dyn_mov_gvev(void) {
+ dyn_get_modrm();
+ DynReg * rm_reg=&DynRegs[decode.modrm.reg];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ dyn_read_word_release(DREG(EA),rm_reg,decode.big_op);
+ } else {
+ gen_dop_word(DOP_MOV,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm]);
+ }
+}
+static void dyn_mov_eviv(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ gen_call_write(DREG(EA),decode.big_op ? decode_fetchd() : decode_fetchw(),decode.big_op?4:2);
+ dyn_check_bool_exception_al();
+ } else {
+ gen_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],decode.big_op ? decode_fetchd() : decode_fetchw());
+ }
+}
+
+static void dyn_mov_ev_gb(bool sign) {
+ dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ dyn_read_byte_release(DREG(EA),DREG(TMPB),false);
+ gen_extend_byte(sign,decode.big_op,rm_reg,DREG(TMPB),0);
+ gen_releasereg(DREG(TMPB));
+ } else {
+ gen_extend_byte(sign,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4);
+ }
+}
+
+static void dyn_mov_ev_gw(bool sign) {
+ if (!decode.big_op) {
+ dyn_mov_gvev();
+ return;
+ }
+ dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ dyn_read_word_release(DREG(EA),DREG(TMPW),false);
+ gen_extend_word(sign,rm_reg,DREG(TMPW));
+ gen_releasereg(DREG(TMPW));
+ } else {
+ gen_extend_word(sign,rm_reg,&DynRegs[decode.modrm.rm]);
+ }
+}
+
+static void dyn_cmpxchg_evgv(void) {
+ dyn_get_modrm();
+ DynReg * rm_reg=&DynRegs[decode.modrm.reg];
+ gen_protectflags();
+ if (decode.modrm.mod<3) {
+ gen_releasereg(DREG(EAX));
+ gen_releasereg(DREG(TMPB));
+ gen_releasereg(rm_reg);
+
+ dyn_fill_ea();
+ dyn_read_word(DREG(EA),DREG(TMPB),decode.big_op);
+ gen_dop_word(DOP_CMP,decode.big_op,DREG(EAX),DREG(TMPB));
+ Bit8u * branch=gen_create_branch(BR_NZ);
+
+ // eax==mem -> mem:=rm_reg
+ dyn_write_word_release(DREG(EA),rm_reg,decode.big_op);
+ gen_setzeroflag();
+ gen_releasereg(DREG(EAX));
+ gen_releasereg(DREG(TMPB));
+ gen_releasereg(rm_reg);
+
+ Bit8u * jump=gen_create_jump();
+
+ gen_fill_branch(branch);
+ // eax!=mem -> eax:=mem
+ dyn_write_word_release(DREG(EA),DREG(TMPB),decode.big_op); // cmpxchg always issues write
+ gen_dop_word(DOP_MOV,decode.big_op,DREG(EAX),DREG(TMPB));
+ gen_clearzeroflag();
+ gen_releasereg(DREG(EAX));
+ gen_releasereg(DREG(TMPB));
+ gen_releasereg(rm_reg);
+
+ gen_fill_jump(jump);
+ } else {
+ gen_releasereg(DREG(EAX));
+ gen_releasereg(&DynRegs[decode.modrm.rm]);
+ gen_releasereg(rm_reg);
+
+ gen_dop_word(DOP_CMP,decode.big_op,DREG(EAX),&DynRegs[decode.modrm.rm]);
+ Bit8u * branch=gen_create_branch(BR_NZ);
+
+ // eax==rm -> rm:=rm_reg
+ gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg);
+ gen_setzeroflag();
+ gen_releasereg(DREG(EAX));
+ gen_releasereg(&DynRegs[decode.modrm.rm]);
+ gen_releasereg(rm_reg);
+
+ Bit8u * jump=gen_create_jump();
+
+ gen_fill_branch(branch);
+ // eax!=rm -> eax:=rm
+ gen_dop_word(DOP_MOV,decode.big_op,DREG(EAX),&DynRegs[decode.modrm.rm]);
+ gen_clearzeroflag();
+ gen_releasereg(DREG(EAX));
+ gen_releasereg(&DynRegs[decode.modrm.rm]);
+ gen_releasereg(rm_reg);
+
+ gen_fill_jump(jump);
+ }
+}
+
+static void dyn_dshift_ev_gv(bool left,bool immediate) {
+ dyn_get_modrm();
+ DynReg * rm_reg=&DynRegs[decode.modrm.reg];
+ DynReg * ea_reg;
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();ea_reg=DREG(TMPW);
+ dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op);
+ } else ea_reg=&DynRegs[decode.modrm.rm];
+ gen_needflags();
+ if (immediate) gen_dshift_imm(decode.big_op,left,ea_reg,rm_reg,decode_fetchb());
+ else gen_dshift_cl(decode.big_op,left,ea_reg,rm_reg,DREG(ECX));
+ if (decode.modrm.mod<3) {
+ dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op);
+ gen_releasereg(DREG(TMPW));
+ }
+}
+
+
+static DualOps grp1_table[8]={DOP_ADD,DOP_OR,DOP_ADC,DOP_SBB,DOP_AND,DOP_SUB,DOP_XOR,DOP_CMP};
+static void dyn_grp1_eb_ib(void) {
+ dyn_get_modrm();
+ DualOps op=grp1_table[decode.modrm.reg];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true);
+ dyn_read_byte(DREG(EA),DREG(TMPB),false);
+ if (op<=DOP_TEST) {
+ if (op==DOP_ADC || op==DOP_SBB) gen_needcarry();
+ else set_skipflags(false);
+ }
+ gen_dop_byte_imm(op,DREG(TMPB),0,decode_fetchb());
+ if (op!=DOP_CMP) dyn_write_byte_release(DREG(EA),DREG(TMPB),false);
+ else gen_releasereg(DREG(EA));
+ gen_releasereg(DREG(TMPB));
+ } else {
+ if (op<=DOP_TEST) {
+ if (op==DOP_ADC || op==DOP_SBB) gen_needcarry();
+ else gen_discardflags();
+ }
+ dyn_dop_byte_imm(op,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4);
+ }
+}
+
+static void dyn_grp1_ev_ivx(bool withbyte) {
+ dyn_get_modrm();
+ DualOps op=grp1_table[decode.modrm.reg];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true);
+ dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op);
+ if (op<=DOP_TEST) {
+ if (op==DOP_ADC || op==DOP_SBB) gen_needcarry();
+ else set_skipflags(false);
+ }
+ if (!withbyte) {
+ dyn_dop_word_imm(op,decode.big_op,DREG(TMPW));
+ } else {
+ gen_dop_word_imm(op,decode.big_op,DREG(TMPW),(Bit8s)decode_fetchb());
+ }
+ if (op!=DOP_CMP) dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op);
+ else gen_releasereg(DREG(EA));
+ gen_releasereg(DREG(TMPW));
+ } else {
+ if (op<=DOP_TEST) {
+ if (op==DOP_ADC || op==DOP_SBB) gen_needcarry();
+ else gen_discardflags();
+ }
+ if (!withbyte) {
+ dyn_dop_word_imm(op,decode.big_op,&DynRegs[decode.modrm.rm]);
+ } else {
+ gen_dop_word_imm(op,decode.big_op,&DynRegs[decode.modrm.rm],(Bit8s)decode_fetchb());
+ }
+ }
+}
+
+enum grp2_types {
+ grp2_1,grp2_imm,grp2_cl,
+};
+
+static void dyn_grp2_eb(grp2_types type) {
+ dyn_get_modrm();DynReg * src;Bit8u src_i;
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();dyn_read_byte(DREG(EA),DREG(TMPB),false);
+ src=DREG(TMPB);
+ src_i=0;
+ } else {
+ src=&DynRegs[decode.modrm.rm&3];
+ src_i=decode.modrm.rm&4;
+ }
+ switch (type) {
+ case grp2_1:
+ /* rotates (first 4 ops) alter cf/of only; shifts (last 4 ops) alter all flags */
+ if (decode.modrm.reg < 4) gen_needflags();
+ else gen_discardflags();
+ gen_shift_byte_imm(decode.modrm.reg,src,src_i,1);
+ break;
+ case grp2_imm: {
+ Bit8u imm=decode_fetchb();
+ if (imm) {
+ /* rotates (first 4 ops) alter cf/of only; shifts (last 4 ops) alter all flags */
+ if (decode.modrm.reg < 4) gen_needflags();
+ else gen_discardflags();
+ gen_shift_byte_imm(decode.modrm.reg,src,src_i,imm);
+ } else return;
+ }
+ break;
+ case grp2_cl:
+ gen_needflags(); /* flags must not be changed on ecx==0 */
+ gen_shift_byte_cl (decode.modrm.reg,src,src_i,DREG(ECX));
+ break;
+ }
+ if (decode.modrm.mod<3) {
+ dyn_write_byte_release(DREG(EA),src,false);
+ gen_releasereg(src);
+ }
+}
+
+static void dyn_grp2_ev(grp2_types type) {
+ dyn_get_modrm();DynReg * src;
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op);
+ src=DREG(TMPW);
+ } else {
+ src=&DynRegs[decode.modrm.rm];
+ }
+ switch (type) {
+ case grp2_1:
+ /* rotates (first 4 ops) alter cf/of only; shifts (last 4 ops) alter all flags */
+ if (decode.modrm.reg < 4) gen_needflags();
+ else gen_discardflags();
+ gen_shift_word_imm(decode.modrm.reg,decode.big_op,src,1);
+ break;
+ case grp2_imm: {
+ Bitu val;
+ if (decode_fetchb_imm(val)) {
+ if (decode.modrm.reg < 4) gen_needflags();
+ else gen_discardflags();
+ gen_load_host((void*)val,DREG(TMPB),1);
+ gen_shift_word_cl(decode.modrm.reg,decode.big_op,src,DREG(TMPB));
+ gen_releasereg(DREG(TMPB));
+ break;
+ }
+ Bit8u imm=(Bit8u)val;
+ if (imm) {
+ /* rotates (first 4 ops) alter cf/of only; shifts (last 4 ops) alter all flags */
+ if (decode.modrm.reg < 4) gen_needflags();
+ else gen_discardflags();
+ gen_shift_word_imm(decode.modrm.reg,decode.big_op,src,imm);
+ } else return;
+ }
+ break;
+ case grp2_cl:
+ gen_needflags(); /* flags must not be changed on ecx==0 */
+ gen_shift_word_cl (decode.modrm.reg,decode.big_op,src,DREG(ECX));
+ break;
+ }
+ if (decode.modrm.mod<3) {
+ dyn_write_word_release(DREG(EA),src,decode.big_op);
+ gen_releasereg(src);
+ }
+}
+
+static void dyn_grp3_eb(void) {
+ dyn_get_modrm();DynReg * src;Bit8u src_i;
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ if ((decode.modrm.reg==0) || (decode.modrm.reg==3)) set_skipflags(true);
+ dyn_read_byte(DREG(EA),DREG(TMPB),false);
+ src=DREG(TMPB);src_i=0;
+ } else {
+ src=&DynRegs[decode.modrm.rm&3];
+ src_i=decode.modrm.rm&4;
+ }
+ switch (decode.modrm.reg) {
+ case 0x0: /* test eb,ib */
+ set_skipflags(false);gen_dop_byte_imm(DOP_TEST,src,src_i,decode_fetchb());
+ goto skipsave;
+ case 0x2: /* NOT Eb */
+ gen_sop_byte(SOP_NOT,src,src_i);
+ break;
+ case 0x3: /* NEG Eb */
+ set_skipflags(false);gen_sop_byte(SOP_NEG,src,src_i);
+ break;
+ case 0x4: /* mul Eb */
+ gen_needflags();gen_mul_byte(false,DREG(EAX),src,src_i);
+ goto skipsave;
+ case 0x5: /* imul Eb */
+ gen_needflags();gen_mul_byte(true,DREG(EAX),src,src_i);
+ goto skipsave;
+ case 0x6: /* div Eb */
+ case 0x7: /* idiv Eb */
+ /* EAX could be used, so precache it */
+ if (decode.modrm.mod==3)
+ gen_dop_byte(DOP_MOV,DREG(TMPB),0,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4);
+ gen_releasereg(DREG(EAX));
+ gen_call_function((decode.modrm.reg==6) ? (void *)&dyn_helper_divb : (void *)&dyn_helper_idivb,
+ "%Rd%Dd",DREG(TMPB),DREG(TMPB));
+ dyn_check_bool_exception(DREG(TMPB));
+ goto skipsave;
+ }
+ /* Save the result if memory op */
+ if (decode.modrm.mod<3) dyn_write_byte_release(DREG(EA),src,false);
+skipsave:
+ gen_releasereg(DREG(TMPB));gen_releasereg(DREG(EA));
+}
+
+static void dyn_grp3_ev(void) {
+ dyn_get_modrm();DynReg * src;
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();src=DREG(TMPW);
+ if ((decode.modrm.reg==0) || (decode.modrm.reg==3)) set_skipflags(true);
+ dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op);
+ } else src=&DynRegs[decode.modrm.rm];
+ switch (decode.modrm.reg) {
+ case 0x0: /* test ev,iv */
+ set_skipflags(false);gen_dop_word_imm(DOP_TEST,decode.big_op,src,decode.big_op ? decode_fetchd() : decode_fetchw());
+ goto skipsave;
+ case 0x2: /* NOT Ev */
+ gen_sop_word(SOP_NOT,decode.big_op,src);
+ break;
+ case 0x3: /* NEG Eb */
+ set_skipflags(false);gen_sop_word(SOP_NEG,decode.big_op,src);
+ break;
+ case 0x4: /* mul Eb */
+ gen_needflags();gen_mul_word(false,DREG(EAX),DREG(EDX),decode.big_op,src);
+ goto skipsave;
+ case 0x5: /* imul Eb */
+ gen_needflags();gen_mul_word(true,DREG(EAX),DREG(EDX),decode.big_op,src);
+ goto skipsave;
+ case 0x6: /* div Eb */
+ case 0x7: /* idiv Eb */
+ /* EAX could be used, so precache it */
+ if (decode.modrm.mod==3)
+ gen_dop_word(DOP_MOV,decode.big_op,DREG(TMPW),&DynRegs[decode.modrm.rm]);
+ gen_releasereg(DREG(EAX));gen_releasereg(DREG(EDX));
+ void * func=(decode.modrm.reg==6) ?
+ (decode.big_op ? (void *)&dyn_helper_divd : (void *)&dyn_helper_divw) :
+ (decode.big_op ? (void *)&dyn_helper_idivd : (void *)&dyn_helper_idivw);
+ gen_call_function(func,"%Rd%Dd",DREG(TMPB),DREG(TMPW));
+ dyn_check_bool_exception(DREG(TMPB));
+ gen_releasereg(DREG(TMPB));
+ goto skipsave;
+ }
+ /* Save the result if memory op */
+ if (decode.modrm.mod<3) dyn_write_word_release(DREG(EA),src,decode.big_op);
+skipsave:
+ gen_releasereg(DREG(TMPW));gen_releasereg(DREG(EA));
+}
+
+static void dyn_mov_ev_seg(void) {
+ dyn_get_modrm();
+ gen_load_host(&Segs.val[decode.modrm.reg],DREG(TMPW),2);
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ dyn_write_word_release(DREG(EA),DREG(TMPW),false);
+ } else {
+ gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],DREG(TMPW));
+ }
+ gen_releasereg(DREG(TMPW));
+}
+
+static void dyn_load_seg(SegNames seg,DynReg * src) {
+ gen_call_function((void *)&CPU_SetSegGeneral,"%Rd%Id%Drw",DREG(TMPB),seg,src);
+ dyn_check_bool_exception(DREG(TMPB));
+ gen_releasereg(DREG(TMPB));
+ gen_releasereg(&DynRegs[G_ES+seg]);
+}
+
+static void dyn_load_seg_off_ea(SegNames seg) {
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ gen_lea(DREG(TMPB),DREG(EA),0,0,decode.big_op ? 4:2);
+ dyn_read_word(DREG(TMPB),DREG(TMPB),false);
+ dyn_read_word_release(DREG(EA),DREG(TMPW),decode.big_op);
+ dyn_load_seg(seg,DREG(TMPB));gen_releasereg(DREG(TMPB));
+ gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.reg],DREG(TMPW));
+ } else {
+ IllegalOption("dyn_load_seg_off_ea");
+ }
+}
+
+static void dyn_mov_seg_ev(void) {
+ dyn_get_modrm();
+ SegNames seg=(SegNames)decode.modrm.reg;
+ if (GCC_UNLIKELY(seg==cs)) IllegalOption("dyn_mov_seg_ev");
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ dyn_read_word(DREG(EA),DREG(EA),false);
+ dyn_load_seg(seg,DREG(EA));
+ gen_releasereg(DREG(EA));
+ } else {
+ dyn_load_seg(seg,&DynRegs[decode.modrm.rm]);
+ }
+}
+
+static void dyn_push_seg(SegNames seg) {
+ gen_load_host(&Segs.val[seg],DREG(TMPW),2);
+ dyn_push(DREG(TMPW));
+ gen_releasereg(DREG(TMPW));
+}
+
+static void dyn_pop_seg(SegNames seg) {
+ gen_releasereg(DREG(ESP));
+ gen_call_function((void *)&CPU_PopSeg,"%Rd%Id%Id",DREG(TMPB),seg,decode.big_op);
+ dyn_check_bool_exception(DREG(TMPB));
+ gen_releasereg(DREG(TMPB));
+ gen_releasereg(&DynRegs[G_ES+seg]);
+ gen_releasereg(DREG(ESP));
+}
+
+static void dyn_pop_ev(void) {
+ dyn_pop(DREG(TMPW));
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+// dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op);
+ if (decode.big_op) gen_call_function((void *)&mem_writed_inline,"%Ddr%Dd",DREG(EA),DREG(TMPW));
+ else gen_call_function((void *)&mem_writew_inline,"%Ddr%Dd",DREG(EA),DREG(TMPW));
+ } else {
+ gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],DREG(TMPW));
+ }
+ gen_releasereg(DREG(TMPW));
+}
+
+static void dyn_enter(void) {
+ gen_releasereg(DREG(ESP));
+ gen_releasereg(DREG(EBP));
+ Bitu bytes=decode_fetchw();
+ Bitu level=decode_fetchb();
+ gen_call_function((void *)&CPU_ENTER,"%Id%Id%Id",decode.big_op,bytes,level);
+}
+
+static void dyn_leave(void) {
+ gen_protectflags();
+ gen_dop_word_var(DOP_MOV,true,DREG(TMPW),&cpu.stack.mask);
+ gen_sop_word(SOP_NOT,true,DREG(TMPW));
+ gen_dop_word(DOP_AND,true,DREG(ESP),DREG(TMPW));
+ gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(EBP));
+ gen_dop_word_var(DOP_AND,true,DREG(TMPW),&cpu.stack.mask);
+ gen_dop_word(DOP_OR,true,DREG(ESP),DREG(TMPW));
+ dyn_pop(DREG(EBP),false);
+ gen_releasereg(DREG(TMPW));
+}
+
+static void dyn_segprefix(SegNames seg) {
+// if (GCC_UNLIKELY((Bitu)(decode.segprefix))) IllegalOption("dyn_segprefix");
+ decode.segprefix=&DynRegs[G_ES+seg];
+}
+
+static void dyn_closeblock(void) {
+ //Shouldn't create empty block normally but let's do it like this
+ gen_protectflags();
+ dyn_fill_blocks();
+ cache_closeblock();
+}
+
+static void dyn_normal_exit(BlockReturn code) {
+ gen_protectflags();
+ dyn_reduce_cycles();
+ dyn_set_eip_last();
+ dyn_save_critical_regs();
+ gen_return(code);
+ dyn_closeblock();
+}
+
+static void dyn_exit_link(Bits eip_change) {
+ gen_protectflags();
+ gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),(decode.code-decode.code_start)+eip_change);
+ dyn_reduce_cycles();
+ dyn_save_critical_regs();
+ gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start));
+ dyn_closeblock();
+}
+
+static void dyn_branched_exit(BranchTypes btype,Bit32s eip_add) {
+ Bitu eip_base=decode.code-decode.code_start;
+ gen_needflags();
+ gen_protectflags();
+ dyn_save_noncritical_regs();
+ gen_releasereg(DREG(FLAGS));
+ gen_releasereg(DREG(EIP));
+
+ gen_preloadreg(DREG(CYCLES));
+ gen_preloadreg(DREG(EIP));
+ DynReg save_cycles,save_eip;
+ dyn_saveregister(DREG(CYCLES),&save_cycles);
+ dyn_saveregister(DREG(EIP),&save_eip);
+ Bit8u * data=gen_create_branch(btype);
+
+ /* Branch not taken */
+ dyn_reduce_cycles();
+ gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),eip_base);
+ gen_releasereg(DREG(CYCLES));
+ gen_releasereg(DREG(EIP));
+ gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start));
+ gen_fill_branch(data);
+
+ /* Branch taken */
+ dyn_restoreregister(&save_cycles,DREG(CYCLES));
+ dyn_restoreregister(&save_eip,DREG(EIP));
+ dyn_reduce_cycles();
+ gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),eip_base+eip_add);
+ gen_releasereg(DREG(CYCLES));
+ gen_releasereg(DREG(EIP));
+ gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlock,cache.start));
+ dyn_closeblock();
+}
+
+enum LoopTypes {
+ LOOP_NONE,LOOP_NE,LOOP_E,LOOP_JCXZ
+};
+
+static void dyn_loop(LoopTypes type) {
+ dyn_reduce_cycles();
+ Bits eip_add=(Bit8s)decode_fetchb();
+ Bitu eip_base=decode.code-decode.code_start;
+ Bit8u * branch1=0;Bit8u * branch2=0;
+ dyn_save_critical_regs();
+ switch (type) {
+ case LOOP_E:
+ gen_needflags();
+ branch1=gen_create_branch(BR_NZ);
+ break;
+ case LOOP_NE:
+ gen_needflags();
+ branch1=gen_create_branch(BR_Z);
+ break;
+ }
+ gen_protectflags();
+ switch (type) {
+ case LOOP_E:
+ case LOOP_NE:
+ case LOOP_NONE:
+ gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX));
+ gen_releasereg(DREG(ECX));
+ branch2=gen_create_branch(BR_Z);
+ break;
+ case LOOP_JCXZ:
+ gen_dop_word(DOP_OR,decode.big_addr,DREG(ECX),DREG(ECX));
+ gen_releasereg(DREG(ECX));
+ branch2=gen_create_branch(BR_NZ);
+ break;
+ }
+ gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base+eip_add);
+ gen_releasereg(DREG(EIP));
+ gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start));
+ if (branch1) {
+ gen_fill_branch(branch1);
+ gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX));
+ gen_releasereg(DREG(ECX));
+ }
+ /* Branch taken */
+ gen_fill_branch(branch2);
+ gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base);
+ gen_releasereg(DREG(EIP));
+ gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlock,cache.start));
+ dyn_closeblock();
+}
+
+static void dyn_ret_near(Bitu bytes) {
+ gen_protectflags();
+ dyn_reduce_cycles();
+ dyn_pop(DREG(EIP));
+ if (bytes) gen_dop_word_imm(DOP_ADD,true,DREG(ESP),bytes);
+ dyn_save_critical_regs();
+ gen_return(BR_Normal);
+ dyn_closeblock();
+}
+
+static void dyn_call_near_imm(void) {
+ Bits imm;
+ if (decode.big_op) imm=(Bit32s)decode_fetchd();
+ else imm=(Bit16s)decode_fetchw();
+ dyn_set_eip_end(DREG(TMPW));
+ dyn_push(DREG(TMPW));
+ gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(TMPW),imm);
+ if (cpu.code.big) gen_dop_word(DOP_MOV,true,DREG(EIP),DREG(TMPW));
+ else gen_extend_word(false,DREG(EIP),DREG(TMPW));
+ dyn_reduce_cycles();
+ dyn_save_critical_regs();
+ gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start));
+ dyn_closeblock();
+}
+
+static void dyn_ret_far(Bitu bytes) {
+ gen_protectflags();
+ dyn_reduce_cycles();
+ dyn_set_eip_last_end(DREG(TMPW));
+ dyn_flags_gen_to_host();
+ dyn_save_critical_regs();
+ gen_call_function((void*)&CPU_RET,"%Id%Id%Drd",decode.big_op,bytes,DREG(TMPW));
+ gen_return_fast(BR_Normal);
+ dyn_closeblock();
+}
+
+static void dyn_call_far_imm(void) {
+ Bitu sel,off;
+ off=decode.big_op ? decode_fetchd() : decode_fetchw();
+ sel=decode_fetchw();
+ dyn_reduce_cycles();
+ dyn_set_eip_last_end(DREG(TMPW));
+ dyn_flags_gen_to_host();
+ dyn_save_critical_regs();
+ gen_call_function((void*)&CPU_CALL,"%Id%Id%Id%Drd",decode.big_op,sel,off,DREG(TMPW));
+ gen_return_fast(BR_Normal);
+ dyn_closeblock();
+}
+
+static void dyn_jmp_far_imm(void) {
+ Bitu sel,off;
+ gen_protectflags();
+ off=decode.big_op ? decode_fetchd() : decode_fetchw();
+ sel=decode_fetchw();
+ dyn_reduce_cycles();
+ dyn_set_eip_last_end(DREG(TMPW));
+ dyn_flags_gen_to_host();
+ dyn_save_critical_regs();
+ gen_call_function((void*)&CPU_JMP,"%Id%Id%Id%Drd",decode.big_op,sel,off,DREG(TMPW));
+ gen_return_fast(BR_Normal);
+ dyn_closeblock();
+}
+
+static void dyn_iret(void) {
+ gen_protectflags();
+ dyn_flags_gen_to_host();
+ dyn_reduce_cycles();
+ dyn_set_eip_last_end(DREG(TMPW));
+ dyn_save_critical_regs();
+ gen_call_function((void*)&CPU_IRET,"%Id%Drd",decode.big_op,DREG(TMPW));
+ gen_return_fast(BR_Iret);
+ dyn_closeblock();
+}
+
+static void dyn_interrupt(Bitu num) {
+ gen_protectflags();
+ dyn_flags_gen_to_host();
+ dyn_reduce_cycles();
+ dyn_set_eip_last_end(DREG(TMPW));
+ dyn_save_critical_regs();
+ gen_call_function((void*)&CPU_Interrupt,"%Id%Id%Drd",num,CPU_INT_SOFTWARE,DREG(TMPW));
+ gen_return_fast(BR_Normal);
+ dyn_closeblock();
+}
+
+static void dyn_add_iocheck(Bitu access_size) {
+ gen_call_function((void *)&CPU_IO_Exception,"%Dw%Id",DREG(EDX),access_size);
+ dyn_check_bool_exception_al();
+}
+
+static void dyn_add_iocheck_var(Bit8u accessed_port,Bitu access_size) {
+ gen_call_function((void *)&CPU_IO_Exception,"%Id%Id",accessed_port,access_size);
+ dyn_check_bool_exception_al();
+}
+
+#ifdef X86_DYNFPU_DH_ENABLED
+#include "dyn_fpu_dh.h"
+#define dh_fpu_startup() { \
+ fpu_used=true; \
+ gen_protectflags(); \
+ gen_load_host(&dyn_dh_fpu.state_used,DREG(TMPB),4); \
+ gen_dop_word_imm(DOP_CMP,true,DREG(TMPB),0); \
+ gen_releasereg(DREG(TMPB)); \
+ save_info[used_save_info].branch_pos=gen_create_branch_long(BR_Z); \
+ dyn_savestate(&save_info[used_save_info].state); \
+ save_info[used_save_info].return_pos=cache.pos; \
+ save_info[used_save_info].type=fpu_restore; \
+ used_save_info++; \
+}
+#endif
+#include "dyn_fpu.h"
+
+static CacheBlock * CreateCacheBlock(CodePageHandler * codepage,PhysPt start,Bitu max_opcodes) {
+ Bits i;
+/* Init a load of variables */
+ decode.code_start=start;
+ decode.code=start;
+ Bitu cycles=0;
+ decode.page.code=codepage;
+ decode.page.index=start&4095;
+ decode.page.wmap=codepage->write_map;
+ decode.page.invmap=codepage->invalidation_map;
+ decode.page.first=start >> 12;
+ decode.active_block=decode.block=cache_openblock();
+ decode.block->page.start=decode.page.index;
+ codepage->AddCacheBlock(decode.block);
+
+ gen_save_host_direct(&cache.block.running,(Bit32u)decode.block);
+ for (i=0;i<G_MAX;i++) {
+ DynRegs[i].flags&=~(DYNFLG_ACTIVE|DYNFLG_CHANGED);
+ DynRegs[i].genreg=0;
+ }
+ gen_reinit();
+ /* Start with the cycles check */
+ gen_protectflags();
+ gen_dop_word_imm(DOP_CMP,true,DREG(CYCLES),0);
+ save_info[used_save_info].branch_pos=gen_create_branch_long(BR_LE);
+ save_info[used_save_info].type=cycle_check;
+ used_save_info++;
+ gen_releasereg(DREG(CYCLES));
+ decode.cycles=0;
+#ifdef X86_DYNFPU_DH_ENABLED
+ bool fpu_used=false;
+#endif
+ while (max_opcodes--) {
+/* Init prefixes */
+ decode.big_addr=cpu.code.big;
+ decode.big_op=cpu.code.big;
+ decode.segprefix=0;
+ decode.rep=REP_NONE;
+ decode.cycles++;
+ decode.op_start=decode.code;
+restart_prefix:
+ Bitu opcode;
+ if (!decode.page.invmap) opcode=decode_fetchb();
+ else {
+ if (decode.page.index<4096) {
+ if (GCC_UNLIKELY(decode.page.invmap[decode.page.index]>=4)) goto illegalopcode;
+ opcode=decode_fetchb();
+ } else {
+ opcode=decode_fetchb();
+ if (GCC_UNLIKELY(decode.page.invmap &&
+ (decode.page.invmap[decode.page.index-1]>=4))) goto illegalopcode;
+ }
+ }
+ switch (opcode) {
+
+ case 0x00:dyn_dop_ebgb(DOP_ADD);break;
+ case 0x01:dyn_dop_evgv(DOP_ADD);break;
+ case 0x02:dyn_dop_gbeb(DOP_ADD);break;
+ case 0x03:dyn_dop_gvev(DOP_ADD);break;
+ case 0x04:gen_discardflags();gen_dop_byte_imm(DOP_ADD,DREG(EAX),0,decode_fetchb());break;
+ case 0x05:gen_discardflags();dyn_dop_word_imm(DOP_ADD,decode.big_op,DREG(EAX));break;
+ case 0x06:dyn_push_seg(es);break;
+ case 0x07:dyn_pop_seg(es);break;
+
+ case 0x08:dyn_dop_ebgb(DOP_OR);break;
+ case 0x09:dyn_dop_evgv(DOP_OR);break;
+ case 0x0a:dyn_dop_gbeb(DOP_OR);break;
+ case 0x0b:dyn_dop_gvev(DOP_OR);break;
+ case 0x0c:gen_discardflags();gen_dop_byte_imm(DOP_OR,DREG(EAX),0,decode_fetchb());break;
+ case 0x0d:gen_discardflags();gen_dop_word_imm(DOP_OR,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
+ case 0x0e:dyn_push_seg(cs);break;
+ case 0x0f:
+ {
+ Bitu dual_code=decode_fetchb();
+ switch (dual_code) {
+ /* Short conditional jumps */
+ case 0x80:case 0x81:case 0x82:case 0x83:case 0x84:case 0x85:case 0x86:case 0x87:
+ case 0x88:case 0x89:case 0x8a:case 0x8b:case 0x8c:case 0x8d:case 0x8e:case 0x8f:
+ dyn_branched_exit((BranchTypes)(dual_code&0xf),
+ decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw());
+ goto finish_block;
+ /* PUSH/POP FS */
+ case 0xa0:dyn_push_seg(fs);break;
+ case 0xa1:dyn_pop_seg(fs);break;
+ /* SHLD Imm/cl*/
+ case 0xa4:dyn_dshift_ev_gv(true,true);break;
+ case 0xa5:dyn_dshift_ev_gv(true,false);break;
+ /* PUSH/POP GS */
+ case 0xa8:dyn_push_seg(gs);break;
+ case 0xa9:dyn_pop_seg(gs);break;
+ /* SHRD Imm/cl*/
+ case 0xac:dyn_dshift_ev_gv(false,true);break;
+ case 0xad:dyn_dshift_ev_gv(false,false);break;
+ /* Imul Ev,Gv */
+ case 0xaf:dyn_imul_gvev(0);break;
+ /* CMPXCHG */
+ case 0xb1:dyn_cmpxchg_evgv();break;
+ /* LFS,LGS */
+ case 0xb4:
+ dyn_get_modrm();
+ if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode;
+ dyn_load_seg_off_ea(fs);
+ break;
+ case 0xb5:
+ dyn_get_modrm();
+ if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode;
+ dyn_load_seg_off_ea(gs);
+ break;
+ /* MOVZX Gv,Eb/Ew */
+ case 0xb6:dyn_mov_ev_gb(false);break;
+ case 0xb7:dyn_mov_ev_gw(false);break;
+ /* MOVSX Gv,Eb/Ew */
+ case 0xbe:dyn_mov_ev_gb(true);break;
+ case 0xbf:dyn_mov_ev_gw(true);break;
+
+ default:
+#if DYN_LOG
+ LOG_MSG("Unhandled dual opcode 0F%02X",dual_code);
+#endif
+ goto illegalopcode;
+ }
+ }break;
+
+ case 0x10:dyn_dop_ebgb(DOP_ADC);break;
+ case 0x11:dyn_dop_evgv(DOP_ADC);break;
+ case 0x12:dyn_dop_gbeb(DOP_ADC);break;
+ case 0x13:dyn_dop_gvev(DOP_ADC);break;
+ case 0x14:gen_needcarry();gen_dop_byte_imm(DOP_ADC,DREG(EAX),0,decode_fetchb());break;
+ case 0x15:gen_needcarry();gen_dop_word_imm(DOP_ADC,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
+ case 0x16:dyn_push_seg(ss);break;
+ case 0x17:dyn_pop_seg(ss);break;
+
+ case 0x18:dyn_dop_ebgb(DOP_SBB);break;
+ case 0x19:dyn_dop_evgv(DOP_SBB);break;
+ case 0x1a:dyn_dop_gbeb(DOP_SBB);break;
+ case 0x1b:dyn_dop_gvev(DOP_SBB);break;
+ case 0x1c:gen_needcarry();gen_dop_byte_imm(DOP_SBB,DREG(EAX),0,decode_fetchb());break;
+ case 0x1d:gen_needcarry();gen_dop_word_imm(DOP_SBB,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
+ case 0x1e:dyn_push_seg(ds);break;
+ case 0x1f:dyn_pop_seg(ds);break;
+ case 0x20:dyn_dop_ebgb(DOP_AND);break;
+ case 0x21:dyn_dop_evgv(DOP_AND);break;
+ case 0x22:dyn_dop_gbeb(DOP_AND);break;
+ case 0x23:dyn_dop_gvev(DOP_AND);break;
+ case 0x24:gen_discardflags();gen_dop_byte_imm(DOP_AND,DREG(EAX),0,decode_fetchb());break;
+ case 0x25:gen_discardflags();dyn_dop_word_imm(DOP_AND,decode.big_op,DREG(EAX));break;
+ case 0x26:dyn_segprefix(es);goto restart_prefix;
+
+ case 0x28:dyn_dop_ebgb(DOP_SUB);break;
+ case 0x29:dyn_dop_evgv(DOP_SUB);break;
+ case 0x2a:dyn_dop_gbeb(DOP_SUB);break;
+ case 0x2b:dyn_dop_gvev(DOP_SUB);break;
+ case 0x2c:gen_discardflags();gen_dop_byte_imm(DOP_SUB,DREG(EAX),0,decode_fetchb());break;
+ case 0x2d:gen_discardflags();gen_dop_word_imm(DOP_SUB,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
+ case 0x2e:dyn_segprefix(cs);goto restart_prefix;
+
+ case 0x30:dyn_dop_ebgb(DOP_XOR);break;
+ case 0x31:dyn_dop_evgv(DOP_XOR);break;
+ case 0x32:dyn_dop_gbeb(DOP_XOR);break;
+ case 0x33:dyn_dop_gvev(DOP_XOR);break;
+ case 0x34:gen_discardflags();gen_dop_byte_imm(DOP_XOR,DREG(EAX),0,decode_fetchb());break;
+ case 0x35:gen_discardflags();gen_dop_word_imm(DOP_XOR,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
+ case 0x36:dyn_segprefix(ss);goto restart_prefix;
+
+ case 0x38:dyn_dop_ebgb(DOP_CMP);break;
+ case 0x39:dyn_dop_evgv(DOP_CMP);break;
+ case 0x3a:dyn_dop_gbeb(DOP_CMP);break;
+ case 0x3b:dyn_dop_gvev(DOP_CMP);break;
+ case 0x3c:gen_discardflags();gen_dop_byte_imm(DOP_CMP,DREG(EAX),0,decode_fetchb());break;
+ case 0x3d:gen_discardflags();gen_dop_word_imm(DOP_CMP,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
+ case 0x3e:dyn_segprefix(ds);goto restart_prefix;
+
+ /* INC/DEC general register */
+ case 0x40:case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:case 0x47:
+ gen_needcarry();gen_sop_word(SOP_INC,decode.big_op,&DynRegs[opcode&7]);
+ break;
+ case 0x48:case 0x49:case 0x4a:case 0x4b:case 0x4c:case 0x4d:case 0x4e:case 0x4f:
+ gen_needcarry();gen_sop_word(SOP_DEC,decode.big_op,&DynRegs[opcode&7]);
+ break;
+ /* PUSH/POP General register */
+ case 0x50:case 0x51:case 0x52:case 0x53:case 0x55:case 0x56:case 0x57:
+ dyn_push(&DynRegs[opcode&7]);
+ break;
+ case 0x54: /* PUSH SP is special */
+ gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(ESP));
+ dyn_push(DREG(TMPW));
+ gen_releasereg(DREG(TMPW));
+ break;
+ case 0x58:case 0x59:case 0x5a:case 0x5b:case 0x5c:case 0x5d:case 0x5e:case 0x5f:
+ dyn_pop(&DynRegs[opcode&7]);
+ break;
+ case 0x60: /* PUSHA */
+ gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(ESP));
+ for (i=G_EAX;i<=G_EDI;i++) {
+ dyn_push_unchecked((i!=G_ESP) ? &DynRegs[i] : DREG(TMPW));
+ }
+ gen_releasereg(DREG(TMPW));
+ break;
+ case 0x61: /* POPA */
+ for (i=G_EDI;i>=G_EAX;i--) {
+ dyn_pop((i!=G_ESP) ? &DynRegs[i] : DREG(TMPW),false);
+ }
+ gen_releasereg(DREG(TMPW));
+ break;
+ //segprefix FS,GS
+ case 0x64:dyn_segprefix(fs);goto restart_prefix;
+ case 0x65:dyn_segprefix(gs);goto restart_prefix;
+ //Push immediates
+ //Operand size
+ case 0x66:decode.big_op=!cpu.code.big;goto restart_prefix;
+ //Address size
+ case 0x67:decode.big_addr=!cpu.code.big;goto restart_prefix;
+ case 0x68: /* PUSH Iv */
+ gen_dop_word_imm(DOP_MOV,decode.big_op,DREG(TMPW),decode.big_op ? decode_fetchd() : decode_fetchw());
+ dyn_push(DREG(TMPW));
+ gen_releasereg(DREG(TMPW));
+ break;
+ /* Imul Ivx */
+ case 0x69:dyn_imul_gvev(decode.big_op ? 4 : 2);break;
+ case 0x6a: /* PUSH Ibx */
+ gen_dop_word_imm(DOP_MOV,true,DREG(TMPW),(Bit8s)decode_fetchb());
+ dyn_push(DREG(TMPW));
+ gen_releasereg(DREG(TMPW));
+ break;
+ /* Imul Ibx */
+ case 0x6b:dyn_imul_gvev(1);break;
+ /* Short conditional jumps */
+ case 0x70:case 0x71:case 0x72:case 0x73:case 0x74:case 0x75:case 0x76:case 0x77:
+ case 0x78:case 0x79:case 0x7a:case 0x7b:case 0x7c:case 0x7d:case 0x7e:case 0x7f:
+ dyn_branched_exit((BranchTypes)(opcode&0xf),(Bit8s)decode_fetchb());
+ goto finish_block;
+ /* Group 1 */
+ case 0x80:dyn_grp1_eb_ib();break;
+ case 0x81:dyn_grp1_ev_ivx(false);break;
+ case 0x82:dyn_grp1_eb_ib();break;
+ case 0x83:dyn_grp1_ev_ivx(true);break;
+ /* TEST Gb,Eb Gv,Ev */
+ case 0x84:dyn_dop_gbeb(DOP_TEST);break;
+ case 0x85:dyn_dop_gvev(DOP_TEST);break;
+ /* XCHG Eb,Gb Ev,Gv */
+ case 0x86:dyn_dop_ebgb(DOP_XCHG);break;
+ case 0x87:dyn_dop_evgv(DOP_XCHG);break;
+ /* MOV e,g and g,e */
+ case 0x88:dyn_mov_ebgb();break;
+ case 0x89:dyn_mov_evgv();break;
+ case 0x8a:dyn_mov_gbeb();break;
+ case 0x8b:dyn_mov_gvev();break;
+ /* MOV ev,seg */
+ case 0x8c:dyn_mov_ev_seg();break;
+ /* LEA Gv */
+ case 0x8d:
+ dyn_get_modrm();
+ if (decode.big_op) {
+ dyn_fill_ea(false,&DynRegs[decode.modrm.reg]);
+ } else {
+ dyn_fill_ea(false);
+ gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.reg],DREG(EA));
+ gen_releasereg(DREG(EA));
+ }
+ break;
+ /* Mov seg,ev */
+ case 0x8e:dyn_mov_seg_ev();break;
+ /* POP Ev */
+ case 0x8f:dyn_pop_ev();break;
+ case 0x90: //NOP
+ case 0x9b: //WAIT/FWAIT
+ break;
+ //XCHG ax,reg
+ case 0x91:case 0x92:case 0x93:case 0x94:case 0x95:case 0x96:case 0x97:
+ gen_dop_word(DOP_XCHG,decode.big_op,DREG(EAX),&DynRegs[opcode&07]);
+ break;
+ /* CBW/CWDE */
+ case 0x98:
+ gen_cbw(decode.big_op,DREG(EAX));
+ break;
+ /* CWD/CDQ */
+ case 0x99:
+ gen_cwd(decode.big_op,DREG(EAX),DREG(EDX));
+ break;
+ /* CALL FAR Ip */
+ case 0x9a:dyn_call_far_imm();goto finish_block;
+ case 0x9c: //PUSHF
+ gen_protectflags();
+ gen_releasereg(DREG(ESP));
+ dyn_flags_gen_to_host();
+ gen_call_function((void *)&CPU_PUSHF,"%Rd%Id",DREG(TMPB),decode.big_op);
+ dyn_check_bool_exception(DREG(TMPB));
+ gen_releasereg(DREG(TMPB));
+ break;
+ case 0x9d: //POPF
+ gen_releasereg(DREG(ESP));
+ gen_releasereg(DREG(FLAGS));
+ gen_call_function((void *)&CPU_POPF,"%Rd%Id",DREG(TMPB),decode.big_op);
+ dyn_check_bool_exception(DREG(TMPB));
+ dyn_flags_host_to_gen();
+ gen_releasereg(DREG(TMPB));
+ dyn_check_irqrequest();
+ break;
+ /* MOV AL,direct addresses */
+ case 0xa0:
+ gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0,
+ decode.big_addr ? decode_fetchd() : decode_fetchw());
+ dyn_read_byte_release(DREG(EA),DREG(EAX),false);
+ break;
+ /* MOV AX,direct addresses */
+ case 0xa1:
+ gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0,
+ decode.big_addr ? decode_fetchd() : decode_fetchw());
+ dyn_read_word_release(DREG(EA),DREG(EAX),decode.big_op);
+ break;
+ /* MOV direct address,AL */
+ case 0xa2:
+ if (decode.big_addr) {
+ Bitu val;
+ if (decode_fetchd_imm(val)) {
+ gen_lea_imm_mem(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),(void*)val);
+ } else {
+ gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0,(Bits)val);
+ }
+ dyn_write_byte_release(DREG(EA),DREG(EAX),false);
+ } else {
+ gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0,decode_fetchw());
+ dyn_write_byte_release(DREG(EA),DREG(EAX),false);
+ }
+ break;
+ /* MOV direct addresses,AX */
+ case 0xa3:
+ gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0,
+ decode.big_addr ? decode_fetchd() : decode_fetchw());
+ dyn_write_word_release(DREG(EA),DREG(EAX),decode.big_op);
+ break;
+ /* MOVSB/W/D*/
+ case 0xa4:dyn_string(STR_MOVSB);break;
+ case 0xa5:dyn_string(decode.big_op ? STR_MOVSD : STR_MOVSW);break;
+ /* TEST AL,AX Imm */
+ case 0xa8:gen_discardflags();gen_dop_byte_imm(DOP_TEST,DREG(EAX),0,decode_fetchb());break;
+ case 0xa9:gen_discardflags();gen_dop_word_imm(DOP_TEST,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
+ /* STOSB/W/D*/
+ case 0xaa:dyn_string(STR_STOSB);break;
+ case 0xab:dyn_string(decode.big_op ? STR_STOSD : STR_STOSW);break;
+ /* LODSB/W/D*/
+ case 0xac:dyn_string(STR_LODSB);break;
+ case 0xad:dyn_string(decode.big_op ? STR_LODSD : STR_LODSW);break;
+ //Mov Byte reg,Imm byte
+ case 0xb0:case 0xb1:case 0xb2:case 0xb3:case 0xb4:case 0xb5:case 0xb6:case 0xb7:
+ gen_dop_byte_imm(DOP_MOV,&DynRegs[opcode&3],opcode&4,decode_fetchb());
+ break;
+ //Mov word reg imm byte,word,
+ case 0xb8:case 0xb9:case 0xba:case 0xbb:case 0xbc:case 0xbd:case 0xbe:case 0xbf:
+ if (decode.big_op) {
+ dyn_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[opcode&7]);break;
+ } else {
+ gen_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[opcode&7],decode_fetchw());break;
+ }
+ break;
+ //GRP2 Eb/Ev,Ib
+ case 0xc0:dyn_grp2_eb(grp2_imm);break;
+ case 0xc1:dyn_grp2_ev(grp2_imm);break;
+ //RET near Iw / Ret
+ case 0xc2:dyn_ret_near(decode_fetchw());goto finish_block;
+ case 0xc3:dyn_ret_near(0);goto finish_block;
+ //LES
+ case 0xc4:
+ dyn_get_modrm();
+ if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode;
+ dyn_load_seg_off_ea(es);
+ break;
+ //LDS
+ case 0xc5:
+ dyn_get_modrm();
+ if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode;
+ dyn_load_seg_off_ea(ds);
+ break;
+ // MOV Eb/Ev,Ib/Iv
+ case 0xc6:dyn_mov_ebib();break;
+ case 0xc7:dyn_mov_eviv();break;
+ //ENTER and LEAVE
+ case 0xc8:dyn_enter();break;
+ case 0xc9:dyn_leave();break;
+ //RET far Iw / Ret
+ case 0xca:dyn_ret_far(decode_fetchw());goto finish_block;
+ case 0xcb:dyn_ret_far(0);goto finish_block;
+ /* Interrupt */
+// case 0xcd:dyn_interrupt(decode_fetchb());goto finish_block;
+ /* IRET */
+ case 0xcf:dyn_iret();goto finish_block;
+
+ //GRP2 Eb/Ev,1
+ case 0xd0:dyn_grp2_eb(grp2_1);break;
+ case 0xd1:dyn_grp2_ev(grp2_1);break;
+ //GRP2 Eb/Ev,CL
+ case 0xd2:dyn_grp2_eb(grp2_cl);break;
+ case 0xd3:dyn_grp2_ev(grp2_cl);break;
+ //FPU
+#ifdef CPU_FPU
+ case 0xd8:
+#ifdef X86_DYNFPU_DH_ENABLED
+ if (dyn_dh_fpu.dh_fpu_enabled) {
+ if (fpu_used) dh_fpu_esc0();
+ else {
+ dh_fpu_startup();
+ dh_fpu_esc0();
+ }
+ } else
+#endif
+ dyn_fpu_esc0();
+ break;
+ case 0xd9:
+#ifdef X86_DYNFPU_DH_ENABLED
+ if (dyn_dh_fpu.dh_fpu_enabled) {
+ if (fpu_used) dh_fpu_esc1();
+ else {
+ dh_fpu_startup();
+ dh_fpu_esc1();
+ }
+ } else
+#endif
+ dyn_fpu_esc1();
+ break;
+ case 0xda:
+#ifdef X86_DYNFPU_DH_ENABLED
+ if (dyn_dh_fpu.dh_fpu_enabled) {
+ if (fpu_used) dh_fpu_esc2();
+ else {
+ dh_fpu_startup();
+ dh_fpu_esc2();
+ }
+ } else
+#endif
+ dyn_fpu_esc2();
+ break;
+ case 0xdb:
+#ifdef X86_DYNFPU_DH_ENABLED
+ if (dyn_dh_fpu.dh_fpu_enabled) {
+ if (fpu_used) dh_fpu_esc3();
+ else {
+ dh_fpu_startup();
+ dh_fpu_esc3();
+ }
+ } else
+#endif
+ dyn_fpu_esc3();
+ break;
+ case 0xdc:
+#ifdef X86_DYNFPU_DH_ENABLED
+ if (dyn_dh_fpu.dh_fpu_enabled) {
+ if (fpu_used) dh_fpu_esc4();
+ else {
+ dh_fpu_startup();
+ dh_fpu_esc4();
+ }
+ } else
+#endif
+ dyn_fpu_esc4();
+ break;
+ case 0xdd:
+#ifdef X86_DYNFPU_DH_ENABLED
+ if (dyn_dh_fpu.dh_fpu_enabled) {
+ if (fpu_used) dh_fpu_esc5();
+ else {
+ dh_fpu_startup();
+ dh_fpu_esc5();
+ }
+ } else
+#endif
+ dyn_fpu_esc5();
+ break;
+ case 0xde:
+#ifdef X86_DYNFPU_DH_ENABLED
+ if (dyn_dh_fpu.dh_fpu_enabled) {
+ if (fpu_used) dh_fpu_esc6();
+ else {
+ dh_fpu_startup();
+ dh_fpu_esc6();
+ }
+ } else
+#endif
+ dyn_fpu_esc6();
+ break;
+ case 0xdf:
+#ifdef X86_DYNFPU_DH_ENABLED
+ if (dyn_dh_fpu.dh_fpu_enabled) {
+ if (fpu_used) dh_fpu_esc7();
+ else {
+ dh_fpu_startup();
+ dh_fpu_esc7();
+ }
+ } else
+#endif
+ dyn_fpu_esc7();
+ break;
+#endif
+ //Loops
+ case 0xe2:dyn_loop(LOOP_NONE);goto finish_block;
+ case 0xe3:dyn_loop(LOOP_JCXZ);goto finish_block;
+ //IN AL/AX,imm
+ case 0xe4: {
+ Bitu port=decode_fetchb();
+ dyn_add_iocheck_var(port,1);
+ gen_call_function((void*)&IO_ReadB,"%Id%Rl",port,DREG(EAX));
+ } break;
+ case 0xe5: {
+ Bitu port=decode_fetchb();
+ dyn_add_iocheck_var(port,decode.big_op?4:2);
+ if (decode.big_op) {
+ gen_call_function((void*)&IO_ReadD,"%Id%Rd",port,DREG(EAX));
+ } else {
+ gen_call_function((void*)&IO_ReadW,"%Id%Rw",port,DREG(EAX));
+ }
+ } break;
+ //OUT imm,AL
+ case 0xe6: {
+ Bitu port=decode_fetchb();
+ dyn_add_iocheck_var(port,1);
+ gen_call_function((void*)&IO_WriteB,"%Id%Dl",port,DREG(EAX));
+ } break;
+ case 0xe7: {
+ Bitu port=decode_fetchb();
+ dyn_add_iocheck_var(port,decode.big_op?4:2);
+ if (decode.big_op) {
+ gen_call_function((void*)&IO_WriteD,"%Id%Dd",port,DREG(EAX));
+ } else {
+ gen_call_function((void*)&IO_WriteW,"%Id%Dw",port,DREG(EAX));
+ }
+ } break;
+ case 0xe8: /* CALL Ivx */
+ dyn_call_near_imm();
+ goto finish_block;
+ case 0xe9: /* Jmp Ivx */
+ dyn_exit_link(decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw());
+ goto finish_block;
+ case 0xea: /* JMP FAR Ip */
+ dyn_jmp_far_imm();
+ goto finish_block;
+ /* Jmp Ibx */
+ case 0xeb:dyn_exit_link((Bit8s)decode_fetchb());goto finish_block;
+ /* IN AL/AX,DX*/
+ case 0xec:
+ dyn_add_iocheck(1);
+ gen_call_function((void*)&IO_ReadB,"%Dw%Rl",DREG(EDX),DREG(EAX));
+ break;
+ case 0xed:
+ dyn_add_iocheck(decode.big_op?4:2);
+ if (decode.big_op) {
+ gen_call_function((void*)&IO_ReadD,"%Dw%Rd",DREG(EDX),DREG(EAX));
+ } else {
+ gen_call_function((void*)&IO_ReadW,"%Dw%Rw",DREG(EDX),DREG(EAX));
+ }
+ break;
+ /* OUT DX,AL/AX */
+ case 0xee:
+ dyn_add_iocheck(1);
+ gen_call_function((void*)&IO_WriteB,"%Dw%Dl",DREG(EDX),DREG(EAX));
+ break;
+ case 0xef:
+ dyn_add_iocheck(decode.big_op?4:2);
+ if (decode.big_op) {
+ gen_call_function((void*)&IO_WriteD,"%Dw%Dd",DREG(EDX),DREG(EAX));
+ } else {
+ gen_call_function((void*)&IO_WriteW,"%Dw%Dw",DREG(EDX),DREG(EAX));
+ }
+ break;
+ case 0xf0: //LOCK
+ break;
+ case 0xf2: //REPNE/NZ
+ decode.rep=REP_NZ;
+ goto restart_prefix;
+ case 0xf3: //REPE/Z
+ decode.rep=REP_Z;
+ goto restart_prefix;
+ /* Change carry flag */
+ case 0xf5: //CMC
+ case 0xf8: //CLC
+ case 0xf9: //STC
+ gen_needflags();
+ cache_addb(opcode);break;
+ /* GRP 3 Eb/EV */
+ case 0xf6:dyn_grp3_eb();break;
+ case 0xf7:dyn_grp3_ev();break;
+ /* Change interrupt flag */
+ case 0xfa: //CLI
+ gen_releasereg(DREG(FLAGS));
+ gen_call_function((void *)&CPU_CLI,"%Rd",DREG(TMPB));
+ dyn_check_bool_exception(DREG(TMPB));
+ gen_releasereg(DREG(TMPB));
+ break;
+ case 0xfb: //STI
+ gen_releasereg(DREG(FLAGS));
+ gen_call_function((void *)&CPU_STI,"%Rd",DREG(TMPB));
+ dyn_check_bool_exception(DREG(TMPB));
+ gen_releasereg(DREG(TMPB));
+ dyn_check_irqrequest();
+ if (max_opcodes<=0) max_opcodes=1; //Allow 1 extra opcode
+ break;
+ case 0xfc: //CLD
+ gen_protectflags();
+ gen_dop_word_imm(DOP_AND,true,DREG(FLAGS),~FLAG_DF);
+ gen_save_host_direct(&cpu.direction,1);
+ break;
+ case 0xfd: //STD
+ gen_protectflags();
+ gen_dop_word_imm(DOP_OR,true,DREG(FLAGS),FLAG_DF);
+ gen_save_host_direct(&cpu.direction,-1);
+ break;
+ /* GRP 4 Eb and callback's */
+ case 0xfe:
+ dyn_get_modrm();
+ switch (decode.modrm.reg) {
+ case 0x0://INC Eb
+ case 0x1://DEC Eb
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();dyn_read_byte(DREG(EA),DREG(TMPB),false);
+ gen_needcarry();
+ gen_sop_byte(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,DREG(TMPB),0);
+ dyn_write_byte_release(DREG(EA),DREG(TMPB),false);
+ gen_releasereg(DREG(TMPB));
+ } else {
+ gen_needcarry();
+ gen_sop_byte(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,
+ &DynRegs[decode.modrm.rm&3],decode.modrm.rm&4);
+ }
+ break;
+ case 0x7: //CALBACK Iw
+ gen_save_host_direct(&core_dyn.callback,decode_fetchw());
+ dyn_set_eip_end();
+ dyn_reduce_cycles();
+ dyn_save_critical_regs();
+ gen_return(BR_CallBack);
+ dyn_closeblock();
+ goto finish_block;
+ }
+ break;
+
+ case 0xff:
+ {
+ dyn_get_modrm();DynReg * src;
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea();
+ dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op);
+ src=DREG(TMPW);
+ } else src=&DynRegs[decode.modrm.rm];
+ switch (decode.modrm.reg) {
+ case 0x0://INC Ev
+ case 0x1://DEC Ev
+ gen_needcarry();
+ gen_sop_word(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,decode.big_op,src);
+ if (decode.modrm.mod<3){
+ dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op);
+ gen_releasereg(DREG(TMPW));
+ }
+ break;
+ case 0x2: /* CALL Ev */
+ gen_lea(DREG(TMPB),DREG(EIP),0,0,decode.code-decode.code_start);
+ dyn_push(DREG(TMPB));
+ gen_releasereg(DREG(TMPB));
+ gen_dop_word(DOP_MOV,decode.big_op,DREG(EIP),src);
+ goto core_close_block;
+ case 0x4: /* JMP Ev */
+ gen_dop_word(DOP_MOV,decode.big_op,DREG(EIP),src);
+ goto core_close_block;
+ case 0x3: /* CALL Ep */
+ case 0x5: /* JMP Ep */
+ gen_protectflags();
+ dyn_flags_gen_to_host();
+ gen_lea(DREG(EA),DREG(EA),0,0,decode.big_op ? 4: 2);
+ dyn_read_word(DREG(EA),DREG(EA),false);
+ dyn_set_eip_last_end(DREG(TMPB));
+ dyn_save_critical_regs();
+ gen_call_function(
+ decode.modrm.reg == 3 ? (void*)&CPU_CALL : (void*)&CPU_JMP,
+ decode.big_op ? "%Id%Drw%Drd%Drd" : "%Id%Drw%Drw%Drd",
+ decode.big_op,DREG(EA),DREG(TMPW),DREG(TMPB));
+ dyn_flags_host_to_gen();
+ goto core_close_block;
+ case 0x6: /* PUSH Ev */
+ gen_releasereg(DREG(EA));
+ dyn_push(src);
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("CPU:GRP5:Illegal opcode 0xff");
+ goto illegalopcode;
+ }}
+ break;
+ default:
+#if DYN_LOG
+// LOG_MSG("Dynamic unhandled opcode %X",opcode);
+#endif
+ goto illegalopcode;
+ }
+ }
+ // link to next block because the maximum number of opcodes has been reached
+ dyn_set_eip_end();
+ dyn_reduce_cycles();
+ dyn_save_critical_regs();
+ gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start));
+ dyn_closeblock();
+ goto finish_block;
+core_close_block:
+ dyn_reduce_cycles();
+ dyn_save_critical_regs();
+ gen_return(BR_Normal);
+ dyn_closeblock();
+ goto finish_block;
+illegalopcode:
+ dyn_set_eip_last();
+ dyn_reduce_cycles();
+ dyn_save_critical_regs();
+ gen_return(BR_Opcode);
+ dyn_closeblock();
+ goto finish_block;
+#if (C_DEBUG)
+ dyn_set_eip_last();
+ dyn_reduce_cycles();
+ dyn_save_critical_regs();
+ gen_return(BR_OpcodeFull);
+ dyn_closeblock();
+ goto finish_block;
+#endif
+finish_block:
+ /* Setup the correct end-address */
+ decode.active_block->page.end=--decode.page.index;
+// LOG_MSG("Created block size %d start %d end %d",decode.block->cache.size,decode.block->page.start,decode.block->page.end);
+ return decode.block;
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#include "dosbox.h"
+#if C_FPU
+
+#include <math.h>
+#include <float.h>
+#include "cross.h"
+#include "mem.h"
+#include "fpu.h"
+#include "cpu.h"
+
+
+static void FPU_FDECSTP(){
+ TOP = (TOP - 1) & 7;
+}
+
+static void FPU_FINCSTP(){
+ TOP = (TOP + 1) & 7;
+}
+
+static void FPU_FNSTCW(PhysPt addr){
+ mem_writew(addr,fpu.cw);
+}
+
+static void FPU_FFREE(Bitu st) {
+ fpu.tags[st]=TAG_Empty;
+}
+
+
+#if C_FPU_X86
+#include "../../fpu/fpu_instructions_x86.h"
+#else
+#include "../../fpu/fpu_instructions.h"
+#endif
+
+
+#define dyn_fpu_top() { \
+ gen_protectflags(); \
+ gen_load_host(&TOP,DREG(EA),4); \
+ gen_dop_word_imm(DOP_ADD,true,DREG(EA),decode.modrm.rm); \
+ gen_dop_word_imm(DOP_AND,true,DREG(EA),7); \
+ gen_load_host(&TOP,DREG(TMPB),4); \
+}
+
+static void dyn_eatree() {
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ switch (group){
+ case 0x00: /* FADD ST,STi */
+ gen_call_function((void*)&FPU_FADD_EA,"%Ddr",DREG(TMPB));
+ break;
+ case 0x01: /* FMUL ST,STi */
+ gen_call_function((void*)&FPU_FMUL_EA,"%Ddr",DREG(TMPB));
+ break;
+ case 0x02: /* FCOM STi */
+ gen_call_function((void*)&FPU_FCOM_EA,"%Ddr",DREG(TMPB));
+ break;
+ case 0x03: /* FCOMP STi */
+ gen_call_function((void*)&FPU_FCOM_EA,"%Ddr",DREG(TMPB));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ case 0x04: /* FSUB ST,STi */
+ gen_call_function((void*)&FPU_FSUB_EA,"%Ddr",DREG(TMPB));
+ break;
+ case 0x05: /* FSUBR ST,STi */
+ gen_call_function((void*)&FPU_FSUBR_EA,"%Ddr",DREG(TMPB));
+ break;
+ case 0x06: /* FDIV ST,STi */
+ gen_call_function((void*)&FPU_FDIV_EA,"%Ddr",DREG(TMPB));
+ break;
+ case 0x07: /* FDIVR ST,STi */
+ gen_call_function((void*)&FPU_FDIVR_EA,"%Ddr",DREG(TMPB));
+ break;
+ default:
+ break;
+ }
+}
+
+static void dyn_fpu_esc0(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ dyn_fpu_top();
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ switch (group){
+ case 0x00: //FADD ST,STi /
+ gen_call_function((void*)&FPU_FADD,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ case 0x01: // FMUL ST,STi /
+ gen_call_function((void*)&FPU_FMUL,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ case 0x02: // FCOM STi /
+ gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ case 0x03: // FCOMP STi /
+ gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ case 0x04: // FSUB ST,STi /
+ gen_call_function((void*)&FPU_FSUB,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ case 0x05: // FSUBR ST,STi /
+ gen_call_function((void*)&FPU_FSUBR,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ case 0x06: // FDIV ST,STi /
+ gen_call_function((void*)&FPU_FDIV,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ case 0x07: // FDIVR ST,STi /
+ gen_call_function((void*)&FPU_FDIVR,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ default:
+ break;
+ }
+ } else {
+ dyn_fill_ea();
+ gen_call_function((void*)&FPU_FLD_F32_EA,"%Ddr",DREG(EA));
+ gen_load_host(&TOP,DREG(TMPB),4);
+ dyn_eatree();
+ }
+}
+
+static void dyn_fpu_esc1(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ switch (group){
+ case 0x00: /* FLD STi */
+ gen_protectflags();
+ gen_load_host(&TOP,DREG(EA),4);
+ gen_dop_word_imm(DOP_ADD,true,DREG(EA),decode.modrm.rm);
+ gen_dop_word_imm(DOP_AND,true,DREG(EA),7);
+ gen_call_function((void*)&FPU_PREP_PUSH,"");
+ gen_load_host(&TOP,DREG(TMPB),4);
+ gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x01: /* FXCH STi */
+ dyn_fpu_top();
+ gen_call_function((void*)&FPU_FXCH,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ case 0x02: /* FNOP */
+ gen_call_function((void*)&FPU_FNOP,"");
+ break;
+ case 0x03: /* FSTP STi */
+ dyn_fpu_top();
+ gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ case 0x04:
+ switch(sub){
+ case 0x00: /* FCHS */
+ gen_call_function((void*)&FPU_FCHS,"");
+ break;
+ case 0x01: /* FABS */
+ gen_call_function((void*)&FPU_FABS,"");
+ break;
+ case 0x02: /* UNKNOWN */
+ case 0x03: /* ILLEGAL */
+ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub);
+ break;
+ case 0x04: /* FTST */
+ gen_call_function((void*)&FPU_FTST,"");
+ break;
+ case 0x05: /* FXAM */
+ gen_call_function((void*)&FPU_FXAM,"");
+ break;
+ case 0x06: /* FTSTP (cyrix)*/
+ case 0x07: /* UNKNOWN */
+ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub);
+ break;
+ }
+ break;
+ case 0x05:
+ switch(sub){
+ case 0x00: /* FLD1 */
+ gen_call_function((void*)&FPU_FLD1,"");
+ break;
+ case 0x01: /* FLDL2T */
+ gen_call_function((void*)&FPU_FLDL2T,"");
+ break;
+ case 0x02: /* FLDL2E */
+ gen_call_function((void*)&FPU_FLDL2E,"");
+ break;
+ case 0x03: /* FLDPI */
+ gen_call_function((void*)&FPU_FLDPI,"");
+ break;
+ case 0x04: /* FLDLG2 */
+ gen_call_function((void*)&FPU_FLDLG2,"");
+ break;
+ case 0x05: /* FLDLN2 */
+ gen_call_function((void*)&FPU_FLDLN2,"");
+ break;
+ case 0x06: /* FLDZ*/
+ gen_call_function((void*)&FPU_FLDZ,"");
+ break;
+ case 0x07: /* ILLEGAL */
+ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub);
+ break;
+ }
+ break;
+ case 0x06:
+ switch(sub){
+ case 0x00: /* F2XM1 */
+ gen_call_function((void*)&FPU_F2XM1,"");
+ break;
+ case 0x01: /* FYL2X */
+ gen_call_function((void*)&FPU_FYL2X,"");
+ break;
+ case 0x02: /* FPTAN */
+ gen_call_function((void*)&FPU_FPTAN,"");
+ break;
+ case 0x03: /* FPATAN */
+ gen_call_function((void*)&FPU_FPATAN,"");
+ break;
+ case 0x04: /* FXTRACT */
+ gen_call_function((void*)&FPU_FXTRACT,"");
+ break;
+ case 0x05: /* FPREM1 */
+ gen_call_function((void*)&FPU_FPREM1,"");
+ break;
+ case 0x06: /* FDECSTP */
+ gen_call_function((void*)&FPU_FDECSTP,"");
+ break;
+ case 0x07: /* FINCSTP */
+ gen_call_function((void*)&FPU_FINCSTP,"");
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub);
+ break;
+ }
+ break;
+ case 0x07:
+ switch(sub){
+ case 0x00: /* FPREM */
+ gen_call_function((void*)&FPU_FPREM,"");
+ break;
+ case 0x01: /* FYL2XP1 */
+ gen_call_function((void*)&FPU_FYL2XP1,"");
+ break;
+ case 0x02: /* FSQRT */
+ gen_call_function((void*)&FPU_FSQRT,"");
+ break;
+ case 0x03: /* FSINCOS */
+ gen_call_function((void*)&FPU_FSINCOS,"");
+ break;
+ case 0x04: /* FRNDINT */
+ gen_call_function((void*)&FPU_FRNDINT,"");
+ break;
+ case 0x05: /* FSCALE */
+ gen_call_function((void*)&FPU_FSCALE,"");
+ break;
+ case 0x06: /* FSIN */
+ gen_call_function((void*)&FPU_FSIN,"");
+ break;
+ case 0x07: /* FCOS */
+ gen_call_function((void*)&FPU_FCOS,"");
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub);
+ break;
+ }
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub);
+ break;
+ }
+ } else {
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ dyn_fill_ea();
+ switch(group){
+ case 0x00: /* FLD float*/
+ gen_protectflags();
+ gen_call_function((void*)&FPU_PREP_PUSH,"");
+ gen_load_host(&TOP,DREG(TMPB),4);
+ gen_call_function((void*)&FPU_FLD_F32,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x01: /* UNKNOWN */
+ LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub);
+ break;
+ case 0x02: /* FST float*/
+ gen_call_function((void*)&FPU_FST_F32,"%Ddr",DREG(EA));
+ break;
+ case 0x03: /* FSTP float*/
+ gen_call_function((void*)&FPU_FST_F32,"%Ddr",DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ case 0x04: /* FLDENV */
+ gen_call_function((void*)&FPU_FLDENV,"%Ddr",DREG(EA));
+ break;
+ case 0x05: /* FLDCW */
+ gen_call_function((void *)&FPU_FLDCW,"%Ddr",DREG(EA));
+ break;
+ case 0x06: /* FSTENV */
+ gen_call_function((void *)&FPU_FSTENV,"%Ddr",DREG(EA));
+ break;
+ case 0x07: /* FNSTCW*/
+ gen_call_function((void *)&FPU_FNSTCW,"%Ddr",DREG(EA));
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ }
+}
+
+static void dyn_fpu_esc2(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ switch(group){
+ case 0x05:
+ switch(sub){
+ case 0x01: /* FUCOMPP */
+ gen_protectflags();
+ gen_load_host(&TOP,DREG(EA),4);
+ gen_dop_word_imm(DOP_ADD,true,DREG(EA),1);
+ gen_dop_word_imm(DOP_AND,true,DREG(EA),7);
+ gen_load_host(&TOP,DREG(TMPB),4);
+ gen_call_function((void *)&FPU_FUCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ gen_call_function((void *)&FPU_FPOP,"");
+ gen_call_function((void *)&FPU_FPOP,"");
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ } else {
+ dyn_fill_ea();
+ gen_call_function((void*)&FPU_FLD_I32_EA,"%Ddr",DREG(EA));
+ gen_load_host(&TOP,DREG(TMPB),4);
+ dyn_eatree();
+ }
+}
+
+static void dyn_fpu_esc3(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ switch (group) {
+ case 0x04:
+ switch (sub) {
+ case 0x00: //FNENI
+ case 0x01: //FNDIS
+ LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfuntion :%d",sub);
+ break;
+ case 0x02: //FNCLEX FCLEX
+ gen_call_function((void*)&FPU_FCLEX,"");
+ break;
+ case 0x03: //FNINIT FINIT
+ gen_call_function((void*)&FPU_FINIT,"");
+ break;
+ case 0x04: //FNSETPM
+ case 0x05: //FRSTPM
+// LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done");
+ break;
+ default:
+ E_Exit("ESC 3:ILLEGAL OPCODE group %d subfunction %d",group,sub);
+ }
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 3:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ } else {
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ dyn_fill_ea();
+ switch(group){
+ case 0x00: /* FILD */
+ gen_call_function((void*)&FPU_PREP_PUSH,"");
+ gen_protectflags();
+ gen_load_host(&TOP,DREG(TMPB),4);
+ gen_call_function((void*)&FPU_FLD_I32,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x01: /* FISTTP */
+ LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub);
+ break;
+ case 0x02: /* FIST */
+ gen_call_function((void*)&FPU_FST_I32,"%Ddr",DREG(EA));
+ break;
+ case 0x03: /* FISTP */
+ gen_call_function((void*)&FPU_FST_I32,"%Ddr",DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ case 0x05: /* FLD 80 Bits Real */
+ gen_call_function((void*)&FPU_PREP_PUSH,"");
+ gen_call_function((void*)&FPU_FLD_F80,"%Ddr",DREG(EA));
+ break;
+ case 0x07: /* FSTP 80 Bits Real */
+ gen_call_function((void*)&FPU_FST_F80,"%Ddr",DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub);
+ }
+ }
+}
+
+static void dyn_fpu_esc4(){
+ dyn_get_modrm();
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ if (decode.modrm.val >= 0xc0) {
+ dyn_fpu_top();
+ switch(group){
+ case 0x00: /* FADD STi,ST*/
+ gen_call_function((void*)&FPU_FADD,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x01: /* FMUL STi,ST*/
+ gen_call_function((void*)&FPU_FMUL,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x02: /* FCOM*/
+ gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ case 0x03: /* FCOMP*/
+ gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ case 0x04: /* FSUBR STi,ST*/
+ gen_call_function((void*)&FPU_FSUBR,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x05: /* FSUB STi,ST*/
+ gen_call_function((void*)&FPU_FSUB,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x06: /* FDIVR STi,ST*/
+ gen_call_function((void*)&FPU_FDIVR,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x07: /* FDIV STi,ST*/
+ gen_call_function((void*)&FPU_FDIV,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ default:
+ break;
+ }
+ } else {
+ dyn_fill_ea();
+ gen_call_function((void*)&FPU_FLD_F64_EA,"%Ddr",DREG(EA));
+ gen_load_host(&TOP,DREG(TMPB),4);
+ dyn_eatree();
+ }
+}
+
+static void dyn_fpu_esc5(){
+ dyn_get_modrm();
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ if (decode.modrm.val >= 0xc0) {
+ dyn_fpu_top();
+ switch(group){
+ case 0x00: /* FFREE STi */
+ gen_call_function((void*)&FPU_FFREE,"%Ddr",DREG(EA));
+ break;
+ case 0x01: /* FXCH STi*/
+ gen_call_function((void*)&FPU_FXCH,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ case 0x02: /* FST STi */
+ gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ case 0x03: /* FSTP STi*/
+ gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ case 0x04: /* FUCOM STi */
+ gen_call_function((void*)&FPU_FUCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ case 0x05: /*FUCOMP STi */
+ gen_call_function((void*)&FPU_FUCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 5:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ gen_releasereg(DREG(EA));
+ gen_releasereg(DREG(TMPB));
+ } else {
+ dyn_fill_ea();
+ switch(group){
+ case 0x00: /* FLD double real*/
+ gen_call_function((void*)&FPU_PREP_PUSH,"");
+ gen_protectflags();
+ gen_load_host(&TOP,DREG(TMPB),4);
+ gen_call_function((void*)&FPU_FLD_F64,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x01: /* FISTTP longint*/
+ LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub);
+ break;
+ case 0x02: /* FST double real*/
+ gen_call_function((void*)&FPU_FST_F64,"%Ddr",DREG(EA));
+ break;
+ case 0x03: /* FSTP double real*/
+ gen_call_function((void*)&FPU_FST_F64,"%Ddr",DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ case 0x04: /* FRSTOR */
+ gen_call_function((void*)&FPU_FRSTOR,"%Ddr",DREG(EA));
+ break;
+ case 0x06: /* FSAVE */
+ gen_call_function((void*)&FPU_FSAVE,"%Ddr",DREG(EA));
+ break;
+ case 0x07: /*FNSTSW */
+ gen_protectflags();
+ gen_load_host(&TOP,DREG(TMPB),4);
+ gen_call_function((void*)&FPU_SET_TOP,"%Dd",DREG(TMPB));
+ gen_load_host(&fpu.sw,DREG(TMPB),4);
+ gen_call_function((void*)&mem_writew,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub);
+ }
+ }
+}
+
+static void dyn_fpu_esc6(){
+ dyn_get_modrm();
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ if (decode.modrm.val >= 0xc0) {
+ dyn_fpu_top();
+ switch(group){
+ case 0x00: /*FADDP STi,ST*/
+ gen_call_function((void*)&FPU_FADD,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x01: /* FMULP STi,ST*/
+ gen_call_function((void*)&FPU_FMUL,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x02: /* FCOMP5*/
+ gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break; /* TODO IS THIS ALLRIGHT ????????? */
+ case 0x03: /*FCOMPP*/
+ if(sub != 1) {
+ LOG(LOG_FPU,LOG_WARN)("ESC 6:Unhandled group %d subfunction %d",group,sub);
+ return;
+ }
+ gen_load_host(&TOP,DREG(EA),4);
+ gen_dop_word_imm(DOP_ADD,true,DREG(EA),1);
+ gen_dop_word_imm(DOP_AND,true,DREG(EA),7);
+ gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,""); /* extra pop at the bottom*/
+ break;
+ case 0x04: /* FSUBRP STi,ST*/
+ gen_call_function((void*)&FPU_FSUBR,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x05: /* FSUBP STi,ST*/
+ gen_call_function((void*)&FPU_FSUB,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x06: /* FDIVRP STi,ST*/
+ gen_call_function((void*)&FPU_FDIVR,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x07: /* FDIVP STi,ST*/
+ gen_call_function((void*)&FPU_FDIV,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ default:
+ break;
+ }
+ gen_call_function((void*)&FPU_FPOP,"");
+ } else {
+ dyn_fill_ea();
+ gen_call_function((void*)&FPU_FLD_I16_EA,"%Ddr",DREG(EA));
+ gen_load_host(&TOP,DREG(TMPB),4);
+ dyn_eatree();
+ }
+}
+
+static void dyn_fpu_esc7(){
+ dyn_get_modrm();
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ if (decode.modrm.val >= 0xc0) {
+ switch (group){
+ case 0x00: /* FFREEP STi*/
+ dyn_fpu_top();
+ gen_call_function((void*)&FPU_FFREE,"%Ddr",DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ case 0x01: /* FXCH STi*/
+ dyn_fpu_top();
+ gen_call_function((void*)&FPU_FXCH,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ break;
+ case 0x02: /* FSTP STi*/
+ case 0x03: /* FSTP STi*/
+ dyn_fpu_top();
+ gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(TMPB),DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ case 0x04:
+ switch(sub){
+ case 0x00: /* FNSTSW AX*/
+ gen_load_host(&TOP,DREG(TMPB),4);
+ gen_call_function((void*)&FPU_SET_TOP,"%Ddr",DREG(TMPB));
+ gen_mov_host(&fpu.sw,DREG(EAX),2);
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ } else {
+ dyn_fill_ea();
+ switch(group){
+ case 0x00: /* FILD Bit16s */
+ gen_call_function((void*)&FPU_PREP_PUSH,"");
+ gen_load_host(&TOP,DREG(TMPB),4);
+ gen_call_function((void*)&FPU_FLD_I16,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x01:
+ LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub);
+ break;
+ case 0x02: /* FIST Bit16s */
+ gen_call_function((void*)&FPU_FST_I16,"%Ddr",DREG(EA));
+ break;
+ case 0x03: /* FISTP Bit16s */
+ gen_call_function((void*)&FPU_FST_I16,"%Ddr",DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ case 0x04: /* FBLD packed BCD */
+ gen_call_function((void*)&FPU_PREP_PUSH,"");
+ gen_load_host(&TOP,DREG(TMPB),4);
+ gen_call_function((void*)&FPU_FBLD,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x05: /* FILD Bit64s */
+ gen_call_function((void*)&FPU_PREP_PUSH,"");
+ gen_load_host(&TOP,DREG(TMPB),4);
+ gen_call_function((void*)&FPU_FLD_I64,"%Ddr%Ddr",DREG(EA),DREG(TMPB));
+ break;
+ case 0x06: /* FBSTP packed BCD */
+ gen_call_function((void*)&FPU_FBST,"%Ddr",DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ case 0x07: /* FISTP Bit64s */
+ gen_call_function((void*)&FPU_FST_I64,"%Ddr",DREG(EA));
+ gen_call_function((void*)&FPU_FPOP,"");
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ }
+}
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#include "dosbox.h"
+#if C_FPU
+
+static void FPU_FLD_16(PhysPt addr) {
+ dyn_dh_fpu.temp.m1 = (Bit32u)mem_readw(addr);
+}
+
+static void FPU_FST_16(PhysPt addr) {
+ mem_writew(addr,(Bit16u)dyn_dh_fpu.temp.m1);
+}
+
+static void FPU_FLD_32(PhysPt addr) {
+ dyn_dh_fpu.temp.m1 = mem_readd(addr);
+}
+
+static void FPU_FST_32(PhysPt addr) {
+ mem_writed(addr,dyn_dh_fpu.temp.m1);
+}
+
+static void FPU_FLD_64(PhysPt addr) {
+ dyn_dh_fpu.temp.m1 = mem_readd(addr);
+ dyn_dh_fpu.temp.m2 = mem_readd(addr+4);
+}
+
+static void FPU_FST_64(PhysPt addr) {
+ mem_writed(addr,dyn_dh_fpu.temp.m1);
+ mem_writed(addr+4,dyn_dh_fpu.temp.m2);
+}
+
+static void FPU_FLD_80(PhysPt addr) {
+ dyn_dh_fpu.temp.m1 = mem_readd(addr);
+ dyn_dh_fpu.temp.m2 = mem_readd(addr+4);
+ dyn_dh_fpu.temp.m3 = mem_readw(addr+8);
+}
+
+static void FPU_FST_80(PhysPt addr) {
+ mem_writed(addr,dyn_dh_fpu.temp.m1);
+ mem_writed(addr+4,dyn_dh_fpu.temp.m2);
+ mem_writew(addr+8,dyn_dh_fpu.temp.m3);
+}
+
+static void FPU_FLDCW_DH(PhysPt addr){
+ dyn_dh_fpu.cw = mem_readw(addr);
+ dyn_dh_fpu.temp.m1 = (Bit32u)(dyn_dh_fpu.cw|0x3f);
+}
+
+static void FPU_FNSTCW_DH(PhysPt addr){
+ mem_writew(addr,(Bit16u)(dyn_dh_fpu.cw&0xffff));
+}
+
+static void FPU_FNINIT_DH(void){
+ dyn_dh_fpu.cw = 0x37f;
+}
+
+static void FPU_FSTENV_DH(PhysPt addr){
+ if(!cpu.code.big) {
+ mem_writew(addr+0,(Bit16u)dyn_dh_fpu.cw);
+ mem_writew(addr+2,(Bit16u)dyn_dh_fpu.temp.m2);
+ mem_writew(addr+4,dyn_dh_fpu.temp.m3);
+ } else {
+ mem_writed(addr+0,dyn_dh_fpu.temp.m1);
+ mem_writew(addr+0,(Bit16u)dyn_dh_fpu.cw);
+ mem_writed(addr+4,dyn_dh_fpu.temp.m2);
+ mem_writed(addr+8,dyn_dh_fpu.temp.m3);
+ }
+}
+
+static void FPU_FLDENV_DH(PhysPt addr){
+ if(!cpu.code.big) {
+ dyn_dh_fpu.cw = (Bit32u)mem_readw(addr);
+ dyn_dh_fpu.temp.m1 = dyn_dh_fpu.cw|0x3f;
+ dyn_dh_fpu.temp.m2 = (Bit32u)mem_readw(addr+2);
+ dyn_dh_fpu.temp.m3 = mem_readw(addr+4);
+ } else {
+ dyn_dh_fpu.cw = (Bit32u)mem_readw(addr);
+ dyn_dh_fpu.temp.m1 = mem_readd(addr)|0x3f;
+ dyn_dh_fpu.temp.m2 = mem_readd(addr+4);
+ dyn_dh_fpu.temp.m3 = mem_readw(addr+8);
+ dyn_dh_fpu.temp.d1 = mem_readw(addr+10);
+ }
+}
+
+static void FPU_FSAVE_DH(PhysPt addr){
+ if (!cpu.code.big) {
+ mem_writew(addr,(Bit16u)dyn_dh_fpu.cw);
+ addr+=2;
+ mem_writeb(addr++,dyn_dh_fpu.temp_state[0x04]);
+ mem_writeb(addr++,dyn_dh_fpu.temp_state[0x05]);
+ mem_writeb(addr++,dyn_dh_fpu.temp_state[0x08]);
+ mem_writeb(addr++,dyn_dh_fpu.temp_state[0x09]);
+ mem_writeb(addr++,dyn_dh_fpu.temp_state[0x0c]);
+ mem_writeb(addr++,dyn_dh_fpu.temp_state[0x0d]);
+ mem_writeb(addr++,dyn_dh_fpu.temp_state[0x10]);
+ mem_writeb(addr++,dyn_dh_fpu.temp_state[0x11]);
+ mem_writeb(addr++,dyn_dh_fpu.temp_state[0x14]);
+ mem_writeb(addr++,dyn_dh_fpu.temp_state[0x15]);
+ mem_writeb(addr++,dyn_dh_fpu.temp_state[0x18]);
+ mem_writeb(addr++,dyn_dh_fpu.temp_state[0x19]);
+ for(Bitu i=28;i<108;i++) mem_writeb(addr++,dyn_dh_fpu.temp_state[i]);
+ } else {
+ mem_writew(addr,(Bit16u)dyn_dh_fpu.cw);
+ addr+=2;
+ for(Bitu i=2;i<108;i++) mem_writeb(addr++,dyn_dh_fpu.temp_state[i]);
+ }
+}
+
+static void FPU_FRSTOR_DH(PhysPt addr){
+ if (!cpu.code.big) {
+ dyn_dh_fpu.cw = (Bit32u)mem_readw(addr);
+ dyn_dh_fpu.temp_state[0x00] = mem_readb(addr++)|0x3f;
+ dyn_dh_fpu.temp_state[0x01] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0x04] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0x05] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0x08] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0x09] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0x0c] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0x0d] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0x10] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0x11] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0x14] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0x15] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0x18] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0x19] = mem_readb(addr++);
+ for(Bitu i=28;i<108;i++) dyn_dh_fpu.temp_state[i] = mem_readb(addr++);
+ } else {
+ dyn_dh_fpu.cw = (Bit32u)mem_readw(addr);
+ for(Bitu i=0;i<108;i++) dyn_dh_fpu.temp_state[i] = mem_readb(addr++);
+ dyn_dh_fpu.temp_state[0]|=0x3f;
+ }
+}
+
+static void dh_fpu_esc0(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ cache_addb(0xd8);
+ cache_addb(decode.modrm.val);
+ } else {
+ dyn_fill_ea();
+ gen_call_function((void*)&FPU_FLD_32,"%Ddr",DREG(EA));
+ cache_addb(0xd8);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ }
+}
+
+static void dh_fpu_esc1(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ cache_addb(0xd9);
+ cache_addb(decode.modrm.val);
+ } else {
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ dyn_fill_ea();
+ switch(group){
+ case 0x00: /* FLD float*/
+ gen_call_function((void*)&FPU_FLD_32,"%Ddr",DREG(EA));
+ cache_addb(0xd9);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ break;
+ case 0x01: /* UNKNOWN */
+ LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub);
+ break;
+ case 0x02: /* FST float*/
+ cache_addb(0xd9);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FST_32,"%Ddr",DREG(EA));
+ break;
+ case 0x03: /* FSTP float*/
+ cache_addb(0xd9);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FST_32,"%Ddr",DREG(EA));
+ break;
+ case 0x04: /* FLDENV */
+ gen_call_function((void*)&FPU_FLDENV_DH,"%Ddr",DREG(EA));
+ cache_addb(0xd9);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ break;
+ case 0x05: /* FLDCW */
+ gen_call_function((void *)&FPU_FLDCW_DH,"%Ddr",DREG(EA));
+ cache_addb(0xd9);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ break;
+ case 0x06: /* FSTENV */
+ cache_addb(0xd9);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FSTENV_DH,"%Ddr",DREG(EA));
+ break;
+ case 0x07: /* FNSTCW*/
+ gen_call_function((void*)&FPU_FNSTCW_DH,"%Ddr",DREG(EA));
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ }
+}
+
+static void dh_fpu_esc2(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ cache_addb(0xda);
+ cache_addb(decode.modrm.val);
+ } else {
+ dyn_fill_ea();
+ gen_call_function((void*)&FPU_FLD_32,"%Ddr",DREG(EA));
+ cache_addb(0xda);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ }
+}
+
+static void dh_fpu_esc3(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ switch (group) {
+ case 0x04:
+ switch (sub) {
+ case 0x00: //FNENI
+ case 0x01: //FNDIS
+ LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfuntion :%d",sub);
+ break;
+ case 0x02: //FNCLEX FCLEX
+ cache_addb(0xdb);
+ cache_addb(decode.modrm.val);
+ break;
+ case 0x03: //FNINIT FINIT
+ gen_call_function((void*)&FPU_FNINIT_DH,"");
+ cache_addb(0xdb);
+ cache_addb(decode.modrm.val);
+ break;
+ case 0x04: //FNSETPM
+ case 0x05: //FRSTPM
+// LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done");
+ break;
+ default:
+ E_Exit("ESC 3:ILLEGAL OPCODE group %d subfunction %d",group,sub);
+ }
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 3:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ } else {
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ dyn_fill_ea();
+ switch(group){
+ case 0x00: /* FILD */
+ gen_call_function((void*)&FPU_FLD_32,"%Ddr",DREG(EA));
+ cache_addb(0xdb);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ break;
+ case 0x01: /* FISTTP */
+ LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub);
+ break;
+ case 0x02: /* FIST */
+ cache_addb(0xdb);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FST_32,"%Ddr",DREG(EA));
+ break;
+ case 0x03: /* FISTP */
+ cache_addb(0xdb);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FST_32,"%Ddr",DREG(EA));
+ break;
+ case 0x05: /* FLD 80 Bits Real */
+ gen_call_function((void*)&FPU_FLD_80,"%Ddr",DREG(EA));
+ cache_addb(0xdb);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ break;
+ case 0x07: /* FSTP 80 Bits Real */
+ cache_addb(0xdb);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FST_80,"%Ddr",DREG(EA));
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub);
+ }
+ }
+}
+
+static void dh_fpu_esc4(){
+ dyn_get_modrm();
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ if (decode.modrm.val >= 0xc0) {
+ cache_addb(0xdc);
+ cache_addb(decode.modrm.val);
+ } else {
+ dyn_fill_ea();
+ gen_call_function((void*)&FPU_FLD_64,"%Ddr",DREG(EA));
+ cache_addb(0xdc);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ }
+}
+
+static void dh_fpu_esc5(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ cache_addb(0xdd);
+ cache_addb(decode.modrm.val);
+ } else {
+ dyn_fill_ea();
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ switch(group){
+ case 0x00: /* FLD double real*/
+ gen_call_function((void*)&FPU_FLD_64,"%Ddr",DREG(EA));
+ cache_addb(0xdd);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ break;
+ case 0x01: /* FISTTP longint*/
+ LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub);
+ break;
+ case 0x02: /* FST double real*/
+ cache_addb(0xdd);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FST_64,"%Ddr",DREG(EA));
+ break;
+ case 0x03: /* FSTP double real*/
+ cache_addb(0xdd);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FST_64,"%Ddr",DREG(EA));
+ break;
+ case 0x04: /* FRSTOR */
+ gen_call_function((void*)&FPU_FRSTOR_DH,"%Ddr",DREG(EA));
+ cache_addb(0xdd);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp_state[0])));
+ break;
+ case 0x06: /* FSAVE */
+ cache_addb(0xdd);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp_state[0])));
+ gen_call_function((void*)&FPU_FSAVE_DH,"%Ddr",DREG(EA));
+ cache_addb(0xdb);
+ cache_addb(0xe3);
+ break;
+ case 0x07: /* FNSTSW */
+ cache_addb(0xdd);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FST_16,"%Ddr",DREG(EA));
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub);
+ }
+ }
+}
+
+static void dh_fpu_esc6(){
+ dyn_get_modrm();
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ if (decode.modrm.val >= 0xc0) {
+ cache_addb(0xde);
+ cache_addb(decode.modrm.val);
+ } else {
+ dyn_fill_ea();
+ gen_call_function((void*)&FPU_FLD_16,"%Ddr",DREG(EA));
+ cache_addb(0xde);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ }
+}
+
+static void dh_fpu_esc7(){
+ dyn_get_modrm();
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ Bitu sub=(decode.modrm.val & 7);
+ if (decode.modrm.val >= 0xc0) {
+ switch (group){
+ case 0x00: /* FFREEP STi*/
+ cache_addb(0xdf);
+ cache_addb(decode.modrm.val);
+ break;
+ case 0x01: /* FXCH STi*/
+ cache_addb(0xdf);
+ cache_addb(decode.modrm.val);
+ break;
+ case 0x02: /* FSTP STi*/
+ case 0x03: /* FSTP STi*/
+ cache_addb(0xdf);
+ cache_addb(decode.modrm.val);
+ break;
+ case 0x04:
+ switch(sub){
+ case 0x00: /* FNSTSW AX*/
+ cache_addb(0xdd);
+ cache_addb(0x05|(0x07<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_load_host(&(dyn_dh_fpu.temp.m1),DREG(TMPB),4);
+ gen_dop_word(DOP_MOV,false,DREG(EAX),DREG(TMPB));
+ gen_releasereg(DREG(TMPB));
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ } else {
+ dyn_fill_ea();
+ switch(group){
+ case 0x00: /* FILD Bit16s */
+ gen_call_function((void*)&FPU_FLD_16,"%Ddr",DREG(EA));
+ cache_addb(0xdf);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ break;
+ case 0x01:
+ LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub);
+ break;
+ case 0x02: /* FIST Bit16s */
+ cache_addb(0xdf);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FST_16,"%Ddr",DREG(EA));
+ break;
+ case 0x03: /* FISTP Bit16s */
+ cache_addb(0xdf);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FST_16,"%Ddr",DREG(EA));
+ break;
+ case 0x04: /* FBLD packed BCD */
+ gen_call_function((void*)&FPU_FLD_80,"%Ddr",DREG(EA));
+ cache_addb(0xdf);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ break;
+ case 0x05: /* FILD Bit64s */
+ gen_call_function((void*)&FPU_FLD_64,"%Ddr",DREG(EA));
+ cache_addb(0xdf);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ break;
+ case 0x06: /* FBSTP packed BCD */
+ cache_addb(0xdf);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FST_80,"%Ddr",DREG(EA));
+ break;
+ case 0x07: /* FISTP Bit64s */
+ cache_addb(0xdf);
+ cache_addb(0x05|(decode.modrm.reg<<3));
+ cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1)));
+ gen_call_function((void*)&FPU_FST_64,"%Ddr",DREG(EA));
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub);
+ break;
+ }
+ }
+}
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+static bool dyn_helper_divb(Bit8u val) {
+ if (!val) return CPU_PrepareException(0,0);
+ Bitu quo=reg_ax / val;
+ Bit8u rem=(Bit8u)(reg_ax % val);
+ Bit8u quo8=(Bit8u)(quo&0xff);
+ if (quo>0xff) return CPU_PrepareException(0,0);
+ reg_ah=rem;
+ reg_al=quo8;
+ return false;
+}
+
+static bool dyn_helper_idivb(Bit8s val) {
+ if (!val) return CPU_PrepareException(0,0);
+ Bits quo=(Bit16s)reg_ax / val;
+ Bit8s rem=(Bit8s)((Bit16s)reg_ax % val);
+ Bit8s quo8s=(Bit8s)(quo&0xff);
+ if (quo!=(Bit16s)quo8s) return CPU_PrepareException(0,0);
+ reg_ah=rem;
+ reg_al=quo8s;
+ return false;
+}
+
+static bool dyn_helper_divw(Bit16u val) {
+ if (!val) return CPU_PrepareException(0,0);
+ Bitu num=(reg_dx<<16)|reg_ax;
+ Bitu quo=num/val;
+ Bit16u rem=(Bit16u)(num % val);
+ Bit16u quo16=(Bit16u)(quo&0xffff);
+ if (quo!=(Bit32u)quo16) return CPU_PrepareException(0,0);
+ reg_dx=rem;
+ reg_ax=quo16;
+ return false;
+}
+
+static bool dyn_helper_idivw(Bit16s val) {
+ if (!val) return CPU_PrepareException(0,0);
+ Bits num=(reg_dx<<16)|reg_ax;
+ Bits quo=num/val;
+ Bit16s rem=(Bit16s)(num % val);
+ Bit16s quo16s=(Bit16s)quo;
+ if (quo!=(Bit32s)quo16s) return CPU_PrepareException(0,0);
+ reg_dx=rem;
+ reg_ax=quo16s;
+ return false;
+}
+
+static bool dyn_helper_divd(Bit32u val) {
+ if (!val) return CPU_PrepareException(0,0);
+ Bit64u num=(((Bit64u)reg_edx)<<32)|reg_eax;
+ Bit64u quo=num/val;
+ Bit32u rem=(Bit32u)(num % val);
+ Bit32u quo32=(Bit32u)(quo&0xffffffff);
+ if (quo!=(Bit64u)quo32) return CPU_PrepareException(0,0);
+ reg_edx=rem;
+ reg_eax=quo32;
+ return false;
+}
+
+static bool dyn_helper_idivd(Bit32s val) {
+ if (!val) return CPU_PrepareException(0,0);
+ Bit64s num=(((Bit64u)reg_edx)<<32)|reg_eax;
+ Bit64s quo=num/val;
+ Bit32s rem=(Bit32s)(num % val);
+ Bit32s quo32s=(Bit32s)(quo&0xffffffff);
+ if (quo!=(Bit64s)quo32s) return CPU_PrepareException(0,0);
+ reg_edx=rem;
+ reg_eax=quo32s;
+ return false;
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+
+static void gen_init(void);
+
+/* End of needed */
+
+#define X86_REGS 7
+#define X86_REG_EAX 0x00
+#define X86_REG_ECX 0x01
+#define X86_REG_EDX 0x02
+#define X86_REG_EBX 0x03
+#define X86_REG_EBP 0x04
+#define X86_REG_ESI 0x05
+#define X86_REG_EDI 0x06
+
+#define X86_REG_MASK(_REG_) (1 << X86_REG_ ## _REG_)
+
+static struct {
+ bool flagsactive;
+ Bitu last_used;
+ GenReg * regs[X86_REGS];
+} x86gen;
+
+class GenReg {
+public:
+ GenReg(Bit8u _index) {
+ index=_index;
+ notusable=false;dynreg=0;
+ }
+ DynReg * dynreg;
+ Bitu last_used; //Keeps track of last assigned regs
+ Bit8u index;
+ bool notusable;
+ void Load(DynReg * _dynreg,bool stale=false) {
+ if (!_dynreg) return;
+ if (GCC_UNLIKELY((Bitu)dynreg)) Clear();
+ dynreg=_dynreg;
+ last_used=x86gen.last_used;
+ dynreg->flags&=~DYNFLG_CHANGED;
+ dynreg->genreg=this;
+ if ((!stale) && (dynreg->flags & (DYNFLG_LOAD|DYNFLG_ACTIVE))) {
+ cache_addw(0x058b+(index << (8+3))); //Mov reg,[data]
+ cache_addd((Bit32u)dynreg->data);
+ }
+ dynreg->flags|=DYNFLG_ACTIVE;
+ }
+ void Save(void) {
+ if (GCC_UNLIKELY(!((Bitu)dynreg))) IllegalOption("GenReg->Save");
+ dynreg->flags&=~DYNFLG_CHANGED;
+ cache_addw(0x0589+(index << (8+3))); //Mov [data],reg
+ cache_addd((Bit32u)dynreg->data);
+ }
+ void Release(void) {
+ if (GCC_UNLIKELY(!((Bitu)dynreg))) return;
+ if (dynreg->flags&DYNFLG_CHANGED && dynreg->flags&DYNFLG_SAVE) {
+ Save();
+ }
+ dynreg->flags&=~(DYNFLG_CHANGED|DYNFLG_ACTIVE);
+ dynreg->genreg=0;dynreg=0;
+ }
+ void Clear(void) {
+ if (!dynreg) return;
+ if (dynreg->flags&DYNFLG_CHANGED) {
+ Save();
+ }
+ dynreg->genreg=0;dynreg=0;
+ }
+};
+
+static BlockReturn gen_runcode(Bit8u * code) {
+ BlockReturn retval;
+#if defined (_MSC_VER)
+ __asm {
+/* Prepare the flags */
+ mov eax,[code]
+ push ebx
+ push ebp
+ push esi
+ push edi
+ mov ebx,[reg_flags]
+ and ebx,FMASK_TEST
+ push offset(return_address)
+ push ebx
+ jmp eax
+/* Restore the flags */
+return_address:
+ /* return here with flags in ecx */
+ and dword ptr [reg_flags],~FMASK_TEST
+ and ecx,FMASK_TEST
+ or [reg_flags],ecx
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ mov [retval],eax
+ }
+#elif defined (MACOSX)
+ register Bit32u tempflags=reg_flags & FMASK_TEST;
+ __asm__ volatile (
+ "pushl %%ebx \n"
+ "pushl %%ebp \n"
+ "pushl $(run_return_adress) \n"
+ "pushl %2 \n"
+ "jmp *%3 \n"
+ "run_return_adress: \n"
+ "popl %%ebp \n"
+ "popl %%ebx \n"
+ :"=a" (retval), "=c" (tempflags)
+ :"r" (tempflags),"r" (code)
+ :"%edx","%edi","%esi","cc","memory"
+ );
+ reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST);
+#else
+ register Bit32u tempflags=reg_flags & FMASK_TEST;
+ __asm__ volatile (
+ "pushl %%ebp \n"
+ "pushl $(run_return_adress) \n"
+ "pushl %2 \n"
+ "jmp *%3 \n"
+ "run_return_adress: \n"
+ "popl %%ebp \n"
+ :"=a" (retval), "=c" (tempflags)
+ :"r" (tempflags),"r" (code)
+ :"%edx","%ebx","%edi","%esi","cc","memory"
+ );
+ reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST);
+#endif
+ return retval;
+}
+
+static GenReg * FindDynReg(DynReg * dynreg,bool stale=false) {
+ x86gen.last_used++;
+ if (dynreg->genreg) {
+ dynreg->genreg->last_used=x86gen.last_used;
+ return dynreg->genreg;
+ }
+ /* Find best match for selected global reg */
+ Bits i;
+ Bits first_used,first_index;
+ first_used=-1;
+ if (dynreg->flags & DYNFLG_HAS8) {
+ /* Has to be eax,ebx,ecx,edx */
+ for (i=first_index=0;i<=X86_REG_EBX;i++) {
+ GenReg * genreg=x86gen.regs[i];
+ if (genreg->notusable) continue;
+ if (!(genreg->dynreg)) {
+ genreg->Load(dynreg,stale);
+ return genreg;
+ }
+ if (genreg->last_used<(Bitu)first_used) {
+ first_used=genreg->last_used;
+ first_index=i;
+ }
+ }
+ } else {
+ for (i=first_index=X86_REGS-1;i>=0;i--) {
+ GenReg * genreg=x86gen.regs[i];
+ if (genreg->notusable) continue;
+ if (!(genreg->dynreg)) {
+ genreg->Load(dynreg,stale);
+ return genreg;
+ }
+ if (genreg->last_used<(Bitu)first_used) {
+ first_used=genreg->last_used;
+ first_index=i;
+ }
+ }
+ }
+ /* No free register found use earliest assigned one */
+ GenReg * newreg=x86gen.regs[first_index];
+ newreg->Load(dynreg,stale);
+ return newreg;
+}
+
+static GenReg * ForceDynReg(GenReg * genreg,DynReg * dynreg) {
+ genreg->last_used=++x86gen.last_used;
+ if (dynreg->genreg==genreg) return genreg;
+ if (genreg->dynreg) genreg->Clear();
+ if (dynreg->genreg) dynreg->genreg->Clear();
+ genreg->Load(dynreg);
+ return genreg;
+}
+
+static void gen_preloadreg(DynReg * dynreg) {
+ FindDynReg(dynreg);
+}
+
+static void gen_releasereg(DynReg * dynreg) {
+ GenReg * genreg=dynreg->genreg;
+ if (genreg) genreg->Release();
+ else dynreg->flags&=~(DYNFLG_ACTIVE|DYNFLG_CHANGED);
+}
+
+static void gen_setupreg(DynReg * dnew,DynReg * dsetup) {
+ dnew->flags=dsetup->flags;
+ if (dnew->genreg==dsetup->genreg) return;
+ /* Not the same genreg must be wrong */
+ if (dnew->genreg) {
+ /* Check if the genreg i'm changing is actually linked to me */
+ if (dnew->genreg->dynreg==dnew) dnew->genreg->dynreg=0;
+ }
+ dnew->genreg=dsetup->genreg;
+ if (dnew->genreg) dnew->genreg->dynreg=dnew;
+}
+
+static void gen_synchreg(DynReg * dnew,DynReg * dsynch) {
+ /* First make sure the registers match */
+ if (dnew->genreg!=dsynch->genreg) {
+ if (dnew->genreg) dnew->genreg->Clear();
+ if (dsynch->genreg) {
+ dsynch->genreg->Load(dnew);
+ }
+ }
+ /* Always use the loadonce flag from either state */
+ dnew->flags|=(dsynch->flags & dnew->flags&DYNFLG_ACTIVE);
+ if ((dnew->flags ^ dsynch->flags) & DYNFLG_CHANGED) {
+ /* Ensure the changed value gets saved */
+ if (dnew->flags & DYNFLG_CHANGED) {
+ dnew->genreg->Save();
+ } else dnew->flags|=DYNFLG_CHANGED;
+ }
+}
+
+static void gen_needflags(void) {
+ if (!x86gen.flagsactive) {
+ x86gen.flagsactive=true;
+ cache_addb(0x9d); //POPFD
+ }
+}
+
+static void gen_protectflags(void) {
+ if (x86gen.flagsactive) {
+ x86gen.flagsactive=false;
+ cache_addb(0x9c); //PUSHFD
+ }
+}
+
+static void gen_discardflags(void) {
+ if (!x86gen.flagsactive) {
+ x86gen.flagsactive=true;
+ cache_addw(0xc483); //ADD ESP,4
+ cache_addb(0x4);
+ }
+}
+
+static void gen_needcarry(void) {
+ if (!x86gen.flagsactive) {
+ x86gen.flagsactive=true;
+ cache_addw(0x2cd1); //SHR DWORD [ESP],1
+ cache_addb(0x24);
+ cache_addd(0x0424648d); //LEA ESP,[ESP+4]
+ }
+}
+
+static void gen_setzeroflag(void) {
+ if (x86gen.flagsactive) IllegalOption("gen_setzeroflag");
+ cache_addw(0x0c83); //OR DWORD [ESP],0x40
+ cache_addw(0x4024);
+}
+
+static void gen_clearzeroflag(void) {
+ if (x86gen.flagsactive) IllegalOption("gen_clearzeroflag");
+ cache_addw(0x2483); //AND DWORD [ESP],~0x40
+ cache_addw(0xbf24);
+}
+
+static bool skip_flags=false;
+
+static void set_skipflags(bool state) {
+ if (!state) gen_discardflags();
+ skip_flags=state;
+}
+
+static void gen_reinit(void) {
+ x86gen.last_used=0;
+ x86gen.flagsactive=false;
+ for (Bitu i=0;i<X86_REGS;i++) {
+ x86gen.regs[i]->dynreg=0;
+ }
+}
+
+
+static void gen_load_host(void * data,DynReg * dr1,Bitu size) {
+ GenReg * gr1=FindDynReg(dr1,true);
+ switch (size) {
+ case 1:cache_addw(0xb60f);break; //movzx byte
+ case 2:cache_addw(0xb70f);break; //movzx word
+ case 4:cache_addb(0x8b);break; //mov
+ default:
+ IllegalOption("gen_load_host");
+ }
+ cache_addb(0x5+(gr1->index<<3));
+ cache_addd((Bit32u)data);
+ dr1->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_mov_host(void * data,DynReg * dr1,Bitu size,Bit8u di1=0) {
+ GenReg * gr1=FindDynReg(dr1,(size==4));
+ switch (size) {
+ case 1:cache_addb(0x8a);break; //mov byte
+ case 2:cache_addb(0x66); //mov word
+ case 4:cache_addb(0x8b);break; //mov
+ default:
+ IllegalOption("gen_load_host");
+ }
+ cache_addb(0x5+((gr1->index+(di1?4:0))<<3));
+ cache_addd((Bit32u)data);
+ dr1->flags|=DYNFLG_CHANGED;
+}
+
+
+static void gen_dop_byte(DualOps op,DynReg * dr1,Bit8u di1,DynReg * dr2,Bit8u di2) {
+ GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2);
+ Bit8u tmp;
+ switch (op) {
+ case DOP_ADD: tmp=0x02; break;
+ case DOP_ADC: tmp=0x12; break;
+ case DOP_SUB: tmp=0x2a; break;
+ case DOP_SBB: tmp=0x1a; break;
+ case DOP_CMP: tmp=0x3a; goto nochange;
+ case DOP_XOR: tmp=0x32; break;
+ case DOP_AND: tmp=0x22; if ((dr1==dr2) && (di1==di2)) goto nochange; break;
+ case DOP_OR: tmp=0x0a; if ((dr1==dr2) && (di1==di2)) goto nochange; break;
+ case DOP_TEST: tmp=0x84; goto nochange;
+ case DOP_MOV: if ((dr1==dr2) && (di1==di2)) return; tmp=0x8a; break;
+ case DOP_XCHG: tmp=0x86; dr2->flags|=DYNFLG_CHANGED; break;
+ default:
+ IllegalOption("gen_dop_byte");
+ }
+ dr1->flags|=DYNFLG_CHANGED;
+nochange:
+ cache_addw(tmp|(0xc0+((gr1->index+di1)<<3)+gr2->index+di2)<<8);
+}
+
+static void gen_dop_byte_imm(DualOps op,DynReg * dr1,Bit8u di1,Bitu imm) {
+ GenReg * gr1=FindDynReg(dr1);
+ Bit16u tmp;
+ switch (op) {
+ case DOP_ADD: tmp=0xc080; break;
+ case DOP_ADC: tmp=0xd080; break;
+ case DOP_SUB: tmp=0xe880; break;
+ case DOP_SBB: tmp=0xd880; break;
+ case DOP_CMP: tmp=0xf880; goto nochange; //Doesn't change
+ case DOP_XOR: tmp=0xf080; break;
+ case DOP_AND: tmp=0xe080; break;
+ case DOP_OR: tmp=0xc880; break;
+ case DOP_TEST: tmp=0xc0f6; goto nochange; //Doesn't change
+ case DOP_MOV: cache_addb(0xb0+gr1->index+di1);
+ dr1->flags|=DYNFLG_CHANGED;
+ goto finish;
+ default:
+ IllegalOption("gen_dop_byte_imm");
+ }
+ dr1->flags|=DYNFLG_CHANGED;
+nochange:
+ cache_addw(tmp+((gr1->index+di1)<<8));
+finish:
+ cache_addb(imm);
+}
+
+static void gen_dop_byte_imm_mem(DualOps op,DynReg * dr1,Bit8u di1,void* data) {
+ GenReg * gr1=FindDynReg(dr1);
+ Bit16u tmp;
+ switch (op) {
+ case DOP_ADD: tmp=0x0502; break;
+ case DOP_ADC: tmp=0x0512; break;
+ case DOP_SUB: tmp=0x052a; break;
+ case DOP_SBB: tmp=0x051a; break;
+ case DOP_CMP: tmp=0x053a; goto nochange; //Doesn't change
+ case DOP_XOR: tmp=0x0532; break;
+ case DOP_AND: tmp=0x0522; break;
+ case DOP_OR: tmp=0x050a; break;
+ case DOP_TEST: tmp=0x0584; goto nochange; //Doesn't change
+ case DOP_MOV: tmp=0x0585; break;
+ default:
+ IllegalOption("gen_dop_byte_imm_mem");
+ }
+ dr1->flags|=DYNFLG_CHANGED;
+nochange:
+ cache_addw(tmp+((gr1->index+di1)<<11));
+ cache_addd((Bit32u)data);
+}
+
+static void gen_sop_byte(SingleOps op,DynReg * dr1,Bit8u di1) {
+ GenReg * gr1=FindDynReg(dr1);
+ Bit16u tmp;
+ switch (op) {
+ case SOP_INC: tmp=0xc0FE; break;
+ case SOP_DEC: tmp=0xc8FE; break;
+ case SOP_NOT: tmp=0xd0f6; break;
+ case SOP_NEG: tmp=0xd8f6; break;
+ default:
+ IllegalOption("gen_sop_byte");
+ }
+ cache_addw(tmp + ((gr1->index+di1)<<8));
+ dr1->flags|=DYNFLG_CHANGED;
+}
+
+
+static void gen_extend_word(bool sign,DynReg * ddr,DynReg * dsr) {
+ GenReg * gsr=FindDynReg(dsr);
+ GenReg * gdr=FindDynReg(ddr,true);
+ if (sign) cache_addw(0xbf0f);
+ else cache_addw(0xb70f);
+ cache_addb(0xc0+(gdr->index<<3)+(gsr->index));
+ ddr->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_extend_byte(bool sign,bool dword,DynReg * ddr,DynReg * dsr,Bit8u dsi) {
+ GenReg * gsr=FindDynReg(dsr);
+ GenReg * gdr=FindDynReg(ddr,dword);
+ if (!dword) cache_addb(0x66);
+ if (sign) cache_addw(0xbe0f);
+ else cache_addw(0xb60f);
+ cache_addb(0xc0+(gdr->index<<3)+(gsr->index+dsi));
+ ddr->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_lea(DynReg * ddr,DynReg * dsr1,DynReg * dsr2,Bitu scale,Bits imm) {
+ GenReg * gdr=FindDynReg(ddr);
+ Bitu imm_size;
+ Bit8u rm_base=(gdr->index << 3);
+ if (dsr1) {
+ GenReg * gsr1=FindDynReg(dsr1);
+ if (!imm && (gsr1->index!=0x5)) {
+ imm_size=0; rm_base+=0x0; //no imm
+ } else if ((imm>=-128 && imm<=127)) {
+ imm_size=1;rm_base+=0x40; //Signed byte imm
+ } else {
+ imm_size=4;rm_base+=0x80; //Signed dword imm
+ }
+ if (dsr2) {
+ GenReg * gsr2=FindDynReg(dsr2);
+ cache_addb(0x8d); //LEA
+ cache_addb(rm_base+0x4); //The sib indicator
+ Bit8u sib=(gsr1->index)+(gsr2->index<<3)+(scale<<6);
+ cache_addb(sib);
+ } else {
+ if ((ddr==dsr1) && !imm_size) return;
+ cache_addb(0x8d); //LEA
+ cache_addb(rm_base+gsr1->index);
+ }
+ } else {
+ if (dsr2) {
+ GenReg * gsr2=FindDynReg(dsr2);
+ cache_addb(0x8d); //LEA
+ cache_addb(rm_base+0x4); //The sib indicator
+ Bit8u sib=(5+(gsr2->index<<3)+(scale<<6));
+ cache_addb(sib);
+ imm_size=4;
+ } else {
+ cache_addb(0x8d); //LEA
+ cache_addb(rm_base+0x05); //dword imm
+ imm_size=4;
+ }
+ }
+ switch (imm_size) {
+ case 0: break;
+ case 1:cache_addb(imm);break;
+ case 4:cache_addd(imm);break;
+ }
+ ddr->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_lea_imm_mem(DynReg * ddr,DynReg * dsr,void* data) {
+ GenReg * gdr=FindDynReg(ddr);
+ Bit8u rm_base=(gdr->index << 3);
+ cache_addw(0x058b+(rm_base<<8));
+ cache_addd((Bit32u)data);
+ GenReg * gsr=FindDynReg(dsr);
+ cache_addb(0x8d); //LEA
+ cache_addb(rm_base+0x44);
+ cache_addb(rm_base+gsr->index);
+ cache_addb(0x00);
+ ddr->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_dop_word(DualOps op,bool dword,DynReg * dr1,DynReg * dr2) {
+ GenReg * gr2=FindDynReg(dr2);
+ GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
+ Bit8u tmp;
+ switch (op) {
+ case DOP_ADD: tmp=0x03; break;
+ case DOP_ADC: tmp=0x13; break;
+ case DOP_SUB: tmp=0x2b; break;
+ case DOP_SBB: tmp=0x1b; break;
+ case DOP_CMP: tmp=0x3b; goto nochange;
+ case DOP_XOR: tmp=0x33; break;
+ case DOP_AND: tmp=0x23; if (dr1==dr2) goto nochange; break;
+ case DOP_OR: tmp=0x0b; if (dr1==dr2) goto nochange; break;
+ case DOP_TEST: tmp=0x85; goto nochange;
+ case DOP_MOV: if (dr1==dr2) return; tmp=0x8b; break;
+ case DOP_XCHG:
+ dr2->flags|=DYNFLG_CHANGED;
+ if (dword && !((dr1->flags&DYNFLG_HAS8) ^ (dr2->flags&DYNFLG_HAS8))) {
+ dr1->genreg=gr2;dr1->genreg->dynreg=dr1;
+ dr2->genreg=gr1;dr2->genreg->dynreg=dr2;
+ dr1->flags|=DYNFLG_CHANGED;
+ return;
+ }
+ tmp=0x87;
+ break;
+ default:
+ IllegalOption("gen_dop_word");
+ }
+ dr1->flags|=DYNFLG_CHANGED;
+nochange:
+ if (!dword) cache_addb(0x66);
+ cache_addw(tmp|(0xc0+(gr1->index<<3)+gr2->index)<<8);
+}
+
+static void gen_dop_word_imm(DualOps op,bool dword,DynReg * dr1,Bits imm) {
+ GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
+ Bit16u tmp;
+ if (!dword) cache_addb(0x66);
+ switch (op) {
+ case DOP_ADD: tmp=0xc081; break;
+ case DOP_ADC: tmp=0xd081; break;
+ case DOP_SUB: tmp=0xe881; break;
+ case DOP_SBB: tmp=0xd881; break;
+ case DOP_CMP: tmp=0xf881; goto nochange; //Doesn't change
+ case DOP_XOR: tmp=0xf081; break;
+ case DOP_AND: tmp=0xe081; break;
+ case DOP_OR: tmp=0xc881; break;
+ case DOP_TEST: tmp=0xc0f7; goto nochange; //Doesn't change
+ case DOP_MOV: cache_addb(0xb8+(gr1->index)); dr1->flags|=DYNFLG_CHANGED; goto finish;
+ default:
+ IllegalOption("gen_dop_word_imm");
+ }
+ dr1->flags|=DYNFLG_CHANGED;
+nochange:
+ cache_addw(tmp+(gr1->index<<8));
+finish:
+ if (dword) cache_addd(imm);
+ else cache_addw(imm);
+}
+
+static void gen_dop_word_imm_mem(DualOps op,bool dword,DynReg * dr1,void* data) {
+ GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
+ Bit16u tmp;
+ switch (op) {
+ case DOP_ADD: tmp=0x0503; break;
+ case DOP_ADC: tmp=0x0513; break;
+ case DOP_SUB: tmp=0x052b; break;
+ case DOP_SBB: tmp=0x051b; break;
+ case DOP_CMP: tmp=0x053b; goto nochange; //Doesn't change
+ case DOP_XOR: tmp=0x0533; break;
+ case DOP_AND: tmp=0x0523; break;
+ case DOP_OR: tmp=0x050b; break;
+ case DOP_TEST: tmp=0x0585; goto nochange; //Doesn't change
+ case DOP_MOV:
+ gen_mov_host(data,dr1,dword?4:2);
+ dr1->flags|=DYNFLG_CHANGED;
+ return;
+ default:
+ IllegalOption("gen_dop_word_imm_mem");
+ }
+ dr1->flags|=DYNFLG_CHANGED;
+nochange:
+ if (!dword) cache_addb(0x66);
+ cache_addw(tmp+(gr1->index<<11));
+ cache_addd((Bit32u)data);
+}
+
+static void gen_dop_word_var(DualOps op,bool dword,DynReg * dr1,void* drd) {
+ GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
+ Bit8u tmp;
+ switch (op) {
+ case DOP_ADD: tmp=0x03; break;
+ case DOP_ADC: tmp=0x13; break;
+ case DOP_SUB: tmp=0x2b; break;
+ case DOP_SBB: tmp=0x1b; break;
+ case DOP_CMP: tmp=0x3b; break;
+ case DOP_XOR: tmp=0x33; break;
+ case DOP_AND: tmp=0x23; break;
+ case DOP_OR: tmp=0x0b; break;
+ case DOP_TEST: tmp=0x85; break;
+ case DOP_MOV: tmp=0x8b; break;
+ case DOP_XCHG: tmp=0x87; break;
+ default:
+ IllegalOption("gen_dop_word_var");
+ }
+ if (!dword) cache_addb(0x66);
+ cache_addw(tmp|(0x05+((gr1->index)<<3))<<8);
+ cache_addd((Bit32u)drd);
+}
+
+static void gen_imul_word(bool dword,DynReg * dr1,DynReg * dr2) {
+ GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2);
+ dr1->flags|=DYNFLG_CHANGED;
+ if (!dword) {
+ cache_addd(0xaf0f66|(0xc0+(gr1->index<<3)+gr2->index)<<24);
+ } else {
+ cache_addw(0xaf0f);
+ cache_addb(0xc0+(gr1->index<<3)+gr2->index);
+ }
+}
+
+static void gen_imul_word_imm(bool dword,DynReg * dr1,DynReg * dr2,Bits imm) {
+ GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2);
+ if (!dword) cache_addb(0x66);
+ if ((imm>=-128 && imm<=127)) {
+ cache_addb(0x6b);
+ cache_addb(0xc0+(gr1->index<<3)+gr2->index);
+ cache_addb(imm);
+ } else {
+ cache_addb(0x69);
+ cache_addb(0xc0+(gr1->index<<3)+gr2->index);
+ if (dword) cache_addd(imm);
+ else cache_addw(imm);
+ }
+ dr1->flags|=DYNFLG_CHANGED;
+}
+
+
+static void gen_sop_word(SingleOps op,bool dword,DynReg * dr1) {
+ GenReg * gr1=FindDynReg(dr1);
+ if (!dword) cache_addb(0x66);
+ switch (op) {
+ case SOP_INC:cache_addb(0x40+gr1->index);break;
+ case SOP_DEC:cache_addb(0x48+gr1->index);break;
+ case SOP_NOT:cache_addw(0xd0f7+(gr1->index<<8));break;
+ case SOP_NEG:cache_addw(0xd8f7+(gr1->index<<8));break;
+ default:
+ IllegalOption("gen_sop_word");
+ }
+ dr1->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_shift_byte_cl(Bitu op,DynReg * dr1,Bit8u di1,DynReg * drecx) {
+ ForceDynReg(x86gen.regs[X86_REG_ECX],drecx);
+ GenReg * gr1=FindDynReg(dr1);
+ cache_addw(0xc0d2+(((Bit16u)op) << 11)+ ((gr1->index+di1)<<8));
+ dr1->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_shift_byte_imm(Bitu op,DynReg * dr1,Bit8u di1,Bit8u imm) {
+ GenReg * gr1=FindDynReg(dr1);
+ cache_addw(0xc0c0+(((Bit16u)op) << 11) + ((gr1->index+di1)<<8));
+ cache_addb(imm);
+ dr1->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_shift_word_cl(Bitu op,bool dword,DynReg * dr1,DynReg * drecx) {
+ ForceDynReg(x86gen.regs[X86_REG_ECX],drecx);
+ GenReg * gr1=FindDynReg(dr1);
+ if (!dword) cache_addb(0x66);
+ cache_addw(0xc0d3+(((Bit16u)op) << 11) + ((gr1->index)<<8));
+ dr1->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_shift_word_imm(Bitu op,bool dword,DynReg * dr1,Bit8u imm) {
+ GenReg * gr1=FindDynReg(dr1);
+ dr1->flags|=DYNFLG_CHANGED;
+ if (!dword) {
+ cache_addd(0x66|((0xc0c1+((Bit16u)op << 11) + (gr1->index<<8))|imm<<16)<<8);
+ } else {
+ cache_addw(0xc0c1+((Bit16u)op << 11) + (gr1->index<<8));
+ cache_addb(imm);
+ }
+}
+
+static void gen_cbw(bool dword,DynReg * dyn_ax) {
+ ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
+ if (!dword) cache_addb(0x66);
+ cache_addb(0x98);
+ dyn_ax->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_cwd(bool dword,DynReg * dyn_ax,DynReg * dyn_dx) {
+ ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
+ ForceDynReg(x86gen.regs[X86_REG_EDX],dyn_dx);
+ dyn_ax->flags|=DYNFLG_CHANGED;
+ dyn_dx->flags|=DYNFLG_CHANGED;
+ if (!dword) cache_addw(0x9966);
+ else cache_addb(0x99);
+}
+
+static void gen_mul_byte(bool imul,DynReg * dyn_ax,DynReg * dr1,Bit8u di1) {
+ ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
+ GenReg * gr1=FindDynReg(dr1);
+ if (imul) cache_addw(0xe8f6+((gr1->index+di1)<<8));
+ else cache_addw(0xe0f6+((gr1->index+di1)<<8));
+ dyn_ax->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_mul_word(bool imul,DynReg * dyn_ax,DynReg * dyn_dx,bool dword,DynReg * dr1) {
+ ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
+ ForceDynReg(x86gen.regs[X86_REG_EDX],dyn_dx);
+ GenReg * gr1=FindDynReg(dr1);
+ if (!dword) cache_addb(0x66);
+ if (imul) cache_addw(0xe8f7+(gr1->index<<8));
+ else cache_addw(0xe0f7+(gr1->index<<8));
+ dyn_ax->flags|=DYNFLG_CHANGED;
+ dyn_dx->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_dshift_imm(bool dword,bool left,DynReg * dr1,DynReg * dr2,Bitu imm) {
+ GenReg * gr1=FindDynReg(dr1);
+ GenReg * gr2=FindDynReg(dr2);
+ if (!dword) cache_addb(0x66);
+ if (left) cache_addw(0xa40f); //SHLD IMM
+ else cache_addw(0xac0f); //SHRD IMM
+ cache_addb(0xc0+gr1->index+(gr2->index<<3));
+ cache_addb(imm);
+ dr1->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_dshift_cl(bool dword,bool left,DynReg * dr1,DynReg * dr2,DynReg * drecx) {
+ ForceDynReg(x86gen.regs[X86_REG_ECX],drecx);
+ GenReg * gr1=FindDynReg(dr1);
+ GenReg * gr2=FindDynReg(dr2);
+ if (!dword) cache_addb(0x66);
+ if (left) cache_addw(0xa50f); //SHLD CL
+ else cache_addw(0xad0f); //SHRD CL
+ cache_addb(0xc0+gr1->index+(gr2->index<<3));
+ dr1->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_call_function(void * func,char const* ops,...) {
+ Bits paramcount=0;
+ bool release_flags=false;
+ struct ParamInfo {
+ const char * line;
+ Bitu value;
+ } pinfo[32];
+ ParamInfo * retparam=0;
+ /* Clear the EAX Genreg for usage */
+ x86gen.regs[X86_REG_EAX]->Clear();
+ x86gen.regs[X86_REG_EAX]->notusable=true;
+ /* Save the flags */
+ if (GCC_UNLIKELY(!skip_flags)) gen_protectflags();
+ /* Scan for the amount of params */
+ if (ops) {
+ va_list params;
+ va_start(params,ops);
+#if defined (MACOSX)
+ Bitu stack_used=0;
+ bool free_flags=false;
+#endif
+ Bits pindex=0;
+ while (*ops) {
+ if (*ops=='%') {
+ pinfo[pindex].line=ops+1;
+ pinfo[pindex].value=va_arg(params,Bitu);
+#if defined (MACOSX)
+ const char * scan=pinfo[pindex].line;
+ if ((*scan=='I') || (*scan=='D')) stack_used+=4;
+ else if (*scan=='F') free_flags=true;
+#endif
+ pindex++;
+ }
+ ops++;
+ }
+
+#if defined (MACOSX)
+ /* align stack */
+ stack_used+=4; // saving esp on stack as well
+
+ cache_addw(0xc48b); // mov eax,esp
+ cache_addb(0x2d); // sub eax,stack_used
+ cache_addd(stack_used);
+ cache_addw(0xe083); // and eax,0xfffffff0
+ cache_addb(0xf0);
+ cache_addb(0x05); // sub eax,stack_used
+ cache_addd(stack_used);
+ cache_addb(0x94); // xchg eax,esp
+ if (free_flags) {
+ cache_addw(0xc083); // add eax,4
+ cache_addb(0x04);
+ }
+ cache_addb(0x50); // push eax (==old esp)
+#endif
+
+ paramcount=0;
+ while (pindex) {
+ pindex--;
+ const char * scan=pinfo[pindex].line;
+ switch (*scan++) {
+ case 'I': /* immediate value */
+ paramcount++;
+ cache_addb(0x68); //Push immediate
+ cache_addd(pinfo[pindex].value); //Push value
+ break;
+ case 'D': /* Dynamic register */
+ {
+ bool release=false;
+ paramcount++;
+ DynReg * dynreg=(DynReg *)pinfo[pindex].value;
+ GenReg * genreg=FindDynReg(dynreg);
+ scanagain:
+ switch (*scan++) {
+ case 'd':
+ cache_addb(0x50+genreg->index); //Push reg
+ break;
+ case 'w':
+ cache_addw(0xb70f); //MOVZX EAX,reg
+ cache_addb(0xc0+genreg->index);
+ cache_addb(0x50); //Push EAX
+ break;
+ case 'l':
+ cache_addw(0xb60f); //MOVZX EAX,reg[0]
+ cache_addb(0xc0+genreg->index);
+ cache_addb(0x50); //Push EAX
+ break;
+ case 'h':
+ cache_addw(0xb60f); //MOVZX EAX,reg[1]
+ cache_addb(0xc4+genreg->index);
+ cache_addb(0x50); //Push EAX
+ break;
+ case 'r': /* release the reg afterwards */
+ release=true;
+ goto scanagain;
+ default:
+ IllegalOption("gen_call_function param:DREG");
+ }
+ if (release) gen_releasereg(dynreg);
+ }
+ break;
+ case 'R': /* Dynamic register to get the return value */
+ retparam =&pinfo[pindex];
+ pinfo[pindex].line=scan;
+ break;
+ case 'F': /* Release flags from stack */
+ release_flags=true;
+ break;
+ default:
+ IllegalOption("gen_call_function unknown param");
+ }
+ }
+#if defined (MACOSX)
+ if (free_flags) release_flags=false;
+ } else {
+ /* align stack */
+ Bit32u stack_used=8; // saving esp and return address on the stack
+
+ cache_addw(0xc48b); // mov eax,esp
+ cache_addb(0x2d); // sub eax,stack_used
+ cache_addd(stack_used);
+ cache_addw(0xe083); // and eax,0xfffffff0
+ cache_addb(0xf0);
+ cache_addb(0x05); // sub eax,stack_used
+ cache_addd(stack_used);
+ cache_addb(0x94); // xchg eax,esp
+ cache_addb(0x50); // push esp (==old esp)
+#endif
+ }
+
+ /* Clear some unprotected registers */
+ x86gen.regs[X86_REG_ECX]->Clear();
+ x86gen.regs[X86_REG_EDX]->Clear();
+ /* Do the actual call to the procedure */
+ cache_addb(0xe8);
+ cache_addd((Bit32u)func - (Bit32u)cache.pos-4);
+ /* Restore the params of the stack */
+ if (paramcount) {
+ cache_addw(0xc483); //add ESP,imm byte
+ cache_addb(paramcount*4+(release_flags?4:0));
+ } else if (release_flags) {
+ cache_addw(0xc483); //add ESP,imm byte
+ cache_addb(4);
+ }
+ /* Save the return value in correct register */
+ if (retparam) {
+ DynReg * dynreg=(DynReg *)retparam->value;
+ GenReg * genreg=FindDynReg(dynreg);
+ if (genreg->index) // test for (e)ax/al
+ switch (*retparam->line) {
+ case 'd':
+ cache_addw(0xc08b+(genreg->index <<(8+3))); //mov reg,eax
+ break;
+ case 'w':
+ cache_addb(0x66);
+ cache_addw(0xc08b+(genreg->index <<(8+3))); //mov reg,eax
+ break;
+ case 'l':
+ cache_addw(0xc08a+(genreg->index <<(8+3))); //mov reg,eax
+ break;
+ case 'h':
+ cache_addw(0xc08a+((genreg->index+4) <<(8+3))); //mov reg,eax
+ break;
+ }
+ dynreg->flags|=DYNFLG_CHANGED;
+ }
+ /* Restore EAX registers to be used again */
+ x86gen.regs[X86_REG_EAX]->notusable=false;
+
+#if defined (MACOSX)
+ /* restore stack */
+ cache_addb(0x5c); // pop esp
+#endif
+}
+
+static void gen_call_write(DynReg * dr,Bit32u val,Bitu write_size) {
+ /* Clear the EAX Genreg for usage */
+ x86gen.regs[X86_REG_EAX]->Clear();
+ x86gen.regs[X86_REG_EAX]->notusable=true;
+ gen_protectflags();
+
+#if defined (MACOSX)
+ /* align stack */
+ Bitu stack_used=12;
+
+ cache_addw(0xc48b); // mov eax,esp
+ cache_addb(0x2d); // sub eax,stack_used
+ cache_addd(stack_used);
+ cache_addw(0xe083); // and eax,0xfffffff0
+ cache_addb(0xf0);
+ cache_addb(0x05); // sub eax,stack_used
+ cache_addd(stack_used);
+ cache_addb(0x94); // xchg eax,esp
+ cache_addb(0x50); // push eax (==old esp)
+#endif
+
+ cache_addb(0x68); //PUSH val
+ cache_addd(val);
+ GenReg * genreg=FindDynReg(dr);
+ cache_addb(0x50+genreg->index); //PUSH reg
+
+ /* Clear some unprotected registers */
+ x86gen.regs[X86_REG_ECX]->Clear();
+ x86gen.regs[X86_REG_EDX]->Clear();
+ /* Do the actual call to the procedure */
+ cache_addb(0xe8);
+ switch (write_size) {
+ case 1: cache_addd((Bit32u)mem_writeb_checked - (Bit32u)cache.pos-4); break;
+ case 2: cache_addd((Bit32u)mem_writew_checked - (Bit32u)cache.pos-4); break;
+ case 4: cache_addd((Bit32u)mem_writed_checked - (Bit32u)cache.pos-4); break;
+ default: IllegalOption("gen_call_write");
+ }
+
+ cache_addw(0xc483); //ADD ESP,8
+ cache_addb(2*4);
+ x86gen.regs[X86_REG_EAX]->notusable=false;
+ gen_releasereg(dr);
+
+#if defined (MACOSX)
+ /* restore stack */
+ cache_addb(0x5c); // pop esp
+#endif
+}
+
+static Bit8u * gen_create_branch(BranchTypes type) {
+ /* First free all registers */
+ cache_addw(0x70+type);
+ return (cache.pos-1);
+}
+
+static void gen_fill_branch(Bit8u * data,Bit8u * from=cache.pos) {
+#if C_DEBUG
+ Bits len=from-data;
+ if (len<0) len=-len;
+ if (len>126) LOG_MSG("Big jump %d",len);
+#endif
+ *data=(from-data-1);
+}
+
+static Bit8u * gen_create_branch_long(BranchTypes type) {
+ cache_addw(0x800f+(type<<8));
+ cache_addd(0);
+ return (cache.pos-4);
+}
+
+static void gen_fill_branch_long(Bit8u * data,Bit8u * from=cache.pos) {
+ *(Bit32u*)data=(from-data-4);
+}
+
+static Bit8u * gen_create_jump(Bit8u * to=0) {
+ /* First free all registers */
+ cache_addb(0xe9);
+ cache_addd(to-(cache.pos+4));
+ return (cache.pos-4);
+}
+
+static void gen_fill_jump(Bit8u * data,Bit8u * to=cache.pos) {
+ *(Bit32u*)data=(to-data-4);
+}
+
+
+static void gen_jmp_ptr(void * ptr,Bits imm=0) {
+ cache_addb(0xa1);
+ cache_addd((Bit32u)ptr);
+ cache_addb(0xff); //JMP EA
+ if (!imm) { //NO EBP
+ cache_addb(0x20);
+ } else if ((imm>=-128 && imm<=127)) {
+ cache_addb(0x60);
+ cache_addb(imm);
+ } else {
+ cache_addb(0xa0);
+ cache_addd(imm);
+ }
+}
+
+static void gen_save_flags(DynReg * dynreg) {
+ if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_save_flags");
+ GenReg * genreg=FindDynReg(dynreg);
+ cache_addb(0x8b); //MOV REG,[esp]
+ cache_addw(0x2404+(genreg->index << 3));
+ dynreg->flags|=DYNFLG_CHANGED;
+}
+
+static void gen_load_flags(DynReg * dynreg) {
+ if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_load_flags");
+ cache_addw(0xc483); //ADD ESP,4
+ cache_addb(0x4);
+ GenReg * genreg=FindDynReg(dynreg);
+ cache_addb(0x50+genreg->index); //PUSH 32
+}
+
+static void gen_save_host_direct(void * data,Bits imm) {
+ cache_addw(0x05c7); //MOV [],dword
+ cache_addd((Bit32u)data);
+ cache_addd(imm);
+}
+
+static void gen_return(BlockReturn retcode) {
+ gen_protectflags();
+ cache_addb(0x59); //POP ECX, the flags
+ if (retcode==0) cache_addw(0xc033); //MOV EAX, 0
+ else {
+ cache_addb(0xb8); //MOV EAX, retcode
+ cache_addd(retcode);
+ }
+ cache_addb(0xc3); //RET
+}
+
+static void gen_return_fast(BlockReturn retcode,bool ret_exception=false) {
+ if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_return_fast");
+ cache_addw(0x0d8b); //MOV ECX, the flags
+ cache_addd((Bit32u)&cpu_regs.flags);
+ if (!ret_exception) {
+ cache_addw(0xc483); //ADD ESP,4
+ cache_addb(0x4);
+ if (retcode==0) cache_addw(0xc033); //MOV EAX, 0
+ else {
+ cache_addb(0xb8); //MOV EAX, retcode
+ cache_addd(retcode);
+ }
+ }
+ cache_addb(0xc3); //RET
+}
+
+static void gen_init(void) {
+ x86gen.regs[X86_REG_EAX]=new GenReg(0);
+ x86gen.regs[X86_REG_ECX]=new GenReg(1);
+ x86gen.regs[X86_REG_EDX]=new GenReg(2);
+ x86gen.regs[X86_REG_EBX]=new GenReg(3);
+ x86gen.regs[X86_REG_EBP]=new GenReg(5);
+ x86gen.regs[X86_REG_ESI]=new GenReg(6);
+ x86gen.regs[X86_REG_EDI]=new GenReg(7);
+}
+
+
--- /dev/null
+/*
+ * 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.
+ */
+
+enum STRING_OP {
+ STR_OUTSB=0,STR_OUTSW,STR_OUTSD,
+ STR_INSB=4,STR_INSW,STR_INSD,
+ STR_MOVSB=8,STR_MOVSW,STR_MOVSD,
+ STR_LODSB=12,STR_LODSW,STR_LODSD,
+ STR_STOSB=16,STR_STOSW,STR_STOSD,
+ STR_SCASB=20,STR_SCASW,STR_SCASD,
+ STR_CMPSB=24,STR_CMPSW,STR_CMPSD
+};
+
+static void dyn_string(STRING_OP op) {
+ DynReg * si_base=decode.segprefix ? decode.segprefix : DREG(DS);
+ DynReg * di_base=DREG(ES);
+ DynReg * tmp_reg;bool usesi;bool usedi;
+ gen_protectflags();
+ if (decode.rep) {
+ gen_dop_word_imm(DOP_SUB,true,DREG(CYCLES),decode.cycles);
+ gen_releasereg(DREG(CYCLES));
+ decode.cycles=0;
+ }
+ /* Check what each string operation will be using */
+ switch (op) {
+ case STR_MOVSB: case STR_MOVSW: case STR_MOVSD:
+ case STR_CMPSB: case STR_CMPSW: case STR_CMPSD:
+ tmp_reg=DREG(TMPB);usesi=true;usedi=true;break;
+ case STR_LODSB: case STR_LODSW: case STR_LODSD:
+ tmp_reg=DREG(EAX);usesi=true;usedi=false;break;
+ case STR_OUTSB: case STR_OUTSW: case STR_OUTSD:
+ tmp_reg=DREG(TMPB);usesi=true;usedi=false;break;
+ case STR_SCASB: case STR_SCASW: case STR_SCASD:
+ case STR_STOSB: case STR_STOSW: case STR_STOSD:
+ tmp_reg=DREG(EAX);usesi=false;usedi=true;break;
+ case STR_INSB: case STR_INSW: case STR_INSD:
+ tmp_reg=DREG(TMPB);usesi=false;usedi=true;break;
+ default:
+ IllegalOption("dyn_string op");
+ }
+ gen_load_host(&cpu.direction,DREG(TMPW),4);
+ switch (op & 3) {
+ case 0:break;
+ case 1:gen_shift_word_imm(SHIFT_SHL,true,DREG(TMPW),1);break;
+ case 2:gen_shift_word_imm(SHIFT_SHL,true,DREG(TMPW),2);break;
+ default:
+ IllegalOption("dyn_string shift");
+
+ }
+ if (usesi) {
+ gen_preloadreg(DREG(ESI));
+ DynRegs[G_ESI].flags|=DYNFLG_CHANGED;
+ gen_preloadreg(si_base);
+ }
+ if (usedi) {
+ gen_preloadreg(DREG(EDI));
+ DynRegs[G_EDI].flags|=DYNFLG_CHANGED;
+ gen_preloadreg(di_base);
+ }
+ if (decode.rep) {
+ gen_preloadreg(DREG(ECX));
+ DynRegs[G_ECX].flags|=DYNFLG_CHANGED;
+ }
+ DynState rep_state;
+ dyn_savestate(&rep_state);
+ Bit8u * rep_start=cache.pos;
+ Bit8u * rep_ecx_jmp;
+ /* Check if ECX!=zero */
+ if (decode.rep) {
+ gen_dop_word(DOP_OR,decode.big_addr,DREG(ECX),DREG(ECX));
+ rep_ecx_jmp=gen_create_branch_long(BR_Z);
+ }
+ if (usesi) {
+ if (!decode.big_addr) {
+ gen_extend_word(false,DREG(EA),DREG(ESI));
+ gen_lea(DREG(EA),si_base,DREG(EA),0,0);
+ } else {
+ gen_lea(DREG(EA),si_base,DREG(ESI),0,0);
+ }
+ switch (op&3) {
+ case 0:dyn_read_byte(DREG(EA),tmp_reg,false);break;
+ case 1:dyn_read_word(DREG(EA),tmp_reg,false);break;
+ case 2:dyn_read_word(DREG(EA),tmp_reg,true);break;
+ }
+ switch (op) {
+ case STR_OUTSB:
+ gen_call_function((void*)&IO_WriteB,"%Id%Dl",DREG(EDX),tmp_reg);break;
+ case STR_OUTSW:
+ gen_call_function((void*)&IO_WriteW,"%Id%Dw",DREG(EDX),tmp_reg);break;
+ case STR_OUTSD:
+ gen_call_function((void*)&IO_WriteD,"%Id%Dd",DREG(EDX),tmp_reg);break;
+ }
+ }
+ if (usedi) {
+ if (!decode.big_addr) {
+ gen_extend_word(false,DREG(EA),DREG(EDI));
+ gen_lea(DREG(EA),di_base,DREG(EA),0,0);
+ } else {
+ gen_lea(DREG(EA),di_base,DREG(EDI),0,0);
+ }
+ /* Maybe something special to be done to fill the value */
+ switch (op) {
+ case STR_INSB:
+ gen_call_function((void*)&IO_ReadB,"%Dw%Rl",DREG(EDX),tmp_reg);
+ case STR_MOVSB:
+ case STR_STOSB:
+ dyn_write_byte(DREG(EA),tmp_reg,false);
+ break;
+ case STR_INSW:
+ gen_call_function((void*)&IO_ReadW,"%Dw%Rw",DREG(EDX),tmp_reg);
+ case STR_MOVSW:
+ case STR_STOSW:
+ dyn_write_word(DREG(EA),tmp_reg,false);
+ break;
+ case STR_INSD:
+ gen_call_function((void*)&IO_ReadD,"%Dw%Rd",DREG(EDX),tmp_reg);
+ case STR_MOVSD:
+ case STR_STOSD:
+ dyn_write_word(DREG(EA),tmp_reg,true);
+ break;
+ default:
+ IllegalOption("dyn_string op");
+ }
+ }
+ gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB));
+
+ /* update registers */
+ if (usesi) gen_dop_word(DOP_ADD,decode.big_addr,DREG(ESI),DREG(TMPW));
+ if (usedi) gen_dop_word(DOP_ADD,decode.big_addr,DREG(EDI),DREG(TMPW));
+
+ if (decode.rep) {
+ gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX));
+ gen_sop_word(SOP_DEC,true,DREG(CYCLES));
+ gen_releasereg(DREG(CYCLES));
+ dyn_savestate(&save_info[used_save_info].state);
+ save_info[used_save_info].branch_pos=gen_create_branch_long(BR_LE);
+ save_info[used_save_info].eip_change=decode.op_start-decode.code_start;
+ save_info[used_save_info].type=normal;
+ used_save_info++;
+
+ /* Jump back to start of ECX check */
+ dyn_synchstate(&rep_state);
+ gen_create_jump(rep_start);
+
+ dyn_loadstate(&rep_state);
+ gen_fill_branch_long(rep_ecx_jmp);
+ }
+ gen_releasereg(DREG(TMPW));
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#include "dosbox.h"
+
+#if (C_DYNREC)
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#if defined (WIN32)
+#include <windows.h>
+#include <winbase.h>
+#endif
+
+#if (C_HAVE_MPROTECT)
+#include <sys/mman.h>
+
+#include <limits.h>
+#ifndef PAGESIZE
+#define PAGESIZE 4096
+#endif
+#endif /* C_HAVE_MPROTECT */
+
+#include "callback.h"
+#include "regs.h"
+#include "mem.h"
+#include "cpu.h"
+#include "debug.h"
+#include "paging.h"
+#include "inout.h"
+#include "lazyflags.h"
+#include "pic.h"
+
+#define CACHE_MAXSIZE (4096*2)
+#define CACHE_TOTAL (1024*1024*8)
+#define CACHE_PAGES (512)
+#define CACHE_BLOCKS (128*1024)
+#define CACHE_ALIGN (16)
+#define DYN_HASH_SHIFT (4)
+#define DYN_PAGE_HASH (4096>>DYN_HASH_SHIFT)
+#define DYN_LINKS (16)
+
+
+//#define DYN_LOG 1 //Turn Logging on.
+
+
+#if C_FPU
+#define CPU_FPU 1 //Enable FPU escape instructions
+#endif
+
+
+// the emulated x86 registers
+#define DRC_REG_EAX 0
+#define DRC_REG_ECX 1
+#define DRC_REG_EDX 2
+#define DRC_REG_EBX 3
+#define DRC_REG_ESP 4
+#define DRC_REG_EBP 5
+#define DRC_REG_ESI 6
+#define DRC_REG_EDI 7
+
+// the emulated x86 segment registers
+#define DRC_SEG_ES 0
+#define DRC_SEG_CS 1
+#define DRC_SEG_SS 2
+#define DRC_SEG_DS 3
+#define DRC_SEG_FS 4
+#define DRC_SEG_GS 5
+
+
+// access to a general register
+#define DRCD_REG_VAL(reg) (&cpu_regs.regs[reg].dword)
+// access to a segment register
+#define DRCD_SEG_VAL(seg) (&Segs.val[seg])
+// access to the physical value of a segment register/selector
+#define DRCD_SEG_PHYS(seg) (&Segs.phys[seg])
+
+// access to an 8bit general register
+#define DRCD_REG_BYTE(reg,idx) (&cpu_regs.regs[reg].byte[idx?BH_INDEX:BL_INDEX])
+// access to 16/32bit general registers
+#define DRCD_REG_WORD(reg,dwrd) ((dwrd)?((void*)(&cpu_regs.regs[reg].dword[DW_INDEX])):((void*)(&cpu_regs.regs[reg].word[W_INDEX])))
+
+
+enum BlockReturn {
+ BR_Normal=0,
+ BR_Cycles,
+ BR_Link1,BR_Link2,
+ BR_Opcode,
+#if (C_DEBUG)
+ BR_OpcodeFull,
+#endif
+ BR_Iret,
+ BR_CallBack,
+ BR_SMCBlock
+};
+
+// identificator to signal self-modification of the currently executed block
+#define SMC_CURRENT_BLOCK 0xffff
+
+
+static void IllegalOptionDynrec(const char* msg) {
+ E_Exit("DynrecCore: illegal option in %s",msg);
+}
+
+static struct {
+ BlockReturn (*runcode)(Bit8u*); // points to code that can start a block
+ Bitu callback; // the occurred callback
+ Bitu readdata; // spare space used when reading from memory
+ Bit32u protected_regs[8]; // space to save/restore register values
+} core_dynrec;
+
+
+#include "core_dynrec/cache.h"
+
+#define X86 0x01
+#define X86_64 0x02
+#define MIPSEL 0x03
+#define ARMV4LE 0x04
+#define ARMV7LE 0x05
+#define POWERPC 0x04
+
+#if C_TARGETCPU == X86_64
+#include "core_dynrec/risc_x64.h"
+#elif C_TARGETCPU == X86
+#include "core_dynrec/risc_x86.h"
+#elif C_TARGETCPU == MIPSEL
+#include "core_dynrec/risc_mipsel32.h"
+#elif (C_TARGETCPU == ARMV4LE) || (C_TARGETCPU == ARMV7LE)
+#include "core_dynrec/risc_armv4le.h"
+#elif C_TARGETCPU == POWERPC
+#include "core_dynrec/risc_ppc.h"
+#endif
+
+#include "core_dynrec/decoder.h"
+
+CacheBlockDynRec * LinkBlocks(BlockReturn ret) {
+ CacheBlockDynRec * block=NULL;
+ // the last instruction was a control flow modifying instruction
+ Bitu temp_ip=SegPhys(cs)+reg_eip;
+ CodePageHandlerDynRec * temp_handler=(CodePageHandlerDynRec *)get_tlb_readhandler(temp_ip);
+ if (temp_handler->flags & PFLAG_HASCODE) {
+ // see if the target is an already translated block
+ block=temp_handler->FindCacheBlock(temp_ip & 4095);
+ if (!block) return NULL;
+
+ // found it, link the current block to
+ cache.block.running->LinkTo(ret==BR_Link2,block);
+ return block;
+ }
+ return NULL;
+}
+
+/*
+ The core tries to find the block that should be executed next.
+ If such a block is found, it is run, otherwise the instruction
+ stream starting at ip_point is translated (see decoder.h) and
+ makes up a new code block that will be run.
+ When control is returned to CPU_Core_Dynrec_Run (which might
+ be right after the block is run, or somewhen long after that
+ due to the direct cacheblock linking) the returncode decides
+ the next action. This might be continuing the translation and
+ execution process, or returning from the core etc.
+*/
+
+Bits CPU_Core_Dynrec_Run(void) {
+ for (;;) {
+ // Determine the linear address of CS:EIP
+ PhysPt ip_point=SegPhys(cs)+reg_eip;
+ #if C_HEAVY_DEBUG
+ if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+ #endif
+
+ CodePageHandlerDynRec * chandler=0;
+ // see if the current page is present and contains code
+ if (GCC_UNLIKELY(MakeCodePage(ip_point,chandler))) {
+ // page not present, throw the exception
+ CPU_Exception(cpu.exception.which,cpu.exception.error);
+ continue;
+ }
+
+ // page doesn't contain code or is special
+ if (GCC_UNLIKELY(!chandler)) return CPU_Core_Normal_Run();
+
+ // find correct Dynamic Block to run
+ CacheBlockDynRec * block=chandler->FindCacheBlock(ip_point&4095);
+ if (!block) {
+ // no block found, thus translate the instruction stream
+ // unless the instruction is known to be modified
+ if (!chandler->invalidation_map || (chandler->invalidation_map[ip_point&4095]<4)) {
+ // translate up to 32 instructions
+ block=CreateCacheBlock(chandler,ip_point,32);
+ } else {
+ // let the normal core handle this instruction to avoid zero-sized blocks
+ Bitu old_cycles=CPU_Cycles;
+ CPU_Cycles=1;
+ Bits nc_retcode=CPU_Core_Normal_Run();
+ if (!nc_retcode) {
+ CPU_Cycles=old_cycles-1;
+ continue;
+ }
+ CPU_CycleLeft+=old_cycles;
+ return nc_retcode;
+ }
+ }
+
+run_block:
+ cache.block.running=0;
+ // now we're ready to run the dynamic code block
+// BlockReturn ret=((BlockReturn (*)(void))(block->cache.start))();
+ BlockReturn ret=core_dynrec.runcode(block->cache.start);
+
+ switch (ret) {
+ case BR_Iret:
+#if C_DEBUG
+#if C_HEAVY_DEBUG
+ if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+#endif
+#endif
+ if (!GETFLAG(TF)) {
+ if (GETFLAG(IF) && PIC_IRQCheck) return CBRET_NONE;
+ break;
+ }
+ // trapflag is set, switch to the trap-aware decoder
+ cpudecoder=CPU_Core_Dynrec_Trap_Run;
+ return CBRET_NONE;
+
+ case BR_Normal:
+ // the block was exited due to a non-predictable control flow
+ // modifying instruction (like ret) or some nontrivial cpu state
+ // changing instruction (for example switch to/from pmode),
+ // or the maximum number of instructions to translate was reached
+#if C_DEBUG
+#if C_HEAVY_DEBUG
+ if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+#endif
+#endif
+ break;
+
+ case BR_Cycles:
+ // cycles went negative, return from the core to handle
+ // external events, schedule the pic...
+#if C_DEBUG
+#if C_HEAVY_DEBUG
+ if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
+#endif
+#endif
+ return CBRET_NONE;
+
+ case BR_CallBack:
+ // the callback code is executed in dosbox.conf, return the callback number
+ FillFlags();
+ return core_dynrec.callback;
+
+ case BR_SMCBlock:
+// LOG_MSG("selfmodification of running block at %x:%x",SegValue(cs),reg_eip);
+ cpu.exception.which=0;
+ // fallthrough, let the normal core handle the block-modifying instruction
+ case BR_Opcode:
+ // some instruction has been encountered that could not be translated
+ // (thus it is not part of the code block), the normal core will
+ // handle this instruction
+ CPU_CycleLeft+=CPU_Cycles;
+ CPU_Cycles=1;
+ return CPU_Core_Normal_Run();
+
+#if (C_DEBUG)
+ case BR_OpcodeFull:
+ CPU_CycleLeft+=CPU_Cycles;
+ CPU_Cycles=1;
+ return CPU_Core_Full_Run();
+#endif
+
+ case BR_Link1:
+ case BR_Link2:
+ block=LinkBlocks(ret);
+ if (block) goto run_block;
+ break;
+
+ default:
+ E_Exit("Invalid return code %d", ret);
+ }
+ }
+ return CBRET_NONE;
+}
+
+Bits CPU_Core_Dynrec_Trap_Run(void) {
+ Bits oldCycles = CPU_Cycles;
+ CPU_Cycles = 1;
+ cpu.trap_skip = false;
+
+ // let the normal core execute the next (only one!) instruction
+ Bits ret=CPU_Core_Normal_Run();
+
+ // trap to int1 unless the last instruction deferred this
+ // (allows hardware interrupts to be served without interaction)
+ if (!cpu.trap_skip) CPU_HW_Interrupt(1);
+
+ CPU_Cycles = oldCycles-1;
+ // continue (either the trapflag was clear anyways, or the int1 cleared it)
+ cpudecoder = &CPU_Core_Dynrec_Run;
+
+ return ret;
+}
+
+void CPU_Core_Dynrec_Init(void) {
+}
+
+void CPU_Core_Dynrec_Cache_Init(bool enable_cache) {
+ // Initialize code cache and dynamic blocks
+ cache_init(enable_cache);
+}
+
+void CPU_Core_Dynrec_Cache_Close(void) {
+ cache_close();
+}
+
+#endif
--- /dev/null
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# src/cpu/core_dynrec/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/dosbox
+pkgincludedir = $(includedir)/dosbox
+pkglibdir = $(libdir)/dosbox
+pkglibexecdir = $(libexecdir)/dosbox
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = src/cpu/core_dynrec
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = aclocal-1.16
+ALSA_CFLAGS =
+ALSA_LIBS = -lasound -lm -ldl -lpthread
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+AUTOCONF = autoconf
+AUTOHEADER = autoheader
+AUTOMAKE = automake-1.16
+AWK = gawk
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS = -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
+CXX = g++
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+ECHO_C =
+ECHO_N = -n
+ECHO_T =
+EGREP = /bin/grep -E
+EXEEXT =
+GREP = /bin/grep
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LDFLAGS =
+LIBOBJS =
+LIBS = -lasound -lm -ldl -lpthread -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL -lXfont2 -lXi -lpng -lz -lX11 -lGL
+LTLIBOBJS =
+MAKEINFO = makeinfo
+MKDIR_P = /bin/mkdir -p
+OBJEXT = o
+PACKAGE = dosbox
+PACKAGE_BUGREPORT =
+PACKAGE_NAME = dosbox
+PACKAGE_STRING = dosbox 0.74
+PACKAGE_TARNAME = dosbox
+PACKAGE_URL =
+PACKAGE_VERSION = 0.74
+PATH_SEPARATOR = :
+RANLIB = ranlib
+SDL_CFLAGS = -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
+SDL_CONFIG = /usr/local/bin/sdl-config
+SDL_LIBS = -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL -lXfont2 -lXi -lpthread
+SET_MAKE =
+SHELL = /bin/bash
+STRIP =
+VERSION = 0.74
+WINDRES = :
+abs_builddir = /home/whatisthis/src/DOSVAXJ3/src/cpu/core_dynrec
+abs_srcdir = /home/whatisthis/src/DOSVAXJ3/src/cpu/core_dynrec
+abs_top_builddir = /home/whatisthis/src/DOSVAXJ3
+abs_top_srcdir = /home/whatisthis/src/DOSVAXJ3
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = $${TAR-tar} chof - "$$tardir"
+am__untar = $${TAR-tar} xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias =
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = x86_64-pc-linux-gnu
+host_alias =
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/whatisthis/src/DOSVAXJ3/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+runstatedir = ${localstatedir}/run
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target_alias =
+top_build_prefix = ../../../
+top_builddir = ../../..
+top_srcdir = ../../..
+noinst_HEADERS = cache.h decoder.h decoder_basic.h decoder_opcodes.h \
+ dyn_fpu.h operators.h risc_x64.h risc_x86.h risc_mipsel32.h \
+ risc_armv4le.h risc_armv4le-common.h \
+ risc_armv4le-o3.h risc_armv4le-thumb.h \
+ risc_armv4le-thumb-iw.h risc_armv4le-thumb-niw.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/cpu/core_dynrec/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/cpu/core_dynrec/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+noinst_HEADERS = cache.h decoder.h decoder_basic.h decoder_opcodes.h \
+ dyn_fpu.h operators.h risc_x64.h risc_x86.h risc_mipsel32.h \
+ risc_armv4le.h risc_armv4le-common.h \
+ risc_armv4le-o3.h risc_armv4le-thumb.h \
+ risc_armv4le-thumb-iw.h risc_armv4le-thumb-niw.h
--- /dev/null
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/cpu/core_dynrec
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WINDRES = @WINDRES@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = cache.h decoder.h decoder_basic.h decoder_opcodes.h \
+ dyn_fpu.h operators.h risc_x64.h risc_x86.h risc_mipsel32.h \
+ risc_armv4le.h risc_armv4le-common.h \
+ risc_armv4le-o3.h risc_armv4le-thumb.h \
+ risc_armv4le-thumb-iw.h risc_armv4le-thumb-niw.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/cpu/core_dynrec/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/cpu/core_dynrec/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+/*
+ * 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.
+ */
+
+
+class CodePageHandlerDynRec; // forward
+
+// basic cache block representation
+class CacheBlockDynRec {
+public:
+ void Clear(void);
+ // link this cache block to another block, index specifies the code
+ // path (always zero for unconditional links, 0/1 for conditional ones
+ void LinkTo(Bitu index,CacheBlockDynRec * toblock) {
+ assert(toblock);
+ link[index].to=toblock;
+ link[index].next=toblock->link[index].from; // set target block
+ toblock->link[index].from=this; // remember who links me
+ }
+ struct {
+ Bit16u start,end; // where in the page is the original code
+ CodePageHandlerDynRec * handler; // page containing this code
+ } page;
+ struct {
+ Bit8u * start; // where in the cache are we
+ Bitu size;
+ CacheBlockDynRec * next;
+ // writemap masking maskpointer/start/length
+ // to allow holes in the writemap
+ Bit8u * wmapmask;
+ Bit16u maskstart;
+ Bit16u masklen;
+ } cache;
+ struct {
+ Bitu index;
+ CacheBlockDynRec * next;
+ } hash;
+ struct {
+ CacheBlockDynRec * to; // this block can transfer control to the to-block
+ CacheBlockDynRec * next;
+ CacheBlockDynRec * from; // the from-block can transfer control to this block
+ } link[2]; // maximum two links (conditional jumps)
+ CacheBlockDynRec * crossblock;
+};
+
+static struct {
+ struct {
+ CacheBlockDynRec * first; // the first cache block in the list
+ CacheBlockDynRec * active; // the current cache block
+ CacheBlockDynRec * free; // pointer to the free list
+ CacheBlockDynRec * running; // the last block that was entered for execution
+ } block;
+ Bit8u * pos; // position in the cache block
+ CodePageHandlerDynRec * free_pages; // pointer to the free list
+ CodePageHandlerDynRec * used_pages; // pointer to the list of used pages
+ CodePageHandlerDynRec * last_page; // the last used page
+} cache;
+
+
+// cache memory pointers, to be malloc'd later
+static Bit8u * cache_code_start_ptr=NULL;
+static Bit8u * cache_code=NULL;
+static Bit8u * cache_code_link_blocks=NULL;
+
+static CacheBlockDynRec * cache_blocks=NULL;
+static CacheBlockDynRec link_blocks[2]; // default linking (specially marked)
+
+
+// the CodePageHandlerDynRec class provides access to the contained
+// cache blocks and intercepts writes to the code for special treatment
+class CodePageHandlerDynRec : public PageHandler {
+public:
+ CodePageHandlerDynRec() {
+ invalidation_map=NULL;
+ }
+
+ void SetupAt(Bitu _phys_page,PageHandler * _old_pagehandler) {
+ // initialize this codepage handler
+ phys_page=_phys_page;
+ // save the old pagehandler to provide direct read access to the memory,
+ // and to be able to restore it later on
+ old_pagehandler=_old_pagehandler;
+
+ // adjust flags
+ flags=old_pagehandler->flags|PFLAG_HASCODE;
+ flags&=~PFLAG_WRITEABLE;
+
+ active_blocks=0;
+ active_count=16;
+
+ // initialize the maps with zero (no cache blocks as well as code present)
+ memset(&hash_map,0,sizeof(hash_map));
+ memset(&write_map,0,sizeof(write_map));
+ if (invalidation_map!=NULL) {
+ free(invalidation_map);
+ invalidation_map=NULL;
+ }
+ }
+
+ // clear out blocks that contain code which has been modified
+ bool InvalidateRange(Bitu start,Bitu end) {
+ Bits index=1+(end>>DYN_HASH_SHIFT);
+ bool is_current_block=false; // if the current block is modified, it has to be exited as soon as possible
+
+ Bit32u ip_point=SegPhys(cs)+reg_eip;
+ ip_point=(PAGING_GetPhysicalPage(ip_point)-(phys_page<<12))+(ip_point&0xfff);
+ while (index>=0) {
+ Bitu map=0;
+ // see if there is still some code in the range
+ for (Bitu count=start;count<=end;count++) map+=write_map[count];
+ if (!map) return is_current_block; // no more code, finished
+
+ CacheBlockDynRec * block=hash_map[index];
+ while (block) {
+ CacheBlockDynRec * nextblock=block->hash.next;
+ // test if this block is in the range
+ if (start<=block->page.end && end>=block->page.start) {
+ if (ip_point<=block->page.end && ip_point>=block->page.start) is_current_block=true;
+ block->Clear(); // clear the block, decrements the write_map accordingly
+ }
+ block=nextblock;
+ }
+ index--;
+ }
+ return is_current_block;
+ }
+
+ // the following functions will clean all cache blocks that are invalid now due to the write
+ void writeb(PhysPt addr,Bitu val){
+ addr&=4095;
+ if (host_readb(hostmem+addr)==(Bit8u)val) return;
+ host_writeb(hostmem+addr,val);
+ // see if there's code where we are writing to
+ if (!host_readb(&write_map[addr])) {
+ if (active_blocks) return; // still some blocks in this page
+ active_count--;
+ if (!active_count) Release(); // delay page releasing until active_count is zero
+ return;
+ } else if (!invalidation_map) {
+ invalidation_map=(Bit8u*)malloc(4096);
+ memset(invalidation_map,0,4096);
+ }
+ invalidation_map[addr]++;
+ InvalidateRange(addr,addr);
+ }
+ void writew(PhysPt addr,Bitu val){
+ addr&=4095;
+ if (host_readw(hostmem+addr)==(Bit16u)val) return;
+ host_writew(hostmem+addr,val);
+ // see if there's code where we are writing to
+ if (!host_readw(&write_map[addr])) {
+ if (active_blocks) return; // still some blocks in this page
+ active_count--;
+ if (!active_count) Release(); // delay page releasing until active_count is zero
+ return;
+ } else if (!invalidation_map) {
+ invalidation_map=(Bit8u*)malloc(4096);
+ memset(invalidation_map,0,4096);
+ }
+#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY)
+ host_writew(&invalidation_map[addr],
+ host_readw(&invalidation_map[addr])+0x101);
+#else
+ (*(Bit16u*)&invalidation_map[addr])+=0x101;
+#endif
+ InvalidateRange(addr,addr+1);
+ }
+ void writed(PhysPt addr,Bitu val){
+ addr&=4095;
+ if (host_readd(hostmem+addr)==(Bit32u)val) return;
+ host_writed(hostmem+addr,val);
+ // see if there's code where we are writing to
+ if (!host_readd(&write_map[addr])) {
+ if (active_blocks) return; // still some blocks in this page
+ active_count--;
+ if (!active_count) Release(); // delay page releasing until active_count is zero
+ return;
+ } else if (!invalidation_map) {
+ invalidation_map=(Bit8u*)malloc(4096);
+ memset(invalidation_map,0,4096);
+ }
+#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY)
+ host_writed(&invalidation_map[addr],
+ host_readd(&invalidation_map[addr])+0x1010101);
+#else
+ (*(Bit32u*)&invalidation_map[addr])+=0x1010101;
+#endif
+ InvalidateRange(addr,addr+3);
+ }
+ bool writeb_checked(PhysPt addr,Bitu val) {
+ addr&=4095;
+ if (host_readb(hostmem+addr)==(Bit8u)val) return false;
+ // see if there's code where we are writing to
+ if (!host_readb(&write_map[addr])) {
+ if (!active_blocks) {
+ // no blocks left in this page, still delay the page releasing a bit
+ active_count--;
+ if (!active_count) Release();
+ }
+ } else {
+ if (!invalidation_map) {
+ invalidation_map=(Bit8u*)malloc(4096);
+ memset(invalidation_map,0,4096);
+ }
+ invalidation_map[addr]++;
+ if (InvalidateRange(addr,addr)) {
+ cpu.exception.which=SMC_CURRENT_BLOCK;
+ return true;
+ }
+ }
+ host_writeb(hostmem+addr,val);
+ return false;
+ }
+ bool writew_checked(PhysPt addr,Bitu val) {
+ addr&=4095;
+ if (host_readw(hostmem+addr)==(Bit16u)val) return false;
+ // see if there's code where we are writing to
+ if (!host_readw(&write_map[addr])) {
+ if (!active_blocks) {
+ // no blocks left in this page, still delay the page releasing a bit
+ active_count--;
+ if (!active_count) Release();
+ }
+ } else {
+ if (!invalidation_map) {
+ invalidation_map=(Bit8u*)malloc(4096);
+ memset(invalidation_map,0,4096);
+ }
+#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY)
+ host_writew(&invalidation_map[addr],
+ host_readw(&invalidation_map[addr])+0x101);
+#else
+ (*(Bit16u*)&invalidation_map[addr])+=0x101;
+#endif
+ if (InvalidateRange(addr,addr+1)) {
+ cpu.exception.which=SMC_CURRENT_BLOCK;
+ return true;
+ }
+ }
+ host_writew(hostmem+addr,val);
+ return false;
+ }
+ bool writed_checked(PhysPt addr,Bitu val) {
+ addr&=4095;
+ if (host_readd(hostmem+addr)==(Bit32u)val) return false;
+ // see if there's code where we are writing to
+ if (!host_readd(&write_map[addr])) {
+ if (!active_blocks) {
+ // no blocks left in this page, still delay the page releasing a bit
+ active_count--;
+ if (!active_count) Release();
+ }
+ } else {
+ if (!invalidation_map) {
+ invalidation_map=(Bit8u*)malloc(4096);
+ memset(invalidation_map,0,4096);
+ }
+#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY)
+ host_writed(&invalidation_map[addr],
+ host_readd(&invalidation_map[addr])+0x1010101);
+#else
+ (*(Bit32u*)&invalidation_map[addr])+=0x1010101;
+#endif
+ if (InvalidateRange(addr,addr+3)) {
+ cpu.exception.which=SMC_CURRENT_BLOCK;
+ return true;
+ }
+ }
+ host_writed(hostmem+addr,val);
+ return false;
+ }
+
+ // add a cache block to this page and note it in the hash map
+ void AddCacheBlock(CacheBlockDynRec * block) {
+ Bitu index=1+(block->page.start>>DYN_HASH_SHIFT);
+ block->hash.next=hash_map[index]; // link to old block at index from the new block
+ block->hash.index=index;
+ hash_map[index]=block; // put new block at hash position
+ block->page.handler=this;
+ active_blocks++;
+ }
+ // there's a block whose code started in a different page
+ void AddCrossBlock(CacheBlockDynRec * block) {
+ block->hash.next=hash_map[0];
+ block->hash.index=0;
+ hash_map[0]=block;
+ block->page.handler=this;
+ active_blocks++;
+ }
+ // remove a cache block
+ void DelCacheBlock(CacheBlockDynRec * block) {
+ active_blocks--;
+ active_count=16;
+ CacheBlockDynRec * * bwhere=&hash_map[block->hash.index];
+ while (*bwhere!=block) {
+ bwhere=&((*bwhere)->hash.next);
+ //Will crash if a block isn't found, which should never happen.
+ }
+ *bwhere=block->hash.next;
+
+ // remove the cleared block from the write map
+ if (GCC_UNLIKELY(block->cache.wmapmask!=NULL)) {
+ // first part is not influenced by the mask
+ for (Bitu i=block->page.start;i<block->cache.maskstart;i++) {
+ if (write_map[i]) write_map[i]--;
+ }
+ Bitu maskct=0;
+ // last part sticks to the writemap mask
+ for (Bitu i=block->cache.maskstart;i<=block->page.end;i++,maskct++) {
+ if (write_map[i]) {
+ // only adjust writemap if it isn't masked
+ if ((maskct>=block->cache.masklen) || (!block->cache.wmapmask[maskct])) write_map[i]--;
+ }
+ }
+ free(block->cache.wmapmask);
+ block->cache.wmapmask=NULL;
+ } else {
+ for (Bitu i=block->page.start;i<=block->page.end;i++) {
+ if (write_map[i]) write_map[i]--;
+ }
+ }
+ }
+
+ void Release(void) {
+ MEM_SetPageHandler(phys_page,1,old_pagehandler); // revert to old handler
+ PAGING_ClearTLB();
+
+ // remove page from the lists
+ if (prev) prev->next=next;
+ else cache.used_pages=next;
+ if (next) next->prev=prev;
+ else cache.last_page=prev;
+ next=cache.free_pages;
+ cache.free_pages=this;
+ prev=0;
+ }
+ void ClearRelease(void) {
+ // clear out all cache blocks in this page
+ for (Bitu index=0;index<(1+DYN_PAGE_HASH);index++) {
+ CacheBlockDynRec * block=hash_map[index];
+ while (block) {
+ CacheBlockDynRec * nextblock=block->hash.next;
+ block->page.handler=0; // no need, full clear
+ block->Clear();
+ block=nextblock;
+ }
+ }
+ Release(); // now can release this page
+ }
+
+ CacheBlockDynRec * FindCacheBlock(Bitu start) {
+ CacheBlockDynRec * block=hash_map[1+(start>>DYN_HASH_SHIFT)];
+ // see if there's a cache block present at the start address
+ while (block) {
+ if (block->page.start==start) return block; // found
+ block=block->hash.next;
+ }
+ return 0; // none found
+ }
+
+ HostPt GetHostReadPt(Bitu phys_page) {
+ hostmem=old_pagehandler->GetHostReadPt(phys_page);
+ return hostmem;
+ }
+ HostPt GetHostWritePt(Bitu phys_page) {
+ return GetHostReadPt( phys_page );
+ }
+public:
+ // the write map, there are write_map[i] cache blocks that cover the byte at address i
+ Bit8u write_map[4096];
+ Bit8u * invalidation_map;
+ CodePageHandlerDynRec * next, * prev; // page linking
+private:
+ PageHandler * old_pagehandler;
+
+ // hash map to quickly find the cache blocks in this page
+ CacheBlockDynRec * hash_map[1+DYN_PAGE_HASH];
+
+ Bitu active_blocks; // the number of cache blocks in this page
+ Bitu active_count; // delaying parameter to not immediately release a page
+ HostPt hostmem;
+ Bitu phys_page;
+};
+
+
+static INLINE void cache_addunusedblock(CacheBlockDynRec * block) {
+ // block has become unused, add it to the freelist
+ block->cache.next=cache.block.free;
+ cache.block.free=block;
+}
+
+static CacheBlockDynRec * cache_getblock(void) {
+ // get a free cache block and advance the free pointer
+ CacheBlockDynRec * ret=cache.block.free;
+ if (!ret) E_Exit("Ran out of CacheBlocks" );
+ cache.block.free=ret->cache.next;
+ ret->cache.next=0;
+ return ret;
+}
+
+void CacheBlockDynRec::Clear(void) {
+ Bitu ind;
+ // check if this is not a cross page block
+ if (hash.index) for (ind=0;ind<2;ind++) {
+ CacheBlockDynRec * fromlink=link[ind].from;
+ link[ind].from=0;
+ while (fromlink) {
+ CacheBlockDynRec * nextlink=fromlink->link[ind].next;
+ // clear the next-link and let the block point to the standard linkcode
+ fromlink->link[ind].next=0;
+ fromlink->link[ind].to=&link_blocks[ind];
+
+ fromlink=nextlink;
+ }
+ if (link[ind].to!=&link_blocks[ind]) {
+ // not linked to the standard linkcode, find the block that links to this block
+ CacheBlockDynRec * * wherelink=&link[ind].to->link[ind].from;
+ while (*wherelink != this && *wherelink) {
+ wherelink = &(*wherelink)->link[ind].next;
+ }
+ // now remove the link
+ if(*wherelink)
+ *wherelink = (*wherelink)->link[ind].next;
+ else {
+ LOG(LOG_CPU,LOG_ERROR)("Cache anomaly. please investigate");
+ }
+ }
+ } else
+ cache_addunusedblock(this);
+ if (crossblock) {
+ // clear out the crossblock (in the page before) as well
+ crossblock->crossblock=0;
+ crossblock->Clear();
+ crossblock=0;
+ }
+ if (page.handler) {
+ // clear out the code page handler
+ page.handler->DelCacheBlock(this);
+ page.handler=0;
+ }
+ if (cache.wmapmask){
+ free(cache.wmapmask);
+ cache.wmapmask=NULL;
+ }
+}
+
+
+static CacheBlockDynRec * cache_openblock(void) {
+ CacheBlockDynRec * block=cache.block.active;
+ // check for enough space in this block
+ Bitu size=block->cache.size;
+ CacheBlockDynRec * nextblock=block->cache.next;
+ if (block->page.handler)
+ block->Clear();
+ // block size must be at least CACHE_MAXSIZE
+ while (size<CACHE_MAXSIZE) {
+ if (!nextblock)
+ goto skipresize;
+ // merge blocks
+ size+=nextblock->cache.size;
+ CacheBlockDynRec * tempblock=nextblock->cache.next;
+ if (nextblock->page.handler)
+ nextblock->Clear();
+ // block is free now
+ cache_addunusedblock(nextblock);
+ nextblock=tempblock;
+ }
+skipresize:
+ // adjust parameters and open this block
+ block->cache.size=size;
+ block->cache.next=nextblock;
+ cache.pos=block->cache.start;
+ return block;
+}
+
+static void cache_closeblock(void) {
+ CacheBlockDynRec * block=cache.block.active;
+ // links point to the default linking code
+ block->link[0].to=&link_blocks[0];
+ block->link[1].to=&link_blocks[1];
+ block->link[0].from=0;
+ block->link[1].from=0;
+ block->link[0].next=0;
+ block->link[1].next=0;
+ // close the block with correct alignment
+ Bitu written=(Bitu)(cache.pos-block->cache.start);
+ if (written>block->cache.size) {
+ if (!block->cache.next) {
+ if (written>block->cache.size+CACHE_MAXSIZE) E_Exit("CacheBlock overrun 1 %d",written-block->cache.size);
+ } else E_Exit("CacheBlock overrun 2 written %d size %d",written,block->cache.size);
+ } else {
+ Bitu new_size;
+ Bitu left=block->cache.size-written;
+ // smaller than cache align then don't bother to resize
+ if (left>CACHE_ALIGN) {
+ new_size=((written-1)|(CACHE_ALIGN-1))+1;
+ CacheBlockDynRec * newblock=cache_getblock();
+ // align block now to CACHE_ALIGN
+ newblock->cache.start=block->cache.start+new_size;
+ newblock->cache.size=block->cache.size-new_size;
+ newblock->cache.next=block->cache.next;
+ block->cache.next=newblock;
+ block->cache.size=new_size;
+ }
+ }
+ // advance the active block pointer
+ if (!block->cache.next || (block->cache.next->cache.start>(cache_code_start_ptr + CACHE_TOTAL - CACHE_MAXSIZE))) {
+// LOG_MSG("Cache full restarting");
+ cache.block.active=cache.block.first;
+ } else {
+ cache.block.active=block->cache.next;
+ }
+}
+
+
+// place an 8bit value into the cache
+static INLINE void cache_addb(Bit8u val) {
+ *cache.pos++=val;
+}
+
+// place a 16bit value into the cache
+static INLINE void cache_addw(Bit16u val) {
+ *(Bit16u*)cache.pos=val;
+ cache.pos+=2;
+}
+
+// place a 32bit value into the cache
+static INLINE void cache_addd(Bit32u val) {
+ *(Bit32u*)cache.pos=val;
+ cache.pos+=4;
+}
+
+// place a 64bit value into the cache
+static INLINE void cache_addq(Bit64u val) {
+ *(Bit64u*)cache.pos=val;
+ cache.pos+=8;
+}
+
+
+static void dyn_return(BlockReturn retcode,bool ret_exception);
+static void dyn_run_code(void);
+
+
+/* Define temporary pagesize so the MPROTECT case and the regular case share as much code as possible */
+#if (C_HAVE_MPROTECT)
+#define PAGESIZE_TEMP PAGESIZE
+#else
+#define PAGESIZE_TEMP 4096
+#endif
+
+static bool cache_initialized = false;
+
+static void cache_init(bool enable) {
+ Bits i;
+ if (enable) {
+ // see if cache is already initialized
+ if (cache_initialized) return;
+ cache_initialized = true;
+ if (cache_blocks == NULL) {
+ // allocate the cache blocks memory
+ cache_blocks=(CacheBlockDynRec*)malloc(CACHE_BLOCKS*sizeof(CacheBlockDynRec));
+ if(!cache_blocks) E_Exit("Allocating cache_blocks has failed");
+ memset(cache_blocks,0,sizeof(CacheBlockDynRec)*CACHE_BLOCKS);
+ cache.block.free=&cache_blocks[0];
+ // initialize the cache blocks
+ for (i=0;i<CACHE_BLOCKS-1;i++) {
+ cache_blocks[i].link[0].to=(CacheBlockDynRec *)1;
+ cache_blocks[i].link[1].to=(CacheBlockDynRec *)1;
+ cache_blocks[i].cache.next=&cache_blocks[i+1];
+ }
+ }
+ if (cache_code_start_ptr==NULL) {
+ // allocate the code cache memory
+#if defined (WIN32)
+ cache_code_start_ptr=(Bit8u*)VirtualAlloc(0,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP,
+ MEM_COMMIT,PAGE_EXECUTE_READWRITE);
+ if (!cache_code_start_ptr)
+ cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
+#else
+ cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
+#endif
+ if(!cache_code_start_ptr) E_Exit("Allocating dynamic cache failed");
+
+ // align the cache at a page boundary
+ cache_code=(Bit8u*)(((Bitu)cache_code_start_ptr + PAGESIZE_TEMP-1) & ~(PAGESIZE_TEMP-1));//Bitu is same size as a pointer.
+
+ cache_code_link_blocks=cache_code;
+ cache_code=cache_code+PAGESIZE_TEMP;
+
+#if (C_HAVE_MPROTECT)
+ if(mprotect(cache_code_link_blocks,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP,PROT_WRITE|PROT_READ|PROT_EXEC))
+ LOG_MSG("Setting excute permission on the code cache has failed");
+#endif
+ CacheBlockDynRec * block=cache_getblock();
+ cache.block.first=block;
+ cache.block.active=block;
+ block->cache.start=&cache_code[0];
+ block->cache.size=CACHE_TOTAL;
+ block->cache.next=0; // last block in the list
+ }
+ // setup the default blocks for block linkage returns
+ cache.pos=&cache_code_link_blocks[0];
+ link_blocks[0].cache.start=cache.pos;
+ // link code that returns with a special return code
+ dyn_return(BR_Link1,false);
+ cache.pos=&cache_code_link_blocks[32];
+ link_blocks[1].cache.start=cache.pos;
+ // link code that returns with a special return code
+ dyn_return(BR_Link2,false);
+
+ cache.pos=&cache_code_link_blocks[64];
+ core_dynrec.runcode=(BlockReturn (*)(Bit8u*))cache.pos;
+// link_blocks[1].cache.start=cache.pos;
+ dyn_run_code();
+
+ cache.free_pages=0;
+ cache.last_page=0;
+ cache.used_pages=0;
+ // setup the code pages
+ for (i=0;i<CACHE_PAGES;i++) {
+ CodePageHandlerDynRec * newpage=new CodePageHandlerDynRec();
+ newpage->next=cache.free_pages;
+ cache.free_pages=newpage;
+ }
+ }
+}
+
+static void cache_close(void) {
+/* for (;;) {
+ if (cache.used_pages) {
+ CodePageHandler * cpage=cache.used_pages;
+ CodePageHandler * npage=cache.used_pages->next;
+ cpage->ClearRelease();
+ delete cpage;
+ cache.used_pages=npage;
+ } else break;
+ }
+ if (cache_blocks != NULL) {
+ free(cache_blocks);
+ cache_blocks = NULL;
+ }
+ if (cache_code_start_ptr != NULL) {
+ ### care: under windows VirtualFree() has to be used if
+ ### VirtualAlloc was used for memory allocation
+ free(cache_code_start_ptr);
+ cache_code_start_ptr = NULL;
+ }
+ cache_code = NULL;
+ cache_code_link_blocks = NULL;
+ cache_initialized = false; */
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+#include "decoder_basic.h"
+#include "operators.h"
+#include "decoder_opcodes.h"
+
+#include "dyn_fpu.h"
+
+/*
+ The function CreateCacheBlock translates the instruction stream
+ until either an unhandled instruction is found, the maximum
+ number of translated instructions is reached or some critical
+ instruction is encountered.
+*/
+
+static CacheBlockDynRec * CreateCacheBlock(CodePageHandlerDynRec * codepage,PhysPt start,Bitu max_opcodes) {
+ // initialize a load of variables
+ decode.code_start=start;
+ decode.code=start;
+ decode.page.code=codepage;
+ decode.page.index=start&4095;
+ decode.page.wmap=codepage->write_map;
+ decode.page.invmap=codepage->invalidation_map;
+ decode.page.first=start >> 12;
+ decode.active_block=decode.block=cache_openblock();
+ decode.block->page.start=(Bit16u)decode.page.index;
+ codepage->AddCacheBlock(decode.block);
+
+ InitFlagsOptimization();
+
+ // every codeblock that is run sets cache.block.running to itself
+ // so the block linking knows the last executed block
+ gen_mov_direct_ptr(&cache.block.running,(DRC_PTR_SIZE_IM)decode.block);
+
+ // start with the cycles check
+ gen_mov_word_to_reg(FC_RETOP,&CPU_Cycles,true);
+ save_info_dynrec[used_save_info_dynrec].branch_pos=gen_create_branch_long_leqzero(FC_RETOP);
+ save_info_dynrec[used_save_info_dynrec].type=cycle_check;
+ used_save_info_dynrec++;
+
+ decode.cycles=0;
+ while (max_opcodes--) {
+ // Init prefixes
+ decode.big_addr=cpu.code.big;
+ decode.big_op=cpu.code.big;
+ decode.seg_prefix=0;
+ decode.seg_prefix_used=false;
+ decode.rep=REP_NONE;
+ decode.cycles++;
+ decode.op_start=decode.code;
+restart_prefix:
+ Bitu opcode;
+ if (!decode.page.invmap) opcode=decode_fetchb();
+ else {
+ // some entries in the invalidation map, see if the next
+ // instruction is known to be modified a lot
+ if (decode.page.index<4096) {
+ if (GCC_UNLIKELY(decode.page.invmap[decode.page.index]>=4)) goto illegalopcode;
+ opcode=decode_fetchb();
+ } else {
+ // switch to the next page
+ opcode=decode_fetchb();
+ if (GCC_UNLIKELY(decode.page.invmap &&
+ (decode.page.invmap[decode.page.index-1]>=4))) goto illegalopcode;
+ }
+ }
+ switch (opcode) {
+ // instructions 'op reg8,reg8' and 'op [],reg8'
+ case 0x00:dyn_dop_ebgb(DOP_ADD);break;
+ case 0x08:dyn_dop_ebgb(DOP_OR);break;
+ case 0x10:dyn_dop_ebgb(DOP_ADC);break;
+ case 0x18:dyn_dop_ebgb(DOP_SBB);break;
+ case 0x20:dyn_dop_ebgb(DOP_AND);break;
+ case 0x28:dyn_dop_ebgb(DOP_SUB);break;
+ case 0x30:dyn_dop_ebgb(DOP_XOR);break;
+ case 0x38:dyn_dop_ebgb(DOP_CMP);break;
+
+ // instructions 'op reg8,reg8' and 'op reg8,[]'
+ case 0x02:dyn_dop_gbeb(DOP_ADD);break;
+ case 0x0a:dyn_dop_gbeb(DOP_OR);break;
+ case 0x12:dyn_dop_gbeb(DOP_ADC);break;
+ case 0x1a:dyn_dop_gbeb(DOP_SBB);break;
+ case 0x22:dyn_dop_gbeb(DOP_AND);break;
+ case 0x2a:dyn_dop_gbeb(DOP_SUB);break;
+ case 0x32:dyn_dop_gbeb(DOP_XOR);break;
+ case 0x3a:dyn_dop_gbeb(DOP_CMP);break;
+
+ // instructions 'op reg16/32,reg16/32' and 'op [],reg16/32'
+ case 0x01:dyn_dop_evgv(DOP_ADD);break;
+ case 0x09:dyn_dop_evgv(DOP_OR);break;
+ case 0x11:dyn_dop_evgv(DOP_ADC);break;
+ case 0x19:dyn_dop_evgv(DOP_SBB);break;
+ case 0x21:dyn_dop_evgv(DOP_AND);break;
+ case 0x29:dyn_dop_evgv(DOP_SUB);break;
+ case 0x31:dyn_dop_evgv(DOP_XOR);break;
+ case 0x39:dyn_dop_evgv(DOP_CMP);break;
+
+ // instructions 'op reg16/32,reg16/32' and 'op reg16/32,[]'
+ case 0x03:dyn_dop_gvev(DOP_ADD);break;
+ case 0x0b:dyn_dop_gvev(DOP_OR);break;
+ case 0x13:dyn_dop_gvev(DOP_ADC);break;
+ case 0x1b:dyn_dop_gvev(DOP_SBB);break;
+ case 0x23:dyn_dop_gvev(DOP_AND);break;
+ case 0x2b:dyn_dop_gvev(DOP_SUB);break;
+ case 0x33:dyn_dop_gvev(DOP_XOR);break;
+ case 0x3b:dyn_dop_gvev(DOP_CMP);break;
+
+ // instructions 'op reg8,imm8'
+ case 0x04:dyn_dop_byte_imm(DOP_ADD,DRC_REG_EAX,0);break;
+ case 0x0c:dyn_dop_byte_imm(DOP_OR,DRC_REG_EAX,0);break;
+ case 0x14:dyn_dop_byte_imm(DOP_ADC,DRC_REG_EAX,0);break;
+ case 0x1c:dyn_dop_byte_imm(DOP_SBB,DRC_REG_EAX,0);break;
+ case 0x24:dyn_dop_byte_imm(DOP_AND,DRC_REG_EAX,0);break;
+ case 0x2c:dyn_dop_byte_imm(DOP_SUB,DRC_REG_EAX,0);break;
+ case 0x34:dyn_dop_byte_imm(DOP_XOR,DRC_REG_EAX,0);break;
+ case 0x3c:dyn_dop_byte_imm(DOP_CMP,DRC_REG_EAX,0);break;
+
+ // instructions 'op reg16/32,imm16/32'
+ case 0x05:dyn_dop_word_imm(DOP_ADD,DRC_REG_EAX);break;
+ case 0x0d:dyn_dop_word_imm_old(DOP_OR,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break;
+ case 0x15:dyn_dop_word_imm_old(DOP_ADC,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break;
+ case 0x1d:dyn_dop_word_imm_old(DOP_SBB,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break;
+ case 0x25:dyn_dop_word_imm(DOP_AND,DRC_REG_EAX);break;
+ case 0x2d:dyn_dop_word_imm_old(DOP_SUB,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break;
+ case 0x35:dyn_dop_word_imm_old(DOP_XOR,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break;
+ case 0x3d:dyn_dop_word_imm_old(DOP_CMP,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break;
+
+ // push segment register onto stack
+ case 0x06:dyn_push_seg(DRC_SEG_ES);break;
+ case 0x0e:dyn_push_seg(DRC_SEG_CS);break;
+ case 0x16:dyn_push_seg(DRC_SEG_SS);break;
+ case 0x1e:dyn_push_seg(DRC_SEG_DS);break;
+
+ // pop segment register from stack
+ case 0x07:dyn_pop_seg(DRC_SEG_ES);break;
+ case 0x17:dyn_pop_seg(DRC_SEG_SS);break;
+ case 0x1f:dyn_pop_seg(DRC_SEG_DS);break;
+
+ // segment prefixes
+ case 0x26:dyn_segprefix(DRC_SEG_ES);goto restart_prefix;
+ case 0x2e:dyn_segprefix(DRC_SEG_CS);goto restart_prefix;
+ case 0x36:dyn_segprefix(DRC_SEG_SS);goto restart_prefix;
+ case 0x3e:dyn_segprefix(DRC_SEG_DS);goto restart_prefix;
+ case 0x64:dyn_segprefix(DRC_SEG_FS);goto restart_prefix;
+ case 0x65:dyn_segprefix(DRC_SEG_GS);goto restart_prefix;
+
+// case 0x27: DAA missing
+// case 0x2f: DAS missing
+// case 0x37: AAA missing
+// case 0x3f: AAS missing
+
+ // dual opcodes
+ case 0x0f:
+ {
+ Bitu dual_code=decode_fetchb();
+ switch (dual_code) {
+ case 0x00:
+ if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode;
+ dyn_grp6();
+ break;
+ case 0x01:
+ if (dyn_grp7()) goto finish_block;
+ break;
+/* case 0x02:
+ if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode;
+ dyn_larlsl(true);
+ break;
+ case 0x03:
+ if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode;
+ dyn_larlsl(false);
+ break; */
+
+ case 0x20:dyn_mov_from_crx();break;
+ case 0x22:dyn_mov_to_crx();goto finish_block;
+
+ // short conditional jumps
+ case 0x80:case 0x81:case 0x82:case 0x83:case 0x84:case 0x85:case 0x86:case 0x87:
+ case 0x88:case 0x89:case 0x8a:case 0x8b:case 0x8c:case 0x8d:case 0x8e:case 0x8f:
+ dyn_branched_exit((BranchTypes)(dual_code&0xf),
+ decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw());
+ goto finish_block;
+
+ // conditional byte set instructions
+/* case 0x90:case 0x91:case 0x92:case 0x93:case 0x94:case 0x95:case 0x96:case 0x97:
+ case 0x98:case 0x99:case 0x9a:case 0x9b:case 0x9c:case 0x9d:case 0x9e:case 0x9f:
+ dyn_set_byte_on_condition((BranchTypes)(dual_code&0xf));
+ AcquireFlags(FMASK_TEST);
+ break; */
+
+ // push/pop segment registers
+ case 0xa0:dyn_push_seg(DRC_SEG_FS);break;
+ case 0xa1:dyn_pop_seg(DRC_SEG_FS);break;
+ case 0xa8:dyn_push_seg(DRC_SEG_GS);break;
+ case 0xa9:dyn_pop_seg(DRC_SEG_GS);break;
+
+ // double shift instructions
+ case 0xa4:dyn_dshift_ev_gv(true,true);break;
+ case 0xa5:dyn_dshift_ev_gv(true,false);break;
+ case 0xac:dyn_dshift_ev_gv(false,true);break;
+ case 0xad:dyn_dshift_ev_gv(false,false);break;
+
+ case 0xaf:dyn_imul_gvev(0);break;
+
+ // lfs
+ case 0xb4:
+ dyn_get_modrm();
+ if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode;
+ dyn_load_seg_off_ea(DRC_SEG_FS);
+ break;
+ // lgs
+ case 0xb5:
+ dyn_get_modrm();
+ if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode;
+ dyn_load_seg_off_ea(DRC_SEG_GS);
+ break;
+
+ // zero-extending moves
+ case 0xb6:dyn_movx_ev_gb(false);break;
+ case 0xb7:dyn_movx_ev_gw(false);break;
+
+ // sign-extending moves
+ case 0xbe:dyn_movx_ev_gb(true);break;
+ case 0xbf:dyn_movx_ev_gw(true);break;
+
+ default:
+#if DYN_LOG
+// LOG_MSG("Unhandled dual opcode 0F%02X",dual_code);
+#endif
+ goto illegalopcode;
+ }
+ break;
+ }
+
+ // 'inc/dec reg16/32'
+ case 0x40:case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:case 0x47:
+ dyn_sop_word(SOP_INC,opcode&7);
+ break;
+ case 0x48:case 0x49:case 0x4a:case 0x4b:case 0x4c:case 0x4d:case 0x4e:case 0x4f:
+ dyn_sop_word(SOP_DEC,opcode&7);
+ break;
+
+ // 'push/pop reg16/32'
+ case 0x50:case 0x51:case 0x52:case 0x53:case 0x54:case 0x55:case 0x56:case 0x57:
+ dyn_push_reg(opcode&7);
+ break;
+ case 0x58:case 0x59:case 0x5a:case 0x5b:case 0x5c:case 0x5d:case 0x5e:case 0x5f:
+ dyn_pop_reg(opcode&7);
+ break;
+
+ case 0x60:
+ if (decode.big_op) gen_call_function_raw((void *)&dynrec_pusha_dword);
+ else gen_call_function_raw((void *)&dynrec_pusha_word);
+ break;
+ case 0x61:
+ if (decode.big_op) gen_call_function_raw((void *)&dynrec_popa_dword);
+ else gen_call_function_raw((void *)&dynrec_popa_word);
+ break;
+
+// case 0x62: BOUND missing
+// case 0x61: ARPL missing
+
+ case 0x66:decode.big_op=!cpu.code.big;goto restart_prefix;
+ case 0x67:decode.big_addr=!cpu.code.big;goto restart_prefix;
+
+ // 'push imm8/16/32'
+ case 0x68:
+ dyn_push_word_imm(decode.big_op ? decode_fetchd() : decode_fetchw());
+ break;
+ case 0x6a:
+ dyn_push_byte_imm((Bit8s)decode_fetchb());
+ break;
+
+ // signed multiplication
+ case 0x69:dyn_imul_gvev(decode.big_op ? 4 : 2);break;
+ case 0x6b:dyn_imul_gvev(1);break;
+
+// case 0x6c to 0x6f missing (ins/outs)
+
+ // short conditional jumps
+ case 0x70:case 0x71:case 0x72:case 0x73:case 0x74:case 0x75:case 0x76:case 0x77:
+ case 0x78:case 0x79:case 0x7a:case 0x7b:case 0x7c:case 0x7d:case 0x7e:case 0x7f:
+ dyn_branched_exit((BranchTypes)(opcode&0xf),(Bit8s)decode_fetchb());
+ goto finish_block;
+
+ // 'op []/reg8,imm8'
+ case 0x80:
+ case 0x82:dyn_grp1_eb_ib();break;
+
+ // 'op []/reg16/32,imm16/32'
+ case 0x81:dyn_grp1_ev_iv(false);break;
+ case 0x83:dyn_grp1_ev_iv(true);break;
+
+ // 'test []/reg8/16/32,reg8/16/32'
+ case 0x84:dyn_dop_gbeb(DOP_TEST);break;
+ case 0x85:dyn_dop_gvev(DOP_TEST);break;
+
+ // 'xchg reg8/16/32,[]/reg8/16/32'
+ case 0x86:dyn_dop_ebgb_xchg();break;
+ case 0x87:dyn_dop_evgv_xchg();break;
+
+ // 'mov []/reg8/16/32,reg8/16/32'
+ case 0x88:dyn_dop_ebgb_mov();break;
+ case 0x89:dyn_dop_evgv_mov();break;
+ // 'mov reg8/16/32,[]/reg8/16/32'
+ case 0x8a:dyn_dop_gbeb_mov();break;
+ case 0x8b:dyn_dop_gvev_mov();break;
+
+ // move segment register into memory or a 16bit register
+ case 0x8c:dyn_mov_ev_seg();break;
+
+ // load effective address
+ case 0x8d:dyn_lea();break;
+
+ // move a value from memory or a 16bit register into a segment register
+ case 0x8e:dyn_mov_seg_ev();break;
+
+ // 'pop []'
+ case 0x8f:dyn_pop_ev();break;
+
+ case 0x90: // nop
+ case 0x9b: // wait
+ case 0xf0: // lock
+ break;
+
+ case 0x91:case 0x92:case 0x93:case 0x94:case 0x95:case 0x96:case 0x97:
+ dyn_xchg_ax(opcode&7);
+ break;
+
+ // sign-extend al into ax/sign-extend ax into eax
+ case 0x98:dyn_cbw();break;
+ // sign-extend ax into dx:ax/sign-extend eax into edx:eax
+ case 0x99:dyn_cwd();break;
+
+ case 0x9a:dyn_call_far_imm();goto finish_block;
+
+ case 0x9c: // pushf
+ AcquireFlags(FMASK_TEST);
+ gen_call_function_I((void *)&CPU_PUSHF,decode.big_op);
+ dyn_check_exception(FC_RETOP);
+ break;
+ case 0x9d: // popf
+ gen_call_function_I((void *)&CPU_POPF,decode.big_op);
+ dyn_check_exception(FC_RETOP);
+ InvalidateFlags();
+ break;
+
+ case 0x9e:dyn_sahf();break;
+// case 0x9f: LAHF missing
+
+ // 'mov al/ax,[]'
+ case 0xa0:
+ dyn_mov_byte_al_direct(decode.big_addr ? decode_fetchd() : decode_fetchw());
+ break;
+ case 0xa1:
+ dyn_mov_byte_ax_direct(decode.big_addr ? decode_fetchd() : decode_fetchw());
+ break;
+ // 'mov [],al/ax'
+ case 0xa2:
+ dyn_mov_byte_direct_al();
+ break;
+ case 0xa3:
+ dyn_mov_byte_direct_ax(decode.big_addr ? decode_fetchd() : decode_fetchw());
+ break;
+
+
+// case 0xa6 to 0xaf string operations, some missing
+
+ // movsb/w/d
+ case 0xa4:dyn_string(STR_MOVSB);break;
+ case 0xa5:dyn_string(decode.big_op ? STR_MOVSD : STR_MOVSW);break;
+
+ // stosb/w/d
+ case 0xaa:dyn_string(STR_STOSB);break;
+ case 0xab:dyn_string(decode.big_op ? STR_STOSD : STR_STOSW);break;
+
+ // lodsb/w/d
+ case 0xac:dyn_string(STR_LODSB);break;
+ case 0xad:dyn_string(decode.big_op ? STR_LODSD : STR_LODSW);break;
+
+
+ // 'test reg8/16/32,imm8/16/32'
+ case 0xa8:dyn_dop_byte_imm(DOP_TEST,DRC_REG_EAX,0);break;
+ case 0xa9:dyn_dop_word_imm_old(DOP_TEST,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break;
+
+ // 'mov reg8/16/32,imm8/16/32'
+ case 0xb0:case 0xb1:case 0xb2:case 0xb3:case 0xb4:case 0xb5:case 0xb6:case 0xb7:
+ dyn_mov_byte_imm(opcode&3,(opcode>>2)&1,decode_fetchb());
+ break;
+ case 0xb8:case 0xb9:case 0xba:case 0xbb:case 0xbc:case 0xbd:case 0xbe:case 0xbf:
+ dyn_mov_word_imm(opcode&7);break;
+ break;
+
+ // 'shiftop []/reg8,imm8/1/cl'
+ case 0xc0:dyn_grp2_eb(grp2_imm);break;
+ case 0xd0:dyn_grp2_eb(grp2_1);break;
+ case 0xd2:dyn_grp2_eb(grp2_cl);break;
+
+ // 'shiftop []/reg16/32,imm8/1/cl'
+ case 0xc1:dyn_grp2_ev(grp2_imm);break;
+ case 0xd1:dyn_grp2_ev(grp2_1);break;
+ case 0xd3:dyn_grp2_ev(grp2_cl);break;
+
+ // retn [param]
+ case 0xc2:dyn_ret_near(decode_fetchw());goto finish_block;
+ case 0xc3:dyn_ret_near(0);goto finish_block;
+
+ // les
+ case 0xc4:
+ dyn_get_modrm();
+ if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode;
+ dyn_load_seg_off_ea(DRC_SEG_ES);
+ break;
+ // lds
+ case 0xc5:
+ dyn_get_modrm();
+ if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode;
+ dyn_load_seg_off_ea(DRC_SEG_DS);break;
+
+ // 'mov []/reg8/16/32,imm8/16/32'
+ case 0xc6:dyn_dop_ebib_mov();break;
+ case 0xc7:dyn_dop_eviv_mov();break;
+
+ case 0xc8:dyn_enter();break;
+ case 0xc9:dyn_leave();break;
+
+ // retf [param]
+ case 0xca:dyn_ret_far(decode_fetchw());goto finish_block;
+ case 0xcb:dyn_ret_far(0);goto finish_block;
+
+ // int/iret
+ case 0xcd:dyn_interrupt(decode_fetchb());goto finish_block;
+ case 0xcf:dyn_iret();goto finish_block;
+
+// case 0xd4: AAM missing
+// case 0xd5: AAD missing
+
+// case 0xd6: SALC missing
+// case 0xd7: XLAT missing
+
+
+#ifdef CPU_FPU
+ // floating point instructions
+ case 0xd8:
+ dyn_fpu_esc0();
+ break;
+ case 0xd9:
+ dyn_fpu_esc1();
+ break;
+ case 0xda:
+ dyn_fpu_esc2();
+ break;
+ case 0xdb:
+ dyn_fpu_esc3();
+ break;
+ case 0xdc:
+ dyn_fpu_esc4();
+ break;
+ case 0xdd:
+ dyn_fpu_esc5();
+ break;
+ case 0xde:
+ dyn_fpu_esc6();
+ break;
+ case 0xdf:
+ dyn_fpu_esc7();
+ break;
+#endif
+
+
+ // loop instructions
+ case 0xe0:dyn_loop(LOOP_NE);goto finish_block;
+ case 0xe1:dyn_loop(LOOP_E);goto finish_block;
+ case 0xe2:dyn_loop(LOOP_NONE);goto finish_block;
+ case 0xe3:dyn_loop(LOOP_JCXZ);goto finish_block;
+
+
+ // 'in al/ax/eax,port_imm'
+ case 0xe4:dyn_read_port_byte_direct(decode_fetchb());break;
+ case 0xe5:dyn_read_port_word_direct(decode_fetchb());break;
+ // 'out port_imm,al/ax/eax'
+ case 0xe6:dyn_write_port_byte_direct(decode_fetchb());break;
+ case 0xe7:dyn_write_port_word_direct(decode_fetchb());break;
+
+ // 'in al/ax/eax,port_dx'
+ case 0xec:dyn_read_port_byte();break;
+ case 0xed:dyn_read_port_word();break;
+ // 'out port_dx,al/ax/eax'
+ case 0xee:dyn_write_port_byte();break;
+ case 0xef:dyn_write_port_word();break;
+
+
+ // 'call near imm16/32'
+ case 0xe8:
+ dyn_call_near_imm();
+ goto finish_block;
+ // 'jmp near imm16/32'
+ case 0xe9:
+ dyn_exit_link(decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw());
+ goto finish_block;
+ // 'jmp far'
+ case 0xea:
+ dyn_jmp_far_imm();
+ goto finish_block;
+ // 'jmp short imm8'
+ case 0xeb:
+ dyn_exit_link((Bit8s)decode_fetchb());
+ goto finish_block;
+
+
+ // repeat prefixes
+ case 0xf2:
+ decode.rep=REP_NZ;
+ goto restart_prefix;
+ case 0xf3:
+ decode.rep=REP_Z;
+ goto restart_prefix;
+
+ case 0xf5: //CMC
+ gen_call_function_raw((void*)dynrec_cmc);
+ break;
+ case 0xf8: //CLC
+ gen_call_function_raw((void*)dynrec_clc);
+ break;
+ case 0xf9: //STC
+ gen_call_function_raw((void*)dynrec_stc);
+ break;
+
+ case 0xf6:dyn_grp3_eb();break;
+ case 0xf7:dyn_grp3_ev();break;
+
+ case 0xfa: //CLI
+ gen_call_function_raw((void *)&CPU_CLI);
+ dyn_check_exception(FC_RETOP);
+ break;
+ case 0xfb: //STI
+ gen_call_function_raw((void *)&CPU_STI);
+ dyn_check_exception(FC_RETOP);
+ if (max_opcodes<=0) max_opcodes=1; //Allow 1 extra opcode
+ break;
+
+ case 0xfc: //CLD
+ gen_call_function_raw((void*)dynrec_cld);
+ break;
+ case 0xfd: //STD
+ gen_call_function_raw((void*)dynrec_std);
+ break;
+
+ case 0xfe:
+ if (dyn_grp4_eb()) goto finish_block;
+ break;
+ case 0xff:
+ switch (dyn_grp4_ev()) {
+ case 0:
+ break;
+ case 1:
+ goto core_close_block;
+ case 2:
+ goto illegalopcode;
+ default:
+ break;
+ }
+ break;
+
+ default:
+#if DYN_LOG
+// LOG_MSG("Dynrec unhandled opcode %X",opcode);
+#endif
+ goto illegalopcode;
+ }
+ }
+ // link to next block because the maximum number of opcodes has been reached
+ dyn_set_eip_end();
+ dyn_reduce_cycles();
+ gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start));
+ dyn_closeblock();
+ goto finish_block;
+core_close_block:
+ dyn_reduce_cycles();
+ dyn_return(BR_Normal);
+ dyn_closeblock();
+ goto finish_block;
+illegalopcode:
+ // some unhandled opcode has been encountered
+ dyn_set_eip_last();
+ dyn_reduce_cycles();
+ dyn_return(BR_Opcode); // tell the core what happened
+ dyn_closeblock();
+ goto finish_block;
+finish_block:
+
+ // setup the correct end-address
+ decode.page.index--;
+ decode.active_block->page.end=(Bit16u)decode.page.index;
+// LOG_MSG("Created block size %d start %d end %d",decode.block->cache.size,decode.block->page.start,decode.block->page.end);
+
+ return decode.block;
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+/*
+ This file provides some definitions and basic level functions
+ that use code generating functions from risc_?.h
+ Important is the function call generation including parameter
+ loading, the effective address calculation and the memory
+ access functions.
+*/
+
+
+// instructions that use one operand
+enum SingleOps {
+ SOP_INC,SOP_DEC,
+ SOP_NOT,SOP_NEG
+};
+
+// instructions that use two operand
+enum DualOps {
+ DOP_ADD,DOP_ADC,
+ DOP_SUB,DOP_SBB,
+ DOP_CMP,DOP_XOR,
+ DOP_AND,DOP_OR,
+ DOP_TEST,
+ DOP_MOV,
+ DOP_XCHG
+};
+
+// shift and rotate functions
+enum ShiftOps {
+ SHIFT_ROL,SHIFT_ROR,
+ SHIFT_RCL,SHIFT_RCR,
+ SHIFT_SHL,SHIFT_SHR,
+ SHIFT_SAL,SHIFT_SAR
+};
+
+// branch conditions
+enum BranchTypes {
+ BR_O,BR_NO,BR_B,BR_NB,
+ BR_Z,BR_NZ,BR_BE,BR_NBE,
+ BR_S,BR_NS,BR_P,BR_NP,
+ BR_L,BR_NL,BR_LE,BR_NLE
+};
+
+// string instructions
+enum StringOps {
+ STR_OUTSB=0,STR_OUTSW,STR_OUTSD,
+ STR_INSB=4,STR_INSW,STR_INSD,
+ STR_MOVSB=8,STR_MOVSW,STR_MOVSD,
+ STR_LODSB=12,STR_LODSW,STR_LODSD,
+ STR_STOSB=16,STR_STOSW,STR_STOSD,
+ STR_SCASB=20,STR_SCASW,STR_SCASD,
+ STR_CMPSB=24,STR_CMPSW,STR_CMPSD
+};
+
+// repeat prefix type (for string operations)
+enum REP_Type {
+ REP_NONE=0,REP_NZ,REP_Z
+};
+
+// loop type
+enum LoopTypes {
+ LOOP_NONE,LOOP_NE,LOOP_E,LOOP_JCXZ
+};
+
+// rotate operand type
+enum grp2_types {
+ grp2_1,grp2_imm,grp2_cl
+};
+
+// opcode mapping for group1 instructions
+static DualOps grp1_table[8]={
+ DOP_ADD,DOP_OR,DOP_ADC,DOP_SBB,DOP_AND,DOP_SUB,DOP_XOR,DOP_CMP
+};
+
+
+// decoding information used during translation of a code block
+static struct DynDecode {
+ PhysPt code; // pointer to next byte in the instruction stream
+ PhysPt code_start; // pointer to the start of the current code block
+ PhysPt op_start; // pointer to the start of the current instruction
+ bool big_op; // operand modifier
+ bool big_addr; // address modifier
+ REP_Type rep; // current repeat prefix
+ Bitu cycles; // number cycles used by currently translated code
+ bool seg_prefix_used; // segment overridden
+ Bit8u seg_prefix; // segment prefix (if seg_prefix_used==true)
+
+ // block that contains the first instruction translated
+ CacheBlockDynRec * block;
+ // block that contains the current byte of the instruction stream
+ CacheBlockDynRec * active_block;
+
+ // the active page (containing the current byte of the instruction stream)
+ struct {
+ CodePageHandlerDynRec * code;
+ Bitu index; // index to the current byte of the instruction stream
+ Bit8u * wmap; // write map that indicates code presence for every byte of this page
+ Bit8u * invmap; // invalidation map
+ Bitu first; // page number
+ } page;
+
+ // modrm state of the current instruction (if used)
+ struct {
+ Bitu val;
+ Bitu mod;
+ Bitu rm;
+ Bitu reg;
+ } modrm;
+} decode;
+
+
+static bool MakeCodePage(Bitu lin_addr,CodePageHandlerDynRec * &cph) {
+ Bit8u rdval;
+ //Ensure page contains memory:
+ if (GCC_UNLIKELY(mem_readb_checked(lin_addr,&rdval))) return true;
+
+ PageHandler * handler=get_tlb_readhandler(lin_addr);
+ if (handler->flags & PFLAG_HASCODE) {
+ // this is a codepage handler, and the one that we're looking for
+ cph=(CodePageHandlerDynRec *)handler;
+ return false;
+ }
+ if (handler->flags & PFLAG_NOCODE) {
+ if (PAGING_ForcePageInit(lin_addr)) {
+ handler=get_tlb_readhandler(lin_addr);
+ if (handler->flags & PFLAG_HASCODE) {
+ cph=(CodePageHandlerDynRec *)handler;
+ return false;
+ }
+ }
+ if (handler->flags & PFLAG_NOCODE) {
+ LOG_MSG("DYNREC:Can't run code in this page");
+ cph=0;
+ return false;
+ }
+ }
+ Bitu lin_page=lin_addr>>12;
+ Bitu phys_page=lin_page;
+ // find the physical page that the linear page is mapped to
+ if (!PAGING_MakePhysPage(phys_page)) {
+ LOG_MSG("DYNREC:Can't find physpage");
+ cph=0;
+ return false;
+ }
+ // find a free CodePage
+ if (!cache.free_pages) {
+ if (cache.used_pages!=decode.page.code) cache.used_pages->ClearRelease();
+ else {
+ // try another page to avoid clearing our source-crosspage
+ if ((cache.used_pages->next) && (cache.used_pages->next!=decode.page.code))
+ cache.used_pages->next->ClearRelease();
+ else {
+ LOG_MSG("DYNREC:Invalid cache links");
+ cache.used_pages->ClearRelease();
+ }
+ }
+ }
+ CodePageHandlerDynRec * cpagehandler=cache.free_pages;
+ cache.free_pages=cache.free_pages->next;
+
+ // adjust previous and next page pointer
+ cpagehandler->prev=cache.last_page;
+ cpagehandler->next=0;
+ if (cache.last_page) cache.last_page->next=cpagehandler;
+ cache.last_page=cpagehandler;
+ if (!cache.used_pages) cache.used_pages=cpagehandler;
+
+ // initialize the code page handler and add the handler to the memory page
+ cpagehandler->SetupAt(phys_page,handler);
+ MEM_SetPageHandler(phys_page,1,cpagehandler);
+ PAGING_UnlinkPages(lin_page,1);
+ cph=cpagehandler;
+ return false;
+}
+
+static void decode_advancepage(void) {
+ // Advance to the next page
+ decode.active_block->page.end=4095;
+ // trigger possible page fault here
+ decode.page.first++;
+ Bitu faddr=decode.page.first << 12;
+ mem_readb(faddr);
+ MakeCodePage(faddr,decode.page.code);
+ CacheBlockDynRec * newblock=cache_getblock();
+ decode.active_block->crossblock=newblock;
+ newblock->crossblock=decode.active_block;
+ decode.active_block=newblock;
+ decode.active_block->page.start=0;
+ decode.page.code->AddCrossBlock(decode.active_block);
+ decode.page.wmap=decode.page.code->write_map;
+ decode.page.invmap=decode.page.code->invalidation_map;
+ decode.page.index=0;
+}
+
+// fetch the next byte of the instruction stream
+static Bit8u decode_fetchb(void) {
+ if (GCC_UNLIKELY(decode.page.index>=4096)) {
+ decode_advancepage();
+ }
+ decode.page.wmap[decode.page.index]+=0x01;
+ decode.page.index++;
+ decode.code+=1;
+ return mem_readb(decode.code-1);
+}
+// fetch the next word of the instruction stream
+static Bit16u decode_fetchw(void) {
+ if (GCC_UNLIKELY(decode.page.index>=4095)) {
+ Bit16u val=decode_fetchb();
+ val|=decode_fetchb() << 8;
+ return val;
+ }
+ *(Bit16u *)&decode.page.wmap[decode.page.index]+=0x0101;
+ decode.code+=2;decode.page.index+=2;
+ return mem_readw(decode.code-2);
+}
+// fetch the next dword of the instruction stream
+static Bit32u decode_fetchd(void) {
+ if (GCC_UNLIKELY(decode.page.index>=4093)) {
+ Bit32u val=decode_fetchb();
+ val|=decode_fetchb() << 8;
+ val|=decode_fetchb() << 16;
+ val|=decode_fetchb() << 24;
+ return val;
+ /* Advance to the next page */
+ }
+ *(Bit32u *)&decode.page.wmap[decode.page.index]+=0x01010101;
+ decode.code+=4;decode.page.index+=4;
+ return mem_readd(decode.code-4);
+}
+
+#define START_WMMEM 64
+
+// adjust writemap mask to care for map holes due to special
+// codefetch functions
+static void INLINE decode_increase_wmapmask(Bitu size) {
+ Bitu mapidx;
+ CacheBlockDynRec* activecb=decode.active_block;
+ if (GCC_UNLIKELY(!activecb->cache.wmapmask)) {
+ // no mask memory yet allocated, start with a small buffer
+ activecb->cache.wmapmask=(Bit8u*)malloc(START_WMMEM);
+ memset(activecb->cache.wmapmask,0,START_WMMEM);
+ activecb->cache.maskstart=decode.page.index; // start of buffer is current code position
+ activecb->cache.masklen=START_WMMEM;
+ mapidx=0;
+ } else {
+ mapidx=decode.page.index-activecb->cache.maskstart;
+ if (GCC_UNLIKELY(mapidx+size>=activecb->cache.masklen)) {
+ // mask buffer too small, increase
+ Bitu newmasklen=activecb->cache.masklen*4;
+ if (newmasklen<mapidx+size) newmasklen=((mapidx+size)&~3)*2;
+ Bit8u* tempmem=(Bit8u*)malloc(newmasklen);
+ memset(tempmem,0,newmasklen);
+ memcpy(tempmem,activecb->cache.wmapmask,activecb->cache.masklen);
+ free(activecb->cache.wmapmask);
+ activecb->cache.wmapmask=tempmem;
+ activecb->cache.masklen=newmasklen;
+ }
+ }
+ // update mask entries
+ switch (size) {
+ case 1 : activecb->cache.wmapmask[mapidx]+=0x01; break;
+ case 2 : (*(Bit16u*)&activecb->cache.wmapmask[mapidx])+=0x0101; break;
+ case 4 : (*(Bit32u*)&activecb->cache.wmapmask[mapidx])+=0x01010101; break;
+ }
+}
+
+// fetch a byte, val points to the code location if possible,
+// otherwise val contains the current value read from the position
+static bool decode_fetchb_imm(Bitu & val) {
+ if (GCC_UNLIKELY(decode.page.index>=4096)) {
+ decode_advancepage();
+ }
+ // see if position is directly accessible
+ if (decode.page.invmap != NULL) {
+ if (decode.page.invmap[decode.page.index] == 0) {
+ // position not yet modified
+ val=(Bit32u)decode_fetchb();
+ return false;
+ }
+
+ HostPt tlb_addr=get_tlb_read(decode.code);
+ if (tlb_addr) {
+ val=(Bitu)(tlb_addr+decode.code);
+ decode_increase_wmapmask(1);
+ decode.code++;
+ decode.page.index++;
+ return true;
+ }
+ }
+ // first time decoding or not directly accessible, just fetch the value
+ val=(Bit32u)decode_fetchb();
+ return false;
+}
+
+// fetch a word, val points to the code location if possible,
+// otherwise val contains the current value read from the position
+static bool decode_fetchw_imm(Bitu & val) {
+ if (decode.page.index<4095) {
+ if (decode.page.invmap != NULL) {
+ if ((decode.page.invmap[decode.page.index] == 0) &&
+ (decode.page.invmap[decode.page.index + 1] == 0)) {
+ // position not yet modified
+ val=decode_fetchw();
+ return false;
+ }
+
+ HostPt tlb_addr=get_tlb_read(decode.code);
+ // see if position is directly accessible
+ if (tlb_addr) {
+ val=(Bitu)(tlb_addr+decode.code);
+ decode_increase_wmapmask(2);
+ decode.code+=2;
+ decode.page.index+=2;
+ return true;
+ }
+ }
+ }
+ // first time decoding or not directly accessible, just fetch the value
+ val=decode_fetchw();
+ return false;
+}
+
+// fetch a dword, val points to the code location if possible,
+// otherwise val contains the current value read from the position
+static bool decode_fetchd_imm(Bitu & val) {
+ if (decode.page.index<4093) {
+ if (decode.page.invmap != NULL) {
+ if ((decode.page.invmap[decode.page.index] == 0) &&
+ (decode.page.invmap[decode.page.index + 1] == 0) &&
+ (decode.page.invmap[decode.page.index + 2] == 0) &&
+ (decode.page.invmap[decode.page.index + 3] == 0)) {
+ // position not yet modified
+ val=decode_fetchd();
+ return false;
+ }
+
+ HostPt tlb_addr=get_tlb_read(decode.code);
+ // see if position is directly accessible
+ if (tlb_addr) {
+ val=(Bitu)(tlb_addr+decode.code);
+ decode_increase_wmapmask(4);
+ decode.code+=4;
+ decode.page.index+=4;
+ return true;
+ }
+ }
+ }
+ // first time decoding or not directly accessible, just fetch the value
+ val=decode_fetchd();
+ return false;
+}
+
+
+// modrm decoding helper
+static void INLINE dyn_get_modrm(void) {
+ decode.modrm.val=decode_fetchb();
+ decode.modrm.mod=(decode.modrm.val >> 6) & 3;
+ decode.modrm.reg=(decode.modrm.val >> 3) & 7;
+ decode.modrm.rm=(decode.modrm.val & 7);
+}
+
+
+#ifdef DRC_USE_SEGS_ADDR
+
+#define MOV_SEG_VAL_TO_HOST_REG(host_reg, seg_index) gen_mov_seg16_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_SEG_VAL(seg_index)) - (DRC_PTR_SIZE_IM)(&Segs))
+
+#define MOV_SEG_PHYS_TO_HOST_REG(host_reg, seg_index) gen_mov_seg32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_SEG_PHYS(seg_index)) - (DRC_PTR_SIZE_IM)(&Segs))
+#define ADD_SEG_PHYS_TO_HOST_REG(host_reg, seg_index) gen_add_seg32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_SEG_PHYS(seg_index)) - (DRC_PTR_SIZE_IM)(&Segs))
+
+#else
+
+#define MOV_SEG_VAL_TO_HOST_REG(host_reg, seg_index) gen_mov_word_to_reg(host_reg,DRCD_SEG_VAL(seg_index),false)
+
+#define MOV_SEG_PHYS_TO_HOST_REG(host_reg, seg_index) gen_mov_word_to_reg(host_reg,DRCD_SEG_PHYS(seg_index),true)
+#define ADD_SEG_PHYS_TO_HOST_REG(host_reg, seg_index) gen_add(host_reg,DRCD_SEG_PHYS(seg_index))
+
+#endif
+
+
+#ifdef DRC_USE_REGS_ADDR
+
+#define MOV_REG_VAL_TO_HOST_REG(host_reg, reg_index) gen_mov_regval32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_VAL(reg_index)) - (DRC_PTR_SIZE_IM)(&cpu_regs))
+#define ADD_REG_VAL_TO_HOST_REG(host_reg, reg_index) gen_add_regval32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_VAL(reg_index)) - (DRC_PTR_SIZE_IM)(&cpu_regs))
+
+#define MOV_REG_WORD16_TO_HOST_REG(host_reg, reg_index) gen_mov_regval16_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,false)) - (DRC_PTR_SIZE_IM)(&cpu_regs))
+#define MOV_REG_WORD32_TO_HOST_REG(host_reg, reg_index) gen_mov_regval32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,true)) - (DRC_PTR_SIZE_IM)(&cpu_regs))
+#define MOV_REG_WORD_TO_HOST_REG(host_reg, reg_index, dword) gen_mov_regword_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,dword)) - (DRC_PTR_SIZE_IM)(&cpu_regs), dword)
+
+#define MOV_REG_WORD16_FROM_HOST_REG(host_reg, reg_index) gen_mov_regval16_from_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,false)) - (DRC_PTR_SIZE_IM)(&cpu_regs))
+#define MOV_REG_WORD32_FROM_HOST_REG(host_reg, reg_index) gen_mov_regval32_from_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,true)) - (DRC_PTR_SIZE_IM)(&cpu_regs))
+#define MOV_REG_WORD_FROM_HOST_REG(host_reg, reg_index, dword) gen_mov_regword_from_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,dword)) - (DRC_PTR_SIZE_IM)(&cpu_regs), dword)
+
+#define MOV_REG_BYTE_TO_HOST_REG_LOW(host_reg, reg_index, high_byte) gen_mov_regbyte_to_reg_low(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_BYTE(reg_index,high_byte)) - (DRC_PTR_SIZE_IM)(&cpu_regs))
+#define MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(host_reg, reg_index, high_byte) gen_mov_regbyte_to_reg_low_canuseword(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_BYTE(reg_index,high_byte)) - (DRC_PTR_SIZE_IM)(&cpu_regs))
+#define MOV_REG_BYTE_FROM_HOST_REG_LOW(host_reg, reg_index, high_byte) gen_mov_regbyte_from_reg_low(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_BYTE(reg_index,high_byte)) - (DRC_PTR_SIZE_IM)(&cpu_regs))
+
+#else
+
+#define MOV_REG_VAL_TO_HOST_REG(host_reg, reg_index) gen_mov_word_to_reg(host_reg,DRCD_REG_VAL(reg_index),true)
+#define ADD_REG_VAL_TO_HOST_REG(host_reg, reg_index) gen_add(host_reg,DRCD_REG_VAL(reg_index))
+
+#define MOV_REG_WORD16_TO_HOST_REG(host_reg, reg_index) gen_mov_word_to_reg(host_reg,DRCD_REG_WORD(reg_index,false),false)
+#define MOV_REG_WORD32_TO_HOST_REG(host_reg, reg_index) gen_mov_word_to_reg(host_reg,DRCD_REG_WORD(reg_index,true),true)
+#define MOV_REG_WORD_TO_HOST_REG(host_reg, reg_index, dword) gen_mov_word_to_reg(host_reg,DRCD_REG_WORD(reg_index,dword),dword)
+
+#define MOV_REG_WORD16_FROM_HOST_REG(host_reg, reg_index) gen_mov_word_from_reg(host_reg,DRCD_REG_WORD(reg_index,false),false)
+#define MOV_REG_WORD32_FROM_HOST_REG(host_reg, reg_index) gen_mov_word_from_reg(host_reg,DRCD_REG_WORD(reg_index,true),true)
+#define MOV_REG_WORD_FROM_HOST_REG(host_reg, reg_index, dword) gen_mov_word_from_reg(host_reg,DRCD_REG_WORD(reg_index,dword),dword)
+
+#define MOV_REG_BYTE_TO_HOST_REG_LOW(host_reg, reg_index, high_byte) gen_mov_byte_to_reg_low(host_reg,DRCD_REG_BYTE(reg_index,high_byte))
+#define MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(host_reg, reg_index, high_byte) gen_mov_byte_to_reg_low_canuseword(host_reg,DRCD_REG_BYTE(reg_index,high_byte))
+#define MOV_REG_BYTE_FROM_HOST_REG_LOW(host_reg, reg_index, high_byte) gen_mov_byte_from_reg_low(host_reg,DRCD_REG_BYTE(reg_index,high_byte))
+
+#endif
+
+
+#define DYN_LEA_MEM_MEM(ea_reg, op1, op2, scale, imm) dyn_lea_mem_mem(ea_reg,op1,op2,scale,imm)
+
+#if defined(DRC_USE_REGS_ADDR) && defined(DRC_USE_SEGS_ADDR)
+
+#define DYN_LEA_SEG_PHYS_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_segphys_regval(ea_reg,op1_index,op2_index,scale,imm)
+#define DYN_LEA_REG_VAL_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_regval_regval(ea_reg,op1_index,op2_index,scale,imm)
+#define DYN_LEA_MEM_REG_VAL(ea_reg, op1, op2_index, scale, imm) dyn_lea_mem_regval(ea_reg,op1,op2_index,scale,imm)
+
+#elif defined(DRC_USE_REGS_ADDR)
+
+#define DYN_LEA_SEG_PHYS_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_mem_regval(ea_reg,DRCD_SEG_PHYS(op1_index),op2_index,scale,imm)
+#define DYN_LEA_REG_VAL_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_regval_regval(ea_reg,op1_index,op2_index,scale,imm)
+#define DYN_LEA_MEM_REG_VAL(ea_reg, op1, op2_index, scale, imm) dyn_lea_mem_regval(ea_reg,op1,op2_index,scale,imm)
+
+#elif defined(DRC_USE_SEGS_ADDR)
+
+#define DYN_LEA_SEG_PHYS_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_segphys_mem(ea_reg,op1_index,DRCD_REG_VAL(op2_index),scale,imm)
+#define DYN_LEA_REG_VAL_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,DRCD_REG_VAL(op1_index),DRCD_REG_VAL(op2_index),scale,imm)
+#define DYN_LEA_MEM_REG_VAL(ea_reg, op1, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,op1,DRCD_REG_VAL(op2_index),scale,imm)
+
+#else
+
+#define DYN_LEA_SEG_PHYS_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,DRCD_SEG_PHYS(op1_index),DRCD_REG_VAL(op2_index),scale,imm)
+#define DYN_LEA_REG_VAL_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,DRCD_REG_VAL(op1_index),DRCD_REG_VAL(op2_index),scale,imm)
+#define DYN_LEA_MEM_REG_VAL(ea_reg, op1, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,op1,DRCD_REG_VAL(op2_index),scale,imm)
+
+#endif
+
+
+
+// adjust CPU_Cycles value
+static void dyn_reduce_cycles(void) {
+ if (!decode.cycles) decode.cycles++;
+ gen_sub_direct_word(&CPU_Cycles,decode.cycles,true);
+}
+
+
+// set reg to the start of the next instruction
+// set reg_eip to the start of the current instruction
+static INLINE void dyn_set_eip_last_end(HostReg reg) {
+ gen_mov_word_to_reg(reg,®_eip,true);
+ gen_add_imm(reg,(Bit32u)(decode.code-decode.code_start));
+ gen_add_direct_word(®_eip,decode.op_start-decode.code_start,decode.big_op);
+}
+
+// set reg_eip to the start of the current instruction
+static INLINE void dyn_set_eip_last(void) {
+ gen_add_direct_word(®_eip,decode.op_start-decode.code_start,cpu.code.big);
+}
+
+// set reg_eip to the start of the next instruction
+static INLINE void dyn_set_eip_end(void) {
+ gen_add_direct_word(®_eip,decode.code-decode.code_start,cpu.code.big);
+}
+
+// set reg_eip to the start of the next instruction plus an offset (imm)
+static INLINE void dyn_set_eip_end(HostReg reg,Bit32u imm=0) {
+ gen_mov_word_to_reg(reg,®_eip,true); //get_extend_word will mask off the upper bits
+ //gen_mov_word_to_reg(reg,®_eip,decode.big_op);
+ gen_add_imm(reg,(Bit32u)(decode.code-decode.code_start+imm));
+ if (!decode.big_op) gen_extend_word(false,reg);
+}
+
+
+
+// the following functions generate function calls
+// parameters are loaded by generating code using gen_load_param_ which
+// is architecture dependent
+// R=host register; I=32bit immediate value; A=address value; m=memory
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_R(void * func,Bitu op) {
+ gen_load_param_reg(op,0);
+ return gen_call_function_setup(func, 1);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_R3(void * func,Bitu op) {
+ gen_load_param_reg(op,2);
+ return gen_call_function_setup(func, 3, true);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_RI(void * func,Bitu op1,Bitu op2) {
+ gen_load_param_imm(op2,1);
+ gen_load_param_reg(op1,0);
+ return gen_call_function_setup(func, 2);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_RA(void * func,Bitu op1,DRC_PTR_SIZE_IM op2) {
+ gen_load_param_addr(op2,1);
+ gen_load_param_reg(op1,0);
+ return gen_call_function_setup(func, 2);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_RR(void * func,Bitu op1,Bitu op2) {
+ gen_load_param_reg(op2,1);
+ gen_load_param_reg(op1,0);
+ return gen_call_function_setup(func, 2);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_IR(void * func,Bitu op1,Bitu op2) {
+ gen_load_param_reg(op2,1);
+ gen_load_param_imm(op1,0);
+ return gen_call_function_setup(func, 2);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_I(void * func,Bitu op) {
+ gen_load_param_imm(op,0);
+ return gen_call_function_setup(func, 1);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_II(void * func,Bitu op1,Bitu op2) {
+ gen_load_param_imm(op2,1);
+ gen_load_param_imm(op1,0);
+ return gen_call_function_setup(func, 2);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_III(void * func,Bitu op1,Bitu op2,Bitu op3) {
+ gen_load_param_imm(op3,2);
+ gen_load_param_imm(op2,1);
+ gen_load_param_imm(op1,0);
+ return gen_call_function_setup(func, 3);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_IA(void * func,Bitu op1,DRC_PTR_SIZE_IM op2) {
+ gen_load_param_addr(op2,1);
+ gen_load_param_imm(op1,0);
+ return gen_call_function_setup(func, 2);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_IIR(void * func,Bitu op1,Bitu op2,Bitu op3) {
+ gen_load_param_reg(op3,2);
+ gen_load_param_imm(op2,1);
+ gen_load_param_imm(op1,0);
+ return gen_call_function_setup(func, 3);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_IIIR(void * func,Bitu op1,Bitu op2,Bitu op3,Bitu op4) {
+ gen_load_param_reg(op4,3);
+ gen_load_param_imm(op3,2);
+ gen_load_param_imm(op2,1);
+ gen_load_param_imm(op1,0);
+ return gen_call_function_setup(func, 4);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_IRRR(void * func,Bitu op1,Bitu op2,Bitu op3,Bitu op4) {
+ gen_load_param_reg(op4,3);
+ gen_load_param_reg(op3,2);
+ gen_load_param_reg(op2,1);
+ gen_load_param_imm(op1,0);
+ return gen_call_function_setup(func, 4);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_m(void * func,Bitu op) {
+ gen_load_param_mem(op,2);
+ return gen_call_function_setup(func, 3, true);
+}
+
+static DRC_PTR_SIZE_IM INLINE gen_call_function_mm(void * func,Bitu op1,Bitu op2) {
+ gen_load_param_mem(op2,3);
+ gen_load_param_mem(op1,2);
+ return gen_call_function_setup(func, 4, true);
+}
+
+
+
+enum save_info_type {db_exception, cycle_check, string_break};
+
+
+// function that is called on exceptions
+static BlockReturn DynRunException(Bit32u eip_add,Bit32u cycle_sub) {
+ reg_eip+=eip_add;
+ CPU_Cycles-=cycle_sub;
+ if (cpu.exception.which==SMC_CURRENT_BLOCK) return BR_SMCBlock;
+ CPU_Exception(cpu.exception.which,cpu.exception.error);
+ return BR_Normal;
+}
+
+
+// array with information about code that is generated at the
+// end of a cache block because it is rarely reached (like exceptions)
+static struct {
+ save_info_type type;
+ DRC_PTR_SIZE_IM branch_pos;
+ Bit32u eip_change;
+ Bitu cycles;
+} save_info_dynrec[512];
+
+Bitu used_save_info_dynrec=0;
+
+
+// return from current block, with returncode
+static void dyn_return(BlockReturn retcode,bool ret_exception=false) {
+ if (!ret_exception) {
+ gen_mov_dword_to_reg_imm(FC_RETOP,retcode);
+ }
+ gen_return_function();
+}
+
+static void dyn_run_code(void) {
+ gen_run_code();
+ gen_return_function();
+}
+
+// fill in code at the end of the block that contains rarely-executed code
+// which is executed conditionally (like exceptions)
+static void dyn_fill_blocks(void) {
+ for (Bitu sct=0; sct<used_save_info_dynrec; sct++) {
+ gen_fill_branch_long(save_info_dynrec[sct].branch_pos);
+ switch (save_info_dynrec[sct].type) {
+ case db_exception:
+ // code for exception handling, load cycles and call DynRunException
+ decode.cycles=save_info_dynrec[sct].cycles;
+ if (cpu.code.big) gen_call_function_II((void *)&DynRunException,save_info_dynrec[sct].eip_change,save_info_dynrec[sct].cycles);
+ else gen_call_function_II((void *)&DynRunException,save_info_dynrec[sct].eip_change&0xffff,save_info_dynrec[sct].cycles);
+ dyn_return(BR_Normal,true);
+ break;
+ case cycle_check:
+ // cycles are <=0 so exit the core
+ dyn_return(BR_Cycles);
+ break;
+ case string_break:
+ // interrupt looped string instruction, can be continued later
+ gen_add_direct_word(®_eip,save_info_dynrec[sct].eip_change,decode.big_op);
+ dyn_return(BR_Cycles);
+ break;
+ }
+ }
+ used_save_info_dynrec=0;
+}
+
+
+static void dyn_closeblock(void) {
+ //Shouldn't create empty block normally but let's do it like this
+ dyn_fill_blocks();
+ cache_block_before_close();
+ cache_closeblock();
+ cache_block_closing(decode.block->cache.start,decode.block->cache.size);
+}
+
+
+// add a check that can branch to the exception handling
+static void dyn_check_exception(HostReg reg) {
+ save_info_dynrec[used_save_info_dynrec].branch_pos=gen_create_branch_long_nonzero(reg,false);
+ if (!decode.cycles) decode.cycles++;
+ save_info_dynrec[used_save_info_dynrec].cycles=decode.cycles;
+ // in case of an exception eip will point to the start of the current instruction
+ save_info_dynrec[used_save_info_dynrec].eip_change=decode.op_start-decode.code_start;
+ if (!cpu.code.big) save_info_dynrec[used_save_info_dynrec].eip_change&=0xffff;
+ save_info_dynrec[used_save_info_dynrec].type=db_exception;
+ used_save_info_dynrec++;
+}
+
+
+
+bool DRC_CALL_CONV mem_readb_checked_drc(PhysPt address) DRC_FC;
+bool DRC_CALL_CONV mem_readb_checked_drc(PhysPt address) {
+ HostPt tlb_addr=get_tlb_read(address);
+ if (tlb_addr) {
+ *((Bit8u*)(&core_dynrec.readdata))=host_readb(tlb_addr+address);
+ return false;
+ } else {
+ return get_tlb_readhandler(address)->readb_checked(address, (Bit8u*)(&core_dynrec.readdata));
+ }
+}
+
+bool DRC_CALL_CONV mem_writeb_checked_drc(PhysPt address,Bit8u val) DRC_FC;
+bool DRC_CALL_CONV mem_writeb_checked_drc(PhysPt address,Bit8u val) {
+ HostPt tlb_addr=get_tlb_write(address);
+ if (tlb_addr) {
+ host_writeb(tlb_addr+address,val);
+ return false;
+ } else return get_tlb_writehandler(address)->writeb_checked(address,val);
+}
+
+bool DRC_CALL_CONV mem_readw_checked_drc(PhysPt address) DRC_FC;
+bool DRC_CALL_CONV mem_readw_checked_drc(PhysPt address) {
+ if ((address & 0xfff)<0xfff) {
+ HostPt tlb_addr=get_tlb_read(address);
+ if (tlb_addr) {
+ *((Bit16u*)(&core_dynrec.readdata))=host_readw(tlb_addr+address);
+ return false;
+ } else return get_tlb_readhandler(address)->readw_checked(address, (Bit16u*)(&core_dynrec.readdata));
+ } else return mem_unalignedreadw_checked(address, ((Bit16u*)(&core_dynrec.readdata)));
+}
+
+bool DRC_CALL_CONV mem_readd_checked_drc(PhysPt address) DRC_FC;
+bool DRC_CALL_CONV mem_readd_checked_drc(PhysPt address) {
+ if ((address & 0xfff)<0xffd) {
+ HostPt tlb_addr=get_tlb_read(address);
+ if (tlb_addr) {
+ *((Bit32u*)(&core_dynrec.readdata))=host_readd(tlb_addr+address);
+ return false;
+ } else return get_tlb_readhandler(address)->readd_checked(address, (Bit32u*)(&core_dynrec.readdata));
+ } else return mem_unalignedreadd_checked(address, ((Bit32u*)(&core_dynrec.readdata)));
+}
+
+bool DRC_CALL_CONV mem_writew_checked_drc(PhysPt address,Bit16u val) DRC_FC;
+bool DRC_CALL_CONV mem_writew_checked_drc(PhysPt address,Bit16u val) {
+ if ((address & 0xfff)<0xfff) {
+ HostPt tlb_addr=get_tlb_write(address);
+ if (tlb_addr) {
+ host_writew(tlb_addr+address,val);
+ return false;
+ } else return get_tlb_writehandler(address)->writew_checked(address,val);
+ } else return mem_unalignedwritew_checked(address,val);
+}
+
+bool DRC_CALL_CONV mem_writed_checked_drc(PhysPt address,Bit32u val) DRC_FC;
+bool DRC_CALL_CONV mem_writed_checked_drc(PhysPt address,Bit32u val) {
+ if ((address & 0xfff)<0xffd) {
+ HostPt tlb_addr=get_tlb_write(address);
+ if (tlb_addr) {
+ host_writed(tlb_addr+address,val);
+ return false;
+ } else return get_tlb_writehandler(address)->writed_checked(address,val);
+ } else return mem_unalignedwrited_checked(address,val);
+}
+
+
+// functions that enable access to the memory
+
+// read a byte from a given address and store it in reg_dst
+static void dyn_read_byte(HostReg reg_addr,HostReg reg_dst) {
+ gen_mov_regs(FC_OP1,reg_addr);
+ gen_call_function_raw((void *)&mem_readb_checked_drc);
+ dyn_check_exception(FC_RETOP);
+ gen_mov_byte_to_reg_low(reg_dst,&core_dynrec.readdata);
+}
+static void dyn_read_byte_canuseword(HostReg reg_addr,HostReg reg_dst) {
+ gen_mov_regs(FC_OP1,reg_addr);
+ gen_call_function_raw((void *)&mem_readb_checked_drc);
+ dyn_check_exception(FC_RETOP);
+ gen_mov_byte_to_reg_low_canuseword(reg_dst,&core_dynrec.readdata);
+}
+
+// write a byte from reg_val into the memory given by the address
+static void dyn_write_byte(HostReg reg_addr,HostReg reg_val) {
+ gen_mov_regs(FC_OP2,reg_val);
+ gen_mov_regs(FC_OP1,reg_addr);
+ gen_call_function_raw((void *)&mem_writeb_checked_drc);
+ dyn_check_exception(FC_RETOP);
+}
+
+// read a 32bit (dword=true) or 16bit (dword=false) value
+// from a given address and store it in reg_dst
+static void dyn_read_word(HostReg reg_addr,HostReg reg_dst,bool dword) {
+ gen_mov_regs(FC_OP1,reg_addr);
+ if (dword) gen_call_function_raw((void *)&mem_readd_checked_drc);
+ else gen_call_function_raw((void *)&mem_readw_checked_drc);
+ dyn_check_exception(FC_RETOP);
+ gen_mov_word_to_reg(reg_dst,&core_dynrec.readdata,dword);
+}
+
+// write a 32bit (dword=true) or 16bit (dword=false) value
+// from reg_val into the memory given by the address
+static void dyn_write_word(HostReg reg_addr,HostReg reg_val,bool dword) {
+// if (!dword) gen_extend_word(false,reg_val);
+ gen_mov_regs(FC_OP2,reg_val);
+ gen_mov_regs(FC_OP1,reg_addr);
+ if (dword) gen_call_function_raw((void *)&mem_writed_checked_drc);
+ else gen_call_function_raw((void *)&mem_writew_checked_drc);
+ dyn_check_exception(FC_RETOP);
+}
+
+
+
+// effective address calculation helper, op2 has to be present!
+// loads op1 into ea_reg and adds the scaled op2 and the immediate to it
+static void dyn_lea_mem_mem(HostReg ea_reg,void* op1,void* op2,Bitu scale,Bits imm) {
+ if (scale || imm) {
+ if (op1!=NULL) {
+ gen_mov_word_to_reg(ea_reg,op1,true);
+ gen_mov_word_to_reg(TEMP_REG_DRC,op2,true);
+
+ gen_lea(ea_reg,TEMP_REG_DRC,scale,imm);
+ } else {
+ gen_mov_word_to_reg(ea_reg,op2,true);
+ gen_lea(ea_reg,scale,imm);
+ }
+ } else {
+ gen_mov_word_to_reg(ea_reg,op2,true);
+ if (op1!=NULL) gen_add(ea_reg,op1);
+ }
+}
+
+#ifdef DRC_USE_REGS_ADDR
+// effective address calculation helper
+// loads op1 into ea_reg and adds the scaled op2 and the immediate to it
+// op1 is cpu_regs[op1_index], op2 is cpu_regs[op2_index]
+static void dyn_lea_regval_regval(HostReg ea_reg,Bitu op1_index,Bitu op2_index,Bitu scale,Bits imm) {
+ if (scale || imm) {
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,op1_index);
+ MOV_REG_VAL_TO_HOST_REG(TEMP_REG_DRC,op2_index);
+
+ gen_lea(ea_reg,TEMP_REG_DRC,scale,imm);
+ } else {
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,op2_index);
+ ADD_REG_VAL_TO_HOST_REG(ea_reg,op1_index);
+ }
+}
+
+// effective address calculation helper
+// loads op1 into ea_reg and adds the scaled op2 and the immediate to it
+// op2 is cpu_regs[op2_index]
+static void dyn_lea_mem_regval(HostReg ea_reg,void* op1,Bitu op2_index,Bitu scale,Bits imm) {
+ if (scale || imm) {
+ if (op1!=NULL) {
+ gen_mov_word_to_reg(ea_reg,op1,true);
+ MOV_REG_VAL_TO_HOST_REG(TEMP_REG_DRC,op2_index);
+
+ gen_lea(ea_reg,TEMP_REG_DRC,scale,imm);
+ } else {
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,op2_index);
+ gen_lea(ea_reg,scale,imm);
+ }
+ } else {
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,op2_index);
+ if (op1!=NULL) gen_add(ea_reg,op1);
+ }
+}
+#endif
+
+#ifdef DRC_USE_SEGS_ADDR
+#ifdef DRC_USE_REGS_ADDR
+// effective address calculation helper
+// loads op1 into ea_reg and adds the scaled op2 and the immediate to it
+// op1 is Segs[op1_index], op2 is cpu_regs[op2_index]
+static void dyn_lea_segphys_regval(HostReg ea_reg,Bitu op1_index,Bitu op2_index,Bitu scale,Bits imm) {
+ if (scale || imm) {
+ MOV_SEG_PHYS_TO_HOST_REG(ea_reg,op1_index);
+ MOV_REG_VAL_TO_HOST_REG(TEMP_REG_DRC,op2_index);
+
+ gen_lea(ea_reg,TEMP_REG_DRC,scale,imm);
+ } else {
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,op2_index);
+ ADD_SEG_PHYS_TO_HOST_REG(ea_reg,op1_index);
+ }
+}
+
+#else
+
+// effective address calculation helper, op2 has to be present!
+// loads op1 into ea_reg and adds the scaled op2 and the immediate to it
+// op1 is Segs[op1_index]
+static void dyn_lea_segphys_mem(HostReg ea_reg,Bitu op1_index,void* op2,Bitu scale,Bits imm) {
+ if (scale || imm) {
+ MOV_SEG_PHYS_TO_HOST_REG(ea_reg,op1_index);
+ gen_mov_word_to_reg(TEMP_REG_DRC,op2,true);
+
+ gen_lea(ea_reg,TEMP_REG_DRC,scale,imm);
+ } else {
+ gen_mov_word_to_reg(ea_reg,op2,true);
+ ADD_SEG_PHYS_TO_HOST_REG(ea_reg,op1_index);
+ }
+}
+#endif
+#endif
+
+// calculate the effective address and store it in ea_reg
+static void dyn_fill_ea(HostReg ea_reg,bool addseg=true) {
+ Bit8u seg_base=DRC_SEG_DS;
+ if (!decode.big_addr) {
+ Bits imm;
+ switch (decode.modrm.mod) {
+ case 0:imm=0;break;
+ case 1:imm=(Bit8s)decode_fetchb();break;
+ case 2:imm=(Bit16s)decode_fetchw();break;
+ }
+ switch (decode.modrm.rm) {
+ case 0:// BX+SI
+ DYN_LEA_REG_VAL_REG_VAL(ea_reg,DRC_REG_EBX,DRC_REG_ESI,0,imm);
+ break;
+ case 1:// BX+DI
+ DYN_LEA_REG_VAL_REG_VAL(ea_reg,DRC_REG_EBX,DRC_REG_EDI,0,imm);
+ break;
+ case 2:// BP+SI
+ DYN_LEA_REG_VAL_REG_VAL(ea_reg,DRC_REG_EBP,DRC_REG_ESI,0,imm);
+ seg_base=DRC_SEG_SS;
+ break;
+ case 3:// BP+DI
+ DYN_LEA_REG_VAL_REG_VAL(ea_reg,DRC_REG_EBP,DRC_REG_EDI,0,imm);
+ seg_base=DRC_SEG_SS;
+ break;
+ case 4:// SI
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,DRC_REG_ESI);
+ if (imm) gen_add_imm(ea_reg,(Bit32u)imm);
+ break;
+ case 5:// DI
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,DRC_REG_EDI);
+ if (imm) gen_add_imm(ea_reg,(Bit32u)imm);
+ break;
+ case 6:// imm/BP
+ if (!decode.modrm.mod) {
+ imm=decode_fetchw();
+ gen_mov_dword_to_reg_imm(ea_reg,(Bit32u)imm);
+ goto skip_extend_word;
+ } else {
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,DRC_REG_EBP);
+ gen_add_imm(ea_reg,(Bit32u)imm);
+ seg_base=DRC_SEG_SS;
+ }
+ break;
+ case 7: // BX
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,DRC_REG_EBX);
+ if (imm) gen_add_imm(ea_reg,(Bit32u)imm);
+ break;
+ }
+ // zero out the high 16bit so ea_reg can be used as full register
+ gen_extend_word(false,ea_reg);
+skip_extend_word:
+ if (addseg) {
+ // add the physical segment value if requested
+ ADD_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base));
+ }
+ } else {
+ Bits imm=0;
+ Bit8u base_reg;
+ Bit8u scaled_reg;
+ Bitu scale=0;
+ switch (decode.modrm.rm) {
+ case 0:base_reg=DRC_REG_EAX;break;
+ case 1:base_reg=DRC_REG_ECX;break;
+ case 2:base_reg=DRC_REG_EDX;break;
+ case 3:base_reg=DRC_REG_EBX;break;
+ case 4: // SIB
+ {
+ Bitu sib=decode_fetchb();
+ bool scaled_reg_used=false;
+ static Bit8u scaledtable[8]={
+ DRC_REG_EAX,DRC_REG_ECX,DRC_REG_EDX,DRC_REG_EBX,
+ 0,DRC_REG_EBP,DRC_REG_ESI,DRC_REG_EDI
+ };
+ // see if scaling should be used and which register is to be scaled in this case
+ if (((sib >> 3) &7)!=4) scaled_reg_used=true;
+ scaled_reg=scaledtable[(sib >> 3) &7];
+ scale=(sib >> 6);
+
+ switch (sib & 7) {
+ case 0:base_reg=DRC_REG_EAX;break;
+ case 1:base_reg=DRC_REG_ECX;break;
+ case 2:base_reg=DRC_REG_EDX;break;
+ case 3:base_reg=DRC_REG_EBX;break;
+ case 4:base_reg=DRC_REG_ESP;seg_base=DRC_SEG_SS;break;
+ case 5:
+ if (decode.modrm.mod) {
+ base_reg=DRC_REG_EBP;seg_base=DRC_SEG_SS;
+ } else {
+ // no basereg, maybe scalereg
+ Bitu val;
+ // try to get a pointer to the next dword code position
+ if (decode_fetchd_imm(val)) {
+ // succeeded, use the pointer to avoid code invalidation
+ if (!addseg) {
+ if (!scaled_reg_used) {
+ gen_mov_word_to_reg(ea_reg,(void*)val,true);
+ } else {
+ DYN_LEA_MEM_REG_VAL(ea_reg,NULL,scaled_reg,scale,0);
+ gen_add(ea_reg,(void*)val);
+ }
+ } else {
+ if (!scaled_reg_used) {
+ MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base));
+ } else {
+ DYN_LEA_SEG_PHYS_REG_VAL(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base),scaled_reg,scale,0);
+ }
+ gen_add(ea_reg,(void*)val);
+ }
+ return;
+ }
+ // couldn't get a pointer, use the current value
+ imm=(Bit32s)val;
+
+ if (!addseg) {
+ if (!scaled_reg_used) {
+ gen_mov_dword_to_reg_imm(ea_reg,(Bit32u)imm);
+ } else {
+ DYN_LEA_MEM_REG_VAL(ea_reg,NULL,scaled_reg,scale,imm);
+ }
+ } else {
+ if (!scaled_reg_used) {
+ MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base));
+ if (imm) gen_add_imm(ea_reg,(Bit32u)imm);
+ } else {
+ DYN_LEA_SEG_PHYS_REG_VAL(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base),scaled_reg,scale,imm);
+ }
+ }
+
+ return;
+ }
+ break;
+ case 6:base_reg=DRC_REG_ESI;break;
+ case 7:base_reg=DRC_REG_EDI;break;
+ }
+ // basereg, maybe scalereg
+ switch (decode.modrm.mod) {
+ case 1:
+ imm=(Bit8s)decode_fetchb();
+ break;
+ case 2: {
+ Bitu val;
+ // try to get a pointer to the next dword code position
+ if (decode_fetchd_imm(val)) {
+ // succeeded, use the pointer to avoid code invalidation
+ if (!addseg) {
+ if (!scaled_reg_used) {
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,base_reg);
+ gen_add(ea_reg,(void*)val);
+ } else {
+ DYN_LEA_REG_VAL_REG_VAL(ea_reg,base_reg,scaled_reg,scale,0);
+ gen_add(ea_reg,(void*)val);
+ }
+ } else {
+ if (!scaled_reg_used) {
+ MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base));
+ } else {
+ DYN_LEA_SEG_PHYS_REG_VAL(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base),scaled_reg,scale,0);
+ }
+ ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg);
+ gen_add(ea_reg,(void*)val);
+ }
+ return;
+ }
+ // couldn't get a pointer, use the current value
+ imm=(Bit32s)val;
+ break;
+ }
+ }
+
+ if (!addseg) {
+ if (!scaled_reg_used) {
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,base_reg);
+ gen_add_imm(ea_reg,(Bit32u)imm);
+ } else {
+ DYN_LEA_REG_VAL_REG_VAL(ea_reg,base_reg,scaled_reg,scale,imm);
+ }
+ } else {
+ if (!scaled_reg_used) {
+ MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base));
+ ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg);
+ if (imm) gen_add_imm(ea_reg,(Bit32u)imm);
+ } else {
+ DYN_LEA_SEG_PHYS_REG_VAL(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base),scaled_reg,scale,imm);
+ ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg);
+ }
+ }
+
+ return;
+ }
+ break; // SIB Break
+ case 5:
+ if (decode.modrm.mod) {
+ base_reg=DRC_REG_EBP;seg_base=DRC_SEG_SS;
+ } else {
+ // no base, no scalereg
+
+ imm=(Bit32s)decode_fetchd();
+ if (!addseg) {
+ gen_mov_dword_to_reg_imm(ea_reg,(Bit32u)imm);
+ } else {
+ MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base));
+ if (imm) gen_add_imm(ea_reg,(Bit32u)imm);
+ }
+
+ return;
+ }
+ break;
+ case 6:base_reg=DRC_REG_ESI;break;
+ case 7:base_reg=DRC_REG_EDI;break;
+ }
+
+ // no scalereg, but basereg
+
+ switch (decode.modrm.mod) {
+ case 1:
+ imm=(Bit8s)decode_fetchb();
+ break;
+ case 2: {
+ Bitu val;
+ // try to get a pointer to the next dword code position
+ if (decode_fetchd_imm(val)) {
+ // succeeded, use the pointer to avoid code invalidation
+ if (!addseg) {
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,base_reg);
+ gen_add(ea_reg,(void*)val);
+ } else {
+ MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base));
+ ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg);
+ gen_add(ea_reg,(void*)val);
+ }
+ return;
+ }
+ // couldn't get a pointer, use the current value
+ imm=(Bit32s)val;
+ break;
+ }
+ }
+
+ if (!addseg) {
+ MOV_REG_VAL_TO_HOST_REG(ea_reg,base_reg);
+ if (imm) gen_add_imm(ea_reg,(Bit32u)imm);
+ } else {
+ MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base));
+ ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg);
+ if (imm) gen_add_imm(ea_reg,(Bit32u)imm);
+ }
+ }
+}
+
+
+
+// add code that checks if port access is allowed
+// the port is given in a register
+static void dyn_add_iocheck(HostReg reg_port,Bitu access_size) {
+ if (cpu.pmode) {
+ gen_call_function_RI((void *)&CPU_IO_Exception,reg_port,access_size);
+ dyn_check_exception(FC_RETOP);
+ }
+}
+
+// add code that checks if port access is allowed
+// the port is a constant
+static void dyn_add_iocheck_var(Bit8u accessed_port,Bitu access_size) {
+ if (cpu.pmode) {
+ gen_call_function_II((void *)&CPU_IO_Exception,accessed_port,access_size);
+ dyn_check_exception(FC_RETOP);
+ }
+}
+
+
+
+// save back the address register
+static void gen_protect_addr_reg(void) {
+#ifdef DRC_PROTECT_ADDR_REG
+ gen_mov_word_from_reg(FC_ADDR,&core_dynrec.protected_regs[FC_ADDR],true);
+#endif
+}
+
+// restore the address register
+static void gen_restore_addr_reg(void) {
+#ifdef DRC_PROTECT_ADDR_REG
+ gen_mov_word_to_reg(FC_ADDR,&core_dynrec.protected_regs[FC_ADDR],true);
+#endif
+}
+
+// save back an arbitrary register
+static void gen_protect_reg(HostReg reg) {
+ gen_mov_word_from_reg(reg,&core_dynrec.protected_regs[reg],true);
+}
+
+// restore an arbitrary register
+static void gen_restore_reg(HostReg reg) {
+ gen_mov_word_to_reg(reg,&core_dynrec.protected_regs[reg],true);
+}
+
+// restore an arbitrary register into a different register
+static void gen_restore_reg(HostReg reg,HostReg dest_reg) {
+ gen_mov_word_to_reg(dest_reg,&core_dynrec.protected_regs[reg],true);
+}
+
+
+
+// flags optimization functions
+// they try to find out if a function can be replaced by another
+// one that does not generate any flags at all
+
+static Bitu mf_functions_num=0;
+static struct {
+ Bit8u* pos;
+ void* fct_ptr;
+ Bitu ftype;
+} mf_functions[64];
+
+static void InitFlagsOptimization(void) {
+ mf_functions_num=0;
+}
+
+// replace all queued functions with their simpler variants
+// because the current instruction destroys all condition flags and
+// the flags are not required before
+static void InvalidateFlags(void) {
+#ifdef DRC_FLAGS_INVALIDATION
+ for (Bitu ct=0; ct<mf_functions_num; ct++) {
+ gen_fill_function_ptr(mf_functions[ct].pos,mf_functions[ct].fct_ptr,mf_functions[ct].ftype);
+ }
+ mf_functions_num=0;
+#endif
+}
+
+// replace all queued functions with their simpler variants
+// because the current instruction destroys all condition flags and
+// the flags are not required before
+static void InvalidateFlags(void* current_simple_function,Bitu flags_type) {
+#ifdef DRC_FLAGS_INVALIDATION
+ for (Bitu ct=0; ct<mf_functions_num; ct++) {
+ gen_fill_function_ptr(mf_functions[ct].pos,mf_functions[ct].fct_ptr,mf_functions[ct].ftype);
+ }
+ mf_functions_num=1;
+ mf_functions[0].pos=cache.pos;
+ mf_functions[0].fct_ptr=current_simple_function;
+ mf_functions[0].ftype=flags_type;
+#endif
+}
+
+// enqueue this instruction, if later an instruction is encountered that
+// destroys all condition flags and the flags weren't needed in-between
+// this function can be replaced by a simpler one as well
+static void InvalidateFlagsPartially(void* current_simple_function,Bitu flags_type) {
+#ifdef DRC_FLAGS_INVALIDATION
+ mf_functions[mf_functions_num].pos=cache.pos;
+ mf_functions[mf_functions_num].fct_ptr=current_simple_function;
+ mf_functions[mf_functions_num].ftype=flags_type;
+ mf_functions_num++;
+#endif
+}
+
+// enqueue this instruction, if later an instruction is encountered that
+// destroys all condition flags and the flags weren't needed in-between
+// this function can be replaced by a simpler one as well
+static void InvalidateFlagsPartially(void* current_simple_function,DRC_PTR_SIZE_IM cpos,Bitu flags_type) {
+#ifdef DRC_FLAGS_INVALIDATION
+ mf_functions[mf_functions_num].pos=(Bit8u*)cpos;
+ mf_functions[mf_functions_num].fct_ptr=current_simple_function;
+ mf_functions[mf_functions_num].ftype=flags_type;
+ mf_functions_num++;
+#endif
+}
+
+// the current function needs the condition flags thus reset the queue
+static void AcquireFlags(Bitu flags_mask) {
+#ifdef DRC_FLAGS_INVALIDATION
+ mf_functions_num=0;
+#endif
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+/*
+ The functions in this file are called almost exclusively by decoder.h,
+ they translate an (or a set of) instruction(s) into hostspecific code
+ and use the lower-level functions from decoder_basic.h and generating
+ functions from risc_?.h
+ Some complex instructions as well as most instructions that can modify
+ the condition flags are translated by generating a call to a C-function
+ (see operators.h). Parameter loading and result writeback is done
+ according to the instruction.
+*/
+
+static void dyn_dop_ebgb(DualOps op) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_byte_canuseword(FC_ADDR,FC_OP1);
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ dyn_dop_byte_gencall(op);
+
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) {
+ gen_restore_addr_reg();
+ dyn_write_byte(FC_ADDR,FC_RETOP);
+ }
+ } else {
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ dyn_dop_byte_gencall(op);
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ }
+}
+
+static void dyn_dop_ebgb_mov(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ dyn_write_byte(FC_ADDR,FC_TMP_BA1);
+ } else {
+ MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ }
+}
+
+static void dyn_dop_ebib_mov(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ gen_mov_byte_to_reg_low_imm(FC_TMP_BA1,decode_fetchb());
+ dyn_write_byte(FC_ADDR,FC_TMP_BA1);
+ } else {
+ gen_mov_byte_to_reg_low_imm(FC_TMP_BA1,decode_fetchb());
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ }
+}
+
+static void dyn_dop_ebgb_xchg(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_byte(FC_ADDR,FC_TMP_BA1);
+ MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA2,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ gen_restore_addr_reg();
+ dyn_write_byte(FC_ADDR,FC_TMP_BA2);
+ } else {
+ MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA2,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA2,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ }
+}
+
+static void dyn_dop_gbeb(DualOps op) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_read_byte_canuseword(FC_ADDR,FC_OP2);
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ dyn_dop_byte_gencall(op);
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ } else {
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ dyn_dop_byte_gencall(op);
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ }
+}
+
+static void dyn_dop_gbeb_mov(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_read_byte(FC_ADDR,FC_TMP_BA1);
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ } else {
+ MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1);
+ }
+}
+
+static void dyn_dop_evgv(DualOps op) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_read_word(FC_ADDR,FC_OP1,decode.big_op);
+ gen_protect_addr_reg();
+ MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op);
+ dyn_dop_word_gencall(op,decode.big_op);
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) {
+ gen_restore_addr_reg();
+ dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op);
+ }
+ } else {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op);
+ MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op);
+ dyn_dop_word_gencall(op,decode.big_op);
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op);
+ }
+}
+
+static void dyn_dop_evgv_mov(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op);
+ dyn_write_word(FC_ADDR,FC_OP1,decode.big_op);
+ } else {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op);
+ }
+}
+
+static void dyn_dop_eviv_mov(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP1,decode_fetchd());
+ else gen_mov_word_to_reg_imm(FC_OP1,decode_fetchw());
+ dyn_write_word(FC_ADDR,FC_OP1,decode.big_op);
+ } else {
+ if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP1,decode_fetchd());
+ else gen_mov_word_to_reg_imm(FC_OP1,decode_fetchw());
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op);
+ }
+}
+
+static void dyn_dop_evgv_xchg(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_word(FC_ADDR,FC_OP1,decode.big_op);
+ MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op);
+
+ gen_protect_reg(FC_OP1);
+ gen_restore_addr_reg();
+ dyn_write_word(FC_ADDR,FC_OP2,decode.big_op);
+ gen_restore_reg(FC_OP1);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op);
+ } else {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op);
+ MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP2,decode.modrm.rm,decode.big_op);
+ }
+}
+
+static void dyn_xchg_ax(Bit8u reg) {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_EAX,decode.big_op);
+ MOV_REG_WORD_TO_HOST_REG(FC_OP2,reg,decode.big_op);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,reg,decode.big_op);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP2,DRC_REG_EAX,decode.big_op);
+}
+
+static void dyn_dop_gvev(DualOps op) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_word(FC_ADDR,FC_OP2,decode.big_op);
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op);
+ dyn_dop_word_gencall(op,decode.big_op);
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) {
+ gen_restore_addr_reg();
+ MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.reg,decode.big_op);
+ }
+ } else {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.rm,decode.big_op);
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op);
+ dyn_dop_word_gencall(op,decode.big_op);
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.reg,decode.big_op);
+ }
+}
+
+static void dyn_dop_gvev_mov(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_read_word(FC_ADDR,FC_OP1,decode.big_op);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op);
+ } else {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op);
+ }
+}
+
+static void dyn_dop_byte_imm(DualOps op,Bit8u reg,Bit8u idx) {
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,reg,idx);
+ gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,decode_fetchb());
+ dyn_dop_byte_gencall(op);
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,reg,idx);
+}
+
+static void dyn_dop_byte_imm_mem(DualOps op,Bit8u reg,Bit8u idx) {
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,reg,idx);
+ Bitu val;
+ if (decode_fetchb_imm(val)) {
+ gen_mov_byte_to_reg_low_canuseword(FC_OP2,(void*)val);
+ } else {
+ gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,(Bit8u)val);
+ }
+ dyn_dop_byte_gencall(op);
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,reg,idx);
+}
+
+static void dyn_prep_word_imm(Bit8u reg) {
+ Bitu val;
+ if (decode.big_op) {
+ if (decode_fetchd_imm(val)) {
+ gen_mov_word_to_reg(FC_OP2,(void*)val,true);
+ return;
+ }
+ } else {
+ if (decode_fetchw_imm(val)) {
+ gen_mov_word_to_reg(FC_OP2,(void*)val,false);
+ return;
+ }
+ }
+ if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)val);
+ else gen_mov_word_to_reg_imm(FC_OP2,(Bit16u)val);
+}
+
+static void dyn_dop_word_imm(DualOps op,Bit8u reg) {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,reg,decode.big_op);
+ dyn_prep_word_imm(reg);
+ dyn_dop_word_gencall(op,decode.big_op);
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,reg,decode.big_op);
+}
+
+static void dyn_dop_word_imm_old(DualOps op,Bit8u reg,Bitu imm) {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,reg,decode.big_op);
+ if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)imm);
+ else gen_mov_word_to_reg_imm(FC_OP2,(Bit16u)imm);
+ dyn_dop_word_gencall(op,decode.big_op);
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,reg,decode.big_op);
+}
+
+static void dyn_mov_byte_imm(Bit8u reg,Bit8u idx,Bit8u imm) {
+ gen_mov_byte_to_reg_low_imm(FC_TMP_BA1,imm);
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,reg,idx);
+}
+
+static void dyn_mov_word_imm(Bit8u reg) {
+ Bitu val;
+ if (decode.big_op) {
+ if (decode_fetchd_imm(val)) {
+ gen_mov_word_to_reg(FC_OP1,(void*)val,true);
+ MOV_REG_WORD32_FROM_HOST_REG(FC_OP1,reg);
+ return;
+ }
+ } else {
+ if (decode_fetchw_imm(val)) {
+ gen_mov_word_to_reg(FC_OP1,(void*)val,false);
+ MOV_REG_WORD16_FROM_HOST_REG(FC_OP1,reg);
+ return;
+ }
+ }
+ if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP1,(Bit32u)val);
+ else gen_mov_word_to_reg_imm(FC_OP1,(Bit16u)val);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,reg,decode.big_op);
+}
+
+
+static void dyn_sop_word(SingleOps op,Bit8u reg) {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,reg,decode.big_op);
+ dyn_sop_word_gencall(op,decode.big_op);
+ MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,reg,decode.big_op);
+}
+
+
+static void dyn_mov_byte_al_direct(Bitu imm) {
+ MOV_SEG_PHYS_TO_HOST_REG(FC_ADDR,(decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS));
+ gen_add_imm(FC_ADDR,imm);
+ dyn_read_byte(FC_ADDR,FC_TMP_BA1);
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,DRC_REG_EAX,0);
+}
+
+static void dyn_mov_byte_ax_direct(Bitu imm) {
+ MOV_SEG_PHYS_TO_HOST_REG(FC_ADDR,(decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS));
+ gen_add_imm(FC_ADDR,imm);
+ dyn_read_word(FC_ADDR,FC_OP1,decode.big_op);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,DRC_REG_EAX,decode.big_op);
+}
+
+static void dyn_mov_byte_direct_al() {
+ MOV_SEG_PHYS_TO_HOST_REG(FC_ADDR,(decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS));
+ if (decode.big_addr) {
+ Bitu val;
+ if (decode_fetchd_imm(val)) {
+ gen_add(FC_ADDR,(void*)val);
+ } else {
+ gen_add_imm(FC_ADDR,(Bit32u)val);
+ }
+ } else {
+ gen_add_imm(FC_ADDR,decode_fetchw());
+ }
+ MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,DRC_REG_EAX,0);
+ dyn_write_byte(FC_ADDR,FC_TMP_BA1);
+}
+
+static void dyn_mov_byte_direct_ax(Bitu imm) {
+ MOV_SEG_PHYS_TO_HOST_REG(FC_ADDR,(decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS));
+ gen_add_imm(FC_ADDR,imm);
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_EAX,decode.big_op);
+ dyn_write_word(FC_ADDR,FC_OP1,decode.big_op);
+}
+
+
+static void dyn_movx_ev_gb(bool sign) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_read_byte(FC_ADDR,FC_TMP_BA1);
+ gen_extend_byte(sign,FC_TMP_BA1);
+ MOV_REG_WORD_FROM_HOST_REG(FC_TMP_BA1,decode.modrm.reg,decode.big_op);
+ } else {
+ MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ gen_extend_byte(sign,FC_TMP_BA1);
+ MOV_REG_WORD_FROM_HOST_REG(FC_TMP_BA1,decode.modrm.reg,decode.big_op);
+ }
+}
+
+static void dyn_movx_ev_gw(bool sign) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_read_word(FC_ADDR,FC_OP1,false);
+ gen_extend_word(sign,FC_OP1);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op);
+ } else {
+ MOV_REG_WORD16_TO_HOST_REG(FC_OP1,decode.modrm.rm);
+ gen_extend_word(sign,FC_OP1);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op);
+ }
+}
+
+
+static void dyn_mov_ev_seg(void) {
+ dyn_get_modrm();
+ MOV_SEG_VAL_TO_HOST_REG(FC_OP1,decode.modrm.reg);
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_write_word(FC_ADDR,FC_OP1,false);
+ } else {
+ if (decode.big_op) gen_extend_word(false,FC_OP1);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op);
+ }
+}
+
+
+static void dyn_lea(void) {
+ dyn_get_modrm();
+ dyn_fill_ea(FC_ADDR,false);
+ MOV_REG_WORD_FROM_HOST_REG(FC_ADDR,decode.modrm.reg,decode.big_op);
+}
+
+
+static void dyn_push_seg(Bit8u seg) {
+ MOV_SEG_VAL_TO_HOST_REG(FC_OP1,seg);
+ if (decode.big_op) {
+ gen_extend_word(false,FC_OP1);
+ gen_call_function_raw((void*)&dynrec_push_dword);
+ } else {
+ gen_call_function_raw((void*)&dynrec_push_word);
+ }
+}
+
+static void dyn_pop_seg(Bit8u seg) {
+ gen_call_function_II((void *)&CPU_PopSeg,seg,decode.big_op);
+ dyn_check_exception(FC_RETOP);
+}
+
+static void dyn_push_reg(Bit8u reg) {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,reg,decode.big_op);
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword);
+ else gen_call_function_raw((void*)&dynrec_push_word);
+}
+
+static void dyn_pop_reg(Bit8u reg) {
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_pop_dword);
+ else gen_call_function_raw((void*)&dynrec_pop_word);
+ MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,reg,decode.big_op);
+}
+
+static void dyn_push_byte_imm(Bit8s imm) {
+ gen_mov_dword_to_reg_imm(FC_OP1,(Bit32u)imm);
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword);
+ else gen_call_function_raw((void*)&dynrec_push_word);
+}
+
+static void dyn_push_word_imm(Bitu imm) {
+ if (decode.big_op) {
+ gen_mov_dword_to_reg_imm(FC_OP1,imm);
+ gen_call_function_raw((void*)&dynrec_push_dword);
+ } else {
+ gen_mov_word_to_reg_imm(FC_OP1,(Bit16u)imm);
+ gen_call_function_raw((void*)&dynrec_push_word);
+ }
+}
+
+static void dyn_pop_ev(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+/* dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); // dummy read to trigger possible page faults */
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_pop_dword);
+ else gen_call_function_raw((void*)&dynrec_pop_word);
+ dyn_fill_ea(FC_ADDR);
+// gen_restore_addr_reg();
+ dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op);
+ } else {
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_pop_dword);
+ else gen_call_function_raw((void*)&dynrec_pop_word);
+ MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op);
+ }
+}
+
+
+static void dyn_segprefix(Bit8u seg) {
+// if (GCC_UNLIKELY(decode.seg_prefix_used)) IllegalOptionDynrec("dyn_segprefix");
+ decode.seg_prefix=seg;
+ decode.seg_prefix_used=true;
+}
+
+ static void dyn_mov_seg_ev(void) {
+ dyn_get_modrm();
+ if (GCC_UNLIKELY(decode.modrm.reg==DRC_SEG_CS)) IllegalOptionDynrec("dyn_mov_seg_ev");
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_read_word(FC_ADDR,FC_RETOP,false);
+ } else {
+ MOV_REG_WORD16_TO_HOST_REG(FC_RETOP,decode.modrm.rm);
+ }
+ gen_call_function_IR((void *)&CPU_SetSegGeneral,decode.modrm.reg,FC_RETOP);
+ dyn_check_exception(FC_RETOP);
+}
+
+static void dyn_load_seg_off_ea(Bit8u seg) {
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_word(FC_ADDR,FC_OP1,decode.big_op);
+ gen_protect_reg(FC_OP1);
+
+ gen_restore_addr_reg();
+ gen_add_imm(FC_ADDR,decode.big_op ? 4:2);
+ dyn_read_word(FC_ADDR,FC_RETOP,false);
+
+ gen_call_function_IR((void *)&CPU_SetSegGeneral,seg,FC_RETOP);
+ dyn_check_exception(FC_RETOP);
+
+ gen_restore_reg(FC_OP1);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op);
+ } else {
+ IllegalOptionDynrec("dyn_load_seg_off_ea");
+ }
+}
+
+
+
+static void dyn_imul_gvev(Bitu immsize) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_read_word(FC_ADDR,FC_OP1,decode.big_op);
+ } else {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op);
+ }
+
+ switch (immsize) {
+ case 0:
+ MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op);
+ break;
+ case 1:
+ if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit8s)decode_fetchb());
+ else gen_mov_word_to_reg_imm(FC_OP2,(Bit8s)decode_fetchb());
+ break;
+ case 2:
+ if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit16s)decode_fetchw());
+ else gen_mov_word_to_reg_imm(FC_OP2,(Bit16s)decode_fetchw());
+ break;
+ case 4:
+ if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit32s)decode_fetchd());
+ else gen_mov_word_to_reg_imm(FC_OP2,(Bit16u)((Bit32s)decode_fetchd()));
+ break;
+ }
+
+ if (decode.big_op) gen_call_function_raw((void*)dynrec_dimul_dword);
+ else gen_call_function_raw((void*)dynrec_dimul_word);
+
+ MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.reg,decode.big_op);
+}
+
+static void dyn_dshift_ev_gv(bool left,bool immediate) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_word(FC_ADDR,FC_OP1,decode.big_op);
+ } else {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op);
+ }
+ MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op);
+ if (immediate) gen_mov_byte_to_reg_low_imm(FC_OP3,decode_fetchb());
+ else MOV_REG_BYTE_TO_HOST_REG_LOW(FC_OP3,DRC_REG_ECX,0);
+ if (decode.big_op) dyn_dpshift_dword_gencall(left);
+ else dyn_dpshift_word_gencall(left);
+
+ if (decode.modrm.mod<3) {
+ gen_restore_addr_reg();
+ dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op);
+ } else {
+ MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op);
+ }
+}
+
+
+static void dyn_grp1_eb_ib(void) {
+ dyn_get_modrm();
+ DualOps op=grp1_table[decode.modrm.reg];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_byte_canuseword(FC_ADDR,FC_OP1);
+ gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,decode_fetchb());
+ dyn_dop_byte_gencall(op);
+
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) {
+ gen_restore_addr_reg();
+ dyn_write_byte(FC_ADDR,FC_RETOP);
+ }
+ } else {
+ dyn_dop_byte_imm_mem(op,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ }
+}
+
+static void dyn_grp1_ev_iv(bool withbyte) {
+ dyn_get_modrm();
+ DualOps op=grp1_table[decode.modrm.reg];
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_word(FC_ADDR,FC_OP1,decode.big_op);
+
+ if (!withbyte) {
+ dyn_prep_word_imm(FC_OP2);
+ } else {
+ Bits imm=(Bit8s)decode_fetchb();
+ if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)imm);
+ else gen_mov_word_to_reg_imm(FC_OP2,(Bit16u)imm);
+ }
+
+ dyn_dop_word_gencall(op,decode.big_op);
+
+ if ((op!=DOP_CMP) && (op!=DOP_TEST)) {
+ gen_restore_addr_reg();
+ dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op);
+ }
+ } else {
+ if (!withbyte) {
+ dyn_dop_word_imm(op,decode.modrm.rm);
+ } else {
+ Bits imm=withbyte ? (Bit8s)decode_fetchb() : (decode.big_op ? decode_fetchd(): decode_fetchw());
+ dyn_dop_word_imm_old(op,decode.modrm.rm,imm);
+ }
+ }
+}
+
+
+static void dyn_grp2_eb(grp2_types type) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_byte_canuseword(FC_ADDR,FC_OP1);
+ } else {
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ }
+ switch (type) {
+ case grp2_1:
+ gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,1);
+ dyn_shift_byte_gencall((ShiftOps)decode.modrm.reg);
+ break;
+ case grp2_imm: {
+ Bit8u imm=decode_fetchb();
+ if (imm) {
+ gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,imm&0x1f);
+ dyn_shift_byte_gencall((ShiftOps)decode.modrm.reg);
+ } else return;
+ }
+ break;
+ case grp2_cl:
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,DRC_REG_ECX,0);
+ gen_and_imm(FC_OP2,0x1f);
+ dyn_shift_byte_gencall((ShiftOps)decode.modrm.reg);
+ break;
+ }
+ if (decode.modrm.mod<3) {
+ gen_restore_addr_reg();
+ dyn_write_byte(FC_ADDR,FC_RETOP);
+ } else {
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ }
+}
+
+static void dyn_grp2_ev(grp2_types type) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_word(FC_ADDR,FC_OP1,decode.big_op);
+ } else {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op);
+ }
+ switch (type) {
+ case grp2_1:
+ gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,1);
+ dyn_shift_word_gencall((ShiftOps)decode.modrm.reg,decode.big_op);
+ break;
+ case grp2_imm: {
+ Bitu val;
+ if (decode_fetchb_imm(val)) {
+ gen_mov_byte_to_reg_low_canuseword(FC_OP2,(void*)val);
+ gen_and_imm(FC_OP2,0x1f);
+ dyn_shift_word_gencall((ShiftOps)decode.modrm.reg,decode.big_op);
+ break;
+ }
+ Bit8u imm=(Bit8u)val;
+ if (imm) {
+ gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,imm&0x1f);
+ dyn_shift_word_gencall((ShiftOps)decode.modrm.reg,decode.big_op);
+ } else return;
+ }
+ break;
+ case grp2_cl:
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,DRC_REG_ECX,0);
+ gen_and_imm(FC_OP2,0x1f);
+ dyn_shift_word_gencall((ShiftOps)decode.modrm.reg,decode.big_op);
+ break;
+ }
+ if (decode.modrm.mod<3) {
+ gen_restore_addr_reg();
+ dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op);
+ } else {
+ MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op);
+ }
+}
+
+
+static void dyn_grp3_eb(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ if ((decode.modrm.reg==2) || (decode.modrm.reg==3)) gen_protect_addr_reg();
+ dyn_read_byte_canuseword(FC_ADDR,FC_OP1);
+ } else {
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ }
+ switch (decode.modrm.reg) {
+ case 0x0: // test eb,ib
+ gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,decode_fetchb());
+ dyn_dop_byte_gencall(DOP_TEST);
+ return;
+ case 0x2: // NOT Eb
+ dyn_sop_byte_gencall(SOP_NOT);
+ break;
+ case 0x3: // NEG Eb
+ dyn_sop_byte_gencall(SOP_NEG);
+ break;
+ case 0x4: // mul Eb
+ gen_call_function_raw((void*)&dynrec_mul_byte);
+ return;
+ case 0x5: // imul Eb
+ gen_call_function_raw((void*)&dynrec_imul_byte);
+ return;
+ case 0x6: // div Eb
+ gen_call_function_raw((void*)&dynrec_div_byte);
+ dyn_check_exception(FC_RETOP);
+ return;
+ case 0x7: // idiv Eb
+ gen_call_function_raw((void*)&dynrec_idiv_byte);
+ dyn_check_exception(FC_RETOP);
+ return;
+ }
+ // Save the result if memory op
+ if (decode.modrm.mod<3) {
+ gen_restore_addr_reg();
+ dyn_write_byte(FC_ADDR,FC_RETOP);
+ } else {
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ }
+}
+
+static void dyn_grp3_ev(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ if ((decode.modrm.reg==2) || (decode.modrm.reg==3)) gen_protect_addr_reg();
+ dyn_read_word(FC_ADDR,FC_OP1,decode.big_op);
+ } else {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op);
+ }
+ switch (decode.modrm.reg) {
+ case 0x0: // test ev,iv
+ if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,decode_fetchd());
+ else gen_mov_word_to_reg_imm(FC_OP2,decode_fetchw());
+ dyn_dop_word_gencall(DOP_TEST,decode.big_op);
+ return;
+ case 0x2: // NOT Ev
+ dyn_sop_word_gencall(SOP_NOT,decode.big_op);
+ break;
+ case 0x3: // NEG Eb
+ dyn_sop_word_gencall(SOP_NEG,decode.big_op);
+ break;
+ case 0x4: // mul Eb
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_mul_dword);
+ else gen_call_function_raw((void*)&dynrec_mul_word);
+ return;
+ case 0x5: // imul Eb
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_imul_dword);
+ else gen_call_function_raw((void*)&dynrec_imul_word);
+ return;
+ case 0x6: // div Eb
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_div_dword);
+ else gen_call_function_raw((void*)&dynrec_div_word);
+ dyn_check_exception(FC_RETOP);
+ return;
+ case 0x7: // idiv Eb
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_idiv_dword);
+ else gen_call_function_raw((void*)&dynrec_idiv_word);
+ dyn_check_exception(FC_RETOP);
+ return;
+ }
+ // Save the result if memory op
+ if (decode.modrm.mod<3) {
+ gen_restore_addr_reg();
+ dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op);
+ } else {
+ MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op);
+ }
+}
+
+
+static bool dyn_grp4_eb(void) {
+ dyn_get_modrm();
+ switch (decode.modrm.reg) {
+ case 0x0://INC Eb
+ case 0x1://DEC Eb
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_byte_canuseword(FC_ADDR,FC_OP1);
+ dyn_sop_byte_gencall(decode.modrm.reg==0 ? SOP_INC : SOP_DEC);
+ gen_restore_addr_reg();
+ dyn_write_byte(FC_ADDR,FC_RETOP);
+ } else {
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ dyn_sop_byte_gencall(decode.modrm.reg==0 ? SOP_INC : SOP_DEC);
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ }
+ break;
+ case 0x7: //CALBACK Iw
+ gen_mov_direct_dword(&core_dynrec.callback,decode_fetchw());
+ dyn_set_eip_end();
+ dyn_reduce_cycles();
+ dyn_return(BR_CallBack);
+ dyn_closeblock();
+ return true;
+ default:
+ IllegalOptionDynrec("dyn_grp4_eb");
+ break;
+ }
+ return false;
+}
+
+static Bitu dyn_grp4_ev(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ if ((decode.modrm.reg<2) || (decode.modrm.reg==3) || (decode.modrm.reg==5)) gen_protect_addr_reg();
+ dyn_read_word(FC_ADDR,FC_OP1,decode.big_op);
+ } else {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op);
+ }
+ switch (decode.modrm.reg) {
+ case 0x0://INC Ev
+ case 0x1://DEC Ev
+ dyn_sop_word_gencall(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,decode.big_op);
+ if (decode.modrm.mod<3) {
+ gen_restore_addr_reg();
+ dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op);
+ } else {
+ MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op);
+ }
+ break;
+ case 0x2: // CALL Ev
+ gen_mov_regs(FC_ADDR,FC_OP1);
+ gen_protect_addr_reg();
+ gen_mov_word_to_reg(FC_OP1,decode.big_op?(void*)(®_eip):(void*)(®_ip),decode.big_op);
+ gen_add_imm(FC_OP1,(Bit32u)(decode.code-decode.code_start));
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword);
+ else gen_call_function_raw((void*)&dynrec_push_word);
+
+ gen_restore_addr_reg();
+ gen_mov_word_from_reg(FC_ADDR,decode.big_op?(void*)(®_eip):(void*)(®_ip),decode.big_op);
+ return 1;
+ case 0x4: // JMP Ev
+ gen_mov_word_from_reg(FC_OP1,decode.big_op?(void*)(®_eip):(void*)(®_ip),decode.big_op);
+ return 1;
+ case 0x3: // CALL Ep
+ case 0x5: // JMP Ep
+ if (!decode.big_op) gen_extend_word(false,FC_OP1);
+ if (decode.modrm.mod<3) gen_restore_addr_reg();
+ gen_protect_reg(FC_OP1);
+ gen_add_imm(FC_ADDR,decode.big_op?4:2);
+ dyn_read_word(FC_ADDR,FC_OP2,decode.big_op);
+ gen_extend_word(false,FC_OP2);
+
+ dyn_set_eip_last_end(FC_RETOP);
+ gen_restore_reg(FC_OP1,FC_ADDR);
+ gen_call_function_IRRR(decode.modrm.reg == 3 ? (void*)(&CPU_CALL) : (void*)(&CPU_JMP),
+ decode.big_op,FC_OP2,FC_ADDR,FC_RETOP);
+ return 1;
+ case 0x6: // PUSH Ev
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword);
+ else gen_call_function_raw((void*)&dynrec_push_word);
+ break;
+ default:
+// IllegalOptionDynrec("dyn_grp4_ev");
+ return 2;
+ }
+ return 0;
+}
+
+
+static bool dyn_grp6(void) {
+ dyn_get_modrm();
+ switch (decode.modrm.reg) {
+ case 0x00: // SLDT
+ case 0x01: // STR
+ if (decode.modrm.reg==0) gen_call_function_raw((void*)CPU_SLDT);
+ else gen_call_function_raw((void*)CPU_STR);
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_write_word(FC_ADDR,FC_RETOP,false);
+ } else {
+ MOV_REG_WORD16_FROM_HOST_REG(FC_RETOP,decode.modrm.rm);
+ }
+ break;
+ case 0x02: // LLDT
+ case 0x03: // LTR
+ case 0x04: // VERR
+ case 0x05: // VERW
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_read_word(FC_ADDR,FC_RETOP,false);
+ } else {
+ MOV_REG_WORD16_TO_HOST_REG(FC_RETOP,decode.modrm.rm);
+ }
+ gen_extend_word(false,FC_RETOP);
+ switch (decode.modrm.reg) {
+ case 0x02: // LLDT
+// if (cpu.cpl) return CPU_PrepareException(EXCEPTION_GP,0);
+ if (cpu.cpl) E_Exit("lldt cpl>0");
+ gen_call_function_R((void*)CPU_LLDT,FC_RETOP);
+ dyn_check_exception(FC_RETOP);
+ break;
+ case 0x03: // LTR
+// if (cpu.cpl) return CPU_PrepareException(EXCEPTION_GP,0);
+ if (cpu.cpl) E_Exit("ltr cpl>0");
+ gen_call_function_R((void*)CPU_LTR,FC_RETOP);
+ dyn_check_exception(FC_RETOP);
+ break;
+ case 0x04: // VERR
+ gen_call_function_R((void*)CPU_VERR,FC_RETOP);
+ break;
+ case 0x05: // VERW
+ gen_call_function_R((void*)CPU_VERW,FC_RETOP);
+ break;
+ }
+ break;
+ default: IllegalOptionDynrec("dyn_grp6");
+ }
+ return false;
+}
+
+static bool dyn_grp7(void) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ switch (decode.modrm.reg) {
+ case 0x00: // SGDT
+ gen_call_function_raw((void*)CPU_SGDT_limit);
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_write_word(FC_ADDR,FC_RETOP,false);
+ gen_call_function_raw((void*)CPU_SGDT_base);
+ gen_restore_addr_reg();
+ gen_add_imm(FC_ADDR,2);
+ dyn_write_word(FC_ADDR,FC_RETOP,true);
+ break;
+ case 0x01: // SIDT
+ gen_call_function_raw((void*)CPU_SIDT_limit);
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_write_word(FC_ADDR,FC_RETOP,false);
+ gen_call_function_raw((void*)CPU_SIDT_base);
+ gen_restore_addr_reg();
+ gen_add_imm(FC_ADDR,2);
+ dyn_write_word(FC_ADDR,FC_RETOP,true);
+ break;
+ case 0x02: // LGDT
+ case 0x03: // LIDT
+// if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ if (cpu.pmode && cpu.cpl) IllegalOptionDynrec("lgdt nonpriviledged");
+ dyn_fill_ea(FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_read_word(FC_ADDR,FC_OP1,false);
+ gen_extend_word(false,FC_OP1);
+ gen_protect_reg(FC_OP1);
+
+ gen_restore_addr_reg();
+ gen_add_imm(FC_ADDR,2);
+ dyn_read_word(FC_ADDR,FC_OP2,true);
+ if (!decode.big_op) gen_and_imm(FC_OP2,0xffffff);
+
+ gen_restore_reg(FC_OP1);
+ if (decode.modrm.reg==2) gen_call_function_RR((void*)CPU_LGDT,FC_OP1,FC_OP2);
+ else gen_call_function_RR((void*)CPU_LIDT,FC_OP1,FC_OP2);
+ break;
+ case 0x04: // SMSW
+ gen_call_function_raw((void*)CPU_SMSW);
+ dyn_fill_ea(FC_ADDR);
+ dyn_write_word(FC_ADDR,FC_RETOP,false);
+ break;
+ case 0x06: // LMSW
+ dyn_fill_ea(FC_ADDR);
+ dyn_read_word(FC_ADDR,FC_RETOP,false);
+ gen_call_function_R((void*)CPU_LMSW,FC_RETOP);
+ dyn_check_exception(FC_RETOP);
+ dyn_set_eip_end();
+ dyn_reduce_cycles();
+ dyn_return(BR_Normal);
+ dyn_closeblock();
+ return true;
+ case 0x07: // INVLPG
+// if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ if (cpu.pmode && cpu.cpl) IllegalOptionDynrec("invlpg nonpriviledged");
+ gen_call_function_raw((void*)PAGING_ClearTLB);
+ break;
+ default: IllegalOptionDynrec("dyn_grp7_1");
+ }
+ } else {
+ switch (decode.modrm.reg) {
+ case 0x04: // SMSW
+ gen_call_function_raw((void*)CPU_SMSW);
+ MOV_REG_WORD16_FROM_HOST_REG(FC_RETOP,decode.modrm.rm);
+ break;
+ case 0x06: // LMSW
+ MOV_REG_WORD16_TO_HOST_REG(FC_RETOP,decode.modrm.rm);
+ gen_call_function_R((void*)CPU_LMSW,FC_RETOP);
+ dyn_check_exception(FC_RETOP);
+ dyn_set_eip_end();
+ dyn_reduce_cycles();
+ dyn_return(BR_Normal);
+ dyn_closeblock();
+ return true;
+ default: IllegalOptionDynrec("dyn_grp7_2");
+ }
+ }
+ return false;
+}
+
+
+/*
+static void dyn_larlsl(bool is_lar) {
+ dyn_get_modrm();
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_read_word(FC_ADDR,FC_RETOP,false);
+ } else {
+ MOV_REG_WORD16_TO_HOST_REG(FC_RETOP,decode.modrm.rm);
+ }
+ gen_extend_word(false,FC_RETOP);
+ if (is_lar) gen_call_function((void*)CPU_LAR,"%R%A",FC_RETOP,(DRC_PTR_SIZE_IM)&core_dynrec.readdata);
+ else gen_call_function((void*)CPU_LSL,"%R%A",FC_RETOP,(DRC_PTR_SIZE_IM)&core_dynrec.readdata);
+ DRC_PTR_SIZE_IM brnz=gen_create_branch_on_nonzero(FC_RETOP,true);
+ gen_mov_word_to_reg(FC_OP2,&core_dynrec.readdata,true);
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op);
+ gen_fill_branch(brnz);
+}
+*/
+
+
+static void dyn_mov_from_crx(void) {
+ dyn_get_modrm();
+ gen_call_function_IA((void*)CPU_READ_CRX,decode.modrm.reg,(DRC_PTR_SIZE_IM)&core_dynrec.readdata);
+ dyn_check_exception(FC_RETOP);
+ gen_mov_word_to_reg(FC_OP2,&core_dynrec.readdata,true);
+ MOV_REG_WORD32_FROM_HOST_REG(FC_OP2,decode.modrm.rm);
+}
+
+static void dyn_mov_to_crx(void) {
+ dyn_get_modrm();
+ MOV_REG_WORD32_TO_HOST_REG(FC_RETOP,decode.modrm.rm);
+ gen_call_function_IR((void*)CPU_WRITE_CRX,decode.modrm.reg,FC_RETOP);
+ dyn_check_exception(FC_RETOP);
+ dyn_set_eip_end();
+ dyn_reduce_cycles();
+ dyn_return(BR_Normal);
+ dyn_closeblock();
+}
+
+
+static void dyn_cbw(void) {
+ if (decode.big_op) {
+ MOV_REG_WORD16_TO_HOST_REG(FC_OP1,DRC_REG_EAX);
+ gen_call_function_raw((void *)&dynrec_cwde);
+ MOV_REG_WORD32_FROM_HOST_REG(FC_RETOP,DRC_REG_EAX);
+ } else {
+ MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,DRC_REG_EAX,0);
+ gen_call_function_raw((void *)&dynrec_cbw);
+ MOV_REG_WORD16_FROM_HOST_REG(FC_RETOP,DRC_REG_EAX);
+ }
+}
+
+static void dyn_cwd(void) {
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_EAX,decode.big_op);
+ if (decode.big_op) {
+ gen_call_function_raw((void *)&dynrec_cdq);
+ MOV_REG_WORD32_FROM_HOST_REG(FC_RETOP,DRC_REG_EDX);
+ } else {
+ gen_call_function_raw((void *)&dynrec_cwd);
+ MOV_REG_WORD16_FROM_HOST_REG(FC_RETOP,DRC_REG_EDX);
+ }
+}
+
+static void dyn_sahf(void) {
+ MOV_REG_WORD16_TO_HOST_REG(FC_OP1,DRC_REG_EAX);
+ gen_call_function_raw((void *)&dynrec_sahf);
+ InvalidateFlags();
+}
+
+
+static void dyn_exit_link(Bits eip_change) {
+ gen_add_direct_word(®_eip,(decode.code-decode.code_start)+eip_change,decode.big_op);
+ dyn_reduce_cycles();
+ gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start));
+ dyn_closeblock();
+}
+
+
+static void dyn_branched_exit(BranchTypes btype,Bit32s eip_add) {
+ Bitu eip_base=decode.code-decode.code_start;
+ dyn_reduce_cycles();
+
+ dyn_branchflag_to_reg(btype);
+ DRC_PTR_SIZE_IM data=gen_create_branch_on_nonzero(FC_RETOP,true);
+
+ // Branch not taken
+ gen_add_direct_word(®_eip,eip_base,decode.big_op);
+ gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start));
+ gen_fill_branch(data);
+
+ // Branch taken
+ gen_add_direct_word(®_eip,eip_base+eip_add,decode.big_op);
+ gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlockDynRec,cache.start));
+ dyn_closeblock();
+}
+
+/*
+static void dyn_set_byte_on_condition(BranchTypes btype) {
+ dyn_get_modrm();
+ dyn_branchflag_to_reg(btype);
+ gen_and_imm(FC_RETOP,1);
+ if (decode.modrm.mod<3) {
+ dyn_fill_ea(FC_ADDR);
+ dyn_write_byte(FC_ADDR,FC_RETOP);
+ } else {
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1);
+ }
+}
+*/
+
+static void dyn_loop(LoopTypes type) {
+ dyn_reduce_cycles();
+ Bits eip_add=(Bit8s)decode_fetchb();
+ Bitu eip_base=decode.code-decode.code_start;
+ DRC_PTR_SIZE_IM branch1=0;
+ DRC_PTR_SIZE_IM branch2=0;
+ switch (type) {
+ case LOOP_E:
+ dyn_branchflag_to_reg(BR_NZ);
+ branch1=gen_create_branch_on_nonzero(FC_RETOP,true);
+ break;
+ case LOOP_NE:
+ dyn_branchflag_to_reg(BR_Z);
+ branch1=gen_create_branch_on_nonzero(FC_RETOP,true);
+ break;
+ }
+ switch (type) {
+ case LOOP_E:
+ case LOOP_NE:
+ case LOOP_NONE:
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr);
+ gen_add_imm(FC_OP1,(Bit32u)(-1));
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr);
+ branch2=gen_create_branch_on_zero(FC_OP1,decode.big_addr);
+ break;
+ case LOOP_JCXZ:
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr);
+ branch2=gen_create_branch_on_nonzero(FC_OP1,decode.big_addr);
+ break;
+ }
+ gen_add_direct_word(®_eip,eip_base+eip_add,true);
+ gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start));
+ if (branch1) {
+ gen_fill_branch(branch1);
+ MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr);
+ gen_add_imm(FC_OP1,(Bit32u)(-1));
+ MOV_REG_WORD_FROM_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr);
+ }
+ // Branch taken
+ gen_fill_branch(branch2);
+ gen_add_direct_word(®_eip,eip_base,decode.big_op);
+ gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlockDynRec,cache.start));
+ dyn_closeblock();
+}
+
+
+static void dyn_ret_near(Bitu bytes) {
+ dyn_reduce_cycles();
+
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_pop_dword);
+ else {
+ gen_call_function_raw((void*)&dynrec_pop_word);
+ gen_extend_word(false,FC_RETOP);
+ }
+ gen_mov_word_from_reg(FC_RETOP,decode.big_op?(void*)(®_eip):(void*)(®_ip),true);
+
+ if (bytes) gen_add_direct_word(®_esp,bytes,true);
+ dyn_return(BR_Normal);
+ dyn_closeblock();
+}
+
+static void dyn_call_near_imm(void) {
+ Bits imm;
+ if (decode.big_op) imm=(Bit32s)decode_fetchd();
+ else imm=(Bit16s)decode_fetchw();
+ dyn_set_eip_end(FC_OP1);
+ if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword);
+ else gen_call_function_raw((void*)&dynrec_push_word);
+
+ dyn_set_eip_end(FC_OP1,imm);
+ gen_mov_word_from_reg(FC_OP1,decode.big_op?(void*)(®_eip):(void*)(®_ip),decode.big_op);
+
+ dyn_reduce_cycles();
+ gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start));
+ dyn_closeblock();
+}
+
+static void dyn_ret_far(Bitu bytes) {
+ dyn_reduce_cycles();
+ dyn_set_eip_last_end(FC_RETOP);
+ gen_call_function_IIR((void*)&CPU_RET,decode.big_op,bytes,FC_RETOP);
+ dyn_return(BR_Normal);
+ dyn_closeblock();
+}
+
+static void dyn_call_far_imm(void) {
+ Bitu sel,off;
+ off=decode.big_op ? decode_fetchd() : decode_fetchw();
+ sel=decode_fetchw();
+ dyn_reduce_cycles();
+ dyn_set_eip_last_end(FC_RETOP);
+ gen_call_function_IIIR((void*)&CPU_CALL,decode.big_op,sel,off,FC_RETOP);
+ dyn_return(BR_Normal);
+ dyn_closeblock();
+}
+
+static void dyn_jmp_far_imm(void) {
+ Bitu sel,off;
+ off=decode.big_op ? decode_fetchd() : decode_fetchw();
+ sel=decode_fetchw();
+ dyn_reduce_cycles();
+ dyn_set_eip_last_end(FC_RETOP);
+ gen_call_function_IIIR((void*)&CPU_JMP,decode.big_op,sel,off,FC_RETOP);
+ dyn_return(BR_Normal);
+ dyn_closeblock();
+}
+
+static void dyn_iret(void) {
+ dyn_reduce_cycles();
+ dyn_set_eip_last_end(FC_RETOP);
+ gen_call_function_IR((void*)&CPU_IRET,decode.big_op,FC_RETOP);
+ dyn_return(BR_Iret);
+ dyn_closeblock();
+}
+
+static void dyn_interrupt(Bit8u num) {
+ dyn_reduce_cycles();
+ dyn_set_eip_last_end(FC_RETOP);
+ gen_call_function_IIR((void*)&CPU_Interrupt,num,CPU_INT_SOFTWARE,FC_RETOP);
+ dyn_return(BR_Normal);
+ dyn_closeblock();
+}
+
+
+
+static void dyn_string(StringOps op) {
+ if (decode.rep) MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr);
+ else gen_mov_dword_to_reg_imm(FC_OP1,1);
+ gen_mov_word_to_reg(FC_OP2,&cpu.direction,true);
+ Bit8u di_base_addr=decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS;
+ switch (op) {
+ case STR_MOVSB:
+ if (decode.big_addr) gen_call_function_mm((void*)&dynrec_movsb_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES));
+ else gen_call_function_mm((void*)&dynrec_movsb_word,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES));
+ break;
+ case STR_MOVSW:
+ if (decode.big_addr) gen_call_function_mm((void*)&dynrec_movsw_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES));
+ else gen_call_function_mm((void*)&dynrec_movsw_word,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES));
+ break;
+ case STR_MOVSD:
+ if (decode.big_addr) gen_call_function_mm((void*)&dynrec_movsd_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES));
+ else gen_call_function_mm((void*)&dynrec_movsd_word,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES));
+ break;
+
+ case STR_LODSB:
+ if (decode.big_addr) gen_call_function_m((void*)&dynrec_lodsb_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr));
+ else gen_call_function_m((void*)&dynrec_lodsb_word,(Bitu)DRCD_SEG_PHYS(di_base_addr));
+ break;
+ case STR_LODSW:
+ if (decode.big_addr) gen_call_function_m((void*)&dynrec_lodsw_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr));
+ else gen_call_function_m((void*)&dynrec_lodsw_word,(Bitu)DRCD_SEG_PHYS(di_base_addr));
+ break;
+ case STR_LODSD:
+ if (decode.big_addr) gen_call_function_m((void*)&dynrec_lodsd_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr));
+ else gen_call_function_m((void*)&dynrec_lodsd_word,(Bitu)DRCD_SEG_PHYS(di_base_addr));
+ break;
+
+ case STR_STOSB:
+ if (decode.big_addr) gen_call_function_m((void*)&dynrec_stosb_dword,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES));
+ else gen_call_function_m((void*)&dynrec_stosb_word,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES));
+ break;
+ case STR_STOSW:
+ if (decode.big_addr) gen_call_function_m((void*)&dynrec_stosw_dword,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES));
+ else gen_call_function_m((void*)&dynrec_stosw_word,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES));
+ break;
+ case STR_STOSD:
+ if (decode.big_addr) gen_call_function_m((void*)&dynrec_stosd_dword,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES));
+ else gen_call_function_m((void*)&dynrec_stosd_word,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES));
+ break;
+ default: IllegalOptionDynrec("dyn_string");
+ }
+ if (decode.rep) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,DRC_REG_ECX,decode.big_addr);
+
+ if (op<STR_SCASB) {
+ // those string operations are allowed for premature termination
+ // when not enough cycles left
+ if (!decode.big_addr) gen_extend_word(false,FC_RETOP);
+ save_info_dynrec[used_save_info_dynrec].branch_pos=gen_create_branch_long_nonzero(FC_RETOP,true);
+ save_info_dynrec[used_save_info_dynrec].eip_change=decode.op_start-decode.code_start;
+ save_info_dynrec[used_save_info_dynrec].type=string_break;
+ used_save_info_dynrec++;
+ }
+}
+
+
+static void dyn_read_port_byte_direct(Bit8u port) {
+ dyn_add_iocheck_var(port,1);
+ gen_call_function_I((void*)&IO_ReadB,port);
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,DRC_REG_EAX,0);
+}
+
+static void dyn_read_port_word_direct(Bit8u port) {
+ dyn_add_iocheck_var(port,decode.big_op?4:2);
+ gen_call_function_I(decode.big_op?((void*)&IO_ReadD):((void*)&IO_ReadW),port);
+ MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,DRC_REG_EAX,decode.big_op);
+}
+
+static void dyn_write_port_byte_direct(Bit8u port) {
+ dyn_add_iocheck_var(port,1);
+ MOV_REG_BYTE_TO_HOST_REG_LOW(FC_RETOP,DRC_REG_EAX,0);
+ gen_extend_byte(false,FC_RETOP);
+ gen_call_function_IR((void*)&IO_WriteB,port,FC_RETOP);
+}
+
+static void dyn_write_port_word_direct(Bit8u port) {
+ dyn_add_iocheck_var(port,decode.big_op?4:2);
+ MOV_REG_WORD_TO_HOST_REG(FC_RETOP,DRC_REG_EAX,decode.big_op);
+ if (!decode.big_op) gen_extend_word(false,FC_RETOP);
+ gen_call_function_IR(decode.big_op?((void*)&IO_WriteD):((void*)&IO_WriteW),port,FC_RETOP);
+}
+
+
+static void dyn_read_port_byte(void) {
+ MOV_REG_WORD16_TO_HOST_REG(FC_ADDR,DRC_REG_EDX);
+ gen_extend_word(false,FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_add_iocheck(FC_ADDR,1);
+ gen_restore_addr_reg();
+ gen_call_function_R((void*)&IO_ReadB,FC_ADDR);
+ MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,DRC_REG_EAX,0);
+}
+
+static void dyn_read_port_word(void) {
+ MOV_REG_WORD16_TO_HOST_REG(FC_ADDR,DRC_REG_EDX);
+ gen_extend_word(false,FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_add_iocheck(FC_ADDR,decode.big_op?4:2);
+ gen_restore_addr_reg();
+ gen_call_function_R(decode.big_op?((void*)&IO_ReadD):((void*)&IO_ReadW),FC_ADDR);
+ MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,DRC_REG_EAX,decode.big_op);
+}
+
+static void dyn_write_port_byte(void) {
+ MOV_REG_WORD16_TO_HOST_REG(FC_ADDR,DRC_REG_EDX);
+ gen_extend_word(false,FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_add_iocheck(FC_ADDR,1);
+ MOV_REG_BYTE_TO_HOST_REG_LOW(FC_RETOP,DRC_REG_EAX,0);
+ gen_extend_byte(false,FC_RETOP);
+ gen_restore_addr_reg();
+ gen_call_function_RR((void*)&IO_WriteB,FC_ADDR,FC_RETOP);
+}
+
+static void dyn_write_port_word(void) {
+ MOV_REG_WORD16_TO_HOST_REG(FC_ADDR,DRC_REG_EDX);
+ gen_extend_word(false,FC_ADDR);
+ gen_protect_addr_reg();
+ dyn_add_iocheck(FC_ADDR,decode.big_op?4:2);
+ MOV_REG_WORD_TO_HOST_REG(FC_RETOP,DRC_REG_EAX,decode.big_op);
+ if (!decode.big_op) gen_extend_word(false,FC_RETOP);
+ gen_restore_addr_reg();
+ gen_call_function_RR(decode.big_op?((void*)&IO_WriteD):((void*)&IO_WriteW),FC_ADDR,FC_RETOP);
+}
+
+
+static void dyn_enter(void) {
+ Bitu bytes=decode_fetchw();
+ Bitu level=decode_fetchb();
+ gen_call_function_III((void *)&CPU_ENTER,decode.big_op,bytes,level);
+}
+
+static void dynrec_leave_word(void) {
+ reg_esp&=cpu.stack.notmask;
+ reg_esp|=(reg_ebp&cpu.stack.mask);
+ reg_bp=(Bit16u)CPU_Pop16();
+}
+
+static void dynrec_leave_dword(void) {
+ reg_esp&=cpu.stack.notmask;
+ reg_esp|=(reg_ebp&cpu.stack.mask);
+ reg_ebp=CPU_Pop32();
+}
+
+static void dyn_leave(void) {
+ if (decode.big_op) gen_call_function_raw((void *)dynrec_leave_dword);
+ else gen_call_function_raw((void *)dynrec_leave_word);
+}
+
+
+static void dynrec_pusha_word(void) {
+ Bit16u old_sp=reg_sp;
+ CPU_Push16(reg_ax);CPU_Push16(reg_cx);CPU_Push16(reg_dx);CPU_Push16(reg_bx);
+ CPU_Push16(old_sp);CPU_Push16(reg_bp);CPU_Push16(reg_si);CPU_Push16(reg_di);
+}
+
+static void dynrec_pusha_dword(void) {
+ Bitu tmpesp = reg_esp;
+ CPU_Push32(reg_eax);CPU_Push32(reg_ecx);CPU_Push32(reg_edx);CPU_Push32(reg_ebx);
+ CPU_Push32(tmpesp);CPU_Push32(reg_ebp);CPU_Push32(reg_esi);CPU_Push32(reg_edi);
+}
+
+static void dynrec_popa_word(void) {
+ reg_di=(Bit16u)CPU_Pop16();reg_si=(Bit16u)CPU_Pop16();
+ reg_bp=(Bit16u)CPU_Pop16();CPU_Pop16(); //Don't save SP
+ reg_bx=(Bit16u)CPU_Pop16();reg_dx=(Bit16u)CPU_Pop16();
+ reg_cx=(Bit16u)CPU_Pop16();reg_ax=(Bit16u)CPU_Pop16();
+}
+
+static void dynrec_popa_dword(void) {
+ reg_edi=CPU_Pop32();reg_esi=CPU_Pop32();reg_ebp=CPU_Pop32();CPU_Pop32(); //Don't save ESP
+ reg_ebx=CPU_Pop32();reg_edx=CPU_Pop32();reg_ecx=CPU_Pop32();reg_eax=CPU_Pop32();
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+#include "dosbox.h"
+#if C_FPU
+
+#include <math.h>
+#include <float.h>
+#include "cross.h"
+#include "mem.h"
+#include "fpu.h"
+#include "cpu.h"
+
+
+static void FPU_FDECSTP(){
+ TOP = (TOP - 1) & 7;
+}
+
+static void FPU_FINCSTP(){
+ TOP = (TOP + 1) & 7;
+}
+
+static void FPU_FNSTCW(PhysPt addr){
+ mem_writew(addr,fpu.cw);
+}
+
+static void FPU_FFREE(Bitu st) {
+ fpu.tags[st]=TAG_Empty;
+}
+
+
+#if C_FPU_X86
+#include "../../fpu/fpu_instructions_x86.h"
+#else
+#include "../../fpu/fpu_instructions.h"
+#endif
+
+
+static INLINE void dyn_fpu_top() {
+ gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true);
+ gen_add_imm(FC_OP2,decode.modrm.rm);
+ gen_and_imm(FC_OP2,7);
+ gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true);
+}
+
+static INLINE void dyn_fpu_top_swapped() {
+ gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true);
+ gen_add_imm(FC_OP1,decode.modrm.rm);
+ gen_and_imm(FC_OP1,7);
+ gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true);
+}
+
+static void dyn_eatree() {
+ Bitu group=(decode.modrm.val >> 3) & 7;
+ switch (group){
+ case 0x00: // FADD ST,STi
+ gen_call_function_R((void*)&FPU_FADD_EA,FC_OP1);
+ break;
+ case 0x01: // FMUL ST,STi
+ gen_call_function_R((void*)&FPU_FMUL_EA,FC_OP1);
+ break;
+ case 0x02: // FCOM STi
+ gen_call_function_R((void*)&FPU_FCOM_EA,FC_OP1);
+ break;
+ case 0x03: // FCOMP STi
+ gen_call_function_R((void*)&FPU_FCOM_EA,FC_OP1);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ case 0x04: // FSUB ST,STi
+ gen_call_function_R((void*)&FPU_FSUB_EA,FC_OP1);
+ break;
+ case 0x05: // FSUBR ST,STi
+ gen_call_function_R((void*)&FPU_FSUBR_EA,FC_OP1);
+ break;
+ case 0x06: // FDIV ST,STi
+ gen_call_function_R((void*)&FPU_FDIV_EA,FC_OP1);
+ break;
+ case 0x07: // FDIVR ST,STi
+ gen_call_function_R((void*)&FPU_FDIVR_EA,FC_OP1);
+ break;
+ default:
+ break;
+ }
+}
+
+static void dyn_fpu_esc0(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ dyn_fpu_top();
+ switch (decode.modrm.reg){
+ case 0x00: //FADD ST,STi
+ gen_call_function_RR((void*)&FPU_FADD,FC_OP1,FC_OP2);
+ break;
+ case 0x01: // FMUL ST,STi
+ gen_call_function_RR((void*)&FPU_FMUL,FC_OP1,FC_OP2);
+ break;
+ case 0x02: // FCOM STi
+ gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2);
+ break;
+ case 0x03: // FCOMP STi
+ gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ case 0x04: // FSUB ST,STi
+ gen_call_function_RR((void*)&FPU_FSUB,FC_OP1,FC_OP2);
+ break;
+ case 0x05: // FSUBR ST,STi
+ gen_call_function_RR((void*)&FPU_FSUBR,FC_OP1,FC_OP2);
+ break;
+ case 0x06: // FDIV ST,STi
+ gen_call_function_RR((void*)&FPU_FDIV,FC_OP1,FC_OP2);
+ break;
+ case 0x07: // FDIVR ST,STi
+ gen_call_function_RR((void*)&FPU_FDIVR,FC_OP1,FC_OP2);
+ break;
+ default:
+ break;
+ }
+ } else {
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FLD_F32_EA,FC_ADDR);
+ gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true);
+ dyn_eatree();
+ }
+}
+
+
+static void dyn_fpu_esc1(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ switch (decode.modrm.reg){
+ case 0x00: /* FLD STi */
+ gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true);
+ gen_add_imm(FC_OP1,decode.modrm.rm);
+ gen_and_imm(FC_OP1,7);
+ gen_protect_reg(FC_OP1);
+ gen_call_function_raw((void*)&FPU_PREP_PUSH);
+ gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true);
+ gen_restore_reg(FC_OP1);
+ gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2);
+ break;
+ case 0x01: /* FXCH STi */
+ dyn_fpu_top();
+ gen_call_function_RR((void*)&FPU_FXCH,FC_OP1,FC_OP2);
+ break;
+ case 0x02: /* FNOP */
+ gen_call_function_raw((void*)&FPU_FNOP);
+ break;
+ case 0x03: /* FSTP STi */
+ dyn_fpu_top();
+ gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ case 0x04:
+ switch(decode.modrm.rm){
+ case 0x00: /* FCHS */
+ gen_call_function_raw((void*)&FPU_FCHS);
+ break;
+ case 0x01: /* FABS */
+ gen_call_function_raw((void*)&FPU_FABS);
+ break;
+ case 0x02: /* UNKNOWN */
+ case 0x03: /* ILLEGAL */
+ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm);
+ break;
+ case 0x04: /* FTST */
+ gen_call_function_raw((void*)&FPU_FTST);
+ break;
+ case 0x05: /* FXAM */
+ gen_call_function_raw((void*)&FPU_FXAM);
+ break;
+ case 0x06: /* FTSTP (cyrix)*/
+ case 0x07: /* UNKNOWN */
+ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ break;
+ case 0x05:
+ switch(decode.modrm.rm){
+ case 0x00: /* FLD1 */
+ gen_call_function_raw((void*)&FPU_FLD1);
+ break;
+ case 0x01: /* FLDL2T */
+ gen_call_function_raw((void*)&FPU_FLDL2T);
+ break;
+ case 0x02: /* FLDL2E */
+ gen_call_function_raw((void*)&FPU_FLDL2E);
+ break;
+ case 0x03: /* FLDPI */
+ gen_call_function_raw((void*)&FPU_FLDPI);
+ break;
+ case 0x04: /* FLDLG2 */
+ gen_call_function_raw((void*)&FPU_FLDLG2);
+ break;
+ case 0x05: /* FLDLN2 */
+ gen_call_function_raw((void*)&FPU_FLDLN2);
+ break;
+ case 0x06: /* FLDZ*/
+ gen_call_function_raw((void*)&FPU_FLDZ);
+ break;
+ case 0x07: /* ILLEGAL */
+ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ break;
+ case 0x06:
+ switch(decode.modrm.rm){
+ case 0x00: /* F2XM1 */
+ gen_call_function_raw((void*)&FPU_F2XM1);
+ break;
+ case 0x01: /* FYL2X */
+ gen_call_function_raw((void*)&FPU_FYL2X);
+ break;
+ case 0x02: /* FPTAN */
+ gen_call_function_raw((void*)&FPU_FPTAN);
+ break;
+ case 0x03: /* FPATAN */
+ gen_call_function_raw((void*)&FPU_FPATAN);
+ break;
+ case 0x04: /* FXTRACT */
+ gen_call_function_raw((void*)&FPU_FXTRACT);
+ break;
+ case 0x05: /* FPREM1 */
+ gen_call_function_raw((void*)&FPU_FPREM1);
+ break;
+ case 0x06: /* FDECSTP */
+ gen_call_function_raw((void*)&FPU_FDECSTP);
+ break;
+ case 0x07: /* FINCSTP */
+ gen_call_function_raw((void*)&FPU_FINCSTP);
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ break;
+ case 0x07:
+ switch(decode.modrm.rm){
+ case 0x00: /* FPREM */
+ gen_call_function_raw((void*)&FPU_FPREM);
+ break;
+ case 0x01: /* FYL2XP1 */
+ gen_call_function_raw((void*)&FPU_FYL2XP1);
+ break;
+ case 0x02: /* FSQRT */
+ gen_call_function_raw((void*)&FPU_FSQRT);
+ break;
+ case 0x03: /* FSINCOS */
+ gen_call_function_raw((void*)&FPU_FSINCOS);
+ break;
+ case 0x04: /* FRNDINT */
+ gen_call_function_raw((void*)&FPU_FRNDINT);
+ break;
+ case 0x05: /* FSCALE */
+ gen_call_function_raw((void*)&FPU_FSCALE);
+ break;
+ case 0x06: /* FSIN */
+ gen_call_function_raw((void*)&FPU_FSIN);
+ break;
+ case 0x07: /* FCOS */
+ gen_call_function_raw((void*)&FPU_FCOS);
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ } else {
+ switch(decode.modrm.reg){
+ case 0x00: /* FLD float*/
+ gen_call_function_raw((void*)&FPU_PREP_PUSH);
+ dyn_fill_ea(FC_OP1);
+ gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true);
+ gen_call_function_RR((void*)&FPU_FLD_F32,FC_OP1,FC_OP2);
+ break;
+ case 0x01: /* UNKNOWN */
+ LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ break;
+ case 0x02: /* FST float*/
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FST_F32,FC_ADDR);
+ break;
+ case 0x03: /* FSTP float*/
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FST_F32,FC_ADDR);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ case 0x04: /* FLDENV */
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FLDENV,FC_ADDR);
+ break;
+ case 0x05: /* FLDCW */
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void *)&FPU_FLDCW,FC_ADDR);
+ break;
+ case 0x06: /* FSTENV */
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void *)&FPU_FSTENV,FC_ADDR);
+ break;
+ case 0x07: /* FNSTCW*/
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void *)&FPU_FNSTCW,FC_ADDR);
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ }
+}
+
+static void dyn_fpu_esc2(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ switch(decode.modrm.reg){
+ case 0x05:
+ switch(decode.modrm.rm){
+ case 0x01: /* FUCOMPP */
+ gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true);
+ gen_add_imm(FC_OP2,1);
+ gen_and_imm(FC_OP2,7);
+ gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true);
+ gen_call_function_RR((void *)&FPU_FUCOM,FC_OP1,FC_OP2);
+ gen_call_function_raw((void *)&FPU_FPOP);
+ gen_call_function_raw((void *)&FPU_FPOP);
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ } else {
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FLD_I32_EA,FC_ADDR);
+ gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true);
+ dyn_eatree();
+ }
+}
+
+static void dyn_fpu_esc3(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ switch (decode.modrm.reg) {
+ case 0x04:
+ switch (decode.modrm.rm) {
+ case 0x00: //FNENI
+ case 0x01: //FNDIS
+ LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfuntion: %d",decode.modrm.rm);
+ break;
+ case 0x02: //FNCLEX FCLEX
+ gen_call_function_raw((void*)&FPU_FCLEX);
+ break;
+ case 0x03: //FNINIT FINIT
+ gen_call_function_raw((void*)&FPU_FINIT);
+ break;
+ case 0x04: //FNSETPM
+ case 0x05: //FRSTPM
+// LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done");
+ break;
+ default:
+ E_Exit("ESC 3:ILLEGAL OPCODE group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ }
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 3:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ } else {
+ switch(decode.modrm.reg){
+ case 0x00: /* FILD */
+ gen_call_function_raw((void*)&FPU_PREP_PUSH);
+ dyn_fill_ea(FC_OP1);
+ gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true);
+ gen_call_function_RR((void*)&FPU_FLD_I32,FC_OP1,FC_OP2);
+ break;
+ case 0x01: /* FISTTP */
+ LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ break;
+ case 0x02: /* FIST */
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FST_I32,FC_ADDR);
+ break;
+ case 0x03: /* FISTP */
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FST_I32,FC_ADDR);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ case 0x05: /* FLD 80 Bits Real */
+ gen_call_function_raw((void*)&FPU_PREP_PUSH);
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FLD_F80,FC_ADDR);
+ break;
+ case 0x07: /* FSTP 80 Bits Real */
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FST_F80,FC_ADDR);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ }
+ }
+}
+
+static void dyn_fpu_esc4(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ switch(decode.modrm.reg){
+ case 0x00: /* FADD STi,ST*/
+ dyn_fpu_top_swapped();
+ gen_call_function_RR((void*)&FPU_FADD,FC_OP1,FC_OP2);
+ break;
+ case 0x01: /* FMUL STi,ST*/
+ dyn_fpu_top_swapped();
+ gen_call_function_RR((void*)&FPU_FMUL,FC_OP1,FC_OP2);
+ break;
+ case 0x02: /* FCOM*/
+ dyn_fpu_top();
+ gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2);
+ break;
+ case 0x03: /* FCOMP*/
+ dyn_fpu_top();
+ gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ case 0x04: /* FSUBR STi,ST*/
+ dyn_fpu_top_swapped();
+ gen_call_function_RR((void*)&FPU_FSUBR,FC_OP1,FC_OP2);
+ break;
+ case 0x05: /* FSUB STi,ST*/
+ dyn_fpu_top_swapped();
+ gen_call_function_RR((void*)&FPU_FSUB,FC_OP1,FC_OP2);
+ break;
+ case 0x06: /* FDIVR STi,ST*/
+ dyn_fpu_top_swapped();
+ gen_call_function_RR((void*)&FPU_FDIVR,FC_OP1,FC_OP2);
+ break;
+ case 0x07: /* FDIV STi,ST*/
+ dyn_fpu_top_swapped();
+ gen_call_function_RR((void*)&FPU_FDIV,FC_OP1,FC_OP2);
+ break;
+ default:
+ break;
+ }
+ } else {
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FLD_F64_EA,FC_ADDR);
+ gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true);
+ dyn_eatree();
+ }
+}
+
+static void dyn_fpu_esc5(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ dyn_fpu_top();
+ switch(decode.modrm.reg){
+ case 0x00: /* FFREE STi */
+ gen_call_function_R((void*)&FPU_FFREE,FC_OP2);
+ break;
+ case 0x01: /* FXCH STi*/
+ gen_call_function_RR((void*)&FPU_FXCH,FC_OP1,FC_OP2);
+ break;
+ case 0x02: /* FST STi */
+ gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2);
+ break;
+ case 0x03: /* FSTP STi*/
+ gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ case 0x04: /* FUCOM STi */
+ gen_call_function_RR((void*)&FPU_FUCOM,FC_OP1,FC_OP2);
+ break;
+ case 0x05: /*FUCOMP STi */
+ gen_call_function_RR((void*)&FPU_FUCOM,FC_OP1,FC_OP2);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 5:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ } else {
+ switch(decode.modrm.reg){
+ case 0x00: /* FLD double real*/
+ gen_call_function_raw((void*)&FPU_PREP_PUSH);
+ dyn_fill_ea(FC_OP1);
+ gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true);
+ gen_call_function_RR((void*)&FPU_FLD_F64,FC_OP1,FC_OP2);
+ break;
+ case 0x01: /* FISTTP longint*/
+ LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ break;
+ case 0x02: /* FST double real*/
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FST_F64,FC_ADDR);
+ break;
+ case 0x03: /* FSTP double real*/
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FST_F64,FC_ADDR);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ case 0x04: /* FRSTOR */
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FRSTOR,FC_ADDR);
+ break;
+ case 0x06: /* FSAVE */
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FSAVE,FC_ADDR);
+ break;
+ case 0x07: /*FNSTSW */
+ gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true);
+ gen_call_function_R((void*)&FPU_SET_TOP,FC_OP1);
+ dyn_fill_ea(FC_OP1);
+ gen_mov_word_to_reg(FC_OP2,(void*)(&fpu.sw),false);
+ gen_call_function_RR((void*)&mem_writew,FC_OP1,FC_OP2);
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ }
+ }
+}
+
+static void dyn_fpu_esc6(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ switch(decode.modrm.reg){
+ case 0x00: /*FADDP STi,ST*/
+ dyn_fpu_top_swapped();
+ gen_call_function_RR((void*)&FPU_FADD,FC_OP1,FC_OP2);
+ break;
+ case 0x01: /* FMULP STi,ST*/
+ dyn_fpu_top_swapped();
+ gen_call_function_RR((void*)&FPU_FMUL,FC_OP1,FC_OP2);
+ break;
+ case 0x02: /* FCOMP5*/
+ dyn_fpu_top();
+ gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2);
+ break; /* TODO IS THIS ALLRIGHT ????????? */
+ case 0x03: /*FCOMPP*/
+ if(decode.modrm.rm != 1) {
+ LOG(LOG_FPU,LOG_WARN)("ESC 6:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ return;
+ }
+ gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true);
+ gen_add_imm(FC_OP2,1);
+ gen_and_imm(FC_OP2,7);
+ gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true);
+ gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2);
+ gen_call_function_raw((void*)&FPU_FPOP); /* extra pop at the bottom*/
+ break;
+ case 0x04: /* FSUBRP STi,ST*/
+ dyn_fpu_top_swapped();
+ gen_call_function_RR((void*)&FPU_FSUBR,FC_OP1,FC_OP2);
+ break;
+ case 0x05: /* FSUBP STi,ST*/
+ dyn_fpu_top_swapped();
+ gen_call_function_RR((void*)&FPU_FSUB,FC_OP1,FC_OP2);
+ break;
+ case 0x06: /* FDIVRP STi,ST*/
+ dyn_fpu_top_swapped();
+ gen_call_function_RR((void*)&FPU_FDIVR,FC_OP1,FC_OP2);
+ break;
+ case 0x07: /* FDIVP STi,ST*/
+ dyn_fpu_top_swapped();
+ gen_call_function_RR((void*)&FPU_FDIV,FC_OP1,FC_OP2);
+ break;
+ default:
+ break;
+ }
+ gen_call_function_raw((void*)&FPU_FPOP);
+ } else {
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FLD_I16_EA,FC_ADDR);
+ gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true);
+ dyn_eatree();
+ }
+}
+
+static void dyn_fpu_esc7(){
+ dyn_get_modrm();
+ if (decode.modrm.val >= 0xc0) {
+ switch (decode.modrm.reg){
+ case 0x00: /* FFREEP STi */
+ dyn_fpu_top();
+ gen_call_function_R((void*)&FPU_FFREE,FC_OP2);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ case 0x01: /* FXCH STi*/
+ dyn_fpu_top();
+ gen_call_function_RR((void*)&FPU_FXCH,FC_OP1,FC_OP2);
+ break;
+ case 0x02: /* FSTP STi*/
+ case 0x03: /* FSTP STi*/
+ dyn_fpu_top();
+ gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ case 0x04:
+ switch(decode.modrm.rm){
+ case 0x00: /* FNSTSW AX*/
+ gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true);
+ gen_call_function_R((void*)&FPU_SET_TOP,FC_OP1);
+ gen_mov_word_to_reg(FC_OP1,(void*)(&fpu.sw),false);
+ MOV_REG_WORD16_FROM_HOST_REG(FC_OP1,DRC_REG_EAX);
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ } else {
+ switch(decode.modrm.reg){
+ case 0x00: /* FILD Bit16s */
+ gen_call_function_raw((void*)&FPU_PREP_PUSH);
+ dyn_fill_ea(FC_OP1);
+ gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true);
+ gen_call_function_RR((void*)&FPU_FLD_I16,FC_OP1,FC_OP2);
+ break;
+ case 0x01:
+ LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ break;
+ case 0x02: /* FIST Bit16s */
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FST_I16,FC_ADDR);
+ break;
+ case 0x03: /* FISTP Bit16s */
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FST_I16,FC_ADDR);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ case 0x04: /* FBLD packed BCD */
+ gen_call_function_raw((void*)&FPU_PREP_PUSH);
+ dyn_fill_ea(FC_OP1);
+ gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true);
+ gen_call_function_RR((void*)&FPU_FBLD,FC_OP1,FC_OP2);
+ break;
+ case 0x05: /* FILD Bit64s */
+ gen_call_function_raw((void*)&FPU_PREP_PUSH);
+ dyn_fill_ea(FC_OP1);
+ gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true);
+ gen_call_function_RR((void*)&FPU_FLD_I64,FC_OP1,FC_OP2);
+ break;
+ case 0x06: /* FBSTP packed BCD */
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FBST,FC_ADDR);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ case 0x07: /* FISTP Bit64s */
+ dyn_fill_ea(FC_ADDR);
+ gen_call_function_R((void*)&FPU_FST_I64,FC_ADDR);
+ gen_call_function_raw((void*)&FPU_FPOP);
+ break;
+ default:
+ LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm);
+ break;
+ }
+ }
+}
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+static Bit8u DRC_CALL_CONV dynrec_add_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_add_byte(Bit8u op1,Bit8u op2) {
+ lf_var1b=op1;
+ lf_var2b=op2;
+ lf_resb=(Bit8u)(lf_var1b+lf_var2b);
+ lflags.type=t_ADDb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_add_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_add_byte_simple(Bit8u op1,Bit8u op2) {
+ return op1+op2;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_adc_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_adc_byte(Bit8u op1,Bit8u op2) {
+ lflags.oldcf=get_CF()!=0;
+ lf_var1b=op1;
+ lf_var2b=op2;
+ lf_resb=(Bit8u)(lf_var1b+lf_var2b+lflags.oldcf);
+ lflags.type=t_ADCb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_adc_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_adc_byte_simple(Bit8u op1,Bit8u op2) {
+ return (Bit8u)(op1+op2+(Bitu)(get_CF()!=0));
+}
+
+static Bit8u DRC_CALL_CONV dynrec_sub_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_sub_byte(Bit8u op1,Bit8u op2) {
+ lf_var1b=op1;
+ lf_var2b=op2;
+ lf_resb=(Bit8u)(lf_var1b-lf_var2b);
+ lflags.type=t_SUBb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_sub_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_sub_byte_simple(Bit8u op1,Bit8u op2) {
+ return op1-op2;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_sbb_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_sbb_byte(Bit8u op1,Bit8u op2) {
+ lflags.oldcf=get_CF()!=0;
+ lf_var1b=op1;
+ lf_var2b=op2;
+ lf_resb=(Bit8u)(lf_var1b-(lf_var2b+lflags.oldcf));
+ lflags.type=t_SBBb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_sbb_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_sbb_byte_simple(Bit8u op1,Bit8u op2) {
+ return (Bit8u)(op1-(op2+(Bitu)(get_CF()!=0)));
+}
+
+static void DRC_CALL_CONV dynrec_cmp_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static void DRC_CALL_CONV dynrec_cmp_byte(Bit8u op1,Bit8u op2) {
+ lf_var1b=op1;
+ lf_var2b=op2;
+ lf_resb=(Bit8u)(lf_var1b-lf_var2b);
+ lflags.type=t_CMPb;
+}
+
+static void DRC_CALL_CONV dynrec_cmp_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static void DRC_CALL_CONV dynrec_cmp_byte_simple(Bit8u op1,Bit8u op2) {
+}
+
+static Bit8u DRC_CALL_CONV dynrec_xor_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_xor_byte(Bit8u op1,Bit8u op2) {
+ lf_var1b=op1;
+ lf_var2b=op2;
+ lf_resb=lf_var1b ^ lf_var2b;
+ lflags.type=t_XORb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_xor_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_xor_byte_simple(Bit8u op1,Bit8u op2) {
+ return op1 ^ op2;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_and_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_and_byte(Bit8u op1,Bit8u op2) {
+ lf_var1b=op1;
+ lf_var2b=op2;
+ lf_resb=lf_var1b & lf_var2b;
+ lflags.type=t_ANDb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_and_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_and_byte_simple(Bit8u op1,Bit8u op2) {
+ return op1 & op2;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_or_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_or_byte(Bit8u op1,Bit8u op2) {
+ lf_var1b=op1;
+ lf_var2b=op2;
+ lf_resb=lf_var1b | lf_var2b;
+ lflags.type=t_ORb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_or_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_or_byte_simple(Bit8u op1,Bit8u op2) {
+ return op1 | op2;
+}
+
+static void DRC_CALL_CONV dynrec_test_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static void DRC_CALL_CONV dynrec_test_byte(Bit8u op1,Bit8u op2) {
+ lf_var1b=op1;
+ lf_var2b=op2;
+ lf_resb=lf_var1b & lf_var2b;
+ lflags.type=t_TESTb;
+}
+
+static void DRC_CALL_CONV dynrec_test_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static void DRC_CALL_CONV dynrec_test_byte_simple(Bit8u op1,Bit8u op2) {
+}
+
+static Bit16u DRC_CALL_CONV dynrec_add_word(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_add_word(Bit16u op1,Bit16u op2) {
+ lf_var1w=op1;
+ lf_var2w=op2;
+ lf_resw=(Bit16u)(lf_var1w+lf_var2w);
+ lflags.type=t_ADDw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_add_word_simple(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_add_word_simple(Bit16u op1,Bit16u op2) {
+ return op1+op2;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_adc_word(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_adc_word(Bit16u op1,Bit16u op2) {
+ lflags.oldcf=get_CF()!=0;
+ lf_var1w=op1;
+ lf_var2w=op2;
+ lf_resw=(Bit16u)(lf_var1w+lf_var2w+lflags.oldcf);
+ lflags.type=t_ADCw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_adc_word_simple(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_adc_word_simple(Bit16u op1,Bit16u op2) {
+ return (Bit16u)(op1+op2+(Bitu)(get_CF()!=0));
+}
+
+static Bit16u DRC_CALL_CONV dynrec_sub_word(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_sub_word(Bit16u op1,Bit16u op2) {
+ lf_var1w=op1;
+ lf_var2w=op2;
+ lf_resw=(Bit16u)(lf_var1w-lf_var2w);
+ lflags.type=t_SUBw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_sub_word_simple(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_sub_word_simple(Bit16u op1,Bit16u op2) {
+ return op1-op2;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_sbb_word(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_sbb_word(Bit16u op1,Bit16u op2) {
+ lflags.oldcf=get_CF()!=0;
+ lf_var1w=op1;
+ lf_var2w=op2;
+ lf_resw=(Bit16u)(lf_var1w-(lf_var2w+lflags.oldcf));
+ lflags.type=t_SBBw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_sbb_word_simple(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_sbb_word_simple(Bit16u op1,Bit16u op2) {
+ return (Bit16u)(op1-(op2+(Bitu)(get_CF()!=0)));
+}
+
+static void DRC_CALL_CONV dynrec_cmp_word(Bit16u op1,Bit16u op2) DRC_FC;
+static void DRC_CALL_CONV dynrec_cmp_word(Bit16u op1,Bit16u op2) {
+ lf_var1w=op1;
+ lf_var2w=op2;
+ lf_resw=(Bit16u)(lf_var1w-lf_var2w);
+ lflags.type=t_CMPw;
+}
+
+static void DRC_CALL_CONV dynrec_cmp_word_simple(Bit16u op1,Bit16u op2) DRC_FC;
+static void DRC_CALL_CONV dynrec_cmp_word_simple(Bit16u op1,Bit16u op2) {
+}
+
+static Bit16u DRC_CALL_CONV dynrec_xor_word(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_xor_word(Bit16u op1,Bit16u op2) {
+ lf_var1w=op1;
+ lf_var2w=op2;
+ lf_resw=lf_var1w ^ lf_var2w;
+ lflags.type=t_XORw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_xor_word_simple(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_xor_word_simple(Bit16u op1,Bit16u op2) {
+ return op1 ^ op2;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_and_word(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_and_word(Bit16u op1,Bit16u op2) {
+ lf_var1w=op1;
+ lf_var2w=op2;
+ lf_resw=lf_var1w & lf_var2w;
+ lflags.type=t_ANDw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_and_word_simple(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_and_word_simple(Bit16u op1,Bit16u op2) {
+ return op1 & op2;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_or_word(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_or_word(Bit16u op1,Bit16u op2) {
+ lf_var1w=op1;
+ lf_var2w=op2;
+ lf_resw=lf_var1w | lf_var2w;
+ lflags.type=t_ORw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_or_word_simple(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_or_word_simple(Bit16u op1,Bit16u op2) {
+ return op1 | op2;
+}
+
+static void DRC_CALL_CONV dynrec_test_word(Bit16u op1,Bit16u op2) DRC_FC;
+static void DRC_CALL_CONV dynrec_test_word(Bit16u op1,Bit16u op2) {
+ lf_var1w=op1;
+ lf_var2w=op2;
+ lf_resw=lf_var1w & lf_var2w;
+ lflags.type=t_TESTw;
+}
+
+static void DRC_CALL_CONV dynrec_test_word_simple(Bit16u op1,Bit16u op2) DRC_FC;
+static void DRC_CALL_CONV dynrec_test_word_simple(Bit16u op1,Bit16u op2) {
+}
+
+static Bit32u DRC_CALL_CONV dynrec_add_dword(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_add_dword(Bit32u op1,Bit32u op2) {
+ lf_var1d=op1;
+ lf_var2d=op2;
+ lf_resd=lf_var1d+lf_var2d;
+ lflags.type=t_ADDd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_add_dword_simple(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_add_dword_simple(Bit32u op1,Bit32u op2) {
+ return op1 + op2;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_adc_dword(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_adc_dword(Bit32u op1,Bit32u op2) {
+ lflags.oldcf=get_CF()!=0;
+ lf_var1d=op1;
+ lf_var2d=op2;
+ lf_resd=lf_var1d+lf_var2d+lflags.oldcf;
+ lflags.type=t_ADCd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_adc_dword_simple(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_adc_dword_simple(Bit32u op1,Bit32u op2) {
+ return op1+op2+(Bitu)(get_CF()!=0);
+}
+
+static Bit32u DRC_CALL_CONV dynrec_sub_dword(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_sub_dword(Bit32u op1,Bit32u op2) {
+ lf_var1d=op1;
+ lf_var2d=op2;
+ lf_resd=lf_var1d-lf_var2d;
+ lflags.type=t_SUBd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_sub_dword_simple(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_sub_dword_simple(Bit32u op1,Bit32u op2) {
+ return op1-op2;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_sbb_dword(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_sbb_dword(Bit32u op1,Bit32u op2) {
+ lflags.oldcf=get_CF()!=0;
+ lf_var1d=op1;
+ lf_var2d=op2;
+ lf_resd=lf_var1d-(lf_var2d+lflags.oldcf);
+ lflags.type=t_SBBd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_sbb_dword_simple(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_sbb_dword_simple(Bit32u op1,Bit32u op2) {
+ return op1-(op2+(Bitu)(get_CF()!=0));
+}
+
+static void DRC_CALL_CONV dynrec_cmp_dword(Bit32u op1,Bit32u op2) DRC_FC;
+static void DRC_CALL_CONV dynrec_cmp_dword(Bit32u op1,Bit32u op2) {
+ lf_var1d=op1;
+ lf_var2d=op2;
+ lf_resd=lf_var1d-lf_var2d;
+ lflags.type=t_CMPd;
+}
+
+static void DRC_CALL_CONV dynrec_cmp_dword_simple(Bit32u op1,Bit32u op2) DRC_FC;
+static void DRC_CALL_CONV dynrec_cmp_dword_simple(Bit32u op1,Bit32u op2) {
+}
+
+static Bit32u DRC_CALL_CONV dynrec_xor_dword(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_xor_dword(Bit32u op1,Bit32u op2) {
+ lf_var1d=op1;
+ lf_var2d=op2;
+ lf_resd=lf_var1d ^ lf_var2d;
+ lflags.type=t_XORd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_xor_dword_simple(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_xor_dword_simple(Bit32u op1,Bit32u op2) {
+ return op1 ^ op2;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_and_dword(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_and_dword(Bit32u op1,Bit32u op2) {
+ lf_var1d=op1;
+ lf_var2d=op2;
+ lf_resd=lf_var1d & lf_var2d;
+ lflags.type=t_ANDd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_and_dword_simple(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_and_dword_simple(Bit32u op1,Bit32u op2) {
+ return op1 & op2;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_or_dword(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_or_dword(Bit32u op1,Bit32u op2) {
+ lf_var1d=op1;
+ lf_var2d=op2;
+ lf_resd=lf_var1d | lf_var2d;
+ lflags.type=t_ORd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_or_dword_simple(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_or_dword_simple(Bit32u op1,Bit32u op2) {
+ return op1 | op2;
+}
+
+static void DRC_CALL_CONV dynrec_test_dword(Bit32u op1,Bit32u op2) DRC_FC;
+static void DRC_CALL_CONV dynrec_test_dword(Bit32u op1,Bit32u op2) {
+ lf_var1d=op1;
+ lf_var2d=op2;
+ lf_resd=lf_var1d & lf_var2d;
+ lflags.type=t_TESTd;
+}
+
+static void DRC_CALL_CONV dynrec_test_dword_simple(Bit32u op1,Bit32u op2) DRC_FC;
+static void DRC_CALL_CONV dynrec_test_dword_simple(Bit32u op1,Bit32u op2) {
+}
+
+
+static void dyn_dop_byte_gencall(DualOps op) {
+ switch (op) {
+ case DOP_ADD:
+ InvalidateFlags((void*)&dynrec_add_byte_simple,t_ADDb);
+ gen_call_function_raw((void*)&dynrec_add_byte);
+ break;
+ case DOP_ADC:
+ AcquireFlags(FLAG_CF);
+ InvalidateFlagsPartially((void*)&dynrec_adc_byte_simple,t_ADCb);
+ gen_call_function_raw((void*)&dynrec_adc_byte);
+ break;
+ case DOP_SUB:
+ InvalidateFlags((void*)&dynrec_sub_byte_simple,t_SUBb);
+ gen_call_function_raw((void*)&dynrec_sub_byte);
+ break;
+ case DOP_SBB:
+ AcquireFlags(FLAG_CF);
+ InvalidateFlagsPartially((void*)&dynrec_sbb_byte_simple,t_SBBb);
+ gen_call_function_raw((void*)&dynrec_sbb_byte);
+ break;
+ case DOP_CMP:
+ InvalidateFlags((void*)&dynrec_cmp_byte_simple,t_CMPb);
+ gen_call_function_raw((void*)&dynrec_cmp_byte);
+ break;
+ case DOP_XOR:
+ InvalidateFlags((void*)&dynrec_xor_byte_simple,t_XORb);
+ gen_call_function_raw((void*)&dynrec_xor_byte);
+ break;
+ case DOP_AND:
+ InvalidateFlags((void*)&dynrec_and_byte_simple,t_ANDb);
+ gen_call_function_raw((void*)&dynrec_and_byte);
+ break;
+ case DOP_OR:
+ InvalidateFlags((void*)&dynrec_or_byte_simple,t_ORb);
+ gen_call_function_raw((void*)&dynrec_or_byte);
+ break;
+ case DOP_TEST:
+ InvalidateFlags((void*)&dynrec_test_byte_simple,t_TESTb);
+ gen_call_function_raw((void*)&dynrec_test_byte);
+ break;
+ default: IllegalOptionDynrec("dyn_dop_byte_gencall");
+ }
+}
+
+static void dyn_dop_word_gencall(DualOps op,bool dword) {
+ if (dword) {
+ switch (op) {
+ case DOP_ADD:
+ InvalidateFlags((void*)&dynrec_add_dword_simple,t_ADDd);
+ gen_call_function_raw((void*)&dynrec_add_dword);
+ break;
+ case DOP_ADC:
+ AcquireFlags(FLAG_CF);
+ InvalidateFlagsPartially((void*)&dynrec_adc_dword_simple,t_ADCd);
+ gen_call_function_raw((void*)&dynrec_adc_dword);
+ break;
+ case DOP_SUB:
+ InvalidateFlags((void*)&dynrec_sub_dword_simple,t_SUBd);
+ gen_call_function_raw((void*)&dynrec_sub_dword);
+ break;
+ case DOP_SBB:
+ AcquireFlags(FLAG_CF);
+ InvalidateFlagsPartially((void*)&dynrec_sbb_dword_simple,t_SBBd);
+ gen_call_function_raw((void*)&dynrec_sbb_dword);
+ break;
+ case DOP_CMP:
+ InvalidateFlags((void*)&dynrec_cmp_dword_simple,t_CMPd);
+ gen_call_function_raw((void*)&dynrec_cmp_dword);
+ break;
+ case DOP_XOR:
+ InvalidateFlags((void*)&dynrec_xor_dword_simple,t_XORd);
+ gen_call_function_raw((void*)&dynrec_xor_dword);
+ break;
+ case DOP_AND:
+ InvalidateFlags((void*)&dynrec_and_dword_simple,t_ANDd);
+ gen_call_function_raw((void*)&dynrec_and_dword);
+ break;
+ case DOP_OR:
+ InvalidateFlags((void*)&dynrec_or_dword_simple,t_ORd);
+ gen_call_function_raw((void*)&dynrec_or_dword);
+ break;
+ case DOP_TEST:
+ InvalidateFlags((void*)&dynrec_test_dword_simple,t_TESTd);
+ gen_call_function_raw((void*)&dynrec_test_dword);
+ break;
+ default: IllegalOptionDynrec("dyn_dop_dword_gencall");
+ }
+ } else {
+ switch (op) {
+ case DOP_ADD:
+ InvalidateFlags((void*)&dynrec_add_word_simple,t_ADDw);
+ gen_call_function_raw((void*)&dynrec_add_word);
+ break;
+ case DOP_ADC:
+ AcquireFlags(FLAG_CF);
+ InvalidateFlagsPartially((void*)&dynrec_adc_word_simple,t_ADCw);
+ gen_call_function_raw((void*)&dynrec_adc_word);
+ break;
+ case DOP_SUB:
+ InvalidateFlags((void*)&dynrec_sub_word_simple,t_SUBw);
+ gen_call_function_raw((void*)&dynrec_sub_word);
+ break;
+ case DOP_SBB:
+ AcquireFlags(FLAG_CF);
+ InvalidateFlagsPartially((void*)&dynrec_sbb_word_simple,t_SBBw);
+ gen_call_function_raw((void*)&dynrec_sbb_word);
+ break;
+ case DOP_CMP:
+ InvalidateFlags((void*)&dynrec_cmp_word_simple,t_CMPw);
+ gen_call_function_raw((void*)&dynrec_cmp_word);
+ break;
+ case DOP_XOR:
+ InvalidateFlags((void*)&dynrec_xor_word_simple,t_XORw);
+ gen_call_function_raw((void*)&dynrec_xor_word);
+ break;
+ case DOP_AND:
+ InvalidateFlags((void*)&dynrec_and_word_simple,t_ANDw);
+ gen_call_function_raw((void*)&dynrec_and_word);
+ break;
+ case DOP_OR:
+ InvalidateFlags((void*)&dynrec_or_word_simple,t_ORw);
+ gen_call_function_raw((void*)&dynrec_or_word);
+ break;
+ case DOP_TEST:
+ InvalidateFlags((void*)&dynrec_test_word_simple,t_TESTw);
+ gen_call_function_raw((void*)&dynrec_test_word);
+ break;
+ default: IllegalOptionDynrec("dyn_dop_word_gencall");
+ }
+ }
+}
+
+
+static Bit8u DRC_CALL_CONV dynrec_inc_byte(Bit8u op) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_inc_byte(Bit8u op) {
+ LoadCF;
+ lf_var1b=op;
+ lf_resb=lf_var1b+1;
+ lflags.type=t_INCb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_inc_byte_simple(Bit8u op) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_inc_byte_simple(Bit8u op) {
+ return op+1;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_dec_byte(Bit8u op) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_dec_byte(Bit8u op) {
+ LoadCF;
+ lf_var1b=op;
+ lf_resb=lf_var1b-1;
+ lflags.type=t_DECb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_dec_byte_simple(Bit8u op) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_dec_byte_simple(Bit8u op) {
+ return op-1;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_not_byte(Bit8u op) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_not_byte(Bit8u op) {
+ return ~op;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_neg_byte(Bit8u op) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_neg_byte(Bit8u op) {
+ lf_var1b=op;
+ lf_resb=0-lf_var1b;
+ lflags.type=t_NEGb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_neg_byte_simple(Bit8u op) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_neg_byte_simple(Bit8u op) {
+ return 0-op;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_inc_word(Bit16u op) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_inc_word(Bit16u op) {
+ LoadCF;
+ lf_var1w=op;
+ lf_resw=lf_var1w+1;
+ lflags.type=t_INCw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_inc_word_simple(Bit16u op) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_inc_word_simple(Bit16u op) {
+ return op+1;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_dec_word(Bit16u op) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_dec_word(Bit16u op) {
+ LoadCF;
+ lf_var1w=op;
+ lf_resw=lf_var1w-1;
+ lflags.type=t_DECw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_dec_word_simple(Bit16u op) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_dec_word_simple(Bit16u op) {
+ return op-1;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_not_word(Bit16u op) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_not_word(Bit16u op) {
+ return ~op;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_neg_word(Bit16u op) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_neg_word(Bit16u op) {
+ lf_var1w=op;
+ lf_resw=0-lf_var1w;
+ lflags.type=t_NEGw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_neg_word_simple(Bit16u op) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_neg_word_simple(Bit16u op) {
+ return 0-op;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_inc_dword(Bit32u op) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_inc_dword(Bit32u op) {
+ LoadCF;
+ lf_var1d=op;
+ lf_resd=lf_var1d+1;
+ lflags.type=t_INCd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_inc_dword_simple(Bit32u op) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_inc_dword_simple(Bit32u op) {
+ return op+1;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_dec_dword(Bit32u op) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_dec_dword(Bit32u op) {
+ LoadCF;
+ lf_var1d=op;
+ lf_resd=lf_var1d-1;
+ lflags.type=t_DECd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_dec_dword_simple(Bit32u op) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_dec_dword_simple(Bit32u op) {
+ return op-1;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_not_dword(Bit32u op) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_not_dword(Bit32u op) {
+ return ~op;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_neg_dword(Bit32u op) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_neg_dword(Bit32u op) {
+ lf_var1d=op;
+ lf_resd=0-lf_var1d;
+ lflags.type=t_NEGd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_neg_dword_simple(Bit32u op) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_neg_dword_simple(Bit32u op) {
+ return 0-op;
+}
+
+
+static void dyn_sop_byte_gencall(SingleOps op) {
+ switch (op) {
+ case SOP_INC:
+ InvalidateFlagsPartially((void*)&dynrec_inc_byte_simple,t_INCb);
+ gen_call_function_raw((void*)&dynrec_inc_byte);
+ break;
+ case SOP_DEC:
+ InvalidateFlagsPartially((void*)&dynrec_dec_byte_simple,t_DECb);
+ gen_call_function_raw((void*)&dynrec_dec_byte);
+ break;
+ case SOP_NOT:
+ gen_call_function_raw((void*)&dynrec_not_byte);
+ break;
+ case SOP_NEG:
+ InvalidateFlags((void*)&dynrec_neg_byte_simple,t_NEGb);
+ gen_call_function_raw((void*)&dynrec_neg_byte);
+ break;
+ default: IllegalOptionDynrec("dyn_sop_byte_gencall");
+ }
+}
+
+static void dyn_sop_word_gencall(SingleOps op,bool dword) {
+ if (dword) {
+ switch (op) {
+ case SOP_INC:
+ InvalidateFlagsPartially((void*)&dynrec_inc_dword_simple,t_INCd);
+ gen_call_function_raw((void*)&dynrec_inc_dword);
+ break;
+ case SOP_DEC:
+ InvalidateFlagsPartially((void*)&dynrec_dec_dword_simple,t_DECd);
+ gen_call_function_raw((void*)&dynrec_dec_dword);
+ break;
+ case SOP_NOT:
+ gen_call_function_raw((void*)&dynrec_not_dword);
+ break;
+ case SOP_NEG:
+ InvalidateFlags((void*)&dynrec_neg_dword_simple,t_NEGd);
+ gen_call_function_raw((void*)&dynrec_neg_dword);
+ break;
+ default: IllegalOptionDynrec("dyn_sop_dword_gencall");
+ }
+ } else {
+ switch (op) {
+ case SOP_INC:
+ InvalidateFlagsPartially((void*)&dynrec_inc_word_simple,t_INCw);
+ gen_call_function_raw((void*)&dynrec_inc_word);
+ break;
+ case SOP_DEC:
+ InvalidateFlagsPartially((void*)&dynrec_dec_word_simple,t_DECw);
+ gen_call_function_raw((void*)&dynrec_dec_word);
+ break;
+ case SOP_NOT:
+ gen_call_function_raw((void*)&dynrec_not_word);
+ break;
+ case SOP_NEG:
+ InvalidateFlags((void*)&dynrec_neg_word_simple,t_NEGw);
+ gen_call_function_raw((void*)&dynrec_neg_word);
+ break;
+ default: IllegalOptionDynrec("dyn_sop_word_gencall");
+ }
+ }
+}
+
+
+static Bit8u DRC_CALL_CONV dynrec_rol_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_rol_byte(Bit8u op1,Bit8u op2) {
+ if (!(op2&0x7)) {
+ if (op2&0x18) {
+ FillFlagsNoCFOF();
+ SETFLAGBIT(CF,op1 & 1);
+ SETFLAGBIT(OF,(op1 & 1) ^ (op1 >> 7));
+ }
+ return op1;
+ }
+ FillFlagsNoCFOF();
+ lf_var1b=op1;
+ lf_var2b=op2&0x07;
+ lf_resb=(lf_var1b << lf_var2b) | (lf_var1b >> (8-lf_var2b));
+ SETFLAGBIT(CF,lf_resb & 1);
+ SETFLAGBIT(OF,(lf_resb & 1) ^ (lf_resb >> 7));
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_rol_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_rol_byte_simple(Bit8u op1,Bit8u op2) {
+ if (!(op2&0x7)) return op1;
+ return (op1 << (op2&0x07)) | (op1 >> (8-(op2&0x07)));
+}
+
+static Bit8u DRC_CALL_CONV dynrec_ror_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_ror_byte(Bit8u op1,Bit8u op2) {
+ if (!(op2&0x7)) {
+ if (op2&0x18) {
+ FillFlagsNoCFOF();
+ SETFLAGBIT(CF,op1>>7);
+ SETFLAGBIT(OF,(op1>>7) ^ ((op1>>6) & 1));
+ }
+ return op1;
+ }
+ FillFlagsNoCFOF();
+ lf_var1b=op1;
+ lf_var2b=op2&0x07;
+ lf_resb=(lf_var1b >> lf_var2b) | (lf_var1b << (8-lf_var2b));
+ SETFLAGBIT(CF,lf_resb & 0x80);
+ SETFLAGBIT(OF,(lf_resb ^ (lf_resb<<1)) & 0x80);
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_ror_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_ror_byte_simple(Bit8u op1,Bit8u op2) {
+ if (!(op2&0x7)) return op1;
+ return (op1 >> (op2&0x07)) | (op1 << (8-(op2&0x07)));
+}
+
+static Bit8u DRC_CALL_CONV dynrec_rcl_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_rcl_byte(Bit8u op1,Bit8u op2) {
+ if (op2%9) {
+ Bit8u cf=(Bit8u)FillFlags()&0x1;
+ lf_var1b=op1;
+ lf_var2b=op2%9;
+ lf_resb=(lf_var1b << lf_var2b) | (cf << (lf_var2b-1)) | (lf_var1b >> (9-lf_var2b));
+ SETFLAGBIT(CF,((lf_var1b >> (8-lf_var2b)) & 1));
+ SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resb >> 7));
+ return lf_resb;
+ } else return op1;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_rcr_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_rcr_byte(Bit8u op1,Bit8u op2) {
+ if (op2%9) {
+ Bit8u cf=(Bit8u)FillFlags()&0x1;
+ lf_var1b=op1;
+ lf_var2b=op2%9;
+ lf_resb=(lf_var1b >> lf_var2b) | (cf << (8-lf_var2b)) | (lf_var1b << (9-lf_var2b)); \
+ SETFLAGBIT(CF,(lf_var1b >> (lf_var2b - 1)) & 1);
+ SETFLAGBIT(OF,(lf_resb ^ (lf_resb<<1)) & 0x80);
+ return lf_resb;
+ } else return op1;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_shl_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_shl_byte(Bit8u op1,Bit8u op2) {
+ if (!op2) return op1;
+ lf_var1b=op1;
+ lf_var2b=op2;
+ lf_resb=lf_var1b << lf_var2b;
+ lflags.type=t_SHLb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_shl_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_shl_byte_simple(Bit8u op1,Bit8u op2) {
+ if (!op2) return op1;
+ return op1 << op2;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_shr_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_shr_byte(Bit8u op1,Bit8u op2) {
+ if (!op2) return op1;
+ lf_var1b=op1;
+ lf_var2b=op2;
+ lf_resb=lf_var1b >> lf_var2b;
+ lflags.type=t_SHRb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_shr_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_shr_byte_simple(Bit8u op1,Bit8u op2) {
+ if (!op2) return op1;
+ return op1 >> op2;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_sar_byte(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_sar_byte(Bit8u op1,Bit8u op2) {
+ if (!op2) return op1;
+ lf_var1b=op1;
+ lf_var2b=op2;
+ if (lf_var2b>8) lf_var2b=8;
+ if (lf_var1b & 0x80) {
+ lf_resb=(lf_var1b >> lf_var2b)| (0xff << (8 - lf_var2b));
+ } else {
+ lf_resb=lf_var1b >> lf_var2b;
+ }
+ lflags.type=t_SARb;
+ return lf_resb;
+}
+
+static Bit8u DRC_CALL_CONV dynrec_sar_byte_simple(Bit8u op1,Bit8u op2) DRC_FC;
+static Bit8u DRC_CALL_CONV dynrec_sar_byte_simple(Bit8u op1,Bit8u op2) {
+ if (!op2) return op1;
+ if (op2>8) op2=8;
+ if (op1 & 0x80) return (op1 >> op2) | (0xff << (8 - op2));
+ else return op1 >> op2;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_rol_word(Bit16u op1,Bit8u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_rol_word(Bit16u op1,Bit8u op2) {
+ if (!(op2&0xf)) {
+ if (op2&0x10) {
+ FillFlagsNoCFOF();
+ SETFLAGBIT(CF,op1 & 1);
+ SETFLAGBIT(OF,(op1 & 1) ^ (op1 >> 15));
+ }
+ return op1;
+ }
+ FillFlagsNoCFOF();
+ lf_var1w=op1;
+ lf_var2b=op2&0xf;
+ lf_resw=(lf_var1w << lf_var2b) | (lf_var1w >> (16-lf_var2b));
+ SETFLAGBIT(CF,lf_resw & 1);
+ SETFLAGBIT(OF,(lf_resw & 1) ^ (lf_resw >> 15));
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_rol_word_simple(Bit16u op1,Bit8u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_rol_word_simple(Bit16u op1,Bit8u op2) {
+ if (!(op2&0xf)) return op1;
+ return (op1 << (op2&0xf)) | (op1 >> (16-(op2&0xf)));
+}
+
+static Bit16u DRC_CALL_CONV dynrec_ror_word(Bit16u op1,Bit8u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_ror_word(Bit16u op1,Bit8u op2) {
+ if (!(op2&0xf)) {
+ if (op2&0x10) {
+ FillFlagsNoCFOF();
+ SETFLAGBIT(CF,op1>>15);
+ SETFLAGBIT(OF,(op1>>15) ^ ((op1>>14) & 1));
+ }
+ return op1;
+ }
+ FillFlagsNoCFOF();
+ lf_var1w=op1;
+ lf_var2b=op2&0xf;
+ lf_resw=(lf_var1w >> lf_var2b) | (lf_var1w << (16-lf_var2b));
+ SETFLAGBIT(CF,lf_resw & 0x8000);
+ SETFLAGBIT(OF,(lf_resw ^ (lf_resw<<1)) & 0x8000);
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_ror_word_simple(Bit16u op1,Bit8u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_ror_word_simple(Bit16u op1,Bit8u op2) {
+ if (!(op2&0xf)) return op1;
+ return (op1 >> (op2&0xf)) | (op1 << (16-(op2&0xf)));
+}
+
+static Bit16u DRC_CALL_CONV dynrec_rcl_word(Bit16u op1,Bit8u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_rcl_word(Bit16u op1,Bit8u op2) {
+ if (op2%17) {
+ Bit16u cf=(Bit16u)FillFlags()&0x1;
+ lf_var1w=op1;
+ lf_var2b=op2%17;
+ lf_resw=(lf_var1w << lf_var2b) | (cf << (lf_var2b-1)) | (lf_var1w >> (17-lf_var2b));
+ SETFLAGBIT(CF,((lf_var1w >> (16-lf_var2b)) & 1));
+ SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resw >> 15));
+ return lf_resw;
+ } else return op1;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_rcr_word(Bit16u op1,Bit8u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_rcr_word(Bit16u op1,Bit8u op2) {
+ if (op2%17) {
+ Bit16u cf=(Bit16u)FillFlags()&0x1;
+ lf_var1w=op1;
+ lf_var2b=op2%17;
+ lf_resw=(lf_var1w >> lf_var2b) | (cf << (16-lf_var2b)) | (lf_var1w << (17-lf_var2b));
+ SETFLAGBIT(CF,(lf_var1w >> (lf_var2b - 1)) & 1);
+ SETFLAGBIT(OF,(lf_resw ^ (lf_resw<<1)) & 0x8000);
+ return lf_resw;
+ } else return op1;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_shl_word(Bit16u op1,Bit8u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_shl_word(Bit16u op1,Bit8u op2) {
+ if (!op2) return op1;
+ lf_var1w=op1;
+ lf_var2b=op2;
+ lf_resw=lf_var1w << lf_var2b;
+ lflags.type=t_SHLw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_shl_word_simple(Bit16u op1,Bit8u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_shl_word_simple(Bit16u op1,Bit8u op2) {
+ if (!op2) return op1;
+ return op1 << op2;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_shr_word(Bit16u op1,Bit8u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_shr_word(Bit16u op1,Bit8u op2) {
+ if (!op2) return op1;
+ lf_var1w=op1;
+ lf_var2b=op2;
+ lf_resw=lf_var1w >> lf_var2b;
+ lflags.type=t_SHRw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_shr_word_simple(Bit16u op1,Bit8u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_shr_word_simple(Bit16u op1,Bit8u op2) {
+ if (!op2) return op1;
+ return op1 >> op2;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_sar_word(Bit16u op1,Bit8u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_sar_word(Bit16u op1,Bit8u op2) {
+ if (!op2) return op1;
+ lf_var1w=op1;
+ lf_var2b=op2;
+ if (lf_var2b>16) lf_var2b=16;
+ if (lf_var1w & 0x8000) {
+ lf_resw=(lf_var1w >> lf_var2b) | (0xffff << (16 - lf_var2b));
+ } else {
+ lf_resw=lf_var1w >> lf_var2b;
+ }
+ lflags.type=t_SARw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_sar_word_simple(Bit16u op1,Bit8u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_sar_word_simple(Bit16u op1,Bit8u op2) {
+ if (!op2) return op1;
+ if (op2>16) op2=16;
+ if (op1 & 0x8000) return (op1 >> op2) | (0xffff << (16 - op2));
+ else return op1 >> op2;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_rol_dword(Bit32u op1,Bit8u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_rol_dword(Bit32u op1,Bit8u op2) {
+ if (!op2) return op1;
+ FillFlagsNoCFOF();
+ lf_var1d=op1;
+ lf_var2b=op2;
+ lf_resd=(lf_var1d << lf_var2b) | (lf_var1d >> (32-lf_var2b));
+ SETFLAGBIT(CF,lf_resd & 1);
+ SETFLAGBIT(OF,(lf_resd & 1) ^ (lf_resd >> 31));
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_rol_dword_simple(Bit32u op1,Bit8u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_rol_dword_simple(Bit32u op1,Bit8u op2) {
+ if (!op2) return op1;
+ return (op1 << op2) | (op1 >> (32-op2));
+}
+
+static Bit32u DRC_CALL_CONV dynrec_ror_dword(Bit32u op1,Bit8u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_ror_dword(Bit32u op1,Bit8u op2) {
+ if (!op2) return op1;
+ FillFlagsNoCFOF();
+ lf_var1d=op1;
+ lf_var2b=op2;
+ lf_resd=(lf_var1d >> lf_var2b) | (lf_var1d << (32-lf_var2b));
+ SETFLAGBIT(CF,lf_resd & 0x80000000);
+ SETFLAGBIT(OF,(lf_resd ^ (lf_resd<<1)) & 0x80000000);
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_ror_dword_simple(Bit32u op1,Bit8u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_ror_dword_simple(Bit32u op1,Bit8u op2) {
+ if (!op2) return op1;
+ return (op1 >> op2) | (op1 << (32-op2));
+}
+
+static Bit32u DRC_CALL_CONV dynrec_rcl_dword(Bit32u op1,Bit8u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_rcl_dword(Bit32u op1,Bit8u op2) {
+ if (!op2) return op1;
+ Bit32u cf=(Bit32u)FillFlags()&0x1;
+ lf_var1d=op1;
+ lf_var2b=op2;
+ if (lf_var2b==1) {
+ lf_resd=(lf_var1d << 1) | cf;
+ } else {
+ lf_resd=(lf_var1d << lf_var2b) | (cf << (lf_var2b-1)) | (lf_var1d >> (33-lf_var2b));
+ }
+ SETFLAGBIT(CF,((lf_var1d >> (32-lf_var2b)) & 1));
+ SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resd >> 31));
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_rcr_dword(Bit32u op1,Bit8u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_rcr_dword(Bit32u op1,Bit8u op2) {
+ if (op2) {
+ Bit32u cf=(Bit32u)FillFlags()&0x1;
+ lf_var1d=op1;
+ lf_var2b=op2;
+ if (lf_var2b==1) {
+ lf_resd=lf_var1d >> 1 | cf << 31;
+ } else {
+ lf_resd=(lf_var1d >> lf_var2b) | (cf << (32-lf_var2b)) | (lf_var1d << (33-lf_var2b));
+ }
+ SETFLAGBIT(CF,(lf_var1d >> (lf_var2b - 1)) & 1);
+ SETFLAGBIT(OF,(lf_resd ^ (lf_resd<<1)) & 0x80000000);
+ return lf_resd;
+ } else return op1;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_shl_dword(Bit32u op1,Bit8u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_shl_dword(Bit32u op1,Bit8u op2) {
+ if (!op2) return op1;
+ lf_var1d=op1;
+ lf_var2b=op2;
+ lf_resd=lf_var1d << lf_var2b;
+ lflags.type=t_SHLd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_shl_dword_simple(Bit32u op1,Bit8u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_shl_dword_simple(Bit32u op1,Bit8u op2) {
+ if (!op2) return op1;
+ return op1 << op2;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_shr_dword(Bit32u op1,Bit8u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_shr_dword(Bit32u op1,Bit8u op2) {
+ if (!op2) return op1;
+ lf_var1d=op1;
+ lf_var2b=op2;
+ lf_resd=lf_var1d >> lf_var2b;
+ lflags.type=t_SHRd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_shr_dword_simple(Bit32u op1,Bit8u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_shr_dword_simple(Bit32u op1,Bit8u op2) {
+ if (!op2) return op1;
+ return op1 >> op2;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_sar_dword(Bit32u op1,Bit8u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_sar_dword(Bit32u op1,Bit8u op2) {
+ if (!op2) return op1;
+ lf_var2b=op2;
+ lf_var1d=op1;
+ if (lf_var1d & 0x80000000) {
+ lf_resd=(lf_var1d >> lf_var2b) | (0xffffffff << (32 - lf_var2b));
+ } else {
+ lf_resd=lf_var1d >> lf_var2b;
+ }
+ lflags.type=t_SARd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_sar_dword_simple(Bit32u op1,Bit8u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_sar_dword_simple(Bit32u op1,Bit8u op2) {
+ if (!op2) return op1;
+ if (op1 & 0x80000000) return (op1 >> op2) | (0xffffffff << (32 - op2));
+ else return op1 >> op2;
+}
+
+static void dyn_shift_byte_gencall(ShiftOps op) {
+ switch (op) {
+ case SHIFT_ROL:
+ InvalidateFlagsPartially((void*)&dynrec_rol_byte_simple,t_ROLb);
+ gen_call_function_raw((void*)&dynrec_rol_byte);
+ break;
+ case SHIFT_ROR:
+ InvalidateFlagsPartially((void*)&dynrec_ror_byte_simple,t_RORb);
+ gen_call_function_raw((void*)&dynrec_ror_byte);
+ break;
+ case SHIFT_RCL:
+ AcquireFlags(FLAG_CF);
+ gen_call_function_raw((void*)&dynrec_rcl_byte);
+ break;
+ case SHIFT_RCR:
+ AcquireFlags(FLAG_CF);
+ gen_call_function_raw((void*)&dynrec_rcr_byte);
+ break;
+ case SHIFT_SHL:
+ case SHIFT_SAL:
+ InvalidateFlagsPartially((void*)&dynrec_shl_byte_simple,t_SHLb);
+ gen_call_function_raw((void*)&dynrec_shl_byte);
+ break;
+ case SHIFT_SHR:
+ InvalidateFlagsPartially((void*)&dynrec_shr_byte_simple,t_SHRb);
+ gen_call_function_raw((void*)&dynrec_shr_byte);
+ break;
+ case SHIFT_SAR:
+ InvalidateFlagsPartially((void*)&dynrec_sar_byte_simple,t_SARb);
+ gen_call_function_raw((void*)&dynrec_sar_byte);
+ break;
+ default: IllegalOptionDynrec("dyn_shift_byte_gencall");
+ }
+}
+
+static void dyn_shift_word_gencall(ShiftOps op,bool dword) {
+ if (dword) {
+ switch (op) {
+ case SHIFT_ROL:
+ InvalidateFlagsPartially((void*)&dynrec_rol_dword_simple,t_ROLd);
+ gen_call_function_raw((void*)&dynrec_rol_dword);
+ break;
+ case SHIFT_ROR:
+ InvalidateFlagsPartially((void*)&dynrec_ror_dword_simple,t_RORd);
+ gen_call_function_raw((void*)&dynrec_ror_dword);
+ break;
+ case SHIFT_RCL:
+ AcquireFlags(FLAG_CF);
+ gen_call_function_raw((void*)&dynrec_rcl_dword);
+ break;
+ case SHIFT_RCR:
+ AcquireFlags(FLAG_CF);
+ gen_call_function_raw((void*)&dynrec_rcr_dword);
+ break;
+ case SHIFT_SHL:
+ case SHIFT_SAL:
+ InvalidateFlagsPartially((void*)&dynrec_shl_dword_simple,t_SHLd);
+ gen_call_function_raw((void*)&dynrec_shl_dword);
+ break;
+ case SHIFT_SHR:
+ InvalidateFlagsPartially((void*)&dynrec_shr_dword_simple,t_SHRd);
+ gen_call_function_raw((void*)&dynrec_shr_dword);
+ break;
+ case SHIFT_SAR:
+ InvalidateFlagsPartially((void*)&dynrec_sar_dword_simple,t_SARd);
+ gen_call_function_raw((void*)&dynrec_sar_dword);
+ break;
+ default: IllegalOptionDynrec("dyn_shift_dword_gencall");
+ }
+ } else {
+ switch (op) {
+ case SHIFT_ROL:
+ InvalidateFlagsPartially((void*)&dynrec_rol_word_simple,t_ROLw);
+ gen_call_function_raw((void*)&dynrec_rol_word);
+ break;
+ case SHIFT_ROR:
+ InvalidateFlagsPartially((void*)&dynrec_ror_word_simple,t_RORw);
+ gen_call_function_raw((void*)&dynrec_ror_word);
+ break;
+ case SHIFT_RCL:
+ AcquireFlags(FLAG_CF);
+ gen_call_function_raw((void*)&dynrec_rcl_word);
+ break;
+ case SHIFT_RCR:
+ AcquireFlags(FLAG_CF);
+ gen_call_function_raw((void*)&dynrec_rcr_word);
+ break;
+ case SHIFT_SHL:
+ case SHIFT_SAL:
+ InvalidateFlagsPartially((void*)&dynrec_shl_word_simple,t_SHLw);
+ gen_call_function_raw((void*)&dynrec_shl_word);
+ break;
+ case SHIFT_SHR:
+ InvalidateFlagsPartially((void*)&dynrec_shr_word_simple,t_SHRw);
+ gen_call_function_raw((void*)&dynrec_shr_word);
+ break;
+ case SHIFT_SAR:
+ InvalidateFlagsPartially((void*)&dynrec_sar_word_simple,t_SARw);
+ gen_call_function_raw((void*)&dynrec_sar_word);
+ break;
+ default: IllegalOptionDynrec("dyn_shift_word_gencall");
+ }
+ }
+}
+
+static Bit16u DRC_CALL_CONV dynrec_dshl_word(Bit16u op1,Bit16u op2,Bit8u op3) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_dshl_word(Bit16u op1,Bit16u op2,Bit8u op3) {
+ Bit8u val=op3 & 0x1f;
+ if (!val) return op1;
+ lf_var2b=val;
+ lf_var1d=(op1<<16)|op2;
+ Bit32u tempd=lf_var1d << lf_var2b;
+ if (lf_var2b>16) tempd |= (op2 << (lf_var2b - 16));
+ lf_resw=(Bit16u)(tempd >> 16);
+ lflags.type=t_DSHLw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_dshl_word_simple(Bit16u op1,Bit16u op2,Bit8u op3) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_dshl_word_simple(Bit16u op1,Bit16u op2,Bit8u op3) {
+ Bit8u val=op3 & 0x1f;
+ if (!val) return op1;
+ Bit32u tempd=(Bit32u)((((Bit32u)op1)<<16)|op2) << val;
+ if (val>16) tempd |= (op2 << (val - 16));
+ return (Bit16u)(tempd >> 16);
+}
+
+static Bit32u DRC_CALL_CONV dynrec_dshl_dword(Bit32u op1,Bit32u op2,Bit8u op3) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_dshl_dword(Bit32u op1,Bit32u op2,Bit8u op3) {
+ Bit8u val=op3 & 0x1f;
+ if (!val) return op1;
+ lf_var2b=val;
+ lf_var1d=op1;
+ lf_resd=(lf_var1d << lf_var2b) | (op2 >> (32-lf_var2b));
+ lflags.type=t_DSHLd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_dshl_dword_simple(Bit32u op1,Bit32u op2,Bit8u op3) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_dshl_dword_simple(Bit32u op1,Bit32u op2,Bit8u op3) {
+ Bit8u val=op3 & 0x1f;
+ if (!val) return op1;
+ return (op1 << val) | (op2 >> (32-val));
+}
+
+static Bit16u DRC_CALL_CONV dynrec_dshr_word(Bit16u op1,Bit16u op2,Bit8u op3) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_dshr_word(Bit16u op1,Bit16u op2,Bit8u op3) {
+ Bit8u val=op3 & 0x1f;
+ if (!val) return op1;
+ lf_var2b=val;
+ lf_var1d=(op2<<16)|op1;
+ Bit32u tempd=lf_var1d >> lf_var2b;
+ if (lf_var2b>16) tempd |= (op2 << (32-lf_var2b ));
+ lf_resw=(Bit16u)(tempd);
+ lflags.type=t_DSHRw;
+ return lf_resw;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_dshr_word_simple(Bit16u op1,Bit16u op2,Bit8u op3) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_dshr_word_simple(Bit16u op1,Bit16u op2,Bit8u op3) {
+ Bit8u val=op3 & 0x1f;
+ if (!val) return op1;
+ Bit32u tempd=(Bit32u)((((Bit32u)op2)<<16)|op1) >> val;
+ if (val>16) tempd |= (op2 << (32-val));
+ return (Bit16u)(tempd);
+}
+
+static Bit32u DRC_CALL_CONV dynrec_dshr_dword(Bit32u op1,Bit32u op2,Bit8u op3) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_dshr_dword(Bit32u op1,Bit32u op2,Bit8u op3) {
+ Bit8u val=op3 & 0x1f;
+ if (!val) return op1;
+ lf_var2b=val;
+ lf_var1d=op1;
+ lf_resd=(lf_var1d >> lf_var2b) | (op2 << (32-lf_var2b));
+ lflags.type=t_DSHRd;
+ return lf_resd;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_dshr_dword_simple(Bit32u op1,Bit32u op2,Bit8u op3) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_dshr_dword_simple(Bit32u op1,Bit32u op2,Bit8u op3) {
+ Bit8u val=op3 & 0x1f;
+ if (!val) return op1;
+ return (op1 >> val) | (op2 << (32-val));
+}
+
+static void dyn_dpshift_word_gencall(bool left) {
+ if (left) {
+ DRC_PTR_SIZE_IM proc_addr=gen_call_function_R3((void*)&dynrec_dshl_word,FC_OP3);
+ InvalidateFlagsPartially((void*)&dynrec_dshl_word_simple,proc_addr,t_DSHLw);
+ } else {
+ DRC_PTR_SIZE_IM proc_addr=gen_call_function_R3((void*)&dynrec_dshr_word,FC_OP3);
+ InvalidateFlagsPartially((void*)&dynrec_dshr_word_simple,proc_addr,t_DSHRw);
+ }
+}
+
+static void dyn_dpshift_dword_gencall(bool left) {
+ if (left) {
+ DRC_PTR_SIZE_IM proc_addr=gen_call_function_R3((void*)&dynrec_dshl_dword,FC_OP3);
+ InvalidateFlagsPartially((void*)&dynrec_dshl_dword_simple,proc_addr,t_DSHLd);
+ } else {
+ DRC_PTR_SIZE_IM proc_addr=gen_call_function_R3((void*)&dynrec_dshr_dword,FC_OP3);
+ InvalidateFlagsPartially((void*)&dynrec_dshr_dword_simple,proc_addr,t_DSHRd);
+ }
+}
+
+
+
+static Bit32u DRC_CALL_CONV dynrec_get_of(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_of(void) { return TFLG_O; }
+static Bit32u DRC_CALL_CONV dynrec_get_nof(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_nof(void) { return TFLG_NO; }
+static Bit32u DRC_CALL_CONV dynrec_get_cf(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_cf(void) { return TFLG_B; }
+static Bit32u DRC_CALL_CONV dynrec_get_ncf(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_ncf(void) { return TFLG_NB; }
+static Bit32u DRC_CALL_CONV dynrec_get_zf(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_zf(void) { return TFLG_Z; }
+static Bit32u DRC_CALL_CONV dynrec_get_nzf(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_nzf(void) { return TFLG_NZ; }
+static Bit32u DRC_CALL_CONV dynrec_get_sf(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_sf(void) { return TFLG_S; }
+static Bit32u DRC_CALL_CONV dynrec_get_nsf(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_nsf(void) { return TFLG_NS; }
+static Bit32u DRC_CALL_CONV dynrec_get_pf(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_pf(void) { return TFLG_P; }
+static Bit32u DRC_CALL_CONV dynrec_get_npf(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_npf(void) { return TFLG_NP; }
+
+static Bit32u DRC_CALL_CONV dynrec_get_cf_or_zf(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_cf_or_zf(void) { return TFLG_BE; }
+static Bit32u DRC_CALL_CONV dynrec_get_ncf_and_nzf(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_ncf_and_nzf(void) { return TFLG_NBE; }
+static Bit32u DRC_CALL_CONV dynrec_get_sf_neq_of(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_sf_neq_of(void) { return TFLG_L; }
+static Bit32u DRC_CALL_CONV dynrec_get_sf_eq_of(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_sf_eq_of(void) { return TFLG_NL; }
+static Bit32u DRC_CALL_CONV dynrec_get_zf_or_sf_neq_of(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_zf_or_sf_neq_of(void) { return TFLG_LE; }
+static Bit32u DRC_CALL_CONV dynrec_get_nzf_and_sf_eq_of(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_get_nzf_and_sf_eq_of(void) { return TFLG_NLE; }
+
+
+static void dyn_branchflag_to_reg(BranchTypes btype) {
+ switch (btype) {
+ case BR_O:gen_call_function_raw((void*)&dynrec_get_of);break;
+ case BR_NO:gen_call_function_raw((void*)&dynrec_get_nof);break;
+ case BR_B:gen_call_function_raw((void*)&dynrec_get_cf);break;
+ case BR_NB:gen_call_function_raw((void*)&dynrec_get_ncf);break;
+ case BR_Z:gen_call_function_raw((void*)&dynrec_get_zf);break;
+ case BR_NZ:gen_call_function_raw((void*)&dynrec_get_nzf);break;
+ case BR_BE:gen_call_function_raw((void*)&dynrec_get_cf_or_zf);break;
+ case BR_NBE:gen_call_function_raw((void*)&dynrec_get_ncf_and_nzf);break;
+
+ case BR_S:gen_call_function_raw((void*)&dynrec_get_sf);break;
+ case BR_NS:gen_call_function_raw((void*)&dynrec_get_nsf);break;
+ case BR_P:gen_call_function_raw((void*)&dynrec_get_pf);break;
+ case BR_NP:gen_call_function_raw((void*)&dynrec_get_npf);break;
+ case BR_L:gen_call_function_raw((void*)&dynrec_get_sf_neq_of);break;
+ case BR_NL:gen_call_function_raw((void*)&dynrec_get_sf_eq_of);break;
+ case BR_LE:gen_call_function_raw((void*)&dynrec_get_zf_or_sf_neq_of);break;
+ case BR_NLE:gen_call_function_raw((void*)&dynrec_get_nzf_and_sf_eq_of);break;
+ }
+}
+
+
+static void DRC_CALL_CONV dynrec_mul_byte(Bit8u op) DRC_FC;
+static void DRC_CALL_CONV dynrec_mul_byte(Bit8u op) {
+ FillFlagsNoCFOF();
+ reg_ax=reg_al*op;
+ SETFLAGBIT(ZF,reg_al == 0);
+ if (reg_ax & 0xff00) {
+ SETFLAGBIT(CF,true);
+ SETFLAGBIT(OF,true);
+ } else {
+ SETFLAGBIT(CF,false);
+ SETFLAGBIT(OF,false);
+ }
+}
+
+static void DRC_CALL_CONV dynrec_imul_byte(Bit8u op) DRC_FC;
+static void DRC_CALL_CONV dynrec_imul_byte(Bit8u op) {
+ FillFlagsNoCFOF();
+ reg_ax=((Bit8s)reg_al) * ((Bit8s)op);
+ if ((reg_ax & 0xff80)==0xff80 || (reg_ax & 0xff80)==0x0000) {
+ SETFLAGBIT(CF,false);
+ SETFLAGBIT(OF,false);
+ } else {
+ SETFLAGBIT(CF,true);
+ SETFLAGBIT(OF,true);
+ }
+}
+
+static void DRC_CALL_CONV dynrec_mul_word(Bit16u op) DRC_FC;
+static void DRC_CALL_CONV dynrec_mul_word(Bit16u op) {
+ FillFlagsNoCFOF();
+ Bitu tempu=(Bitu)reg_ax*(Bitu)op;
+ reg_ax=(Bit16u)(tempu);
+ reg_dx=(Bit16u)(tempu >> 16);
+ SETFLAGBIT(ZF,reg_ax == 0);
+ if (reg_dx) {
+ SETFLAGBIT(CF,true);
+ SETFLAGBIT(OF,true);
+ } else {
+ SETFLAGBIT(CF,false);
+ SETFLAGBIT(OF,false);
+ }
+}
+
+static void DRC_CALL_CONV dynrec_imul_word(Bit16u op) DRC_FC;
+static void DRC_CALL_CONV dynrec_imul_word(Bit16u op) {
+ FillFlagsNoCFOF();
+ Bits temps=((Bit16s)reg_ax)*((Bit16s)op);
+ reg_ax=(Bit16s)(temps);
+ reg_dx=(Bit16s)(temps >> 16);
+ if (((temps & 0xffff8000)==0xffff8000 || (temps & 0xffff8000)==0x0000)) {
+ SETFLAGBIT(CF,false);
+ SETFLAGBIT(OF,false);
+ } else {
+ SETFLAGBIT(CF,true);
+ SETFLAGBIT(OF,true);
+ }
+}
+
+static void DRC_CALL_CONV dynrec_mul_dword(Bit32u op) DRC_FC;
+static void DRC_CALL_CONV dynrec_mul_dword(Bit32u op) {
+ FillFlagsNoCFOF();
+ Bit64u tempu=(Bit64u)reg_eax*(Bit64u)op;
+ reg_eax=(Bit32u)(tempu);
+ reg_edx=(Bit32u)(tempu >> 32);
+ SETFLAGBIT(ZF,reg_eax == 0);
+ if (reg_edx) {
+ SETFLAGBIT(CF,true);
+ SETFLAGBIT(OF,true);
+ } else {
+ SETFLAGBIT(CF,false);
+ SETFLAGBIT(OF,false);
+ }
+}
+
+static void DRC_CALL_CONV dynrec_imul_dword(Bit32u op) DRC_FC;
+static void DRC_CALL_CONV dynrec_imul_dword(Bit32u op) {
+ FillFlagsNoCFOF();
+ Bit64s temps=((Bit64s)((Bit32s)reg_eax))*((Bit64s)((Bit32s)op));
+ reg_eax=(Bit32u)(temps);
+ reg_edx=(Bit32u)(temps >> 32);
+ if ((reg_edx==0xffffffff) && (reg_eax & 0x80000000) ) {
+ SETFLAGBIT(CF,false);
+ SETFLAGBIT(OF,false);
+ } else if ( (reg_edx==0x00000000) && (reg_eax< 0x80000000) ) {
+ SETFLAGBIT(CF,false);
+ SETFLAGBIT(OF,false);
+ } else {
+ SETFLAGBIT(CF,true);
+ SETFLAGBIT(OF,true);
+ }
+}
+
+
+static bool DRC_CALL_CONV dynrec_div_byte(Bit8u op) DRC_FC;
+static bool DRC_CALL_CONV dynrec_div_byte(Bit8u op) {
+ Bitu val=op;
+ if (val==0) return CPU_PrepareException(0,0);
+ Bitu quo=reg_ax / val;
+ Bit8u rem=(Bit8u)(reg_ax % val);
+ Bit8u quo8=(Bit8u)(quo&0xff);
+ if (quo>0xff) return CPU_PrepareException(0,0);
+ reg_ah=rem;
+ reg_al=quo8;
+ return false;
+}
+
+static bool DRC_CALL_CONV dynrec_idiv_byte(Bit8u op) DRC_FC;
+static bool DRC_CALL_CONV dynrec_idiv_byte(Bit8u op) {
+ Bits val=(Bit8s)op;
+ if (val==0) return CPU_PrepareException(0,0);
+ Bits quo=((Bit16s)reg_ax) / val;
+ Bit8s rem=(Bit8s)((Bit16s)reg_ax % val);
+ Bit8s quo8s=(Bit8s)(quo&0xff);
+ if (quo!=(Bit16s)quo8s) return CPU_PrepareException(0,0);
+ reg_ah=rem;
+ reg_al=quo8s;
+ return false;
+}
+
+static bool DRC_CALL_CONV dynrec_div_word(Bit16u op) DRC_FC;
+static bool DRC_CALL_CONV dynrec_div_word(Bit16u op) {
+ Bitu val=op;
+ if (val==0) return CPU_PrepareException(0,0);
+ Bitu num=((Bit32u)reg_dx<<16)|reg_ax;
+ Bitu quo=num/val;
+ Bit16u rem=(Bit16u)(num % val);
+ Bit16u quo16=(Bit16u)(quo&0xffff);
+ if (quo!=(Bit32u)quo16) return CPU_PrepareException(0,0);
+ reg_dx=rem;
+ reg_ax=quo16;
+ return false;
+}
+
+static bool DRC_CALL_CONV dynrec_idiv_word(Bit16u op) DRC_FC;
+static bool DRC_CALL_CONV dynrec_idiv_word(Bit16u op) {
+ Bits val=(Bit16s)op;
+ if (val==0) return CPU_PrepareException(0,0);
+ Bits num=(Bit32s)((reg_dx<<16)|reg_ax);
+ Bits quo=num/val;
+ Bit16s rem=(Bit16s)(num % val);
+ Bit16s quo16s=(Bit16s)quo;
+ if (quo!=(Bit32s)quo16s) return CPU_PrepareException(0,0);
+ reg_dx=rem;
+ reg_ax=quo16s;
+ return false;
+}
+
+static bool DRC_CALL_CONV dynrec_div_dword(Bit32u op) DRC_FC;
+static bool DRC_CALL_CONV dynrec_div_dword(Bit32u op) {
+ Bitu val=op;
+ if (val==0) return CPU_PrepareException(0,0);
+ Bit64u num=(((Bit64u)reg_edx)<<32)|reg_eax;
+ Bit64u quo=num/val;
+ Bit32u rem=(Bit32u)(num % val);
+ Bit32u quo32=(Bit32u)(quo&0xffffffff);
+ if (quo!=(Bit64u)quo32) return CPU_PrepareException(0,0);
+ reg_edx=rem;
+ reg_eax=quo32;
+ return false;
+}
+
+static bool DRC_CALL_CONV dynrec_idiv_dword(Bit32u op) DRC_FC;
+static bool DRC_CALL_CONV dynrec_idiv_dword(Bit32u op) {
+ Bits val=(Bit32s)op;
+ if (val==0) return CPU_PrepareException(0,0);
+ Bit64s num=(((Bit64u)reg_edx)<<32)|reg_eax;
+ Bit64s quo=num/val;
+ Bit32s rem=(Bit32s)(num % val);
+ Bit32s quo32s=(Bit32s)(quo&0xffffffff);
+ if (quo!=(Bit64s)quo32s) return CPU_PrepareException(0,0);
+ reg_edx=rem;
+ reg_eax=quo32s;
+ return false;
+}
+
+
+static Bit16u DRC_CALL_CONV dynrec_dimul_word(Bit16u op1,Bit16u op2) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_dimul_word(Bit16u op1,Bit16u op2) {
+ FillFlagsNoCFOF();
+ Bits res=((Bit16s)op1) * ((Bit16s)op2);
+ if ((res>-32768) && (res<32767)) {
+ SETFLAGBIT(CF,false);
+ SETFLAGBIT(OF,false);
+ } else {
+ SETFLAGBIT(CF,true);
+ SETFLAGBIT(OF,true);
+ }
+ return (Bit16u)(res & 0xffff);
+}
+
+static Bit32u DRC_CALL_CONV dynrec_dimul_dword(Bit32u op1,Bit32u op2) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_dimul_dword(Bit32u op1,Bit32u op2) {
+ FillFlagsNoCFOF();
+ Bit64s res=((Bit64s)((Bit32s)op1))*((Bit64s)((Bit32s)op2));
+ if ((res>-((Bit64s)(2147483647)+1)) && (res<(Bit64s)2147483647)) {
+ SETFLAGBIT(CF,false);
+ SETFLAGBIT(OF,false);
+ } else {
+ SETFLAGBIT(CF,true);
+ SETFLAGBIT(OF,true);
+ }
+ return (Bit32s)res;
+}
+
+
+
+static Bit16u DRC_CALL_CONV dynrec_cbw(Bit8u op) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_cbw(Bit8u op) {
+ return (Bit8s)op;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_cwde(Bit16u op) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_cwde(Bit16u op) {
+ return (Bit16s)op;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_cwd(Bit16u op) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_cwd(Bit16u op) {
+ if (op & 0x8000) return 0xffff;
+ else return 0;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_cdq(Bit32u op) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_cdq(Bit32u op) {
+ if (op & 0x80000000) return 0xffffffff;
+ else return 0;
+}
+
+
+static void DRC_CALL_CONV dynrec_sahf(Bit16u op) DRC_FC;
+static void DRC_CALL_CONV dynrec_sahf(Bit16u op) {
+ SETFLAGBIT(OF,get_OF());
+ lflags.type=t_UNKNOWN;
+ CPU_SetFlags(op>>8,FMASK_NORMAL & 0xff);
+}
+
+
+static void DRC_CALL_CONV dynrec_cmc(void) DRC_FC;
+static void DRC_CALL_CONV dynrec_cmc(void) {
+ FillFlags();
+ SETFLAGBIT(CF,!(reg_flags & FLAG_CF));
+}
+static void DRC_CALL_CONV dynrec_clc(void) DRC_FC;
+static void DRC_CALL_CONV dynrec_clc(void) {
+ FillFlags();
+ SETFLAGBIT(CF,false);
+}
+static void DRC_CALL_CONV dynrec_stc(void) DRC_FC;
+static void DRC_CALL_CONV dynrec_stc(void) {
+ FillFlags();
+ SETFLAGBIT(CF,true);
+}
+static void DRC_CALL_CONV dynrec_cld(void) DRC_FC;
+static void DRC_CALL_CONV dynrec_cld(void) {
+ SETFLAGBIT(DF,false);
+ cpu.direction=1;
+}
+static void DRC_CALL_CONV dynrec_std(void) DRC_FC;
+static void DRC_CALL_CONV dynrec_std(void) {
+ SETFLAGBIT(DF,true);
+ cpu.direction=-1;
+}
+
+
+static Bit16u DRC_CALL_CONV dynrec_movsb_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_movsb_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) {
+ Bit16u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=(Bit16u)(count-CPU_Cycles);
+ count=(Bit16u)CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ for (;count>0;count--) {
+ mem_writeb(di_base+reg_di,mem_readb(si_base+reg_si));
+ reg_si+=add_index;
+ reg_di+=add_index;
+ }
+ return count_left;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_movsb_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_movsb_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) {
+ Bit32u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ for (;count>0;count--) {
+ mem_writeb(di_base+reg_edi,mem_readb(si_base+reg_esi));
+ reg_esi+=add_index;
+ reg_edi+=add_index;
+ }
+ return count_left;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_movsw_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_movsw_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) {
+ Bit16u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=(Bit16u)(count-CPU_Cycles);
+ count=(Bit16u)CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ add_index<<=1;
+ for (;count>0;count--) {
+ mem_writew(di_base+reg_di,mem_readw(si_base+reg_si));
+ reg_si+=add_index;
+ reg_di+=add_index;
+ }
+ return count_left;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_movsw_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_movsw_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) {
+ Bit32u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ add_index<<=1;
+ for (;count>0;count--) {
+ mem_writew(di_base+reg_edi,mem_readw(si_base+reg_esi));
+ reg_esi+=add_index;
+ reg_edi+=add_index;
+ }
+ return count_left;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_movsd_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_movsd_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) {
+ Bit16u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=(Bit16u)(count-CPU_Cycles);
+ count=(Bit16u)CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ add_index<<=2;
+ for (;count>0;count--) {
+ mem_writed(di_base+reg_di,mem_readd(si_base+reg_si));
+ reg_si+=add_index;
+ reg_di+=add_index;
+ }
+ return count_left;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_movsd_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_movsd_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) {
+ Bit32u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ add_index<<=2;
+ for (;count>0;count--) {
+ mem_writed(di_base+reg_edi,mem_readd(si_base+reg_esi));
+ reg_esi+=add_index;
+ reg_edi+=add_index;
+ }
+ return count_left;
+}
+
+
+static Bit16u DRC_CALL_CONV dynrec_lodsb_word(Bit16u count,Bit16s add_index,PhysPt si_base) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_lodsb_word(Bit16u count,Bit16s add_index,PhysPt si_base) {
+ Bit16u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=(Bit16u)(count-CPU_Cycles);
+ count=(Bit16u)CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ for (;count>0;count--) {
+ reg_al=mem_readb(si_base+reg_si);
+ reg_si+=add_index;
+ }
+ return count_left;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_lodsb_dword(Bit32u count,Bit32s add_index,PhysPt si_base) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_lodsb_dword(Bit32u count,Bit32s add_index,PhysPt si_base) {
+ Bit32u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ for (;count>0;count--) {
+ reg_al=mem_readb(si_base+reg_esi);
+ reg_esi+=add_index;
+ }
+ return count_left;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_lodsw_word(Bit16u count,Bit16s add_index,PhysPt si_base) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_lodsw_word(Bit16u count,Bit16s add_index,PhysPt si_base) {
+ Bit16u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=(Bit16u)(count-CPU_Cycles);
+ count=(Bit16u)CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ add_index<<=1;
+ for (;count>0;count--) {
+ reg_ax=mem_readw(si_base+reg_si);
+ reg_si+=add_index;
+ }
+ return count_left;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_lodsw_dword(Bit32u count,Bit32s add_index,PhysPt si_base) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_lodsw_dword(Bit32u count,Bit32s add_index,PhysPt si_base) {
+ Bit32u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ add_index<<=1;
+ for (;count>0;count--) {
+ reg_ax=mem_readw(si_base+reg_esi);
+ reg_esi+=add_index;
+ }
+ return count_left;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_lodsd_word(Bit16u count,Bit16s add_index,PhysPt si_base) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_lodsd_word(Bit16u count,Bit16s add_index,PhysPt si_base) {
+ Bit16u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=(Bit16u)(count-CPU_Cycles);
+ count=(Bit16u)CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ add_index<<=2;
+ for (;count>0;count--) {
+ reg_eax=mem_readd(si_base+reg_si);
+ reg_si+=add_index;
+ }
+ return count_left;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_lodsd_dword(Bit32u count,Bit32s add_index,PhysPt si_base) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_lodsd_dword(Bit32u count,Bit32s add_index,PhysPt si_base) {
+ Bit32u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ add_index<<=2;
+ for (;count>0;count--) {
+ reg_eax=mem_readd(si_base+reg_esi);
+ reg_esi+=add_index;
+ }
+ return count_left;
+}
+
+
+static Bit16u DRC_CALL_CONV dynrec_stosb_word(Bit16u count,Bit16s add_index,PhysPt di_base) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_stosb_word(Bit16u count,Bit16s add_index,PhysPt di_base) {
+ Bit16u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=(Bit16u)(count-CPU_Cycles);
+ count=(Bit16u)CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ for (;count>0;count--) {
+ mem_writeb(di_base+reg_di,reg_al);
+ reg_di+=add_index;
+ }
+ return count_left;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_stosb_dword(Bit32u count,Bit32s add_index,PhysPt di_base) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_stosb_dword(Bit32u count,Bit32s add_index,PhysPt di_base) {
+ Bit32u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ for (;count>0;count--) {
+ mem_writeb(di_base+reg_edi,reg_al);
+ reg_edi+=add_index;
+ }
+ return count_left;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_stosw_word(Bit16u count,Bit16s add_index,PhysPt di_base) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_stosw_word(Bit16u count,Bit16s add_index,PhysPt di_base) {
+ Bit16u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=(Bit16u)(count-CPU_Cycles);
+ count=(Bit16u)CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ add_index<<=1;
+ for (;count>0;count--) {
+ mem_writew(di_base+reg_di,reg_ax);
+ reg_di+=add_index;
+ }
+ return count_left;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_stosw_dword(Bit32u count,Bit32s add_index,PhysPt di_base) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_stosw_dword(Bit32u count,Bit32s add_index,PhysPt di_base) {
+ Bit32u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ add_index<<=1;
+ for (;count>0;count--) {
+ mem_writew(di_base+reg_edi,reg_ax);
+ reg_edi+=add_index;
+ }
+ return count_left;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_stosd_word(Bit16u count,Bit16s add_index,PhysPt di_base) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_stosd_word(Bit16u count,Bit16s add_index,PhysPt di_base) {
+ Bit16u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=(Bit16u)(count-CPU_Cycles);
+ count=(Bit16u)CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ add_index<<=2;
+ for (;count>0;count--) {
+ mem_writed(di_base+reg_di,reg_eax);
+ reg_di+=add_index;
+ }
+ return count_left;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_stosd_dword(Bit32u count,Bit32s add_index,PhysPt di_base) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_stosd_dword(Bit32u count,Bit32s add_index,PhysPt di_base) {
+ Bit32u count_left;
+ if (count<(Bitu)CPU_Cycles) {
+ count_left=0;
+ } else {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ add_index<<=2;
+ for (;count>0;count--) {
+ mem_writed(di_base+reg_edi,reg_eax);
+ reg_edi+=add_index;
+ }
+ return count_left;
+}
+
+
+static void DRC_CALL_CONV dynrec_push_word(Bit16u value) DRC_FC;
+static void DRC_CALL_CONV dynrec_push_word(Bit16u value) {
+ Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-2)&cpu.stack.mask);
+ mem_writew(SegPhys(ss) + (new_esp & cpu.stack.mask),value);
+ reg_esp=new_esp;
+}
+
+static void DRC_CALL_CONV dynrec_push_dword(Bit32u value) DRC_FC;
+static void DRC_CALL_CONV dynrec_push_dword(Bit32u value) {
+ Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-4)&cpu.stack.mask);
+ mem_writed(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value);
+ reg_esp=new_esp;
+}
+
+static Bit16u DRC_CALL_CONV dynrec_pop_word(void) DRC_FC;
+static Bit16u DRC_CALL_CONV dynrec_pop_word(void) {
+ Bit16u val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask));
+ reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask);
+ return val;
+}
+
+static Bit32u DRC_CALL_CONV dynrec_pop_dword(void) DRC_FC;
+static Bit32u DRC_CALL_CONV dynrec_pop_dword(void) {
+ Bit32u val=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask));
+ reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask);
+ return val;
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+/* ARMv4 (little endian) backend by M-HT (common data/functions) */
+
+
+// some configuring defines that specify the capabilities of this architecture
+// or aspects of the recompiling
+
+// protect FC_ADDR over function calls if necessaray
+// #define DRC_PROTECT_ADDR_REG
+
+// try to use non-flags generating functions if possible
+#define DRC_FLAGS_INVALIDATION
+// try to replace _simple functions by code
+#define DRC_FLAGS_INVALIDATION_DCODE
+
+// type with the same size as a pointer
+#define DRC_PTR_SIZE_IM Bit32u
+
+// calling convention modifier
+#define DRC_CALL_CONV /* nothing */
+#define DRC_FC /* nothing */
+
+// use FC_REGS_ADDR to hold the address of "cpu_regs" and to access it using FC_REGS_ADDR
+#define DRC_USE_REGS_ADDR
+// use FC_SEGS_ADDR to hold the address of "Segs" and to access it using FC_SEGS_ADDR
+#define DRC_USE_SEGS_ADDR
+
+// register mapping
+typedef Bit8u HostReg;
+
+// "lo" registers
+#define HOST_r0 0
+#define HOST_r1 1
+#define HOST_r2 2
+#define HOST_r3 3
+#define HOST_r4 4
+#define HOST_r5 5
+#define HOST_r6 6
+#define HOST_r7 7
+// "hi" registers
+#define HOST_r8 8
+#define HOST_r9 9
+#define HOST_r10 10
+#define HOST_r11 11
+#define HOST_r12 12
+#define HOST_r13 13
+#define HOST_r14 14
+#define HOST_r15 15
+
+// register aliases
+// "lo" registers
+#define HOST_a1 HOST_r0
+#define HOST_a2 HOST_r1
+#define HOST_a3 HOST_r2
+#define HOST_a4 HOST_r3
+#define HOST_v1 HOST_r4
+#define HOST_v2 HOST_r5
+#define HOST_v3 HOST_r6
+#define HOST_v4 HOST_r7
+// "hi" registers
+#define HOST_v5 HOST_r8
+#define HOST_v6 HOST_r9
+#define HOST_v7 HOST_r10
+#define HOST_v8 HOST_r11
+#define HOST_ip HOST_r12
+#define HOST_sp HOST_r13
+#define HOST_lr HOST_r14
+#define HOST_pc HOST_r15
+
+
+static void cache_block_closing(Bit8u* block_start,Bitu block_size) {
+#if (__ARM_EABI__)
+ //flush cache - eabi
+ register unsigned long _beg __asm ("a1") = (unsigned long)(block_start); // block start
+ register unsigned long _end __asm ("a2") = (unsigned long)(block_start+block_size); // block end
+ register unsigned long _flg __asm ("a3") = 0;
+ register unsigned long _par __asm ("r7") = 0xf0002; // sys_cacheflush
+ __asm __volatile ("swi 0x0"
+ : // no outputs
+ : "r" (_beg), "r" (_end), "r" (_flg), "r" (_par)
+ );
+#else
+// GP2X BEGIN
+ //flush cache - old abi
+ register unsigned long _beg __asm ("a1") = (unsigned long)(block_start); // block start
+ register unsigned long _end __asm ("a2") = (unsigned long)(block_start+block_size); // block end
+ register unsigned long _flg __asm ("a3") = 0;
+ __asm __volatile ("swi 0x9f0002 @ sys_cacheflush"
+ : // no outputs
+ : "r" (_beg), "r" (_end), "r" (_flg)
+ );
+// GP2X END
+#endif
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+/* ARMv4/ARMv7 (little endian) backend by M-HT (arm version) */
+
+
+// temporary registers
+#define temp1 HOST_ip
+#define temp2 HOST_v3
+#define temp3 HOST_v4
+
+// register that holds function return values
+#define FC_RETOP HOST_a1
+
+// register used for address calculations,
+#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG
+
+// register that holds the first parameter
+#define FC_OP1 HOST_a1
+
+// register that holds the second parameter
+#define FC_OP2 HOST_a2
+
+// special register that holds the third parameter for _R3 calls (byte accessible)
+#define FC_OP3 HOST_v2
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA1 HOST_a1
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA2 HOST_a2
+
+// temporary register for LEA
+#define TEMP_REG_DRC HOST_v2
+
+// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code
+#define FC_REGS_ADDR HOST_v7
+
+// used to hold the address of "Segs" - preferably filled in function gen_run_code
+#define FC_SEGS_ADDR HOST_v8
+
+// used to hold the address of "core_dynrec.readdata" - filled in function gen_run_code
+#define readdata_addr HOST_v5
+
+
+// helper macro
+#define ROTATE_SCALE(x) ( (x)?(32 - x):(0) )
+
+
+// instruction encodings
+
+// move
+// mov dst, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define MOV_IMM(dst, imm, rimm) (0xe3a00000 + ((dst) << 12) + (imm) + ((rimm) << 7) )
+// mov dst, src, lsl #imm
+#define MOV_REG_LSL_IMM(dst, src, imm) (0xe1a00000 + ((dst) << 12) + (src) + ((imm) << 7) )
+// movs dst, src, lsl #imm
+#define MOVS_REG_LSL_IMM(dst, src, imm) (0xe1b00000 + ((dst) << 12) + (src) + ((imm) << 7) )
+// mov dst, src, lsr #imm
+#define MOV_REG_LSR_IMM(dst, src, imm) (0xe1a00020 + ((dst) << 12) + (src) + ((imm) << 7) )
+// mov dst, src, asr #imm
+#define MOV_REG_ASR_IMM(dst, src, imm) (0xe1a00040 + ((dst) << 12) + (src) + ((imm) << 7) )
+// mov dst, src, lsl rreg
+#define MOV_REG_LSL_REG(dst, src, rreg) (0xe1a00010 + ((dst) << 12) + (src) + ((rreg) << 8) )
+// mov dst, src, lsr rreg
+#define MOV_REG_LSR_REG(dst, src, rreg) (0xe1a00030 + ((dst) << 12) + (src) + ((rreg) << 8) )
+// mov dst, src, asr rreg
+#define MOV_REG_ASR_REG(dst, src, rreg) (0xe1a00050 + ((dst) << 12) + (src) + ((rreg) << 8) )
+// mov dst, src, ror rreg
+#define MOV_REG_ROR_REG(dst, src, rreg) (0xe1a00070 + ((dst) << 12) + (src) + ((rreg) << 8) )
+// mvn dst, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define MVN_IMM(dst, imm, rimm) (0xe3e00000 + ((dst) << 12) + (imm) + ((rimm) << 7) )
+#if C_TARGETCPU == ARMV7LE
+// movw dst, #imm @ 0 <= imm <= 65535
+#define MOVW(dst, imm) (0xe3000000 + ((dst) << 12) + (((imm) & 0xf000) << 4) + ((imm) & 0x0fff) )
+// movt dst, #imm @ 0 <= imm <= 65535
+#define MOVT(dst, imm) (0xe3400000 + ((dst) << 12) + (((imm) & 0xf000) << 4) + ((imm) & 0x0fff) )
+#endif
+
+// arithmetic
+// add dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define ADD_IMM(dst, src, imm, rimm) (0xe2800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+// add dst, src1, src2, lsl #imm
+#define ADD_REG_LSL_IMM(dst, src1, src2, imm) (0xe0800000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+// sub dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define SUB_IMM(dst, src, imm, rimm) (0xe2400000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+// sub dst, src1, src2, lsl #imm
+#define SUB_REG_LSL_IMM(dst, src1, src2, imm) (0xe0400000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+// rsb dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define RSB_IMM(dst, src, imm, rimm) (0xe2600000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+// cmp src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define CMP_IMM(src, imm, rimm) (0xe3500000 + ((src) << 16) + (imm) + ((rimm) << 7) )
+// nop
+#if C_TARGETCPU == ARMV7LE
+#define NOP (0xe320f000)
+#else
+#define NOP MOV_REG_LSL_IMM(HOST_r0, HOST_r0, 0)
+#endif
+
+// logical
+// tst src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define TST_IMM(src, imm, rimm) (0xe3100000 + ((src) << 16) + (imm) + ((rimm) << 7) )
+// and dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define AND_IMM(dst, src, imm, rimm) (0xe2000000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+// and dst, src1, src2, lsl #imm
+#define AND_REG_LSL_IMM(dst, src1, src2, imm) (0xe0000000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+// orr dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define ORR_IMM(dst, src, imm, rimm) (0xe3800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+// orr dst, src1, src2, lsl #imm
+#define ORR_REG_LSL_IMM(dst, src1, src2, imm) (0xe1800000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+// orr dst, src1, src2, lsr #imm
+#define ORR_REG_LSR_IMM(dst, src1, src2, imm) (0xe1800020 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+// eor dst, src1, src2, lsl #imm
+#define EOR_REG_LSL_IMM(dst, src1, src2, imm) (0xe0200000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+// bic dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define BIC_IMM(dst, src, imm, rimm) (0xe3c00000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+// bic dst, src1, src2, lsl #imm @ 0 <= imm <= 31
+#define BIC_REG_LSL_IMM(dst, src1, src2, imm) (0xe1c00000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+
+// load
+// ldr reg, [addr, #imm] @ 0 <= imm < 4096
+#define LDR_IMM(reg, addr, imm) (0xe5900000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+// ldr reg, [addr, #-(imm)] @ 0 <= imm < 4096
+#define LDR_IMM_M(reg, addr, imm) (0xe5100000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+// ldrh reg, [addr, #imm] @ 0 <= imm < 256
+#define LDRH_IMM(reg, addr, imm) (0xe1d000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) )
+// ldrh reg, [addr, #-(imm)] @ 0 <= imm < 256
+#define LDRH_IMM_M(reg, addr, imm) (0xe15000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) )
+// ldrb reg, [addr, #imm] @ 0 <= imm < 4096
+#define LDRB_IMM(reg, addr, imm) (0xe5d00000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+// ldrb reg, [addr, #-(imm)] @ 0 <= imm < 4096
+#define LDRB_IMM_M(reg, addr, imm) (0xe5500000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+// ldr reg, [addr1, addr2, lsl #imm] @ 0 <= imm < 31
+#define LDR_REG_LSL_IMM(reg, addr1, addr2, imm) (0xe7900000 + ((reg) << 12) + ((addr1) << 16) + (addr2) + ((imm) << 7) )
+
+// store
+// str reg, [addr, #imm] @ 0 <= imm < 4096
+#define STR_IMM(reg, addr, imm) (0xe5800000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+// str reg, [addr, #-(imm)] @ 0 <= imm < 4096
+#define STR_IMM_M(reg, addr, imm) (0xe5000000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+// strh reg, [addr, #imm] @ 0 <= imm < 256
+#define STRH_IMM(reg, addr, imm) (0xe1c000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) )
+// strh reg, [addr, #-(imm)] @ 0 <= imm < 256
+#define STRH_IMM_M(reg, addr, imm) (0xe14000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) )
+// strb reg, [addr, #imm] @ 0 <= imm < 4096
+#define STRB_IMM(reg, addr, imm) (0xe5c00000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+// strb reg, [addr, #-(imm)] @ 0 <= imm < 4096
+#define STRB_IMM_M(reg, addr, imm) (0xe5400000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+
+// branch
+// beq pc+imm @ 0 <= imm < 32M & imm mod 4 = 0
+#define BEQ_FWD(imm) (0x0a000000 + ((imm) >> 2) )
+// bne pc+imm @ 0 <= imm < 32M & imm mod 4 = 0
+#define BNE_FWD(imm) (0x1a000000 + ((imm) >> 2) )
+// ble pc+imm @ 0 <= imm < 32M & imm mod 4 = 0
+#define BLE_FWD(imm) (0xda000000 + ((imm) >> 2) )
+// b pc+imm @ 0 <= imm < 32M & imm mod 4 = 0
+#define B_FWD(imm) (0xea000000 + ((imm) >> 2) )
+// bx reg
+#define BX(reg) (0xe12fff10 + (reg) )
+#if C_TARGETCPU == ARMV7LE
+// blx reg
+#define BLX_REG(reg) (0xe12fff30 + (reg) )
+
+// extend
+// sxth dst, src, ror #rimm @ rimm = 0 | 8 | 16 | 24
+#define SXTH(dst, src, rimm) (0xe6bf0070 + ((dst) << 12) + (src) + (((rimm) & 24) << 7) )
+// sxtb dst, src, ror #rimm @ rimm = 0 | 8 | 16 | 24
+#define SXTB(dst, src, rimm) (0xe6af0070 + ((dst) << 12) + (src) + (((rimm) & 24) << 7) )
+// uxth dst, src, ror #rimm @ rimm = 0 | 8 | 16 | 24
+#define UXTH(dst, src, rimm) (0xe6ff0070 + ((dst) << 12) + (src) + (((rimm) & 24) << 7) )
+// uxtb dst, src, ror #rimm @ rimm = 0 | 8 | 16 | 24
+#define UXTB(dst, src, rimm) (0xe6ef0070 + ((dst) << 12) + (src) + (((rimm) & 24) << 7) )
+
+// bit field
+// bfi dst, src, #lsb, #width @ lsb >= 0, width >= 1, lsb+width <= 32
+#define BFI(dst, src, lsb, width) (0xe7c00010 + ((dst) << 12) + (src) + ((lsb) << 7) + (((lsb) + (width) - 1) << 16) )
+// bfc dst, #lsb, #width @ lsb >= 0, width >= 1, lsb+width <= 32
+#define BFC(dst, lsb, width) (0xe7c0001f + ((dst) << 12) + ((lsb) << 7) + (((lsb) + (width) - 1) << 16) )
+#endif
+
+
+// move a full register from reg_src to reg_dst
+static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) {
+ if(reg_src == reg_dst) return;
+ cache_addd( MOV_REG_LSL_IMM(reg_dst, reg_src, 0) ); // mov reg_dst, reg_src
+}
+
+// helper function
+static bool val_is_operand2(Bit32u value, Bit32u *val_shift) {
+ Bit32u shift;
+
+ if (GCC_UNLIKELY(value == 0)) {
+ *val_shift = 0;
+ return true;
+ }
+
+ shift = 0;
+ while ((value & 3) == 0) {
+ value>>=2;
+ shift+=2;
+ }
+
+ if ((value >> 8) != 0) return false;
+
+ *val_shift = shift;
+ return true;
+}
+
+#if C_TARGETCPU != ARMV7LE
+// helper function
+static Bits get_imm_gen_len(Bit32u imm) {
+ Bits ret;
+ if (imm == 0) {
+ return 1;
+ } else {
+ ret = 0;
+ while (imm) {
+ while ((imm & 3) == 0) {
+ imm>>=2;
+ }
+ ret++;
+ imm>>=8;
+ }
+ return ret;
+ }
+}
+
+// helper function
+static Bits get_min_imm_gen_len(Bit32u imm) {
+ Bits num1, num2;
+
+ num1 = get_imm_gen_len(imm);
+ num2 = get_imm_gen_len(~imm);
+
+ return (num1 <= num2)?num1:num2;
+}
+#endif
+
+// move a 32bit constant value into dest_reg
+static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) {
+#if C_TARGETCPU == ARMV7LE
+ Bit32u scale;
+
+ if ( val_is_operand2(imm, &scale) ) {
+ cache_addd( MOV_IMM(dest_reg, imm >> scale, ROTATE_SCALE(scale)) ); // mov dest_reg, #imm
+ } else if ( val_is_operand2(~imm, &scale) ) {
+ cache_addd( MVN_IMM(dest_reg, (~imm) >> scale, ROTATE_SCALE(scale)) ); // mvn dest_reg, #~imm
+ } else {
+ cache_addd( MOVW(dest_reg, imm & 0xffff) ); // movw dest_reg, #(imm & 0xffff)
+
+ if (imm >= 0x10000)
+ {
+ cache_addd( MOVT(dest_reg, imm >> 16) ); // movt dest_reg, #(imm >> 16)
+ }
+ }
+#else
+ Bit32u imm2, first, scale;
+
+ scale = 0;
+ first = 1;
+ imm2 = ~imm;
+
+ if (get_imm_gen_len(imm) <= get_imm_gen_len(imm2)) {
+ if (imm == 0) {
+ cache_addd( MOV_IMM(dest_reg, 0, 0) ); // mov dest_reg, #0
+ } else {
+ while (imm) {
+ while ((imm & 3) == 0) {
+ imm>>=2;
+ scale+=2;
+ }
+ if (first) {
+ cache_addd( MOV_IMM(dest_reg, imm & 0xff, ROTATE_SCALE(scale)) ); // mov dest_reg, #((imm & 0xff) << scale)
+ first = 0;
+ } else {
+ cache_addd( ORR_IMM(dest_reg, dest_reg, imm & 0xff, ROTATE_SCALE(scale)) ); // orr dest_reg, dest_reg, #((imm & 0xff) << scale)
+ }
+ imm>>=8;
+ scale+=8;
+ }
+ }
+ } else {
+ if (imm2 == 0) {
+ cache_addd( MVN_IMM(dest_reg, 0, 0) ); // mvn dest_reg, #0
+ } else {
+ while (imm2) {
+ while ((imm2 & 3) == 0) {
+ imm2>>=2;
+ scale+=2;
+ }
+ if (first) {
+ cache_addd( MVN_IMM(dest_reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // mvn dest_reg, #((imm2 & 0xff) << scale)
+ first = 0;
+ } else {
+ cache_addd( BIC_IMM(dest_reg, dest_reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // bic dest_reg, dest_reg, #((imm2 & 0xff) << scale)
+ }
+ imm2>>=8;
+ scale+=8;
+ }
+ }
+ }
+#endif
+}
+
+// helper function
+static bool gen_mov_memval_to_reg_helper(HostReg dest_reg, Bit32u data, Bitu size, HostReg addr_reg, Bit32u addr_data) {
+ switch (size) {
+ case 4:
+#if !(defined(C_UNALIGNED_MEMORY) || (C_TARGETCPU == ARMV7LE))
+ if ((data & 3) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 4096)) {
+ cache_addd( LDR_IMM(dest_reg, addr_reg, data - addr_data) ); // ldr dest_reg, [addr_reg, #(data - addr_data)]
+ return true;
+ } else if ((data < addr_data) && (data > addr_data - 4096)) {
+ cache_addd( LDR_IMM_M(dest_reg, addr_reg, addr_data - data) ); // ldr dest_reg, [addr_reg, #-(addr_data - data)]
+ return true;
+ }
+ }
+ break;
+ case 2:
+#if !(defined(C_UNALIGNED_MEMORY) || (C_TARGETCPU == ARMV7LE))
+ if ((data & 1) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 256)) {
+ cache_addd( LDRH_IMM(dest_reg, addr_reg, data - addr_data) ); // ldrh dest_reg, [addr_reg, #(data - addr_data)]
+ return true;
+ } else if ((data < addr_data) && (data > addr_data - 256)) {
+ cache_addd( LDRH_IMM_M(dest_reg, addr_reg, addr_data - data) ); // ldrh dest_reg, [addr_reg, #-(addr_data - data)]
+ return true;
+ }
+ }
+ break;
+ case 1:
+ if ((data >= addr_data) && (data < addr_data + 4096)) {
+ cache_addd( LDRB_IMM(dest_reg, addr_reg, data - addr_data) ); // ldrb dest_reg, [addr_reg, #(data - addr_data)]
+ return true;
+ } else if ((data < addr_data) && (data > addr_data - 4096)) {
+ cache_addd( LDRB_IMM_M(dest_reg, addr_reg, addr_data - data) ); // ldrb dest_reg, [addr_reg, #-(addr_data - data)]
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+// helper function
+static bool gen_mov_memval_to_reg(HostReg dest_reg, void *data, Bitu size) {
+ if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, FC_REGS_ADDR, (Bit32u)&cpu_regs)) return true;
+ if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, readdata_addr, (Bit32u)&core_dynrec.readdata)) return true;
+ if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, FC_SEGS_ADDR, (Bit32u)&Segs)) return true;
+ return false;
+}
+
+// helper function for gen_mov_word_to_reg
+static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) {
+ // alignment....
+ if (dword) {
+#if !(defined(C_UNALIGNED_MEMORY) || (C_TARGETCPU == ARMV7LE))
+ if ((Bit32u)data & 3) {
+ if ( ((Bit32u)data & 3) == 2 ) {
+ cache_addd( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg]
+ cache_addd( LDRH_IMM(temp2, data_reg, 2) ); // ldrh temp2, [data_reg, #2]
+ cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 16) ); // orr dest_reg, dest_reg, temp2, lsl #16
+ } else {
+ cache_addd( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg]
+ cache_addd( LDRH_IMM(temp2, data_reg, 1) ); // ldrh temp2, [data_reg, #1]
+ cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 8) ); // orr dest_reg, dest_reg, temp2, lsl #8
+ cache_addd( LDRB_IMM(temp2, data_reg, 3) ); // ldrb temp2, [data_reg, #3]
+ cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 24) ); // orr dest_reg, dest_reg, temp2, lsl #24
+ }
+ } else
+#endif
+ {
+ cache_addd( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg]
+ }
+ } else {
+#if !(defined(C_UNALIGNED_MEMORY) || (C_TARGETCPU == ARMV7LE))
+ if ((Bit32u)data & 1) {
+ cache_addd( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg]
+ cache_addd( LDRB_IMM(temp2, data_reg, 1) ); // ldrb temp2, [data_reg, #1]
+ cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 8) ); // orr dest_reg, dest_reg, temp2, lsl #8
+ } else
+#endif
+ {
+ cache_addd( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg]
+ }
+ }
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) {
+ if (!gen_mov_memval_to_reg(dest_reg, data, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)data);
+ gen_mov_word_to_reg_helper(dest_reg, data, dword, temp1);
+ }
+}
+
+// move a 16bit constant value into dest_reg
+// the upper 16bit of the destination register may be destroyed
+static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) {
+ gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm);
+}
+
+// helper function
+static bool gen_mov_memval_from_reg_helper(HostReg src_reg, Bit32u data, Bitu size, HostReg addr_reg, Bit32u addr_data) {
+ switch (size) {
+ case 4:
+#if !(defined(C_UNALIGNED_MEMORY) || (C_TARGETCPU == ARMV7LE))
+ if ((data & 3) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 4096)) {
+ cache_addd( STR_IMM(src_reg, addr_reg, data - addr_data) ); // str src_reg, [addr_reg, #(data - addr_data)]
+ return true;
+ } else if ((data < addr_data) && (data > addr_data - 4096)) {
+ cache_addd( STR_IMM_M(src_reg, addr_reg, addr_data - data) ); // str src_reg, [addr_reg, #-(addr_data - data)]
+ return true;
+ }
+ }
+ break;
+ case 2:
+#if !(defined(C_UNALIGNED_MEMORY) || (C_TARGETCPU == ARMV7LE))
+ if ((data & 1) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 256)) {
+ cache_addd( STRH_IMM(src_reg, addr_reg, data - addr_data) ); // strh src_reg, [addr_reg, #(data - addr_data)]
+ return true;
+ } else if ((data < addr_data) && (data > addr_data - 256)) {
+ cache_addd( STRH_IMM_M(src_reg, addr_reg, addr_data - data) ); // strh src_reg, [addr_reg, #-(addr_data - data)]
+ return true;
+ }
+ }
+ break;
+ case 1:
+ if ((data >= addr_data) && (data < addr_data + 4096)) {
+ cache_addd( STRB_IMM(src_reg, addr_reg, data - addr_data) ); // strb src_reg, [addr_reg, #(data - addr_data)]
+ return true;
+ } else if ((data < addr_data) && (data > addr_data - 4096)) {
+ cache_addd( STRB_IMM_M(src_reg, addr_reg, addr_data - data) ); // strb src_reg, [addr_reg, #-(addr_data - data)]
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+// helper function
+static bool gen_mov_memval_from_reg(HostReg src_reg, void *dest, Bitu size) {
+ if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, FC_REGS_ADDR, (Bit32u)&cpu_regs)) return true;
+ if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, readdata_addr, (Bit32u)&core_dynrec.readdata)) return true;
+ if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, FC_SEGS_ADDR, (Bit32u)&Segs)) return true;
+ return false;
+}
+
+// helper function for gen_mov_word_from_reg
+static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) {
+ // alignment....
+ if (dword) {
+#if !(defined(C_UNALIGNED_MEMORY) || (C_TARGETCPU == ARMV7LE))
+ if ((Bit32u)dest & 3) {
+ if ( ((Bit32u)dest & 3) == 2 ) {
+ cache_addd( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg]
+ cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 16) ); // mov temp2, src_reg, lsr #16
+ cache_addd( STRH_IMM(temp2, data_reg, 2) ); // strh temp2, [data_reg, #2]
+ } else {
+ cache_addd( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg]
+ cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 8) ); // mov temp2, src_reg, lsr #8
+ cache_addd( STRH_IMM(temp2, data_reg, 1) ); // strh temp2, [data_reg, #1]
+ cache_addd( MOV_REG_LSR_IMM(temp2, temp2, 16) ); // mov temp2, temp2, lsr #16
+ cache_addd( STRB_IMM(temp2, data_reg, 3) ); // strb temp2, [data_reg, #3]
+ }
+ } else
+#endif
+ {
+ cache_addd( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg]
+ }
+ } else {
+#if !(defined(C_UNALIGNED_MEMORY) || (C_TARGETCPU == ARMV7LE))
+ if ((Bit32u)dest & 1) {
+ cache_addd( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg]
+ cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 8) ); // mov temp2, src_reg, lsr #8
+ cache_addd( STRB_IMM(temp2, data_reg, 1) ); // strb temp2, [data_reg, #1]
+ } else
+#endif
+ {
+ cache_addd( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg]
+ }
+ }
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into memory
+static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) {
+ if (!gen_mov_memval_from_reg(src_reg, dest, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest);
+ gen_mov_word_from_reg_helper(src_reg, dest, dword, temp1);
+ }
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) {
+ if (!gen_mov_memval_to_reg(dest_reg, data, 1)) {
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)data);
+ cache_addd( LDRB_IMM(dest_reg, temp1, 0) ); // ldrb dest_reg, [temp1]
+ }
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) {
+ gen_mov_byte_to_reg_low(dest_reg, data);
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) {
+ cache_addd( MOV_IMM(dest_reg, imm, 0) ); // mov dest_reg, #(imm)
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) {
+ gen_mov_byte_to_reg_low_imm(dest_reg, imm);
+}
+
+// move the lowest 8bit of a register into memory
+static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) {
+ if (!gen_mov_memval_from_reg(src_reg, dest, 1)) {
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest);
+ cache_addd( STRB_IMM(src_reg, temp1, 0) ); // strb src_reg, [temp1]
+ }
+}
+
+
+
+// convert an 8bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_byte(bool sign,HostReg reg) {
+ if (sign) {
+#if C_TARGETCPU == ARMV7LE
+ cache_addd( SXTB(reg, reg, 0) ); // sxtb reg, reg
+#else
+ cache_addd( MOV_REG_LSL_IMM(reg, reg, 24) ); // mov reg, reg, lsl #24
+ cache_addd( MOV_REG_ASR_IMM(reg, reg, 24) ); // mov reg, reg, asr #24
+#endif
+ } else {
+#if C_TARGETCPU == ARMV7LE
+ cache_addd( UXTB(reg, reg, 0) ); // uxtb reg, reg
+#else
+ cache_addd( AND_IMM(reg, reg, 0xff, 0) ); // and reg, reg, #0xff
+#endif
+ }
+}
+
+// convert a 16bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_word(bool sign,HostReg reg) {
+ if (sign) {
+#if C_TARGETCPU == ARMV7LE
+ cache_addd( SXTH(reg, reg, 0) ); // sxth reg, reg
+#else
+ cache_addd( MOV_REG_LSL_IMM(reg, reg, 16) ); // mov reg, reg, lsl #16
+ cache_addd( MOV_REG_ASR_IMM(reg, reg, 16) ); // mov reg, reg, asr #16
+#endif
+ } else {
+#if C_TARGETCPU == ARMV7LE
+ cache_addd( UXTH(reg, reg, 0) ); // uxth reg, reg
+#else
+ cache_addd( MOV_REG_LSL_IMM(reg, reg, 16) ); // mov reg, reg, lsl #16
+ cache_addd( MOV_REG_LSR_IMM(reg, reg, 16) ); // mov reg, reg, lsr #16
+#endif
+ }
+}
+
+// add a 32bit value from memory to a full register
+static void gen_add(HostReg reg,void* op) {
+ gen_mov_word_to_reg(temp3, op, 1);
+ cache_addd( ADD_REG_LSL_IMM(reg, reg, temp3, 0) ); // add reg, reg, temp3
+}
+
+// add a 32bit constant value to a full register
+static void gen_add_imm(HostReg reg,Bit32u imm) {
+ Bit32u imm2, scale;
+
+ if(!imm) return;
+
+ imm2 = (Bit32u) (-((Bit32s)imm));
+
+ if ( val_is_operand2(imm, &scale) ) {
+ cache_addd( ADD_IMM(reg, reg, imm >> scale, ROTATE_SCALE(scale)) ); // add reg, reg, #imm
+ } else if ( val_is_operand2(imm2, &scale) ) {
+ cache_addd( SUB_IMM(reg, reg, imm2 >> scale, ROTATE_SCALE(scale)) ); // sub reg, reg, #(-imm)
+#if C_TARGETCPU == ARMV7LE
+ } else if (imm2 < 0x10000) {
+ cache_addd( MOVW(temp2, imm2) ); // movw temp2, #(-imm)
+ cache_addd( SUB_REG_LSL_IMM(reg, reg, temp2, 0) ); // sub reg, reg, temp2
+#endif
+ } else {
+#if C_TARGETCPU != ARMV7LE
+ if (get_min_imm_gen_len(imm) <= get_min_imm_gen_len(imm2)) {
+#endif
+ gen_mov_dword_to_reg_imm(temp2, imm);
+ cache_addd( ADD_REG_LSL_IMM(reg, reg, temp2, 0) ); // add reg, reg, temp2
+#if C_TARGETCPU != ARMV7LE
+ } else {
+ gen_mov_dword_to_reg_imm(temp2, imm2);
+ cache_addd( SUB_REG_LSL_IMM(reg, reg, temp2, 0) ); // sub reg, reg, temp2
+ }
+#endif
+ }
+}
+
+// and a 32bit constant value with a full register
+static void gen_and_imm(HostReg reg,Bit32u imm) {
+ Bit32u imm2, scale;
+
+ imm2 = ~imm;
+ if(!imm2) return;
+
+ if (!imm) {
+ cache_addd( MOV_IMM(reg, 0, 0) ); // mov reg, #0
+ } else if ( val_is_operand2(imm, &scale) ) {
+ cache_addd( AND_IMM(reg, reg, imm >> scale, ROTATE_SCALE(scale)) ); // and reg, reg, #imm
+ } else if ( val_is_operand2(imm2, &scale) ) {
+ cache_addd( BIC_IMM(reg, reg, imm2 >> scale, ROTATE_SCALE(scale)) ); // bic reg, reg, #(~imm)
+#if C_TARGETCPU == ARMV7LE
+ } else if (imm2 < 0x10000) {
+ cache_addd( MOVW(temp2, imm2) ); // movw temp2, #(~imm)
+ cache_addd( BIC_REG_LSL_IMM(reg, reg, temp2, 0) ); // bic reg, reg, temp2
+#endif
+ } else {
+ gen_mov_dword_to_reg_imm(temp2, imm);
+ cache_addd( AND_REG_LSL_IMM(reg, reg, temp2, 0) ); // and reg, reg, temp2
+ }
+}
+
+
+// move a 32bit constant value into memory
+static void gen_mov_direct_dword(void* dest,Bit32u imm) {
+ gen_mov_dword_to_reg_imm(temp3, imm);
+ gen_mov_word_from_reg(temp3, dest, 1);
+}
+
+// move an address into memory
+static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) {
+ gen_mov_direct_dword(dest,(Bit32u)imm);
+}
+
+// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value
+static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) {
+ if (!dword) imm &= 0xffff;
+ if(!imm) return;
+
+ if (!gen_mov_memval_to_reg(temp3, dest, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest);
+ gen_mov_word_to_reg_helper(temp3, dest, dword, temp1);
+ }
+ gen_add_imm(temp3, imm);
+ if (!gen_mov_memval_from_reg(temp3, dest, (dword)?4:2)) {
+ gen_mov_word_from_reg_helper(temp3, dest, dword, temp1);
+ }
+}
+
+// add an 8bit constant value to a dword memory value
+static void gen_add_direct_byte(void* dest,Bit8s imm) {
+ gen_add_direct_word(dest, (Bit32s)imm, 1);
+}
+
+// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value
+static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) {
+ Bit32u imm2, scale;
+
+ if (!dword) imm &= 0xffff;
+ if(!imm) return;
+
+ if (!gen_mov_memval_to_reg(temp3, dest, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest);
+ gen_mov_word_to_reg_helper(temp3, dest, dword, temp1);
+ }
+
+ imm2 = (Bit32u) (-((Bit32s)imm));
+
+ if ( val_is_operand2(imm, &scale) ) {
+ cache_addd( SUB_IMM(temp3, temp3, imm >> scale, ROTATE_SCALE(scale)) ); // sub temp3, temp3, #imm
+ } else if ( val_is_operand2(imm2, &scale) ) {
+ cache_addd( ADD_IMM(temp3, temp3, imm2 >> scale, ROTATE_SCALE(scale)) ); // add temp3, temp3, #(-imm)
+#if C_TARGETCPU == ARMV7LE
+ } else if (imm2 < 0x10000) {
+ cache_addd( MOVW(temp2, imm2) ); // movw temp2, #(-imm)
+ cache_addd( ADD_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // add temp3, temp3, temp2
+#endif
+ } else {
+#if C_TARGETCPU != ARMV7LE
+ if (get_min_imm_gen_len(imm) <= get_min_imm_gen_len(imm2)) {
+#endif
+ gen_mov_dword_to_reg_imm(temp2, imm);
+ cache_addd( SUB_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // sub temp3, temp3, temp2
+#if C_TARGETCPU != ARMV7LE
+ } else {
+ gen_mov_dword_to_reg_imm(temp2, imm2);
+ cache_addd( ADD_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // add temp3, temp3, temp2
+ }
+#endif
+ }
+
+ if (!gen_mov_memval_from_reg(temp3, dest, (dword)?4:2)) {
+ gen_mov_word_from_reg_helper(temp3, dest, dword, temp1);
+ }
+}
+
+// subtract an 8bit constant value from a dword memory value
+static void gen_sub_direct_byte(void* dest,Bit8s imm) {
+ gen_sub_direct_word(dest, (Bit32s)imm, 1);
+}
+
+// effective address calculation, destination is dest_reg
+// scale_reg is scaled by scale (scale_reg*(2^scale)) and
+// added to dest_reg, then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) {
+ cache_addd( ADD_REG_LSL_IMM(dest_reg, dest_reg, scale_reg, scale) ); // add dest_reg, dest_reg, scale_reg, lsl #(scale)
+ gen_add_imm(dest_reg, imm);
+}
+
+// effective address calculation, destination is dest_reg
+// dest_reg is scaled by scale (dest_reg*(2^scale)),
+// then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) {
+ if (scale) {
+ cache_addd( MOV_REG_LSL_IMM(dest_reg, dest_reg, scale) ); // mov dest_reg, dest_reg, lsl #(scale)
+ }
+ gen_add_imm(dest_reg, imm);
+}
+
+// generate a call to a parameterless function
+static void INLINE gen_call_function_raw(void * func) {
+#if C_TARGETCPU == ARMV7LE
+ cache_addd( MOVW(temp1, ((Bit32u)func) & 0xffff) ); // movw temp1, #(func & 0xffff)
+ cache_addd( MOVT(temp1, ((Bit32u)func) >> 16) ); // movt temp1, #(func >> 16)
+ cache_addd( BLX_REG(temp1) ); // blx temp1
+#else
+ cache_addd( LDR_IMM(temp1, HOST_pc, 4) ); // ldr temp1, [pc, #4]
+ cache_addd( ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4
+ cache_addd( BX(temp1) ); // bx temp1
+ cache_addd((Bit32u)func); // .int func
+#endif
+}
+
+// generate a call to a function with paramcount parameters
+// note: the parameters are loaded in the architecture specific way
+// using the gen_load_param_ functions below
+static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) {
+ Bit32u proc_addr = (Bit32u)cache.pos;
+ gen_call_function_raw(func);
+ return proc_addr;
+}
+
+#if (1)
+// max of 4 parameters in a1-a4
+
+// load an immediate value as param'th function parameter
+static void INLINE gen_load_param_imm(Bitu imm,Bitu param) {
+ gen_mov_dword_to_reg_imm(param, imm);
+}
+
+// load an address as param'th function parameter
+static void INLINE gen_load_param_addr(Bitu addr,Bitu param) {
+ gen_mov_dword_to_reg_imm(param, addr);
+}
+
+// load a host-register as param'th function parameter
+static void INLINE gen_load_param_reg(Bitu reg,Bitu param) {
+ gen_mov_regs(param, reg);
+}
+
+// load a value from memory as param'th function parameter
+static void INLINE gen_load_param_mem(Bitu mem,Bitu param) {
+ gen_mov_word_to_reg(param, (void *)mem, 1);
+}
+#else
+ other arm abis
+#endif
+
+// jump to an address pointed at by ptr, offset is in imm
+static void gen_jmp_ptr(void * ptr,Bits imm=0) {
+ Bit32u scale;
+
+ gen_mov_word_to_reg(temp3, ptr, 1);
+
+#if !(defined(C_UNALIGNED_MEMORY) || (C_TARGETCPU == ARMV7LE))
+// (*ptr) should be word aligned
+ if ((imm & 0x03) == 0) {
+#endif
+ if ((imm >= 0) && (imm < 4096)) {
+ cache_addd( LDR_IMM(temp1, temp3, imm) ); // ldr temp1, [temp3, #imm]
+ } else {
+ gen_mov_dword_to_reg_imm(temp2, imm);
+ cache_addd( LDR_REG_LSL_IMM(temp1, temp3, temp2, 0) ); // ldr temp1, [temp3, temp2]
+ }
+#if !(defined(C_UNALIGNED_MEMORY) || (C_TARGETCPU == ARMV7LE))
+ } else {
+ gen_add_imm(temp3, imm);
+
+ cache_addd( LDRB_IMM(temp1, temp3, 0) ); // ldrb temp1, [temp3]
+ cache_addd( LDRB_IMM(temp2, temp3, 1) ); // ldrb temp2, [temp3, #1]
+ cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 8) ); // orr temp1, temp1, temp2, lsl #8
+ cache_addd( LDRB_IMM(temp2, temp3, 2) ); // ldrb temp2, [temp3, #2]
+ cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 16) ); // orr temp1, temp1, temp2, lsl #16
+ cache_addd( LDRB_IMM(temp2, temp3, 3) ); // ldrb temp2, [temp3, #3]
+ cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 24) ); // orr temp1, temp1, temp2, lsl #24
+ }
+#endif
+
+ cache_addd( BX(temp1) ); // bx temp1
+}
+
+// short conditional jump (+-127 bytes) if register is zero
+// the destination is set by gen_fill_branch() later
+static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) {
+ if (dword) {
+ cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0
+ } else {
+ cache_addd( MOVS_REG_LSL_IMM(temp1, reg, 16) ); // movs temp1, reg, lsl #16
+ }
+ cache_addd( BEQ_FWD(0) ); // beq j
+ return ((Bit32u)cache.pos-4);
+}
+
+// short conditional jump (+-127 bytes) if register is nonzero
+// the destination is set by gen_fill_branch() later
+static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) {
+ if (dword) {
+ cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0
+ } else {
+ cache_addd( MOVS_REG_LSL_IMM(temp1, reg, 16) ); // movs temp1, reg, lsl #16
+ }
+ cache_addd( BNE_FWD(0) ); // bne j
+ return ((Bit32u)cache.pos-4);
+}
+
+// calculate relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) {
+#if C_DEBUG
+ Bits len=(Bit32u)cache.pos-(data+8);
+ if (len<0) len=-len;
+ if (len>0x02000000) LOG_MSG("Big jump %d",len);
+#endif
+ *(Bit32u*)data=( (*(Bit32u*)data) & 0xff000000 ) | ( ( ((Bit32u)cache.pos - (data+8)) >> 2 ) & 0x00ffffff );
+}
+
+// conditional jump if register is nonzero
+// for isdword==true the 32bit of the register are tested
+// for isdword==false the lowest 8bit of the register are tested
+static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) {
+ if (isdword) {
+ cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0
+ } else {
+ cache_addd( TST_IMM(reg, 0xff, 0) ); // tst reg, #0xff
+ }
+ cache_addd( BNE_FWD(0) ); // bne j
+ return ((Bit32u)cache.pos-4);
+}
+
+// compare 32bit-register against zero and jump if value less/equal than zero
+static Bit32u gen_create_branch_long_leqzero(HostReg reg) {
+ cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0
+ cache_addd( BLE_FWD(0) ); // ble j
+ return ((Bit32u)cache.pos-4);
+}
+
+// calculate long relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch_long(Bit32u data) {
+ *(Bit32u*)data=( (*(Bit32u*)data) & 0xff000000 ) | ( ( ((Bit32u)cache.pos - (data+8)) >> 2 ) & 0x00ffffff );
+}
+
+static void gen_run_code(void) {
+#if C_TARGETCPU == ARMV7LE
+ cache_addd(0xe92d4df0); // stmfd sp!, {v1-v5,v7,v8,lr}
+
+ cache_addd( MOVW(FC_SEGS_ADDR, ((Bit32u)&Segs) & 0xffff) ); // movw FC_SEGS_ADDR, #(&Segs & 0xffff)
+ cache_addd( MOVT(FC_SEGS_ADDR, ((Bit32u)&Segs) >> 16) ); // movt FC_SEGS_ADDR, #(&Segs >> 16)
+
+ cache_addd( MOVW(FC_REGS_ADDR, ((Bit32u)&cpu_regs) & 0xffff) ); // movw FC_REGS_ADDR, #(&cpu_regs & 0xffff)
+ cache_addd( MOVT(FC_REGS_ADDR, ((Bit32u)&cpu_regs) >> 16) ); // movt FC_REGS_ADDR, #(&cpu_regs >> 16)
+
+ cache_addd( MOVW(readdata_addr, ((Bitu)&core_dynrec.readdata) & 0xffff) ); // movw readdata_addr, #(&core_dynrec.readdata & 0xffff)
+ cache_addd( MOVT(readdata_addr, ((Bitu)&core_dynrec.readdata) >> 16) ); // movt readdata_addr, #(&core_dynrec.readdata >> 16)
+
+ cache_addd( BX(HOST_r0) ); // bx r0
+#else
+ Bit8u *pos1, *pos2, *pos3;
+
+ cache_addd(0xe92d4df0); // stmfd sp!, {v1-v5,v7,v8,lr}
+
+ pos1 = cache.pos;
+ cache_addd( 0 );
+ pos2 = cache.pos;
+ cache_addd( 0 );
+ pos3 = cache.pos;
+ cache_addd( 0 );
+
+ cache_addd( BX(HOST_r0) ); // bx r0
+
+ // align cache.pos to 32 bytes
+ if ((((Bitu)cache.pos) & 0x1f) != 0) {
+ cache.pos = cache.pos + (32 - (((Bitu)cache.pos) & 0x1f));
+ }
+
+ *(Bit32u*)pos1 = LDR_IMM(FC_SEGS_ADDR, HOST_pc, cache.pos - (pos1 + 8)); // ldr FC_SEGS_ADDR, [pc, #(&Segs)]
+ cache_addd((Bit32u)&Segs); // address of "Segs"
+
+ *(Bit32u*)pos2 = LDR_IMM(FC_REGS_ADDR, HOST_pc, cache.pos - (pos2 + 8)); // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)]
+ cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs"
+
+ *(Bit32u*)pos3 = LDR_IMM(readdata_addr, HOST_pc, cache.pos - (pos3 + 8)); // ldr readdata_addr, [pc, #(&core_dynrec.readdata)]
+ cache_addd((Bit32u)&core_dynrec.readdata); // address of "core_dynrec.readdata"
+
+ // align cache.pos to 32 bytes
+ if ((((Bitu)cache.pos) & 0x1f) != 0) {
+ cache.pos = cache.pos + (32 - (((Bitu)cache.pos) & 0x1f));
+ }
+#endif
+}
+
+// return from a function
+static void gen_return_function(void) {
+ cache_addd(0xe8bd8df0); // ldmfd sp!, {v1-v5,v7,v8,pc}
+}
+
+#ifdef DRC_FLAGS_INVALIDATION
+
+// called when a call to a function can be replaced by a
+// call to a simpler function
+static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) {
+#ifdef DRC_FLAGS_INVALIDATION_DCODE
+ // try to avoid function calls but rather directly fill in code
+ switch (flags_type) {
+ case t_ADDb:
+ case t_ADDw:
+ case t_ADDd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=ADD_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // add FC_RETOP, a1, a2
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=ORR_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // orr FC_RETOP, a1, a2
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=AND_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // and FC_RETOP, a1, a2
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ case t_SUBb:
+ case t_SUBw:
+ case t_SUBd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=SUB_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // sub FC_RETOP, a1, a2
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=EOR_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // eor FC_RETOP, a1, a2
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ case t_CMPb:
+ case t_CMPw:
+ case t_CMPd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ case t_INCb:
+ case t_INCw:
+ case t_INCd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=ADD_IMM(FC_RETOP, HOST_a1, 1, 0); // add FC_RETOP, a1, #1
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ case t_DECb:
+ case t_DECw:
+ case t_DECd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=SUB_IMM(FC_RETOP, HOST_a1, 1, 0); // sub FC_RETOP, a1, #1
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ case t_SHLb:
+ case t_SHLw:
+ case t_SHLd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=MOV_REG_LSL_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsl a2
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ case t_SHRb:
+ *(Bit32u*)pos=NOP; // nop
+#if C_TARGETCPU == ARMV7LE
+ *(Bit32u*)(pos+4)=BFC(HOST_a1, 8, 24); // bfc a1, 8, 24
+ *(Bit32u*)(pos+8)=MOV_REG_LSR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsr a2
+#else
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=AND_IMM(FC_RETOP, HOST_a1, 0xff, 0); // and FC_RETOP, a1, #0xff
+ *(Bit32u*)(pos+12)=MOV_REG_LSR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, lsr a2
+#endif
+ break;
+ case t_SHRw:
+ *(Bit32u*)pos=NOP; // nop
+#if C_TARGETCPU == ARMV7LE
+ *(Bit32u*)(pos+4)=BFC(HOST_a1, 16, 16); // bfc a1, 16, 16
+ *(Bit32u*)(pos+8)=MOV_REG_LSR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsr a2
+#else
+ *(Bit32u*)(pos+4)=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16
+ *(Bit32u*)(pos+8)=MOV_REG_LSR_IMM(FC_RETOP, FC_RETOP, 16); // mov FC_RETOP, FC_RETOP, lsr #16
+ *(Bit32u*)(pos+12)=MOV_REG_LSR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, lsr a2
+#endif
+ break;
+ case t_SHRd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=MOV_REG_LSR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsr a2
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ case t_SARb:
+ *(Bit32u*)pos=NOP; // nop
+#if C_TARGETCPU == ARMV7LE
+ *(Bit32u*)(pos+4)=SXTB(FC_RETOP, HOST_a1, 0); // sxtb FC_RETOP, a1
+ *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2
+#else
+ *(Bit32u*)(pos+4)=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 24); // mov FC_RETOP, a1, lsl #24
+ *(Bit32u*)(pos+8)=MOV_REG_ASR_IMM(FC_RETOP, FC_RETOP, 24); // mov FC_RETOP, FC_RETOP, asr #24
+ *(Bit32u*)(pos+12)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2
+#endif
+ break;
+ case t_SARw:
+ *(Bit32u*)pos=NOP; // nop
+#if C_TARGETCPU == ARMV7LE
+ *(Bit32u*)(pos+4)=SXTH(FC_RETOP, HOST_a1, 0); // sxth FC_RETOP, a1
+ *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2
+#else
+ *(Bit32u*)(pos+4)=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16
+ *(Bit32u*)(pos+8)=MOV_REG_ASR_IMM(FC_RETOP, FC_RETOP, 16); // mov FC_RETOP, FC_RETOP, asr #16
+ *(Bit32u*)(pos+12)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2
+#endif
+ break;
+ case t_SARd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, asr a2
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ case t_RORb:
+#if C_TARGETCPU == ARMV7LE
+ *(Bit32u*)pos=BFI(HOST_a1, HOST_a1, 8, 8); // bfi a1, a1, 8, 8
+ *(Bit32u*)(pos+4)=BFI(HOST_a1, HOST_a1, 16, 16); // bfi a1, a1, 16, 16
+ *(Bit32u*)(pos+8)=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2
+#else
+ *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 24); // mov FC_RETOP, a1, lsl #24
+ *(Bit32u*)(pos+4)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 8); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #8
+ *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
+ *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2
+#endif
+ break;
+ case t_RORw:
+ *(Bit32u*)pos=NOP; // nop
+#if C_TARGETCPU == ARMV7LE
+ *(Bit32u*)(pos+4)=BFI(HOST_a1, HOST_a1, 16, 16); // bfi a1, a1, 16, 16
+ *(Bit32u*)(pos+8)=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2
+#else
+ *(Bit32u*)(pos+4)=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16
+ *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
+ *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2
+#endif
+ break;
+ case t_RORd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ case t_ROLw:
+#if C_TARGETCPU == ARMV7LE
+ *(Bit32u*)pos=BFI(HOST_a1, HOST_a1, 16, 16); // bfi a1, a1, 16, 16
+ *(Bit32u*)(pos+4)=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32
+ *(Bit32u*)(pos+8)=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2
+#else
+ *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16
+ *(Bit32u*)(pos+4)=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32
+ *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
+ *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2
+#endif
+ break;
+ case t_ROLd:
+ *(Bit32u*)pos=NOP; // nop
+#if C_TARGETCPU == ARMV7LE
+ *(Bit32u*)(pos+4)=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32
+ *(Bit32u*)(pos+8)=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2
+#else
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32
+ *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2
+#endif
+ break;
+ case t_NEGb:
+ case t_NEGw:
+ case t_NEGd:
+ *(Bit32u*)pos=NOP; // nop
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=RSB_IMM(FC_RETOP, HOST_a1, 0, 0); // rsb FC_RETOP, a1, #0
+#if C_TARGETCPU != ARMV7LE
+ *(Bit32u*)(pos+12)=NOP; // nop
+#endif
+ break;
+ default:
+#if C_TARGETCPU == ARMV7LE
+ *(Bit32u*)pos=MOVW(temp1, ((Bit32u)fct_ptr) & 0xffff); // movw temp1, #(fct_ptr & 0xffff)
+ *(Bit32u*)(pos+4)=MOVT(temp1, ((Bit32u)fct_ptr) >> 16); // movt temp1, #(fct_ptr >> 16)
+#else
+ *(Bit32u*)(pos+12)=(Bit32u)fct_ptr; // simple_func
+#endif
+ break;
+
+ }
+#else
+#if C_TARGETCPU == ARMV7LE
+ *(Bit32u*)pos=MOVW(temp1, ((Bit32u)fct_ptr) & 0xffff); // movw temp1, #(fct_ptr & 0xffff)
+ *(Bit32u*)(pos+4)=MOVT(temp1, ((Bit32u)fct_ptr) >> 16); // movt temp1, #(fct_ptr >> 16)
+#else
+ *(Bit32u*)(pos+12)=(Bit32u)fct_ptr; // simple_func
+#endif
+#endif
+}
+#endif
+
+static void cache_block_before_close(void) { }
+
+#ifdef DRC_USE_SEGS_ADDR
+
+// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) {
+ cache_addd( LDRH_IMM(dest_reg, FC_SEGS_ADDR, index) ); // ldrh dest_reg, [FC_SEGS_ADDR, #index]
+}
+
+// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) {
+ cache_addd( LDR_IMM(dest_reg, FC_SEGS_ADDR, index) ); // ldr dest_reg, [FC_SEGS_ADDR, #index]
+}
+
+// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero)
+static void gen_add_seg32_to_reg(HostReg reg,Bitu index) {
+ cache_addd( LDR_IMM(temp1, FC_SEGS_ADDR, index) ); // ldr temp1, [FC_SEGS_ADDR, #index]
+ cache_addd( ADD_REG_LSL_IMM(reg, reg, temp1, 0) ); // add reg, reg, temp1
+}
+
+#endif
+
+#ifdef DRC_USE_REGS_ADDR
+
+// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) {
+ cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrh dest_reg, [FC_REGS_ADDR, #index]
+}
+
+// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) {
+ cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldr dest_reg, [FC_REGS_ADDR, #index]
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) {
+ if (dword) {
+ cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldr dest_reg, [FC_REGS_ADDR, #index]
+ } else {
+ cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrh dest_reg, [FC_REGS_ADDR, #index]
+ }
+}
+
+// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) {
+ cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrb dest_reg, [FC_REGS_ADDR, #index]
+}
+
+// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) {
+ cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrb dest_reg, [FC_REGS_ADDR, #index]
+}
+
+
+// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_add_regval32_to_reg(HostReg reg,Bitu index) {
+ cache_addd( LDR_IMM(temp2, FC_REGS_ADDR, index) ); // ldr temp2, [FC_REGS_ADDR, #index]
+ cache_addd( ADD_REG_LSL_IMM(reg, reg, temp2, 0) ); // add reg, reg, temp2
+}
+
+
+// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero)
+static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) {
+ cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) ); // strh src_reg, [FC_REGS_ADDR, #index]
+}
+
+// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) {
+ cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) ); // str src_reg, [FC_REGS_ADDR, #index]
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
+static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) {
+ if (dword) {
+ cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) ); // str src_reg, [FC_REGS_ADDR, #index]
+ } else {
+ cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) ); // strh src_reg, [FC_REGS_ADDR, #index]
+ }
+}
+
+// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR
+static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) {
+ cache_addd( STRB_IMM(src_reg, FC_REGS_ADDR, index) ); // strb src_reg, [FC_REGS_ADDR, #index]
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2002-2010 The DOSBox Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* $Id: risc_armv4le-s3.h,v 1.6 2009-06-27 12:51:10 c2woody Exp $ */
+
+
+/* ARMv4 (little endian) backend by M-HT (speed-tweaked arm version) */
+
+
+// temporary registers
+#define temp1 HOST_ip
+#define temp2 HOST_v3
+#define temp3 HOST_v4
+
+// register that holds function return values
+#define FC_RETOP HOST_a1
+
+// register used for address calculations,
+#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG
+
+// register that holds the first parameter
+#define FC_OP1 HOST_a1
+
+// register that holds the second parameter
+#define FC_OP2 HOST_a2
+
+// special register that holds the third parameter for _R3 calls (byte accessible)
+#define FC_OP3 HOST_v2
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA1 HOST_a1
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA2 HOST_a2
+
+// temporary register for LEA
+#define TEMP_REG_DRC HOST_v2
+
+#ifdef DRC_USE_REGS_ADDR
+// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code
+#define FC_REGS_ADDR HOST_v7
+#endif
+
+#ifdef DRC_USE_SEGS_ADDR
+// used to hold the address of "Segs" - preferably filled in function gen_run_code
+#define FC_SEGS_ADDR HOST_v8
+#endif
+
+
+// helper macro
+#define ROTATE_SCALE(x) ( (x)?(32 - x):(0) )
+
+
+// instruction encodings
+
+// move
+// mov dst, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define MOV_IMM(dst, imm, rimm) (0xe3a00000 + ((dst) << 12) + (imm) + ((rimm) << 7) )
+// mov dst, src, lsl #imm
+#define MOV_REG_LSL_IMM(dst, src, imm) (0xe1a00000 + ((dst) << 12) + (src) + ((imm) << 7) )
+// movs dst, src, lsl #imm
+#define MOVS_REG_LSL_IMM(dst, src, imm) (0xe1b00000 + ((dst) << 12) + (src) + ((imm) << 7) )
+// mov dst, src, lsr #imm
+#define MOV_REG_LSR_IMM(dst, src, imm) (0xe1a00020 + ((dst) << 12) + (src) + ((imm) << 7) )
+// mov dst, src, asr #imm
+#define MOV_REG_ASR_IMM(dst, src, imm) (0xe1a00040 + ((dst) << 12) + (src) + ((imm) << 7) )
+// mov dst, src, lsl rreg
+#define MOV_REG_LSL_REG(dst, src, rreg) (0xe1a00010 + ((dst) << 12) + (src) + ((rreg) << 8) )
+// mov dst, src, lsr rreg
+#define MOV_REG_LSR_REG(dst, src, rreg) (0xe1a00030 + ((dst) << 12) + (src) + ((rreg) << 8) )
+// mov dst, src, asr rreg
+#define MOV_REG_ASR_REG(dst, src, rreg) (0xe1a00050 + ((dst) << 12) + (src) + ((rreg) << 8) )
+// mov dst, src, ror rreg
+#define MOV_REG_ROR_REG(dst, src, rreg) (0xe1a00070 + ((dst) << 12) + (src) + ((rreg) << 8) )
+// mvn dst, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define MVN_IMM(dst, imm, rimm) (0xe3e00000 + ((dst) << 12) + (imm) + ((rimm) << 7) )
+
+// arithmetic
+// add dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define ADD_IMM(dst, src, imm, rimm) (0xe2800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+// add dst, src1, src2, lsl #imm
+#define ADD_REG_LSL_IMM(dst, src1, src2, imm) (0xe0800000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+// sub dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define SUB_IMM(dst, src, imm, rimm) (0xe2400000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+// sub dst, src1, src2, lsl #imm
+#define SUB_REG_LSL_IMM(dst, src1, src2, imm) (0xe0400000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+// rsb dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define RSB_IMM(dst, src, imm, rimm) (0xe2600000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+// cmp src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define CMP_IMM(src, imm, rimm) (0xe3500000 + ((src) << 16) + (imm) + ((rimm) << 7) )
+// nop
+#define NOP MOV_REG_LSL_IMM(HOST_r0, HOST_r0, 0)
+
+// logical
+// tst src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define TST_IMM(src, imm, rimm) (0xe3100000 + ((src) << 16) + (imm) + ((rimm) << 7) )
+// and dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define AND_IMM(dst, src, imm, rimm) (0xe2000000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+// and dst, src1, src2, lsl #imm
+#define AND_REG_LSL_IMM(dst, src1, src2, imm) (0xe0000000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+// orr dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define ORR_IMM(dst, src, imm, rimm) (0xe3800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+// orr dst, src1, src2, lsl #imm
+#define ORR_REG_LSL_IMM(dst, src1, src2, imm) (0xe1800000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+// orr dst, src1, src2, lsr #imm
+#define ORR_REG_LSR_IMM(dst, src1, src2, imm) (0xe1800020 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+// eor dst, src1, src2, lsl #imm
+#define EOR_REG_LSL_IMM(dst, src1, src2, imm) (0xe0200000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) )
+// bic dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define BIC_IMM(dst, src, imm, rimm) (0xe3c00000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+
+// load
+// ldr reg, [addr, #imm] @ 0 <= imm < 4096
+#define LDR_IMM(reg, addr, imm) (0xe5900000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+// ldrh reg, [addr, #imm] @ 0 <= imm < 256
+#define LDRH_IMM(reg, addr, imm) (0xe1d000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) )
+// ldrb reg, [addr, #imm] @ 0 <= imm < 4096
+#define LDRB_IMM(reg, addr, imm) (0xe5d00000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+
+// store
+// str reg, [addr, #imm] @ 0 <= imm < 4096
+#define STR_IMM(reg, addr, imm) (0xe5800000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+// strh reg, [addr, #imm] @ 0 <= imm < 256
+#define STRH_IMM(reg, addr, imm) (0xe1c000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) )
+// strb reg, [addr, #imm] @ 0 <= imm < 4096
+#define STRB_IMM(reg, addr, imm) (0xe5c00000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+
+// branch
+// beq pc+imm @ 0 <= imm < 32M & imm mod 4 = 0
+#define BEQ_FWD(imm) (0x0a000000 + ((imm) >> 2) )
+// bne pc+imm @ 0 <= imm < 32M & imm mod 4 = 0
+#define BNE_FWD(imm) (0x1a000000 + ((imm) >> 2) )
+// bgt pc+imm @ 0 <= imm < 32M & imm mod 4 = 0
+#define BGT_FWD(imm) (0xca000000 + ((imm) >> 2) )
+// b pc+imm @ 0 <= imm < 32M & imm mod 4 = 0
+#define B_FWD(imm) (0xea000000 + ((imm) >> 2) )
+// bx reg
+#define BX(reg) (0xe12fff10 + (reg) )
+
+
+// move a full register from reg_src to reg_dst
+static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) {
+ if(reg_src == reg_dst) return;
+ cache_addd( MOV_REG_LSL_IMM(reg_dst, reg_src, 0) ); // mov reg_dst, reg_src
+}
+
+// move a 32bit constant value into dest_reg
+static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) {
+ Bits first, scale;
+ if (imm == 0) {
+ cache_addd( MOV_IMM(dest_reg, 0, 0) ); // mov dest_reg, #0
+ } else {
+ scale = 0;
+ first = 1;
+ while (imm) {
+ while ((imm & 3) == 0) {
+ imm>>=2;
+ scale+=2;
+ }
+ if (first) {
+ cache_addd( MOV_IMM(dest_reg, imm & 0xff, ROTATE_SCALE(scale)) ); // mov dest_reg, #((imm & 0xff) << scale)
+ first = 0;
+ } else {
+ cache_addd( ORR_IMM(dest_reg, dest_reg, imm & 0xff, ROTATE_SCALE(scale)) ); // orr dest_reg, dest_reg, #((imm & 0xff) << scale)
+ }
+ imm>>=8;
+ scale+=8;
+ }
+ }
+}
+
+// helper function for gen_mov_word_to_reg
+static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) {
+ // alignment....
+ if (dword) {
+ if ((Bit32u)data & 3) {
+ if ( ((Bit32u)data & 3) == 2 ) {
+ cache_addd( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg]
+ cache_addd( LDRH_IMM(temp2, data_reg, 2) ); // ldrh temp2, [data_reg, #2]
+ cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 16) ); // orr dest_reg, dest_reg, temp2, lsl #16
+ } else {
+ cache_addd( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg]
+ cache_addd( LDRH_IMM(temp2, data_reg, 1) ); // ldrh temp2, [data_reg, #1]
+ cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 8) ); // orr dest_reg, dest_reg, temp2, lsl #8
+ cache_addd( LDRB_IMM(temp2, data_reg, 3) ); // ldrb temp2, [data_reg, #3]
+ cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 24) ); // orr dest_reg, dest_reg, temp2, lsl #24
+ }
+ } else {
+ cache_addd( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg]
+ }
+ } else {
+ if ((Bit32u)data & 1) {
+ cache_addd( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg]
+ cache_addd( LDRB_IMM(temp2, data_reg, 1) ); // ldrb temp2, [data_reg, #1]
+ cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 8) ); // orr dest_reg, dest_reg, temp2, lsl #8
+ } else {
+ cache_addd( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg]
+ }
+ }
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) {
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)data);
+ gen_mov_word_to_reg_helper(dest_reg, data, dword, temp1);
+}
+
+// move a 16bit constant value into dest_reg
+// the upper 16bit of the destination register may be destroyed
+static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) {
+ gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm);
+}
+
+// helper function for gen_mov_word_from_reg
+static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) {
+ // alignment....
+ if (dword) {
+ if ((Bit32u)dest & 3) {
+ if ( ((Bit32u)dest & 3) == 2 ) {
+ cache_addd( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg]
+ cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 16) ); // mov temp2, src_reg, lsr #16
+ cache_addd( STRH_IMM(temp2, data_reg, 2) ); // strh temp2, [data_reg, #2]
+ } else {
+ cache_addd( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg]
+ cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 8) ); // mov temp2, src_reg, lsr #8
+ cache_addd( STRH_IMM(temp2, data_reg, 1) ); // strh temp2, [data_reg, #1]
+ cache_addd( MOV_REG_LSR_IMM(temp2, temp2, 16) ); // mov temp2, temp2, lsr #16
+ cache_addd( STRB_IMM(temp2, data_reg, 3) ); // strb temp2, [data_reg, #3]
+ }
+ } else {
+ cache_addd( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg]
+ }
+ } else {
+ if ((Bit32u)dest & 1) {
+ cache_addd( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg]
+ cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 8) ); // mov temp2, src_reg, lsr #8
+ cache_addd( STRB_IMM(temp2, data_reg, 1) ); // strb temp2, [data_reg, #1]
+ } else {
+ cache_addd( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg]
+ }
+ }
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into memory
+static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) {
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest);
+ gen_mov_word_from_reg_helper(src_reg, dest, dword, temp1);
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) {
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)data);
+ cache_addd( LDRB_IMM(dest_reg, temp1, 0) ); // ldrb dest_reg, [temp1]
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) {
+ gen_mov_byte_to_reg_low(dest_reg, data);
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) {
+ cache_addd( MOV_IMM(dest_reg, imm, 0) ); // mov dest_reg, #(imm)
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) {
+ gen_mov_byte_to_reg_low_imm(dest_reg, imm);
+}
+
+// move the lowest 8bit of a register into memory
+static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) {
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest);
+ cache_addd( STRB_IMM(src_reg, temp1, 0) ); // strb src_reg, [temp1]
+}
+
+
+
+// convert an 8bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_byte(bool sign,HostReg reg) {
+ if (sign) {
+ cache_addd( MOV_REG_LSL_IMM(reg, reg, 24) ); // mov reg, reg, lsl #24
+ cache_addd( MOV_REG_ASR_IMM(reg, reg, 24) ); // mov reg, reg, asr #24
+ } else {
+ cache_addd( AND_IMM(reg, reg, 0xff, 0) ); // and reg, reg, #0xff
+ }
+}
+
+// convert a 16bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_word(bool sign,HostReg reg) {
+ if (sign) {
+ cache_addd( MOV_REG_LSL_IMM(reg, reg, 16) ); // mov reg, reg, lsl #16
+ cache_addd( MOV_REG_ASR_IMM(reg, reg, 16) ); // mov reg, reg, asr #16
+ } else {
+ cache_addd( MOV_REG_LSL_IMM(reg, reg, 16) ); // mov reg, reg, lsl #16
+ cache_addd( MOV_REG_LSR_IMM(reg, reg, 16) ); // mov reg, reg, lsr #16
+ }
+}
+
+// add a 32bit value from memory to a full register
+static void gen_add(HostReg reg,void* op) {
+ gen_mov_word_to_reg(temp3, op, 1);
+ cache_addd( ADD_REG_LSL_IMM(reg, reg, temp3, 0) ); // add reg, reg, temp3
+}
+
+// add a 32bit constant value to a full register
+static void gen_add_imm(HostReg reg,Bit32u imm) {
+ Bits scale;
+ if(!imm) return;
+ if (imm == 0xffffffff) {
+ cache_addd( SUB_IMM(reg, reg, 1, 0) ); // sub reg, reg, #1
+ } else {
+ scale = 0;
+ while (imm) {
+ while ((imm & 3) == 0) {
+ imm>>=2;
+ scale+=2;
+ }
+ cache_addd( ADD_IMM(reg, reg, imm & 0xff, ROTATE_SCALE(scale)) ); // add reg, reg, #((imm & 0xff) << scale)
+ imm>>=8;
+ scale+=8;
+ }
+ }
+}
+
+// and a 32bit constant value with a full register
+static void gen_and_imm(HostReg reg,Bit32u imm) {
+ Bits scale;
+ Bit32u imm2;
+ imm2 = ~imm;
+ if(!imm2) return;
+ if (!imm) {
+ cache_addd( MOV_IMM(reg, 0, 0) ); // mov reg, #0
+ } else {
+ scale = 0;
+ while (imm2) {
+ while ((imm2 & 3) == 0) {
+ imm2>>=2;
+ scale+=2;
+ }
+ cache_addd( BIC_IMM(reg, reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // bic reg, reg, #((imm2 & 0xff) << scale)
+ imm2>>=8;
+ scale+=8;
+ }
+ }
+}
+
+
+// move a 32bit constant value into memory
+static void gen_mov_direct_dword(void* dest,Bit32u imm) {
+ gen_mov_dword_to_reg_imm(temp3, imm);
+ gen_mov_word_from_reg(temp3, dest, 1);
+}
+
+// move an address into memory
+static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) {
+ gen_mov_direct_dword(dest,(Bit32u)imm);
+}
+
+// add an 8bit constant value to a dword memory value
+static void gen_add_direct_byte(void* dest,Bit8s imm) {
+ if(!imm) return;
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest);
+ gen_mov_word_to_reg_helper(temp3, dest, 1, temp1);
+ if (imm >= 0) {
+ cache_addd( ADD_IMM(temp3, temp3, (Bit32s)imm, 0) ); // add temp3, temp3, #(imm)
+ } else {
+ cache_addd( SUB_IMM(temp3, temp3, -((Bit32s)imm), 0) ); // sub temp3, temp3, #(-imm)
+ }
+ gen_mov_word_from_reg_helper(temp3, dest, 1, temp1);
+}
+
+// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value
+static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) {
+ if(!imm) return;
+ if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) {
+ gen_add_direct_byte(dest,(Bit8s)imm);
+ return;
+ }
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest);
+ gen_mov_word_to_reg_helper(temp3, dest, dword, temp1);
+ // maybe use function gen_add_imm
+ if (dword) {
+ gen_mov_dword_to_reg_imm(temp2, imm);
+ } else {
+ gen_mov_word_to_reg_imm(temp2, (Bit16u)imm);
+ }
+ cache_addd( ADD_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // add temp3, temp3, temp2
+ gen_mov_word_from_reg_helper(temp3, dest, dword, temp1);
+}
+
+// subtract an 8bit constant value from a dword memory value
+static void gen_sub_direct_byte(void* dest,Bit8s imm) {
+ if(!imm) return;
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest);
+ gen_mov_word_to_reg_helper(temp3, dest, 1, temp1);
+ if (imm >= 0) {
+ cache_addd( SUB_IMM(temp3, temp3, (Bit32s)imm, 0) ); // sub temp3, temp3, #(imm)
+ } else {
+ cache_addd( ADD_IMM(temp3, temp3, -((Bit32s)imm), 0) ); // add temp3, temp3, #(-imm)
+ }
+ gen_mov_word_from_reg_helper(temp3, dest, 1, temp1);
+}
+
+// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value
+static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) {
+ if(!imm) return;
+ if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) {
+ gen_sub_direct_byte(dest,(Bit8s)imm);
+ return;
+ }
+ gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest);
+ gen_mov_word_to_reg_helper(temp3, dest, dword, temp1);
+ // maybe use function gen_add_imm/gen_sub_imm
+ if (dword) {
+ gen_mov_dword_to_reg_imm(temp2, imm);
+ } else {
+ gen_mov_word_to_reg_imm(temp2, (Bit16u)imm);
+ }
+ cache_addd( SUB_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // sub temp3, temp3, temp2
+ gen_mov_word_from_reg_helper(temp3, dest, dword, temp1);
+}
+
+// effective address calculation, destination is dest_reg
+// scale_reg is scaled by scale (scale_reg*(2^scale)) and
+// added to dest_reg, then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) {
+ cache_addd( ADD_REG_LSL_IMM(dest_reg, dest_reg, scale_reg, scale) ); // add dest_reg, dest_reg, scale_reg, lsl #(scale)
+ gen_add_imm(dest_reg, imm);
+}
+
+// effective address calculation, destination is dest_reg
+// dest_reg is scaled by scale (dest_reg*(2^scale)),
+// then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) {
+ if (scale) {
+ cache_addd( MOV_REG_LSL_IMM(dest_reg, dest_reg, scale) ); // mov dest_reg, dest_reg, lsl #(scale)
+ }
+ gen_add_imm(dest_reg, imm);
+}
+
+// generate a call to a parameterless function
+static void INLINE gen_call_function_raw(void * func) {
+ cache_addd( LDR_IMM(temp1, HOST_pc, 4) ); // ldr temp1, [pc, #4]
+ cache_addd( ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4
+ cache_addd( BX(temp1) ); // bx temp1
+ cache_addd((Bit32u)func); // .int func
+}
+
+// generate a call to a function with paramcount parameters
+// note: the parameters are loaded in the architecture specific way
+// using the gen_load_param_ functions below
+static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) {
+ Bit32u proc_addr = (Bit32u)cache.pos;
+ gen_call_function_raw(func);
+ return proc_addr;
+}
+
+#if (1)
+// max of 4 parameters in a1-a4
+
+// load an immediate value as param'th function parameter
+static void INLINE gen_load_param_imm(Bitu imm,Bitu param) {
+ gen_mov_dword_to_reg_imm(param, imm);
+}
+
+// load an address as param'th function parameter
+static void INLINE gen_load_param_addr(Bitu addr,Bitu param) {
+ gen_mov_dword_to_reg_imm(param, addr);
+}
+
+// load a host-register as param'th function parameter
+static void INLINE gen_load_param_reg(Bitu reg,Bitu param) {
+ gen_mov_regs(param, reg);
+}
+
+// load a value from memory as param'th function parameter
+static void INLINE gen_load_param_mem(Bitu mem,Bitu param) {
+ gen_mov_word_to_reg(param, (void *)mem, 1);
+}
+#else
+ other arm abis
+#endif
+
+// jump to an address pointed at by ptr, offset is in imm
+static void gen_jmp_ptr(void * ptr,Bits imm=0) {
+ Bits scale;
+ Bitu imm2;
+ gen_mov_word_to_reg(temp3, ptr, 1);
+
+ if (imm) {
+ scale = 0;
+ imm2 = (Bitu)imm;
+ while (imm2) {
+ while ((imm2 & 3) == 0) {
+ imm2>>=2;
+ scale+=2;
+ }
+ cache_addd( ADD_IMM(temp3, temp3, imm2 & 0xff, ROTATE_SCALE(scale)) ); // add temp3, temp3, #((imm2 & 0xff) << scale)
+ imm2>>=8;
+ scale+=8;
+ }
+ }
+
+#if (1)
+// (*ptr) should be word aligned
+ if ((imm & 0x03) == 0) {
+ cache_addd( LDR_IMM(temp1, temp3, 0) ); // ldr temp1, [temp3]
+ } else
+#endif
+ {
+ cache_addd( LDRB_IMM(temp1, temp3, 0) ); // ldrb temp1, [temp3]
+ cache_addd( LDRB_IMM(temp2, temp3, 1) ); // ldrb temp2, [temp3, #1]
+ cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 8) ); // orr temp1, temp1, temp2, lsl #8
+ cache_addd( LDRB_IMM(temp2, temp3, 2) ); // ldrb temp2, [temp3, #2]
+ cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 16) ); // orr temp1, temp1, temp2, lsl #16
+ cache_addd( LDRB_IMM(temp2, temp3, 3) ); // ldrb temp2, [temp3, #3]
+ cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 24) ); // orr temp1, temp1, temp2, lsl #24
+ }
+
+ cache_addd( BX(temp1) ); // bx temp1
+}
+
+// short conditional jump (+-127 bytes) if register is zero
+// the destination is set by gen_fill_branch() later
+static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) {
+ if (dword) {
+ cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0
+ } else {
+ cache_addd( MOVS_REG_LSL_IMM(temp1, reg, 16) ); // movs temp1, reg, lsl #16
+ }
+ cache_addd( BEQ_FWD(0) ); // beq j
+ return ((Bit32u)cache.pos-4);
+}
+
+// short conditional jump (+-127 bytes) if register is nonzero
+// the destination is set by gen_fill_branch() later
+static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) {
+ if (dword) {
+ cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0
+ } else {
+ cache_addd( MOVS_REG_LSL_IMM(temp1, reg, 16) ); // movs temp1, reg, lsl #16
+ }
+ cache_addd( BNE_FWD(0) ); // bne j
+ return ((Bit32u)cache.pos-4);
+}
+
+// calculate relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) {
+#if C_DEBUG
+ Bits len=(Bit32u)cache.pos-(data+8);
+ if (len<0) len=-len;
+ if (len>0x02000000) LOG_MSG("Big jump %d",len);
+#endif
+ *(Bit32u*)data=( (*(Bit32u*)data) & 0xff000000 ) | ( ( ((Bit32u)cache.pos - (data+8)) >> 2 ) & 0x00ffffff );
+}
+
+// conditional jump if register is nonzero
+// for isdword==true the 32bit of the register are tested
+// for isdword==false the lowest 8bit of the register are tested
+static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) {
+ if (isdword) {
+ cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0
+ } else {
+ cache_addd( TST_IMM(reg, 0xff, 0) ); // tst reg, #0xff
+ }
+ cache_addd( BEQ_FWD(8) ); // beq nobranch (pc +8)
+ cache_addd( LDR_IMM(temp1, HOST_pc, 0) ); // ldr temp1, [pc, #0]
+ cache_addd( BX(temp1) ); // bx temp1
+ cache_addd(0); // fill j
+ // nobranch:
+ return ((Bit32u)cache.pos-4);
+}
+
+// compare 32bit-register against zero and jump if value less/equal than zero
+static Bit32u gen_create_branch_long_leqzero(HostReg reg) {
+ cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0
+ cache_addd( BGT_FWD(8) ); // bgt nobranch (pc+8)
+ cache_addd( LDR_IMM(temp1, HOST_pc, 0) ); // ldr temp1, [pc, #0]
+ cache_addd( BX(temp1) ); // bx temp1
+ cache_addd(0); // fill j
+ // nobranch:
+ return ((Bit32u)cache.pos-4);
+}
+
+// calculate long relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch_long(Bit32u data) {
+ // this is an absolute branch
+ *(Bit32u*)data=(Bit32u)cache.pos;
+}
+
+static void gen_run_code(void) {
+ cache_addd(0xe92d4000); // stmfd sp!, {lr}
+ cache_addd(0xe92d0cf0); // stmfd sp!, {v1-v4,v7,v8}
+
+ // adr: 8
+ cache_addd( LDR_IMM(FC_SEGS_ADDR, HOST_pc, 64 - (8 + 8)) ); // ldr FC_SEGS_ADDR, [pc, #(&Segs)]
+ // adr: 12
+ cache_addd( LDR_IMM(FC_REGS_ADDR, HOST_pc, 68 - (12 + 8)) ); // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)]
+
+ cache_addd( ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4
+ cache_addd(0xe92d4000); // stmfd sp!, {lr}
+ cache_addd( BX(HOST_r0) ); // bx r0
+
+ cache_addd(0xe8bd0cf0); // ldmfd sp!, {v1-v4,v7,v8}
+
+ cache_addd(0xe8bd4000); // ldmfd sp!, {lr}
+ cache_addd( BX(HOST_lr) ); // bx lr
+
+ // fill up to 64 bytes
+ cache_addd( NOP ); // nop
+ cache_addd( NOP ); // nop
+ cache_addd( NOP ); // nop
+ cache_addd( NOP ); // nop
+ cache_addd( NOP ); // nop
+ cache_addd( NOP ); // nop
+
+ // adr: 64
+ cache_addd((Bit32u)&Segs); // address of "Segs"
+ // adr: 68
+ cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs"
+}
+
+// return from a function
+static void gen_return_function(void) {
+ cache_addd(0xe8bd4000); // ldmfd sp!, {lr}
+ cache_addd( BX(HOST_lr) ); // bx lr
+}
+
+#ifdef DRC_FLAGS_INVALIDATION
+
+// called when a call to a function can be replaced by a
+// call to a simpler function
+static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) {
+#ifdef DRC_FLAGS_INVALIDATION_DCODE
+ // try to avoid function calls but rather directly fill in code
+ switch (flags_type) {
+ case t_ADDb:
+ case t_ADDw:
+ case t_ADDd:
+ *(Bit32u*)pos=ADD_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // add FC_RETOP, a1, a2
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ *(Bit32u*)pos=ORR_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // orr FC_RETOP, a1, a2
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ *(Bit32u*)pos=AND_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // and FC_RETOP, a1, a2
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_SUBb:
+ case t_SUBw:
+ case t_SUBd:
+ *(Bit32u*)pos=SUB_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // sub FC_RETOP, a1, a2
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ *(Bit32u*)pos=EOR_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // eor FC_RETOP, a1, a2
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_CMPb:
+ case t_CMPw:
+ case t_CMPd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ *(Bit32u*)pos=B_FWD(8); // b (pc+2*4)
+ break;
+ case t_INCb:
+ case t_INCw:
+ case t_INCd:
+ *(Bit32u*)pos=ADD_IMM(FC_RETOP, HOST_a1, 1, 0); // add FC_RETOP, a1, #1
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_DECb:
+ case t_DECw:
+ case t_DECd:
+ *(Bit32u*)pos=SUB_IMM(FC_RETOP, HOST_a1, 1, 0); // sub FC_RETOP, a1, #1
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_SHLb:
+ case t_SHLw:
+ case t_SHLd:
+ *(Bit32u*)pos=MOV_REG_LSL_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsl a2
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_SHRb:
+ *(Bit32u*)pos=AND_IMM(FC_RETOP, HOST_a1, 0xff, 0); // and FC_RETOP, a1, #0xff
+ *(Bit32u*)(pos+4)=MOV_REG_LSR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, lsr a2
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_SHRw:
+ *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16
+ *(Bit32u*)(pos+4)=MOV_REG_LSR_IMM(FC_RETOP, FC_RETOP, 16); // mov FC_RETOP, FC_RETOP, lsr #16
+ *(Bit32u*)(pos+8)=MOV_REG_LSR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, lsr a2
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_SHRd:
+ *(Bit32u*)pos=MOV_REG_LSR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsr a2
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_SARb:
+ *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 24); // mov FC_RETOP, a1, lsl #24
+ *(Bit32u*)(pos+4)=MOV_REG_ASR_IMM(FC_RETOP, FC_RETOP, 24); // mov FC_RETOP, FC_RETOP, asr #24
+ *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_SARw:
+ *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16
+ *(Bit32u*)(pos+4)=MOV_REG_ASR_IMM(FC_RETOP, FC_RETOP, 16); // mov FC_RETOP, FC_RETOP, asr #16
+ *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_SARd:
+ *(Bit32u*)pos=MOV_REG_ASR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, asr a2
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_RORb:
+ *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 24); // mov FC_RETOP, a1, lsl #24
+ *(Bit32u*)(pos+4)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 8); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #8
+ *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
+ *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2
+ break;
+ case t_RORw:
+ *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16
+ *(Bit32u*)(pos+4)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
+ *(Bit32u*)(pos+8)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_RORd:
+ *(Bit32u*)pos=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_ROLw:
+ *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16
+ *(Bit32u*)(pos+4)=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32
+ *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
+ *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2
+ break;
+ case t_ROLd:
+ *(Bit32u*)pos=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32
+ *(Bit32u*)(pos+4)=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ case t_NEGb:
+ case t_NEGw:
+ case t_NEGd:
+ *(Bit32u*)pos=RSB_IMM(FC_RETOP, HOST_a1, 0, 0); // rsb FC_RETOP, a1, #0
+ *(Bit32u*)(pos+4)=NOP; // nop
+ *(Bit32u*)(pos+8)=NOP; // nop
+ *(Bit32u*)(pos+12)=NOP; // nop
+ break;
+ default:
+ *(Bit32u*)(pos+12)=(Bit32u)fct_ptr; // simple_func
+ break;
+
+ }
+#else
+ *(Bit32u*)(pos+12)=(Bit32u)fct_ptr; // simple_func
+#endif
+}
+#endif
+
+static void cache_block_before_close(void) { }
+
+#ifdef DRC_USE_SEGS_ADDR
+
+// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) {
+ cache_addd( LDRH_IMM(dest_reg, FC_SEGS_ADDR, index) ); // ldrh dest_reg, [FC_SEGS_ADDR, #index]
+}
+
+// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) {
+ cache_addd( LDR_IMM(dest_reg, FC_SEGS_ADDR, index) ); // ldr dest_reg, [FC_SEGS_ADDR, #index]
+}
+
+// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero)
+static void gen_add_seg32_to_reg(HostReg reg,Bitu index) {
+ cache_addd( LDR_IMM(temp1, FC_SEGS_ADDR, index) ); // ldr temp1, [FC_SEGS_ADDR, #index]
+ cache_addd( ADD_REG_LSL_IMM(reg, reg, temp1, 0) ); // add reg, reg, temp1
+}
+
+#endif
+
+#ifdef DRC_USE_REGS_ADDR
+
+// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) {
+ cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrh dest_reg, [FC_REGS_ADDR, #index]
+}
+
+// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) {
+ cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldr dest_reg, [FC_REGS_ADDR, #index]
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) {
+ if (dword) {
+ cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldr dest_reg, [FC_REGS_ADDR, #index]
+ } else {
+ cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrh dest_reg, [FC_REGS_ADDR, #index]
+ }
+}
+
+// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) {
+ cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrb dest_reg, [FC_REGS_ADDR, #index]
+}
+
+// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) {
+ cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrb dest_reg, [FC_REGS_ADDR, #index]
+}
+
+
+// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_add_regval32_to_reg(HostReg reg,Bitu index) {
+ cache_addd( LDR_IMM(temp2, FC_REGS_ADDR, index) ); // ldr temp2, [FC_REGS_ADDR, #index]
+ cache_addd( ADD_REG_LSL_IMM(reg, reg, temp2, 0) ); // add reg, reg, temp2
+}
+
+
+// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero)
+static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) {
+ cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) ); // strh src_reg, [FC_REGS_ADDR, #index]
+}
+
+// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) {
+ cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) ); // str src_reg, [FC_REGS_ADDR, #index]
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
+static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) {
+ if (dword) {
+ cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) ); // str src_reg, [FC_REGS_ADDR, #index]
+ } else {
+ cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) ); // strh src_reg, [FC_REGS_ADDR, #index]
+ }
+}
+
+// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR
+static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) {
+ cache_addd( STRB_IMM(src_reg, FC_REGS_ADDR, index) ); // strb src_reg, [FC_REGS_ADDR, #index]
+}
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+/* ARMv4 (little endian) backend by M-HT (thumb version with data pool, requires -mthumb-interwork switch when compiling dosbox) */
+
+
+// temporary "lo" registers
+#define templo1 HOST_v3
+#define templo2 HOST_v4
+#define templo3 HOST_v2
+
+// register that holds function return values
+#define FC_RETOP HOST_a1
+
+// register used for address calculations,
+#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG
+
+// register that holds the first parameter
+#define FC_OP1 HOST_a1
+
+// register that holds the second parameter
+#define FC_OP2 HOST_a2
+
+// special register that holds the third parameter for _R3 calls (byte accessible)
+#define FC_OP3 HOST_a4
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA1 HOST_a1
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA2 HOST_a2
+
+// temporary register for LEA
+#define TEMP_REG_DRC HOST_a4
+
+// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code
+#define FC_REGS_ADDR HOST_v7
+
+// used to hold the address of "Segs" - preferably filled in function gen_run_code
+#define FC_SEGS_ADDR HOST_v8
+
+// used to hold the address of "core_dynrec.readdata" - filled in function gen_run_code
+#define readdata_addr HOST_v5
+
+
+// instruction encodings
+
+// move
+// mov dst, #imm @ 0 <= imm <= 255
+#define MOV_IMM(dst, imm) (0x2000 + ((dst) << 8) + (imm) )
+// mov dst, src
+#define MOV_REG(dst, src) ADD_IMM3(dst, src, 0)
+// mov dst, src
+#define MOV_LO_HI(dst, src) (0x4640 + (dst) + (((src) - HOST_r8) << 3) )
+// mov dst, src
+#define MOV_HI_LO(dst, src) (0x4680 + ((dst) - HOST_r8) + ((src) << 3) )
+
+// arithmetic
+// add dst, src, #imm @ 0 <= imm <= 7
+#define ADD_IMM3(dst, src, imm) (0x1c00 + (dst) + ((src) << 3) + ((imm) << 6) )
+// add dst, #imm @ 0 <= imm <= 255
+#define ADD_IMM8(dst, imm) (0x3000 + ((dst) << 8) + (imm) )
+// add dst, src1, src2
+#define ADD_REG(dst, src1, src2) (0x1800 + (dst) + ((src1) << 3) + ((src2) << 6) )
+// add dst, pc, #imm @ 0 <= imm < 1024 & imm mod 4 = 0
+#define ADD_LO_PC_IMM(dst, imm) (0xa000 + ((dst) << 8) + ((imm) >> 2) )
+// sub dst, src1, src2
+#define SUB_REG(dst, src1, src2) (0x1a00 + (dst) + ((src1) << 3) + ((src2) << 6) )
+// sub dst, src, #imm @ 0 <= imm <= 7
+#define SUB_IMM3(dst, src, imm) (0x1e00 + (dst) + ((src) << 3) + ((imm) << 6) )
+// sub dst, #imm @ 0 <= imm <= 255
+#define SUB_IMM8(dst, imm) (0x3800 + ((dst) << 8) + (imm) )
+// neg dst, src
+#define NEG(dst, src) (0x4240 + (dst) + ((src) << 3) )
+// cmp dst, #imm @ 0 <= imm <= 255
+#define CMP_IMM(dst, imm) (0x2800 + ((dst) << 8) + (imm) )
+// nop
+#define NOP (0x46c0)
+
+// logical
+// and dst, src
+#define AND(dst, src) (0x4000 + (dst) + ((src) << 3) )
+// bic dst, src
+#define BIC(dst, src) (0x4380 + (dst) + ((src) << 3) )
+// eor dst, src
+#define EOR(dst, src) (0x4040 + (dst) + ((src) << 3) )
+// orr dst, src
+#define ORR(dst, src) (0x4300 + (dst) + ((src) << 3) )
+// mvn dst, src
+#define MVN(dst, src) (0x43c0 + (dst) + ((src) << 3) )
+
+// shift/rotate
+// lsl dst, src, #imm
+#define LSL_IMM(dst, src, imm) (0x0000 + (dst) + ((src) << 3) + ((imm) << 6) )
+// lsl dst, reg
+#define LSL_REG(dst, reg) (0x4080 + (dst) + ((reg) << 3) )
+// lsr dst, src, #imm
+#define LSR_IMM(dst, src, imm) (0x0800 + (dst) + ((src) << 3) + ((imm) << 6) )
+// lsr dst, reg
+#define LSR_REG(dst, reg) (0x40c0 + (dst) + ((reg) << 3) )
+// asr dst, src, #imm
+#define ASR_IMM(dst, src, imm) (0x1000 + (dst) + ((src) << 3) + ((imm) << 6) )
+// asr dst, reg
+#define ASR_REG(dst, reg) (0x4100 + (dst) + ((reg) << 3) )
+// ror dst, reg
+#define ROR_REG(dst, reg) (0x41c0 + (dst) + ((reg) << 3) )
+
+// load
+// ldr reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0
+#define LDR_IMM(reg, addr, imm) (0x6800 + (reg) + ((addr) << 3) + ((imm) << 4) )
+// ldrh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0
+#define LDRH_IMM(reg, addr, imm) (0x8800 + (reg) + ((addr) << 3) + ((imm) << 5) )
+// ldrb reg, [addr, #imm] @ 0 <= imm < 32
+#define LDRB_IMM(reg, addr, imm) (0x7800 + (reg) + ((addr) << 3) + ((imm) << 6) )
+// ldr reg, [pc, #imm] @ 0 <= imm < 1024 & imm mod 4 = 0
+#define LDR_PC_IMM(reg, imm) (0x4800 + ((reg) << 8) + ((imm) >> 2) )
+// ldr reg, [addr1, addr2]
+#define LDR_REG(reg, addr1, addr2) (0x5800 + (reg) + ((addr1) << 3) + ((addr2) << 6) )
+
+// store
+// str reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0
+#define STR_IMM(reg, addr, imm) (0x6000 + (reg) + ((addr) << 3) + ((imm) << 4) )
+// strh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0
+#define STRH_IMM(reg, addr, imm) (0x8000 + (reg) + ((addr) << 3) + ((imm) << 5) )
+// strb reg, [addr, #imm] @ 0 <= imm < 32
+#define STRB_IMM(reg, addr, imm) (0x7000 + (reg) + ((addr) << 3) + ((imm) << 6) )
+
+// branch
+// beq pc+imm @ 0 <= imm < 256 & imm mod 2 = 0
+#define BEQ_FWD(imm) (0xd000 + ((imm) >> 1) )
+// bne pc+imm @ 0 <= imm < 256 & imm mod 2 = 0
+#define BNE_FWD(imm) (0xd100 + ((imm) >> 1) )
+// bgt pc+imm @ 0 <= imm < 256 & imm mod 2 = 0
+#define BGT_FWD(imm) (0xdc00 + ((imm) >> 1) )
+// b pc+imm @ 0 <= imm < 2048 & imm mod 2 = 0
+#define B_FWD(imm) (0xe000 + ((imm) >> 1) )
+// bx reg
+#define BX(reg) (0x4700 + ((reg) << 3) )
+
+
+// arm instructions
+
+// arithmetic
+// add dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define ARM_ADD_IMM(dst, src, imm, rimm) (0xe2800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+
+// load
+// ldr reg, [addr, #imm] @ 0 <= imm < 4096
+#define ARM_LDR_IMM(reg, addr, imm) (0xe5900000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+
+// store
+// str reg, [addr, #-(imm)]! @ 0 <= imm < 4096
+#define ARM_STR_IMM_M_W(reg, addr, imm) (0xe5200000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+
+// branch
+// bx reg
+#define ARM_BX(reg) (0xe12fff10 + (reg) )
+
+
+// data pool defines
+#define CACHE_DATA_JUMP (2)
+#define CACHE_DATA_ALIGN (32)
+#define CACHE_DATA_MIN (32)
+#define CACHE_DATA_MAX (288)
+
+// data pool variables
+static Bit8u * cache_datapos = NULL; // position of data pool in the cache block
+static Bit32u cache_datasize = 0; // total size of data pool
+static Bit32u cache_dataindex = 0; // used size of data pool = index of free data item (in bytes) in data pool
+
+
+// forwarded function
+static void INLINE gen_create_branch_short(void * func);
+
+// function to check distance to data pool
+// if too close, then generate jump after data pool
+static void cache_checkinstr(Bit32u size) {
+ if (cache_datasize == 0) {
+ if (cache_datapos != NULL) {
+ if (cache.pos + size + CACHE_DATA_JUMP >= cache_datapos) {
+ cache_datapos = NULL;
+ }
+ }
+ return;
+ }
+
+ if (cache.pos + size + CACHE_DATA_JUMP <= cache_datapos) return;
+
+ {
+ register Bit8u * newcachepos;
+
+ newcachepos = cache_datapos + cache_datasize;
+ gen_create_branch_short(newcachepos);
+ cache.pos = newcachepos;
+ }
+
+ if (cache.pos + CACHE_DATA_MAX + CACHE_DATA_ALIGN >= cache.block.active->cache.start + cache.block.active->cache.size &&
+ cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) < cache.block.active->cache.start + cache.block.active->cache.size)
+ {
+ cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + cache.block.active->cache.size - CACHE_DATA_ALIGN) & ~(CACHE_DATA_ALIGN - 1));
+ } else {
+ register Bit32u cachemodsize;
+
+ cachemodsize = (cache.pos - cache.block.active->cache.start) & (CACHE_MAXSIZE - 1);
+
+ if (cachemodsize + CACHE_DATA_MAX + CACHE_DATA_ALIGN <= CACHE_MAXSIZE ||
+ cachemodsize + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) > CACHE_MAXSIZE)
+ {
+ cache_datapos = (Bit8u *) (((Bitu)cache.pos + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1));
+ } else {
+ cache_datapos = (Bit8u *) (((Bitu)cache.pos + (CACHE_MAXSIZE - CACHE_DATA_ALIGN) - cachemodsize) & ~(CACHE_DATA_ALIGN - 1));
+ }
+ }
+
+ cache_datasize = 0;
+ cache_dataindex = 0;
+}
+
+// function to reserve item in data pool
+// returns address of item
+static Bit8u * cache_reservedata(void) {
+ // if data pool not yet initialized, then initialize data pool
+ if (GCC_UNLIKELY(cache_datapos == NULL)) {
+ if (cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN < cache.block.active->cache.start + CACHE_DATA_MAX) {
+ cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1));
+ }
+ }
+
+ // if data pool not yet used, then set data pool
+ if (cache_datasize == 0) {
+ // set data pool address is too close (or behind) cache.pos then set new data pool size
+ if (cache.pos + CACHE_DATA_MIN + CACHE_DATA_JUMP /*+ CACHE_DATA_ALIGN*/ > cache_datapos) {
+ if (cache.pos + CACHE_DATA_MAX + CACHE_DATA_ALIGN >= cache.block.active->cache.start + cache.block.active->cache.size &&
+ cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) < cache.block.active->cache.start + cache.block.active->cache.size)
+ {
+ cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + cache.block.active->cache.size - CACHE_DATA_ALIGN) & ~(CACHE_DATA_ALIGN - 1));
+ } else {
+ register Bit32u cachemodsize;
+
+ cachemodsize = (cache.pos - cache.block.active->cache.start) & (CACHE_MAXSIZE - 1);
+
+ if (cachemodsize + CACHE_DATA_MAX + CACHE_DATA_ALIGN <= CACHE_MAXSIZE ||
+ cachemodsize + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) > CACHE_MAXSIZE)
+ {
+ cache_datapos = (Bit8u *) (((Bitu)cache.pos + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1));
+ } else {
+ cache_datapos = (Bit8u *) (((Bitu)cache.pos + (CACHE_MAXSIZE - CACHE_DATA_ALIGN) - cachemodsize) & ~(CACHE_DATA_ALIGN - 1));
+ }
+ }
+ }
+ // set initial data pool size
+ cache_datasize = CACHE_DATA_ALIGN;
+ }
+
+ // if data pool is full, then enlarge data pool
+ if (cache_dataindex == cache_datasize) {
+ cache_datasize += CACHE_DATA_ALIGN;
+ }
+
+ cache_dataindex += 4;
+ return (cache_datapos + (cache_dataindex - 4));
+}
+
+static void cache_block_before_close(void) {
+ // if data pool in use, then resize cache block to include the data pool
+ if (cache_datasize != 0)
+ {
+ cache.pos = cache_datapos + cache_dataindex;
+ }
+
+ // clear the values before next use
+ cache_datapos = NULL;
+ cache_datasize = 0;
+ cache_dataindex = 0;
+}
+
+
+// move a full register from reg_src to reg_dst
+static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) {
+ if(reg_src == reg_dst) return;
+ cache_checkinstr(2);
+ cache_addw( MOV_REG(reg_dst, reg_src) ); // mov reg_dst, reg_src
+}
+
+// helper function
+static bool val_single_shift(Bit32u value, Bit32u *val_shift) {
+ Bit32u shift;
+
+ if (GCC_UNLIKELY(value == 0)) {
+ *val_shift = 0;
+ return true;
+ }
+
+ shift = 0;
+ while ((value & 1) == 0) {
+ value>>=1;
+ shift+=1;
+ }
+
+ if ((value >> 8) != 0) return false;
+
+ *val_shift = shift;
+ return true;
+}
+
+// move a 32bit constant value into dest_reg
+static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) {
+ Bit32u scale;
+
+ if (imm < 256) {
+ cache_checkinstr(2);
+ cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm)
+ } else if ((~imm) < 256) {
+ cache_checkinstr(4);
+ cache_addw( MOV_IMM(dest_reg, ~imm) ); // mov dest_reg, #(~imm)
+ cache_addw( MVN(dest_reg, dest_reg) ); // mvn dest_reg, dest_reg
+ } else if (val_single_shift(imm, &scale)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_IMM(dest_reg, imm >> scale) ); // mov dest_reg, #(imm >> scale)
+ cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #scale
+ } else {
+ Bit32u diff;
+
+ cache_checkinstr(4);
+
+ diff = imm - ((Bit32u)cache.pos+4);
+
+ if ((diff < 1024) && ((imm & 0x03) == 0)) {
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( ADD_LO_PC_IMM(dest_reg, diff >> 2) ); // add dest_reg, pc, #(diff >> 2)
+ } else {
+ cache_addw( NOP ); // nop
+ cache_addw( ADD_LO_PC_IMM(dest_reg, (diff - 2) >> 2) ); // add dest_reg, pc, #((diff - 2) >> 2)
+ }
+ } else {
+ Bit8u *datapos;
+
+ datapos = cache_reservedata();
+ *(Bit32u*)datapos=imm;
+
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( LDR_PC_IMM(dest_reg, datapos - (cache.pos + 4)) ); // ldr dest_reg, [pc, datapos]
+ } else {
+ cache_addw( LDR_PC_IMM(dest_reg, datapos - (cache.pos + 2)) ); // ldr dest_reg, [pc, datapos]
+ }
+ }
+ }
+}
+
+// helper function
+static bool gen_mov_memval_to_reg_helper(HostReg dest_reg, Bit32u data, Bitu size, HostReg addr_reg, Bit32u addr_data) {
+ switch (size) {
+ case 4:
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((data & 3) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 128) && (((data - addr_data) & 3) == 0)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( LDR_IMM(dest_reg, templo2, data - addr_data) ); // ldr dest_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ }
+ break;
+ case 2:
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((data & 1) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 64) && (((data - addr_data) & 1) == 0)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( LDRH_IMM(dest_reg, templo2, data - addr_data) ); // ldrh dest_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ }
+ break;
+ case 1:
+ if ((data >= addr_data) && (data < addr_data + 32)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( LDRB_IMM(dest_reg, templo2, data - addr_data) ); // ldrb dest_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+// helper function
+static bool gen_mov_memval_to_reg(HostReg dest_reg, void *data, Bitu size) {
+ if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, FC_REGS_ADDR, (Bit32u)&cpu_regs)) return true;
+ if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, readdata_addr, (Bit32u)&core_dynrec.readdata)) return true;
+ if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, FC_SEGS_ADDR, (Bit32u)&Segs)) return true;
+ return false;
+}
+
+// helper function for gen_mov_word_to_reg
+static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) {
+ // alignment....
+ if (dword) {
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((Bit32u)data & 3) {
+ if ( ((Bit32u)data & 3) == 2 ) {
+ cache_checkinstr(8);
+ cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg]
+ cache_addw( LDRH_IMM(templo1, data_reg, 2) ); // ldrh templo1, [data_reg, #2]
+ cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16
+ cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1
+ } else {
+ cache_checkinstr(16);
+ cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg]
+ cache_addw( ADD_IMM3(templo1, data_reg, 1) ); // add templo1, data_reg, #1
+ cache_addw( LDRH_IMM(templo1, templo1, 0) ); // ldrh templo1, [templo1]
+ cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8
+ cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1
+ cache_addw( LDRB_IMM(templo1, data_reg, 3) ); // ldrb templo1, [data_reg, #3]
+ cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24
+ cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1
+ }
+ } else
+#endif
+ {
+ cache_checkinstr(2);
+ cache_addw( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg]
+ }
+ } else {
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((Bit32u)data & 1) {
+ cache_checkinstr(8);
+ cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg]
+ cache_addw( LDRB_IMM(templo1, data_reg, 1) ); // ldrb templo1, [data_reg, #1]
+ cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8
+ cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1
+ } else
+#endif
+ {
+ cache_checkinstr(2);
+ cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg]
+ }
+ }
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) {
+ if (!gen_mov_memval_to_reg(dest_reg, data, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(templo2, (Bit32u)data);
+ gen_mov_word_to_reg_helper(dest_reg, data, dword, templo2);
+ }
+}
+
+// move a 16bit constant value into dest_reg
+// the upper 16bit of the destination register may be destroyed
+static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) {
+ gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm);
+}
+
+// helper function
+static bool gen_mov_memval_from_reg_helper(HostReg src_reg, Bit32u data, Bitu size, HostReg addr_reg, Bit32u addr_data) {
+ switch (size) {
+ case 4:
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((data & 3) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 128) && (((data - addr_data) & 3) == 0)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( STR_IMM(src_reg, templo2, data - addr_data) ); // str src_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ }
+ break;
+ case 2:
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((data & 1) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 64) && (((data - addr_data) & 1) == 0)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( STRH_IMM(src_reg, templo2, data - addr_data) ); // strh src_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ }
+ break;
+ case 1:
+ if ((data >= addr_data) && (data < addr_data + 32)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( STRB_IMM(src_reg, templo2, data - addr_data) ); // strb src_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+// helper function
+static bool gen_mov_memval_from_reg(HostReg src_reg, void *dest, Bitu size) {
+ if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, FC_REGS_ADDR, (Bit32u)&cpu_regs)) return true;
+ if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, readdata_addr, (Bit32u)&core_dynrec.readdata)) return true;
+ if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, FC_SEGS_ADDR, (Bit32u)&Segs)) return true;
+ return false;
+}
+
+// helper function for gen_mov_word_from_reg
+static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) {
+ // alignment....
+ if (dword) {
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((Bit32u)dest & 3) {
+ if ( ((Bit32u)dest & 3) == 2 ) {
+ cache_checkinstr(8);
+ cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16
+ cache_addw( STRH_IMM(templo1, data_reg, 2) ); // strh templo1, [data_reg, #2]
+ } else {
+ cache_checkinstr(20);
+ cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8
+ cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16
+ cache_addw( STRB_IMM(templo1, data_reg, 2) ); // strb templo1, [data_reg, #2]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 24) ); // lsr templo1, templo1, #24
+ cache_addw( STRB_IMM(templo1, data_reg, 3) ); // strb templo1, [data_reg, #3]
+ }
+ } else
+#endif
+ {
+ cache_checkinstr(2);
+ cache_addw( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg]
+ }
+ } else {
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((Bit32u)dest & 1) {
+ cache_checkinstr(8);
+ cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8
+ cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1]
+ } else
+#endif
+ {
+ cache_checkinstr(2);
+ cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg]
+ }
+ }
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into memory
+static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) {
+ if (!gen_mov_memval_from_reg(src_reg, dest, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest);
+ gen_mov_word_from_reg_helper(src_reg, dest, dword, templo2);
+ }
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) {
+ if (!gen_mov_memval_to_reg(dest_reg, data, 1)) {
+ gen_mov_dword_to_reg_imm(templo1, (Bit32u)data);
+ cache_checkinstr(2);
+ cache_addw( LDRB_IMM(dest_reg, templo1, 0) ); // ldrb dest_reg, [templo1]
+ }
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) {
+ gen_mov_byte_to_reg_low(dest_reg, data);
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) {
+ cache_checkinstr(2);
+ cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm)
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) {
+ gen_mov_byte_to_reg_low_imm(dest_reg, imm);
+}
+
+// move the lowest 8bit of a register into memory
+static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) {
+ if (!gen_mov_memval_from_reg(src_reg, dest, 1)) {
+ gen_mov_dword_to_reg_imm(templo1, (Bit32u)dest);
+ cache_checkinstr(2);
+ cache_addw( STRB_IMM(src_reg, templo1, 0) ); // strb src_reg, [templo1]
+ }
+}
+
+
+
+// convert an 8bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_byte(bool sign,HostReg reg) {
+ cache_checkinstr(4);
+ cache_addw( LSL_IMM(reg, reg, 24) ); // lsl reg, reg, #24
+
+ if (sign) {
+ cache_addw( ASR_IMM(reg, reg, 24) ); // asr reg, reg, #24
+ } else {
+ cache_addw( LSR_IMM(reg, reg, 24) ); // lsr reg, reg, #24
+ }
+}
+
+// convert a 16bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_word(bool sign,HostReg reg) {
+ cache_checkinstr(4);
+ cache_addw( LSL_IMM(reg, reg, 16) ); // lsl reg, reg, #16
+
+ if (sign) {
+ cache_addw( ASR_IMM(reg, reg, 16) ); // asr reg, reg, #16
+ } else {
+ cache_addw( LSR_IMM(reg, reg, 16) ); // lsr reg, reg, #16
+ }
+}
+
+// add a 32bit value from memory to a full register
+static void gen_add(HostReg reg,void* op) {
+ gen_mov_word_to_reg(templo3, op, 1);
+ cache_checkinstr(2);
+ cache_addw( ADD_REG(reg, reg, templo3) ); // add reg, reg, templo3
+}
+
+// add a 32bit constant value to a full register
+static void gen_add_imm(HostReg reg,Bit32u imm) {
+ Bit32u imm2, scale;
+
+ if(!imm) return;
+
+ imm2 = (Bit32u) (-((Bit32s)imm));
+
+ if (imm <= 255) {
+ cache_checkinstr(2);
+ cache_addw( ADD_IMM8(reg, imm) ); // add reg, #imm
+ } else if (imm2 <= 255) {
+ cache_checkinstr(2);
+ cache_addw( SUB_IMM8(reg, imm2) ); // sub reg, #(-imm)
+ } else {
+ if (val_single_shift(imm2, &scale)) {
+ cache_checkinstr((scale)?6:4);
+ cache_addw( MOV_IMM(templo1, imm2 >> scale) ); // mov templo1, #(~imm >> scale)
+ if (scale) {
+ cache_addw( LSL_IMM(templo1, templo1, scale) ); // lsl templo1, templo1, #scale
+ }
+ cache_addw( SUB_REG(reg, reg, templo1) ); // sub reg, reg, templo1
+ } else {
+ gen_mov_dword_to_reg_imm(templo1, imm);
+ cache_checkinstr(2);
+ cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1
+ }
+ }
+}
+
+// and a 32bit constant value with a full register
+static void gen_and_imm(HostReg reg,Bit32u imm) {
+ Bit32u imm2, scale;
+
+ imm2 = ~imm;
+ if(!imm2) return;
+
+ if (!imm) {
+ cache_checkinstr(2);
+ cache_addw( MOV_IMM(reg, 0) ); // mov reg, #0
+ } else {
+ if (val_single_shift(imm2, &scale)) {
+ cache_checkinstr((scale)?6:4);
+ cache_addw( MOV_IMM(templo1, imm2 >> scale) ); // mov templo1, #(~imm >> scale)
+ if (scale) {
+ cache_addw( LSL_IMM(templo1, templo1, scale) ); // lsl templo1, templo1, #scale
+ }
+ cache_addw( BIC(reg, templo1) ); // bic reg, templo1
+ } else {
+ gen_mov_dword_to_reg_imm(templo1, imm);
+ cache_checkinstr(2);
+ cache_addw( AND(reg, templo1) ); // and reg, templo1
+ }
+ }
+}
+
+
+// move a 32bit constant value into memory
+static void gen_mov_direct_dword(void* dest,Bit32u imm) {
+ gen_mov_dword_to_reg_imm(templo3, imm);
+ gen_mov_word_from_reg(templo3, dest, 1);
+}
+
+// move an address into memory
+static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) {
+ gen_mov_direct_dword(dest,(Bit32u)imm);
+}
+
+// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value
+static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) {
+ if (!dword) imm &= 0xffff;
+ if(!imm) return;
+
+ if (!gen_mov_memval_to_reg(templo3, dest, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest);
+ gen_mov_word_to_reg_helper(templo3, dest, dword, templo2);
+ }
+ gen_add_imm(templo3, imm);
+ if (!gen_mov_memval_from_reg(templo3, dest, (dword)?4:2)) {
+ gen_mov_word_from_reg_helper(templo3, dest, dword, templo2);
+ }
+}
+
+// add an 8bit constant value to a dword memory value
+static void gen_add_direct_byte(void* dest,Bit8s imm) {
+ gen_add_direct_word(dest, (Bit32s)imm, 1);
+}
+
+// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value
+static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) {
+ Bit32u imm2, scale;
+
+ if (!dword) imm &= 0xffff;
+ if(!imm) return;
+
+ if (!gen_mov_memval_to_reg(templo3, dest, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest);
+ gen_mov_word_to_reg_helper(templo3, dest, dword, templo2);
+ }
+
+ imm2 = (Bit32u) (-((Bit32s)imm));
+
+ if (imm <= 255) {
+ cache_checkinstr(2);
+ cache_addw( SUB_IMM8(templo3, imm) ); // sub templo3, #imm
+ } else if (imm2 <= 255) {
+ cache_checkinstr(2);
+ cache_addw( ADD_IMM8(templo3, imm2) ); // add templo3, #(-imm)
+ } else {
+ if (val_single_shift(imm2, &scale)) {
+ cache_checkinstr((scale)?6:4);
+ cache_addw( MOV_IMM(templo1, imm2 >> scale) ); // mov templo1, #(~imm >> scale)
+ if (scale) {
+ cache_addw( LSL_IMM(templo1, templo1, scale) ); // lsl templo1, templo1, #scale
+ }
+ cache_addw( ADD_REG(templo3, templo3, templo1) ); // add templo3, templo3, templo1
+ } else {
+ gen_mov_dword_to_reg_imm(templo1, imm);
+ cache_checkinstr(2);
+ cache_addw( SUB_REG(templo3, templo3, templo1) ); // sub templo3, templo3, templo1
+ }
+ }
+
+ if (!gen_mov_memval_from_reg(templo3, dest, (dword)?4:2)) {
+ gen_mov_word_from_reg_helper(templo3, dest, dword, templo2);
+ }
+}
+
+// subtract an 8bit constant value from a dword memory value
+static void gen_sub_direct_byte(void* dest,Bit8s imm) {
+ gen_sub_direct_word(dest, (Bit32s)imm, 1);
+}
+
+// effective address calculation, destination is dest_reg
+// scale_reg is scaled by scale (scale_reg*(2^scale)) and
+// added to dest_reg, then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) {
+ if (scale) {
+ cache_checkinstr(4);
+ cache_addw( LSL_IMM(templo1, scale_reg, scale) ); // lsl templo1, scale_reg, #(scale)
+ cache_addw( ADD_REG(dest_reg, dest_reg, templo1) ); // add dest_reg, dest_reg, templo1
+ } else {
+ cache_checkinstr(2);
+ cache_addw( ADD_REG(dest_reg, dest_reg, scale_reg) ); // add dest_reg, dest_reg, scale_reg
+ }
+ gen_add_imm(dest_reg, imm);
+}
+
+// effective address calculation, destination is dest_reg
+// dest_reg is scaled by scale (dest_reg*(2^scale)),
+// then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) {
+ if (scale) {
+ cache_checkinstr(2);
+ cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #(scale)
+ }
+ gen_add_imm(dest_reg, imm);
+}
+
+// helper function for gen_call_function_raw and gen_call_function_setup
+static void gen_call_function_helper(void * func) {
+ Bit8u *datapos;
+
+ datapos = cache_reservedata();
+ *(Bit32u*)datapos=(Bit32u)func;
+
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos]
+ cache_addw( ADD_LO_PC_IMM(templo2, 8) ); // adr templo2, after_call (add templo2, pc, #8)
+ cache_addw( ADD_IMM8(templo2, 1) ); // add templo2, #1
+ cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2
+ cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state
+ cache_addw( NOP ); // nop
+ } else {
+ cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos]
+ cache_addw( ADD_LO_PC_IMM(templo2, 4) ); // adr templo2, after_call (add templo2, pc, #4)
+ cache_addw( ADD_IMM8(templo2, 1) ); // add templo2, #1
+ cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2
+ cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state
+ }
+ // after_call:
+
+ // thumb state from now on
+}
+
+// generate a call to a parameterless function
+static void INLINE gen_call_function_raw(void * func) {
+ cache_checkinstr(12);
+ gen_call_function_helper(func);
+}
+
+// generate a call to a function with paramcount parameters
+// note: the parameters are loaded in the architecture specific way
+// using the gen_load_param_ functions below
+static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) {
+ cache_checkinstr(12);
+ Bit32u proc_addr = (Bit32u)cache.pos;
+ gen_call_function_helper(func);
+ return proc_addr;
+ // if proc_addr is on word boundary ((proc_addr & 0x03) == 0)
+ // then length of generated code is 12 bytes
+ // otherwise length of generated code is 10 bytes
+}
+
+#if (1)
+// max of 4 parameters in a1-a4
+
+// load an immediate value as param'th function parameter
+static void INLINE gen_load_param_imm(Bitu imm,Bitu param) {
+ gen_mov_dword_to_reg_imm(param, imm);
+}
+
+// load an address as param'th function parameter
+static void INLINE gen_load_param_addr(Bitu addr,Bitu param) {
+ gen_mov_dword_to_reg_imm(param, addr);
+}
+
+// load a host-register as param'th function parameter
+static void INLINE gen_load_param_reg(Bitu reg,Bitu param) {
+ gen_mov_regs(param, reg);
+}
+
+// load a value from memory as param'th function parameter
+static void INLINE gen_load_param_mem(Bitu mem,Bitu param) {
+ gen_mov_word_to_reg(param, (void *)mem, 1);
+}
+#else
+ other arm abis
+#endif
+
+// jump to an address pointed at by ptr, offset is in imm
+static void gen_jmp_ptr(void * ptr,Bits imm=0) {
+ gen_mov_word_to_reg(templo3, ptr, 1);
+
+#if !defined(C_UNALIGNED_MEMORY)
+// (*ptr) should be word aligned
+ if ((imm & 0x03) == 0) {
+#endif
+ if ((imm >= 0) && (imm < 128) && ((imm & 3) == 0)) {
+ cache_checkinstr(6);
+ cache_addw( LDR_IMM(templo2, templo3, imm) ); // ldr templo2, [templo3, #imm]
+ } else {
+ gen_mov_dword_to_reg_imm(templo2, imm);
+ cache_checkinstr(6);
+ cache_addw( LDR_REG(templo2, templo3, templo2) ); // ldr templo2, [templo3, templo2]
+ }
+#if !defined(C_UNALIGNED_MEMORY)
+ } else {
+ gen_add_imm(templo3, imm);
+
+ cache_checkinstr(24);
+ cache_addw( LDRB_IMM(templo2, templo3, 0) ); // ldrb templo2, [templo3]
+ cache_addw( LDRB_IMM(templo1, templo3, 1) ); // ldrb templo1, [templo3, #1]
+ cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8
+ cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1
+ cache_addw( LDRB_IMM(templo1, templo3, 2) ); // ldrb templo1, [templo3, #2]
+ cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16
+ cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1
+ cache_addw( LDRB_IMM(templo1, templo3, 3) ); // ldrb templo1, [templo3, #3]
+ cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24
+ cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1
+ }
+#endif
+
+ // increase jmp address to keep thumb state
+ cache_addw( ADD_IMM3(templo2, templo2, 1) ); // add templo2, templo2, #1
+
+ cache_addw( BX(templo2) ); // bx templo2
+}
+
+// short conditional jump (+-127 bytes) if register is zero
+// the destination is set by gen_fill_branch() later
+static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) {
+ cache_checkinstr(4);
+ if (dword) {
+ cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0
+ } else {
+ cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16
+ }
+ cache_addw( BEQ_FWD(0) ); // beq j
+ return ((Bit32u)cache.pos-2);
+}
+
+// short conditional jump (+-127 bytes) if register is nonzero
+// the destination is set by gen_fill_branch() later
+static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) {
+ cache_checkinstr(4);
+ if (dword) {
+ cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0
+ } else {
+ cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16
+ }
+ cache_addw( BNE_FWD(0) ); // bne j
+ return ((Bit32u)cache.pos-2);
+}
+
+// calculate relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) {
+#if C_DEBUG
+ Bits len=(Bit32u)cache.pos-(data+4);
+ if (len<0) len=-len;
+ if (len>252) LOG_MSG("Big jump %d",len);
+#endif
+ *(Bit8u*)data=(Bit8u)( ((Bit32u)cache.pos-(data+4)) >> 1 );
+}
+
+
+// conditional jump if register is nonzero
+// for isdword==true the 32bit of the register are tested
+// for isdword==false the lowest 8bit of the register are tested
+static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) {
+ Bit8u *datapos;
+
+ cache_checkinstr(8);
+ datapos = cache_reservedata();
+
+ if (isdword) {
+ cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0
+ } else {
+ cache_addw( LSL_IMM(templo2, reg, 24) ); // lsl templo2, reg, #24
+ }
+ cache_addw( BEQ_FWD(2) ); // beq nobranch (pc+2)
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos]
+ } else {
+ cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos]
+ }
+ cache_addw( BX(templo1) ); // bx templo1
+ // nobranch:
+ return ((Bit32u)datapos);
+}
+
+// compare 32bit-register against zero and jump if value less/equal than zero
+static Bit32u gen_create_branch_long_leqzero(HostReg reg) {
+ Bit8u *datapos;
+
+ cache_checkinstr(8);
+ datapos = cache_reservedata();
+
+ cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0
+ cache_addw( BGT_FWD(2) ); // bgt nobranch (pc+2)
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos]
+ } else {
+ cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos]
+ }
+ cache_addw( BX(templo1) ); // bx templo1
+ // nobranch:
+ return ((Bit32u)datapos);
+}
+
+// calculate long relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch_long(Bit32u data) {
+ // this is an absolute branch
+ *(Bit32u*)data=((Bit32u)cache.pos) + 1; // add 1 to keep processor in thumb state
+}
+
+static void gen_run_code(void) {
+ Bit8u *pos1, *pos2, *pos3;
+
+#if (__ARM_EABI__)
+ // 8-byte stack alignment
+ cache_addd(0xe92d4ff0); // stmfd sp!, {v1-v8,lr}
+#else
+ cache_addd(0xe92d4df0); // stmfd sp!, {v1-v5,v7,v8,lr}
+#endif
+
+ cache_addd( ARM_ADD_IMM(HOST_r0, HOST_r0, 1, 0) ); // add r0, r0, #1
+
+ pos1 = cache.pos;
+ cache_addd( 0 );
+ pos2 = cache.pos;
+ cache_addd( 0 );
+ pos3 = cache.pos;
+ cache_addd( 0 );
+
+ cache_addd( ARM_ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4
+ cache_addd( ARM_STR_IMM_M_W(HOST_lr, HOST_sp, 4) ); // str lr, [sp, #-4]!
+ cache_addd( ARM_BX(HOST_r0) ); // bx r0
+
+#if (__ARM_EABI__)
+ cache_addd(0xe8bd4ff0); // ldmfd sp!, {v1-v8,lr}
+#else
+ cache_addd(0xe8bd4df0); // ldmfd sp!, {v1-v5,v7,v8,lr}
+#endif
+ cache_addd( ARM_BX(HOST_lr) ); // bx lr
+
+ // align cache.pos to 32 bytes
+ if ((((Bitu)cache.pos) & 0x1f) != 0) {
+ cache.pos = cache.pos + (32 - (((Bitu)cache.pos) & 0x1f));
+ }
+
+ *(Bit32u*)pos1 = ARM_LDR_IMM(FC_SEGS_ADDR, HOST_pc, cache.pos - (pos1 + 8)); // ldr FC_SEGS_ADDR, [pc, #(&Segs)]
+ cache_addd((Bit32u)&Segs); // address of "Segs"
+
+ *(Bit32u*)pos2 = ARM_LDR_IMM(FC_REGS_ADDR, HOST_pc, cache.pos - (pos2 + 8)); // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)]
+ cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs"
+
+ *(Bit32u*)pos3 = ARM_LDR_IMM(readdata_addr, HOST_pc, cache.pos - (pos3 + 8)); // ldr readdata_addr, [pc, #(&core_dynrec.readdata)]
+ cache_addd((Bit32u)&core_dynrec.readdata); // address of "core_dynrec.readdata"
+
+ // align cache.pos to 32 bytes
+ if ((((Bitu)cache.pos) & 0x1f) != 0) {
+ cache.pos = cache.pos + (32 - (((Bitu)cache.pos) & 0x1f));
+ }
+}
+
+// return from a function
+static void gen_return_function(void) {
+ cache_checkinstr(4);
+ cache_addw(0xbc08); // pop {r3}
+ cache_addw( BX(HOST_r3) ); // bx r3
+}
+
+
+// short unconditional jump (over data pool)
+// must emit at most CACHE_DATA_JUMP bytes
+static void INLINE gen_create_branch_short(void * func) {
+ cache_addw( B_FWD((Bit32u)func - ((Bit32u)cache.pos + 4)) ); // b func
+}
+
+
+#ifdef DRC_FLAGS_INVALIDATION
+
+// called when a call to a function can be replaced by a
+// call to a simpler function
+static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) {
+ if ((*(Bit16u*)pos & 0xf000) == 0xe000) {
+ if ((*(Bit16u*)pos & 0x0fff) >= ((CACHE_DATA_ALIGN / 2) - 1) &&
+ (*(Bit16u*)pos & 0x0fff) < 0x0800)
+ {
+ pos = (Bit8u *) ( ( ( (Bit32u)(*(Bit16u*)pos & 0x0fff) ) << 1 ) + ((Bit32u)pos + 4) );
+ }
+ }
+
+#ifdef DRC_FLAGS_INVALIDATION_DCODE
+ if (((Bit32u)pos & 0x03) == 0)
+ {
+ // try to avoid function calls but rather directly fill in code
+ switch (flags_type) {
+ case t_ADDb:
+ case t_ADDw:
+ case t_ADDd:
+ *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_SUBb:
+ case t_SUBw:
+ case t_SUBd:
+ *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_CMPb:
+ case t_CMPw:
+ case t_CMPd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ *(Bit16u*)pos=B_FWD(8); // b after_call (pc+8)
+ break;
+ case t_INCb:
+ case t_INCw:
+ case t_INCd:
+ *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1
+ *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_DECb:
+ case t_DECw:
+ case t_DECd:
+ *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1
+ *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_SHLb:
+ case t_SHLw:
+ case t_SHLd:
+ *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_SHRb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=NOP; // nop
+ *(Bit16u*)(pos+4)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24
+ *(Bit16u*)(pos+6)=NOP; // nop
+ *(Bit16u*)(pos+8)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+10)=NOP; // nop
+ break;
+ case t_SHRw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=NOP; // nop
+ *(Bit16u*)(pos+4)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16
+ *(Bit16u*)(pos+6)=NOP; // nop
+ *(Bit16u*)(pos+8)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+10)=NOP; // nop
+ break;
+ case t_SHRd:
+ *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_SARb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=NOP; // nop
+ *(Bit16u*)(pos+4)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24
+ *(Bit16u*)(pos+6)=NOP; // nop
+ *(Bit16u*)(pos+8)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+10)=NOP; // nop
+ break;
+ case t_SARw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=NOP; // nop
+ *(Bit16u*)(pos+4)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16
+ *(Bit16u*)(pos+6)=NOP; // nop
+ *(Bit16u*)(pos+8)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+10)=NOP; // nop
+ break;
+ case t_SARd:
+ *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_RORb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8
+ *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+6)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ break;
+ case t_RORw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+4)=NOP; // nop
+ *(Bit16u*)(pos+6)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+8)=NOP; // nop
+ *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ break;
+ case t_RORd:
+ *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_ROLw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ break;
+ case t_ROLd:
+ *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+2)=NOP; // nop
+ *(Bit16u*)(pos+4)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+6)=NOP; // nop
+ *(Bit16u*)(pos+8)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+10)=NOP; // nop
+ break;
+ case t_NEGb:
+ case t_NEGw:
+ case t_NEGd:
+ *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1
+ *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6)
+ break;
+ default:
+ *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 4) ) = (Bit32u)fct_ptr; // simple_func
+ break;
+ }
+ }
+ else
+ {
+ // try to avoid function calls but rather directly fill in code
+ switch (flags_type) {
+ case t_ADDb:
+ case t_ADDw:
+ case t_ADDd:
+ *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_SUBb:
+ case t_SUBw:
+ case t_SUBd:
+ *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_CMPb:
+ case t_CMPw:
+ case t_CMPd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ *(Bit16u*)pos=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_INCb:
+ case t_INCw:
+ case t_INCd:
+ *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1
+ *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_DECb:
+ case t_DECw:
+ case t_DECd:
+ *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1
+ *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_SHLb:
+ case t_SHLw:
+ case t_SHLd:
+ *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_SHRb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=NOP; // nop
+ *(Bit16u*)(pos+4)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24
+ *(Bit16u*)(pos+6)=NOP; // nop
+ *(Bit16u*)(pos+8)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ break;
+ case t_SHRw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=NOP; // nop
+ *(Bit16u*)(pos+4)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16
+ *(Bit16u*)(pos+6)=NOP; // nop
+ *(Bit16u*)(pos+8)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ break;
+ case t_SHRd:
+ *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_SARb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=NOP; // nop
+ *(Bit16u*)(pos+4)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24
+ *(Bit16u*)(pos+6)=NOP; // nop
+ *(Bit16u*)(pos+8)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ break;
+ case t_SARw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=NOP; // nop
+ *(Bit16u*)(pos+4)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16
+ *(Bit16u*)(pos+6)=NOP; // nop
+ *(Bit16u*)(pos+8)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ break;
+ case t_SARd:
+ *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_RORw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+4)=NOP; // nop
+ *(Bit16u*)(pos+6)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+8)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ break;
+ case t_RORd:
+ *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_ROLd:
+ *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+2)=NOP; // nop
+ *(Bit16u*)(pos+4)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+6)=NOP; // nop
+ *(Bit16u*)(pos+8)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ break;
+ case t_NEGb:
+ case t_NEGw:
+ case t_NEGd:
+ *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1
+ *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4)
+ break;
+ default:
+ *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 2) ) = (Bit32u)fct_ptr; // simple_func
+ break;
+ }
+
+ }
+#else
+ if (((Bit32u)pos & 0x03) == 0)
+ {
+ *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 4) ) = (Bit32u)fct_ptr; // simple_func
+ }
+ else
+ {
+ *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 2) ) = (Bit32u)fct_ptr; // simple_func
+ }
+#endif
+}
+#endif
+
+#ifdef DRC_USE_SEGS_ADDR
+
+// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR
+ cache_addw( LDRH_IMM(dest_reg, templo1, index) ); // ldrh dest_reg, [templo1, #index]
+}
+
+// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR
+ cache_addw( LDR_IMM(dest_reg, templo1, index) ); // ldr dest_reg, [templo1, #index]
+}
+
+// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero)
+static void gen_add_seg32_to_reg(HostReg reg,Bitu index) {
+ cache_checkinstr(6);
+ cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR
+ cache_addw( LDR_IMM(templo2, templo1, index) ); // ldr templo2, [templo1, #index]
+ cache_addw( ADD_REG(reg, reg, templo2) ); // add reg, reg, templo2
+}
+
+#endif
+
+#ifdef DRC_USE_REGS_ADDR
+
+// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index]
+}
+
+// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index]
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ if (dword) {
+ cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index]
+ } else {
+ cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index]
+ }
+}
+
+// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index]
+}
+
+// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index]
+}
+
+
+// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_add_regval32_to_reg(HostReg reg,Bitu index) {
+ cache_checkinstr(6);
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDR_IMM(templo1, templo2, index) ); // ldr templo1, [templo2, #index]
+ cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1
+}
+
+
+// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero)
+static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR
+ cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index]
+}
+
+// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR
+ cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index]
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
+static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR
+ if (dword) {
+ cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index]
+ } else {
+ cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index]
+ }
+}
+
+// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR
+static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR
+ cache_addw( STRB_IMM(src_reg, templo1, index) ); // strb src_reg, [templo1, #index]
+}
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+/* ARMv4 (little endian) backend by M-HT (thumb version with data pool) */
+
+
+// temporary "lo" registers
+#define templo1 HOST_v3
+#define templo2 HOST_v4
+#define templo3 HOST_v2
+
+// register that holds function return values
+#define FC_RETOP HOST_a1
+
+// register used for address calculations,
+#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG
+
+// register that holds the first parameter
+#define FC_OP1 HOST_a1
+
+// register that holds the second parameter
+#define FC_OP2 HOST_a2
+
+// special register that holds the third parameter for _R3 calls (byte accessible)
+#define FC_OP3 HOST_a4
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA1 HOST_a1
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA2 HOST_a2
+
+// temporary register for LEA
+#define TEMP_REG_DRC HOST_a4
+
+// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code
+#define FC_REGS_ADDR HOST_v7
+
+// used to hold the address of "Segs" - preferably filled in function gen_run_code
+#define FC_SEGS_ADDR HOST_v8
+
+// used to hold the address of "core_dynrec.readdata" - filled in function gen_run_code
+#define readdata_addr HOST_v5
+
+
+// instruction encodings
+
+// move
+// mov dst, #imm @ 0 <= imm <= 255
+#define MOV_IMM(dst, imm) (0x2000 + ((dst) << 8) + (imm) )
+// mov dst, src
+#define MOV_REG(dst, src) ADD_IMM3(dst, src, 0)
+// mov dst, src
+#define MOV_LO_HI(dst, src) (0x4640 + (dst) + (((src) - HOST_r8) << 3) )
+// mov dst, src
+#define MOV_HI_LO(dst, src) (0x4680 + ((dst) - HOST_r8) + ((src) << 3) )
+
+// arithmetic
+// add dst, src, #imm @ 0 <= imm <= 7
+#define ADD_IMM3(dst, src, imm) (0x1c00 + (dst) + ((src) << 3) + ((imm) << 6) )
+// add dst, #imm @ 0 <= imm <= 255
+#define ADD_IMM8(dst, imm) (0x3000 + ((dst) << 8) + (imm) )
+// add dst, src1, src2
+#define ADD_REG(dst, src1, src2) (0x1800 + (dst) + ((src1) << 3) + ((src2) << 6) )
+// add dst, pc, #imm @ 0 <= imm < 1024 & imm mod 4 = 0
+#define ADD_LO_PC_IMM(dst, imm) (0xa000 + ((dst) << 8) + ((imm) >> 2) )
+// sub dst, src1, src2
+#define SUB_REG(dst, src1, src2) (0x1a00 + (dst) + ((src1) << 3) + ((src2) << 6) )
+// sub dst, src, #imm @ 0 <= imm <= 7
+#define SUB_IMM3(dst, src, imm) (0x1e00 + (dst) + ((src) << 3) + ((imm) << 6) )
+// sub dst, #imm @ 0 <= imm <= 255
+#define SUB_IMM8(dst, imm) (0x3800 + ((dst) << 8) + (imm) )
+// neg dst, src
+#define NEG(dst, src) (0x4240 + (dst) + ((src) << 3) )
+// cmp dst, #imm @ 0 <= imm <= 255
+#define CMP_IMM(dst, imm) (0x2800 + ((dst) << 8) + (imm) )
+// nop
+#define NOP (0x46c0)
+
+// logical
+// and dst, src
+#define AND(dst, src) (0x4000 + (dst) + ((src) << 3) )
+// bic dst, src
+#define BIC(dst, src) (0x4380 + (dst) + ((src) << 3) )
+// eor dst, src
+#define EOR(dst, src) (0x4040 + (dst) + ((src) << 3) )
+// orr dst, src
+#define ORR(dst, src) (0x4300 + (dst) + ((src) << 3) )
+// mvn dst, src
+#define MVN(dst, src) (0x43c0 + (dst) + ((src) << 3) )
+
+// shift/rotate
+// lsl dst, src, #imm
+#define LSL_IMM(dst, src, imm) (0x0000 + (dst) + ((src) << 3) + ((imm) << 6) )
+// lsl dst, reg
+#define LSL_REG(dst, reg) (0x4080 + (dst) + ((reg) << 3) )
+// lsr dst, src, #imm
+#define LSR_IMM(dst, src, imm) (0x0800 + (dst) + ((src) << 3) + ((imm) << 6) )
+// lsr dst, reg
+#define LSR_REG(dst, reg) (0x40c0 + (dst) + ((reg) << 3) )
+// asr dst, src, #imm
+#define ASR_IMM(dst, src, imm) (0x1000 + (dst) + ((src) << 3) + ((imm) << 6) )
+// asr dst, reg
+#define ASR_REG(dst, reg) (0x4100 + (dst) + ((reg) << 3) )
+// ror dst, reg
+#define ROR_REG(dst, reg) (0x41c0 + (dst) + ((reg) << 3) )
+
+// load
+// ldr reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0
+#define LDR_IMM(reg, addr, imm) (0x6800 + (reg) + ((addr) << 3) + ((imm) << 4) )
+// ldrh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0
+#define LDRH_IMM(reg, addr, imm) (0x8800 + (reg) + ((addr) << 3) + ((imm) << 5) )
+// ldrb reg, [addr, #imm] @ 0 <= imm < 32
+#define LDRB_IMM(reg, addr, imm) (0x7800 + (reg) + ((addr) << 3) + ((imm) << 6) )
+// ldr reg, [pc, #imm] @ 0 <= imm < 1024 & imm mod 4 = 0
+#define LDR_PC_IMM(reg, imm) (0x4800 + ((reg) << 8) + ((imm) >> 2) )
+// ldr reg, [addr1, addr2]
+#define LDR_REG(reg, addr1, addr2) (0x5800 + (reg) + ((addr1) << 3) + ((addr2) << 6) )
+
+// store
+// str reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0
+#define STR_IMM(reg, addr, imm) (0x6000 + (reg) + ((addr) << 3) + ((imm) << 4) )
+// strh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0
+#define STRH_IMM(reg, addr, imm) (0x8000 + (reg) + ((addr) << 3) + ((imm) << 5) )
+// strb reg, [addr, #imm] @ 0 <= imm < 32
+#define STRB_IMM(reg, addr, imm) (0x7000 + (reg) + ((addr) << 3) + ((imm) << 6) )
+
+// branch
+// beq pc+imm @ 0 <= imm < 256 & imm mod 2 = 0
+#define BEQ_FWD(imm) (0xd000 + ((imm) >> 1) )
+// bne pc+imm @ 0 <= imm < 256 & imm mod 2 = 0
+#define BNE_FWD(imm) (0xd100 + ((imm) >> 1) )
+// bgt pc+imm @ 0 <= imm < 256 & imm mod 2 = 0
+#define BGT_FWD(imm) (0xdc00 + ((imm) >> 1) )
+// b pc+imm @ 0 <= imm < 2048 & imm mod 2 = 0
+#define B_FWD(imm) (0xe000 + ((imm) >> 1) )
+// bx reg
+#define BX(reg) (0x4700 + ((reg) << 3) )
+
+
+// arm instructions
+
+// arithmetic
+// add dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define ARM_ADD_IMM(dst, src, imm, rimm) (0xe2800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+
+// load
+// ldr reg, [addr, #imm] @ 0 <= imm < 4096
+#define ARM_LDR_IMM(reg, addr, imm) (0xe5900000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+
+// store
+// str reg, [addr, #-(imm)]! @ 0 <= imm < 4096
+#define ARM_STR_IMM_M_W(reg, addr, imm) (0xe5200000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+
+// branch
+// bx reg
+#define ARM_BX(reg) (0xe12fff10 + (reg) )
+
+
+// data pool defines
+#define CACHE_DATA_JUMP (2)
+#define CACHE_DATA_ALIGN (32)
+#define CACHE_DATA_MIN (32)
+#define CACHE_DATA_MAX (288)
+
+// data pool variables
+static Bit8u * cache_datapos = NULL; // position of data pool in the cache block
+static Bit32u cache_datasize = 0; // total size of data pool
+static Bit32u cache_dataindex = 0; // used size of data pool = index of free data item (in bytes) in data pool
+
+
+// forwarded function
+static void INLINE gen_create_branch_short(void * func);
+
+// function to check distance to data pool
+// if too close, then generate jump after data pool
+static void cache_checkinstr(Bit32u size) {
+ if (cache_datasize == 0) {
+ if (cache_datapos != NULL) {
+ if (cache.pos + size + CACHE_DATA_JUMP >= cache_datapos) {
+ cache_datapos = NULL;
+ }
+ }
+ return;
+ }
+
+ if (cache.pos + size + CACHE_DATA_JUMP <= cache_datapos) return;
+
+ {
+ register Bit8u * newcachepos;
+
+ newcachepos = cache_datapos + cache_datasize;
+ gen_create_branch_short(newcachepos);
+ cache.pos = newcachepos;
+ }
+
+ if (cache.pos + CACHE_DATA_MAX + CACHE_DATA_ALIGN >= cache.block.active->cache.start + cache.block.active->cache.size &&
+ cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) < cache.block.active->cache.start + cache.block.active->cache.size)
+ {
+ cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + cache.block.active->cache.size - CACHE_DATA_ALIGN) & ~(CACHE_DATA_ALIGN - 1));
+ } else {
+ register Bit32u cachemodsize;
+
+ cachemodsize = (cache.pos - cache.block.active->cache.start) & (CACHE_MAXSIZE - 1);
+
+ if (cachemodsize + CACHE_DATA_MAX + CACHE_DATA_ALIGN <= CACHE_MAXSIZE ||
+ cachemodsize + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) > CACHE_MAXSIZE)
+ {
+ cache_datapos = (Bit8u *) (((Bitu)cache.pos + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1));
+ } else {
+ cache_datapos = (Bit8u *) (((Bitu)cache.pos + (CACHE_MAXSIZE - CACHE_DATA_ALIGN) - cachemodsize) & ~(CACHE_DATA_ALIGN - 1));
+ }
+ }
+
+ cache_datasize = 0;
+ cache_dataindex = 0;
+}
+
+// function to reserve item in data pool
+// returns address of item
+static Bit8u * cache_reservedata(void) {
+ // if data pool not yet initialized, then initialize data pool
+ if (GCC_UNLIKELY(cache_datapos == NULL)) {
+ if (cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN < cache.block.active->cache.start + CACHE_DATA_MAX) {
+ cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1));
+ }
+ }
+
+ // if data pool not yet used, then set data pool
+ if (cache_datasize == 0) {
+ // set data pool address is too close (or behind) cache.pos then set new data pool size
+ if (cache.pos + CACHE_DATA_MIN + CACHE_DATA_JUMP /*+ CACHE_DATA_ALIGN*/ > cache_datapos) {
+ if (cache.pos + CACHE_DATA_MAX + CACHE_DATA_ALIGN >= cache.block.active->cache.start + cache.block.active->cache.size &&
+ cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) < cache.block.active->cache.start + cache.block.active->cache.size)
+ {
+ cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + cache.block.active->cache.size - CACHE_DATA_ALIGN) & ~(CACHE_DATA_ALIGN - 1));
+ } else {
+ register Bit32u cachemodsize;
+
+ cachemodsize = (cache.pos - cache.block.active->cache.start) & (CACHE_MAXSIZE - 1);
+
+ if (cachemodsize + CACHE_DATA_MAX + CACHE_DATA_ALIGN <= CACHE_MAXSIZE ||
+ cachemodsize + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) > CACHE_MAXSIZE)
+ {
+ cache_datapos = (Bit8u *) (((Bitu)cache.pos + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1));
+ } else {
+ cache_datapos = (Bit8u *) (((Bitu)cache.pos + (CACHE_MAXSIZE - CACHE_DATA_ALIGN) - cachemodsize) & ~(CACHE_DATA_ALIGN - 1));
+ }
+ }
+ }
+ // set initial data pool size
+ cache_datasize = CACHE_DATA_ALIGN;
+ }
+
+ // if data pool is full, then enlarge data pool
+ if (cache_dataindex == cache_datasize) {
+ cache_datasize += CACHE_DATA_ALIGN;
+ }
+
+ cache_dataindex += 4;
+ return (cache_datapos + (cache_dataindex - 4));
+}
+
+static void cache_block_before_close(void) {
+ // if data pool in use, then resize cache block to include the data pool
+ if (cache_datasize != 0)
+ {
+ cache.pos = cache_datapos + cache_dataindex;
+ }
+
+ // clear the values before next use
+ cache_datapos = NULL;
+ cache_datasize = 0;
+ cache_dataindex = 0;
+}
+
+
+// move a full register from reg_src to reg_dst
+static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) {
+ if(reg_src == reg_dst) return;
+ cache_checkinstr(2);
+ cache_addw( MOV_REG(reg_dst, reg_src) ); // mov reg_dst, reg_src
+}
+
+// helper function
+static bool val_single_shift(Bit32u value, Bit32u *val_shift) {
+ Bit32u shift;
+
+ if (GCC_UNLIKELY(value == 0)) {
+ *val_shift = 0;
+ return true;
+ }
+
+ shift = 0;
+ while ((value & 1) == 0) {
+ value>>=1;
+ shift+=1;
+ }
+
+ if ((value >> 8) != 0) return false;
+
+ *val_shift = shift;
+ return true;
+}
+
+// move a 32bit constant value into dest_reg
+static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) {
+ Bit32u scale;
+
+ if (imm < 256) {
+ cache_checkinstr(2);
+ cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm)
+ } else if ((~imm) < 256) {
+ cache_checkinstr(4);
+ cache_addw( MOV_IMM(dest_reg, ~imm) ); // mov dest_reg, #(~imm)
+ cache_addw( MVN(dest_reg, dest_reg) ); // mvn dest_reg, dest_reg
+ } else if (val_single_shift(imm, &scale)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_IMM(dest_reg, imm >> scale) ); // mov dest_reg, #(imm >> scale)
+ cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #scale
+ } else {
+ Bit32u diff;
+
+ cache_checkinstr(4);
+
+ diff = imm - ((Bit32u)cache.pos+4);
+
+ if ((diff < 1024) && ((imm & 0x03) == 0)) {
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( ADD_LO_PC_IMM(dest_reg, diff >> 2) ); // add dest_reg, pc, #(diff >> 2)
+ } else {
+ cache_addw( NOP ); // nop
+ cache_addw( ADD_LO_PC_IMM(dest_reg, (diff - 2) >> 2) ); // add dest_reg, pc, #((diff - 2) >> 2)
+ }
+ } else {
+ Bit8u *datapos;
+
+ datapos = cache_reservedata();
+ *(Bit32u*)datapos=imm;
+
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( LDR_PC_IMM(dest_reg, datapos - (cache.pos + 4)) ); // ldr dest_reg, [pc, datapos]
+ } else {
+ cache_addw( LDR_PC_IMM(dest_reg, datapos - (cache.pos + 2)) ); // ldr dest_reg, [pc, datapos]
+ }
+ }
+ }
+}
+
+// helper function
+static bool gen_mov_memval_to_reg_helper(HostReg dest_reg, Bit32u data, Bitu size, HostReg addr_reg, Bit32u addr_data) {
+ switch (size) {
+ case 4:
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((data & 3) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 128) && (((data - addr_data) & 3) == 0)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( LDR_IMM(dest_reg, templo2, data - addr_data) ); // ldr dest_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ }
+ break;
+ case 2:
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((data & 1) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 64) && (((data - addr_data) & 1) == 0)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( LDRH_IMM(dest_reg, templo2, data - addr_data) ); // ldrh dest_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ }
+ break;
+ case 1:
+ if ((data >= addr_data) && (data < addr_data + 32)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( LDRB_IMM(dest_reg, templo2, data - addr_data) ); // ldrb dest_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+// helper function
+static bool gen_mov_memval_to_reg(HostReg dest_reg, void *data, Bitu size) {
+ if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, FC_REGS_ADDR, (Bit32u)&cpu_regs)) return true;
+ if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, readdata_addr, (Bit32u)&core_dynrec.readdata)) return true;
+ if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, FC_SEGS_ADDR, (Bit32u)&Segs)) return true;
+ return false;
+}
+
+// helper function for gen_mov_word_to_reg
+static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) {
+ // alignment....
+ if (dword) {
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((Bit32u)data & 3) {
+ if ( ((Bit32u)data & 3) == 2 ) {
+ cache_checkinstr(8);
+ cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg]
+ cache_addw( LDRH_IMM(templo1, data_reg, 2) ); // ldrh templo1, [data_reg, #2]
+ cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16
+ cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1
+ } else {
+ cache_checkinstr(16);
+ cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg]
+ cache_addw( ADD_IMM3(templo1, data_reg, 1) ); // add templo1, data_reg, #1
+ cache_addw( LDRH_IMM(templo1, templo1, 0) ); // ldrh templo1, [templo1]
+ cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8
+ cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1
+ cache_addw( LDRB_IMM(templo1, data_reg, 3) ); // ldrb templo1, [data_reg, #3]
+ cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24
+ cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1
+ }
+ } else
+#endif
+ {
+ cache_checkinstr(2);
+ cache_addw( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg]
+ }
+ } else {
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((Bit32u)data & 1) {
+ cache_checkinstr(8);
+ cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg]
+ cache_addw( LDRB_IMM(templo1, data_reg, 1) ); // ldrb templo1, [data_reg, #1]
+ cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8
+ cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1
+ } else
+#endif
+ {
+ cache_checkinstr(2);
+ cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg]
+ }
+ }
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) {
+ if (!gen_mov_memval_to_reg(dest_reg, data, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(templo2, (Bit32u)data);
+ gen_mov_word_to_reg_helper(dest_reg, data, dword, templo2);
+ }
+}
+
+// move a 16bit constant value into dest_reg
+// the upper 16bit of the destination register may be destroyed
+static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) {
+ gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm);
+}
+
+// helper function
+static bool gen_mov_memval_from_reg_helper(HostReg src_reg, Bit32u data, Bitu size, HostReg addr_reg, Bit32u addr_data) {
+ switch (size) {
+ case 4:
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((data & 3) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 128) && (((data - addr_data) & 3) == 0)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( STR_IMM(src_reg, templo2, data - addr_data) ); // str src_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ }
+ break;
+ case 2:
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((data & 1) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 64) && (((data - addr_data) & 1) == 0)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( STRH_IMM(src_reg, templo2, data - addr_data) ); // strh src_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ }
+ break;
+ case 1:
+ if ((data >= addr_data) && (data < addr_data + 32)) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( STRB_IMM(src_reg, templo2, data - addr_data) ); // strb src_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+// helper function
+static bool gen_mov_memval_from_reg(HostReg src_reg, void *dest, Bitu size) {
+ if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, FC_REGS_ADDR, (Bit32u)&cpu_regs)) return true;
+ if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, readdata_addr, (Bit32u)&core_dynrec.readdata)) return true;
+ if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, FC_SEGS_ADDR, (Bit32u)&Segs)) return true;
+ return false;
+}
+
+// helper function for gen_mov_word_from_reg
+static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) {
+ // alignment....
+ if (dword) {
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((Bit32u)dest & 3) {
+ if ( ((Bit32u)dest & 3) == 2 ) {
+ cache_checkinstr(8);
+ cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16
+ cache_addw( STRH_IMM(templo1, data_reg, 2) ); // strh templo1, [data_reg, #2]
+ } else {
+ cache_checkinstr(20);
+ cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8
+ cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16
+ cache_addw( STRB_IMM(templo1, data_reg, 2) ); // strb templo1, [data_reg, #2]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 24) ); // lsr templo1, templo1, #24
+ cache_addw( STRB_IMM(templo1, data_reg, 3) ); // strb templo1, [data_reg, #3]
+ }
+ } else
+#endif
+ {
+ cache_checkinstr(2);
+ cache_addw( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg]
+ }
+ } else {
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((Bit32u)dest & 1) {
+ cache_checkinstr(8);
+ cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8
+ cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1]
+ } else
+#endif
+ {
+ cache_checkinstr(2);
+ cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg]
+ }
+ }
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into memory
+static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) {
+ if (!gen_mov_memval_from_reg(src_reg, dest, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest);
+ gen_mov_word_from_reg_helper(src_reg, dest, dword, templo2);
+ }
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) {
+ if (!gen_mov_memval_to_reg(dest_reg, data, 1)) {
+ gen_mov_dword_to_reg_imm(templo1, (Bit32u)data);
+ cache_checkinstr(2);
+ cache_addw( LDRB_IMM(dest_reg, templo1, 0) ); // ldrb dest_reg, [templo1]
+ }
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) {
+ gen_mov_byte_to_reg_low(dest_reg, data);
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) {
+ cache_checkinstr(2);
+ cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm)
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) {
+ gen_mov_byte_to_reg_low_imm(dest_reg, imm);
+}
+
+// move the lowest 8bit of a register into memory
+static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) {
+ if (!gen_mov_memval_from_reg(src_reg, dest, 1)) {
+ gen_mov_dword_to_reg_imm(templo1, (Bit32u)dest);
+ cache_checkinstr(2);
+ cache_addw( STRB_IMM(src_reg, templo1, 0) ); // strb src_reg, [templo1]
+ }
+}
+
+
+
+// convert an 8bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_byte(bool sign,HostReg reg) {
+ cache_checkinstr(4);
+ cache_addw( LSL_IMM(reg, reg, 24) ); // lsl reg, reg, #24
+
+ if (sign) {
+ cache_addw( ASR_IMM(reg, reg, 24) ); // asr reg, reg, #24
+ } else {
+ cache_addw( LSR_IMM(reg, reg, 24) ); // lsr reg, reg, #24
+ }
+}
+
+// convert a 16bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_word(bool sign,HostReg reg) {
+ cache_checkinstr(4);
+ cache_addw( LSL_IMM(reg, reg, 16) ); // lsl reg, reg, #16
+
+ if (sign) {
+ cache_addw( ASR_IMM(reg, reg, 16) ); // asr reg, reg, #16
+ } else {
+ cache_addw( LSR_IMM(reg, reg, 16) ); // lsr reg, reg, #16
+ }
+}
+
+// add a 32bit value from memory to a full register
+static void gen_add(HostReg reg,void* op) {
+ gen_mov_word_to_reg(templo3, op, 1);
+ cache_checkinstr(2);
+ cache_addw( ADD_REG(reg, reg, templo3) ); // add reg, reg, templo3
+}
+
+// add a 32bit constant value to a full register
+static void gen_add_imm(HostReg reg,Bit32u imm) {
+ Bit32u imm2, scale;
+
+ if(!imm) return;
+
+ imm2 = (Bit32u) (-((Bit32s)imm));
+
+ if (imm <= 255) {
+ cache_checkinstr(2);
+ cache_addw( ADD_IMM8(reg, imm) ); // add reg, #imm
+ } else if (imm2 <= 255) {
+ cache_checkinstr(2);
+ cache_addw( SUB_IMM8(reg, imm2) ); // sub reg, #(-imm)
+ } else {
+ if (val_single_shift(imm2, &scale)) {
+ cache_checkinstr((scale)?6:4);
+ cache_addw( MOV_IMM(templo1, imm2 >> scale) ); // mov templo1, #(~imm >> scale)
+ if (scale) {
+ cache_addw( LSL_IMM(templo1, templo1, scale) ); // lsl templo1, templo1, #scale
+ }
+ cache_addw( SUB_REG(reg, reg, templo1) ); // sub reg, reg, templo1
+ } else {
+ gen_mov_dword_to_reg_imm(templo1, imm);
+ cache_checkinstr(2);
+ cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1
+ }
+ }
+}
+
+// and a 32bit constant value with a full register
+static void gen_and_imm(HostReg reg,Bit32u imm) {
+ Bit32u imm2, scale;
+
+ imm2 = ~imm;
+ if(!imm2) return;
+
+ if (!imm) {
+ cache_checkinstr(2);
+ cache_addw( MOV_IMM(reg, 0) ); // mov reg, #0
+ } else {
+ if (val_single_shift(imm2, &scale)) {
+ cache_checkinstr((scale)?6:4);
+ cache_addw( MOV_IMM(templo1, imm2 >> scale) ); // mov templo1, #(~imm >> scale)
+ if (scale) {
+ cache_addw( LSL_IMM(templo1, templo1, scale) ); // lsl templo1, templo1, #scale
+ }
+ cache_addw( BIC(reg, templo1) ); // bic reg, templo1
+ } else {
+ gen_mov_dword_to_reg_imm(templo1, imm);
+ cache_checkinstr(2);
+ cache_addw( AND(reg, templo1) ); // and reg, templo1
+ }
+ }
+}
+
+
+// move a 32bit constant value into memory
+static void gen_mov_direct_dword(void* dest,Bit32u imm) {
+ gen_mov_dword_to_reg_imm(templo3, imm);
+ gen_mov_word_from_reg(templo3, dest, 1);
+}
+
+// move an address into memory
+static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) {
+ gen_mov_direct_dword(dest,(Bit32u)imm);
+}
+
+// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value
+static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) {
+ if (!dword) imm &= 0xffff;
+ if(!imm) return;
+
+ if (!gen_mov_memval_to_reg(templo3, dest, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest);
+ gen_mov_word_to_reg_helper(templo3, dest, dword, templo2);
+ }
+ gen_add_imm(templo3, imm);
+ if (!gen_mov_memval_from_reg(templo3, dest, (dword)?4:2)) {
+ gen_mov_word_from_reg_helper(templo3, dest, dword, templo2);
+ }
+}
+
+// add an 8bit constant value to a dword memory value
+static void gen_add_direct_byte(void* dest,Bit8s imm) {
+ gen_add_direct_word(dest, (Bit32s)imm, 1);
+}
+
+// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value
+static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) {
+ Bit32u imm2, scale;
+
+ if (!dword) imm &= 0xffff;
+ if(!imm) return;
+
+ if (!gen_mov_memval_to_reg(templo3, dest, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest);
+ gen_mov_word_to_reg_helper(templo3, dest, dword, templo2);
+ }
+
+ imm2 = (Bit32u) (-((Bit32s)imm));
+
+ if (imm <= 255) {
+ cache_checkinstr(2);
+ cache_addw( SUB_IMM8(templo3, imm) ); // sub templo3, #imm
+ } else if (imm2 <= 255) {
+ cache_checkinstr(2);
+ cache_addw( ADD_IMM8(templo3, imm2) ); // add templo3, #(-imm)
+ } else {
+ if (val_single_shift(imm2, &scale)) {
+ cache_checkinstr((scale)?6:4);
+ cache_addw( MOV_IMM(templo1, imm2 >> scale) ); // mov templo1, #(~imm >> scale)
+ if (scale) {
+ cache_addw( LSL_IMM(templo1, templo1, scale) ); // lsl templo1, templo1, #scale
+ }
+ cache_addw( ADD_REG(templo3, templo3, templo1) ); // add templo3, templo3, templo1
+ } else {
+ gen_mov_dword_to_reg_imm(templo1, imm);
+ cache_checkinstr(2);
+ cache_addw( SUB_REG(templo3, templo3, templo1) ); // sub templo3, templo3, templo1
+ }
+ }
+
+ if (!gen_mov_memval_from_reg(templo3, dest, (dword)?4:2)) {
+ gen_mov_word_from_reg_helper(templo3, dest, dword, templo2);
+ }
+}
+
+// subtract an 8bit constant value from a dword memory value
+static void gen_sub_direct_byte(void* dest,Bit8s imm) {
+ gen_sub_direct_word(dest, (Bit32s)imm, 1);
+}
+
+// effective address calculation, destination is dest_reg
+// scale_reg is scaled by scale (scale_reg*(2^scale)) and
+// added to dest_reg, then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) {
+ if (scale) {
+ cache_checkinstr(4);
+ cache_addw( LSL_IMM(templo1, scale_reg, scale) ); // lsl templo1, scale_reg, #(scale)
+ cache_addw( ADD_REG(dest_reg, dest_reg, templo1) ); // add dest_reg, dest_reg, templo1
+ } else {
+ cache_checkinstr(2);
+ cache_addw( ADD_REG(dest_reg, dest_reg, scale_reg) ); // add dest_reg, dest_reg, scale_reg
+ }
+ gen_add_imm(dest_reg, imm);
+}
+
+// effective address calculation, destination is dest_reg
+// dest_reg is scaled by scale (dest_reg*(2^scale)),
+// then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) {
+ if (scale) {
+ cache_checkinstr(2);
+ cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #(scale)
+ }
+ gen_add_imm(dest_reg, imm);
+}
+
+// helper function for gen_call_function_raw and gen_call_function_setup
+static void gen_call_function_helper(void * func) {
+ Bit8u *datapos;
+
+ datapos = cache_reservedata();
+ *(Bit32u*)datapos=(Bit32u)func;
+
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos]
+ cache_addw( ADD_LO_PC_IMM(templo2, 4) ); // adr templo2, after_call (add templo2, pc, #4)
+ cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2
+ cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state
+ } else {
+ cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos]
+ cache_addw( ADD_LO_PC_IMM(templo2, 4) ); // adr templo2, after_call (add templo2, pc, #4)
+ cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2
+ cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state
+ cache_addw( NOP ); // nop
+ }
+ // after_call:
+
+ // switch from arm to thumb state
+ cache_addd(0xe2800000 + (templo1 << 12) + (HOST_pc << 16) + (1)); // add templo1, pc, #1
+ cache_addd(0xe12fff10 + (templo1)); // bx templo1
+
+ // thumb state from now on
+}
+
+// generate a call to a parameterless function
+static void INLINE gen_call_function_raw(void * func) {
+ cache_checkinstr(18);
+ gen_call_function_helper(func);
+}
+
+// generate a call to a function with paramcount parameters
+// note: the parameters are loaded in the architecture specific way
+// using the gen_load_param_ functions below
+static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) {
+ cache_checkinstr(18);
+ Bit32u proc_addr = (Bit32u)cache.pos;
+ gen_call_function_helper(func);
+ return proc_addr;
+ // if proc_addr is on word boundary ((proc_addr & 0x03) == 0)
+ // then length of generated code is 16 bytes
+ // otherwise length of generated code is 18 bytes
+}
+
+#if (1)
+// max of 4 parameters in a1-a4
+
+// load an immediate value as param'th function parameter
+static void INLINE gen_load_param_imm(Bitu imm,Bitu param) {
+ gen_mov_dword_to_reg_imm(param, imm);
+}
+
+// load an address as param'th function parameter
+static void INLINE gen_load_param_addr(Bitu addr,Bitu param) {
+ gen_mov_dword_to_reg_imm(param, addr);
+}
+
+// load a host-register as param'th function parameter
+static void INLINE gen_load_param_reg(Bitu reg,Bitu param) {
+ gen_mov_regs(param, reg);
+}
+
+// load a value from memory as param'th function parameter
+static void INLINE gen_load_param_mem(Bitu mem,Bitu param) {
+ gen_mov_word_to_reg(param, (void *)mem, 1);
+}
+#else
+ other arm abis
+#endif
+
+// jump to an address pointed at by ptr, offset is in imm
+static void gen_jmp_ptr(void * ptr,Bits imm=0) {
+ gen_mov_word_to_reg(templo3, ptr, 1);
+
+#if !defined(C_UNALIGNED_MEMORY)
+// (*ptr) should be word aligned
+ if ((imm & 0x03) == 0) {
+#endif
+ if ((imm >= 0) && (imm < 128) && ((imm & 3) == 0)) {
+ cache_checkinstr(6);
+ cache_addw( LDR_IMM(templo2, templo3, imm) ); // ldr templo2, [templo3, #imm]
+ } else {
+ gen_mov_dword_to_reg_imm(templo2, imm);
+ cache_checkinstr(6);
+ cache_addw( LDR_REG(templo2, templo3, templo2) ); // ldr templo2, [templo3, templo2]
+ }
+#if !defined(C_UNALIGNED_MEMORY)
+ } else {
+ gen_add_imm(templo3, imm);
+
+ cache_checkinstr(24);
+ cache_addw( LDRB_IMM(templo2, templo3, 0) ); // ldrb templo2, [templo3]
+ cache_addw( LDRB_IMM(templo1, templo3, 1) ); // ldrb templo1, [templo3, #1]
+ cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8
+ cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1
+ cache_addw( LDRB_IMM(templo1, templo3, 2) ); // ldrb templo1, [templo3, #2]
+ cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16
+ cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1
+ cache_addw( LDRB_IMM(templo1, templo3, 3) ); // ldrb templo1, [templo3, #3]
+ cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24
+ cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1
+ }
+#endif
+
+ // increase jmp address to keep thumb state
+ cache_addw( ADD_IMM3(templo2, templo2, 1) ); // add templo2, templo2, #1
+
+ cache_addw( BX(templo2) ); // bx templo2
+}
+
+// short conditional jump (+-127 bytes) if register is zero
+// the destination is set by gen_fill_branch() later
+static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) {
+ cache_checkinstr(4);
+ if (dword) {
+ cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0
+ } else {
+ cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16
+ }
+ cache_addw( BEQ_FWD(0) ); // beq j
+ return ((Bit32u)cache.pos-2);
+}
+
+// short conditional jump (+-127 bytes) if register is nonzero
+// the destination is set by gen_fill_branch() later
+static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) {
+ cache_checkinstr(4);
+ if (dword) {
+ cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0
+ } else {
+ cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16
+ }
+ cache_addw( BNE_FWD(0) ); // bne j
+ return ((Bit32u)cache.pos-2);
+}
+
+// calculate relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) {
+#if C_DEBUG
+ Bits len=(Bit32u)cache.pos-(data+4);
+ if (len<0) len=-len;
+ if (len>252) LOG_MSG("Big jump %d",len);
+#endif
+ *(Bit8u*)data=(Bit8u)( ((Bit32u)cache.pos-(data+4)) >> 1 );
+}
+
+
+// conditional jump if register is nonzero
+// for isdword==true the 32bit of the register are tested
+// for isdword==false the lowest 8bit of the register are tested
+static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) {
+ Bit8u *datapos;
+
+ cache_checkinstr(8);
+ datapos = cache_reservedata();
+
+ if (isdword) {
+ cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0
+ } else {
+ cache_addw( LSL_IMM(templo2, reg, 24) ); // lsl templo2, reg, #24
+ }
+ cache_addw( BEQ_FWD(2) ); // beq nobranch (pc+2)
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos]
+ } else {
+ cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos]
+ }
+ cache_addw( BX(templo1) ); // bx templo1
+ // nobranch:
+ return ((Bit32u)datapos);
+}
+
+// compare 32bit-register against zero and jump if value less/equal than zero
+static Bit32u gen_create_branch_long_leqzero(HostReg reg) {
+ Bit8u *datapos;
+
+ cache_checkinstr(8);
+ datapos = cache_reservedata();
+
+ cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0
+ cache_addw( BGT_FWD(2) ); // bgt nobranch (pc+2)
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos]
+ } else {
+ cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos]
+ }
+ cache_addw( BX(templo1) ); // bx templo1
+ // nobranch:
+ return ((Bit32u)datapos);
+}
+
+// calculate long relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch_long(Bit32u data) {
+ // this is an absolute branch
+ *(Bit32u*)data=((Bit32u)cache.pos) + 1; // add 1 to keep processor in thumb state
+}
+
+static void gen_run_code(void) {
+ Bit8u *pos1, *pos2, *pos3;
+
+#if (__ARM_EABI__)
+ // 8-byte stack alignment
+ cache_addd(0xe92d4ff0); // stmfd sp!, {v1-v8,lr}
+#else
+ cache_addd(0xe92d4df0); // stmfd sp!, {v1-v5,v7,v8,lr}
+#endif
+
+ cache_addd( ARM_ADD_IMM(HOST_r0, HOST_r0, 1, 0) ); // add r0, r0, #1
+
+ pos1 = cache.pos;
+ cache_addd( 0 );
+ pos2 = cache.pos;
+ cache_addd( 0 );
+ pos3 = cache.pos;
+ cache_addd( 0 );
+
+ cache_addd( ARM_ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4
+ cache_addd( ARM_STR_IMM_M_W(HOST_lr, HOST_sp, 4) ); // str lr, [sp, #-4]!
+ cache_addd( ARM_BX(HOST_r0) ); // bx r0
+
+#if (__ARM_EABI__)
+ cache_addd(0xe8bd4ff0); // ldmfd sp!, {v1-v8,lr}
+#else
+ cache_addd(0xe8bd4df0); // ldmfd sp!, {v1-v5,v7,v8,lr}
+#endif
+ cache_addd( ARM_BX(HOST_lr) ); // bx lr
+
+ // align cache.pos to 32 bytes
+ if ((((Bitu)cache.pos) & 0x1f) != 0) {
+ cache.pos = cache.pos + (32 - (((Bitu)cache.pos) & 0x1f));
+ }
+
+ *(Bit32u*)pos1 = ARM_LDR_IMM(FC_SEGS_ADDR, HOST_pc, cache.pos - (pos1 + 8)); // ldr FC_SEGS_ADDR, [pc, #(&Segs)]
+ cache_addd((Bit32u)&Segs); // address of "Segs"
+
+ *(Bit32u*)pos2 = ARM_LDR_IMM(FC_REGS_ADDR, HOST_pc, cache.pos - (pos2 + 8)); // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)]
+ cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs"
+
+ *(Bit32u*)pos3 = ARM_LDR_IMM(readdata_addr, HOST_pc, cache.pos - (pos3 + 8)); // ldr readdata_addr, [pc, #(&core_dynrec.readdata)]
+ cache_addd((Bit32u)&core_dynrec.readdata); // address of "core_dynrec.readdata"
+
+ // align cache.pos to 32 bytes
+ if ((((Bitu)cache.pos) & 0x1f) != 0) {
+ cache.pos = cache.pos + (32 - (((Bitu)cache.pos) & 0x1f));
+ }
+}
+
+// return from a function
+static void gen_return_function(void) {
+ cache_checkinstr(4);
+ cache_addw(0xbc08); // pop {r3}
+ cache_addw( BX(HOST_r3) ); // bx r3
+}
+
+
+// short unconditional jump (over data pool)
+// must emit at most CACHE_DATA_JUMP bytes
+static void INLINE gen_create_branch_short(void * func) {
+ cache_addw( B_FWD((Bit32u)func - ((Bit32u)cache.pos + 4)) ); // b func
+}
+
+
+#ifdef DRC_FLAGS_INVALIDATION
+
+// called when a call to a function can be replaced by a
+// call to a simpler function
+static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) {
+ if ((*(Bit16u*)pos & 0xf000) == 0xe000) {
+ if ((*(Bit16u*)pos & 0x0fff) >= ((CACHE_DATA_ALIGN / 2) - 1) &&
+ (*(Bit16u*)pos & 0x0fff) < 0x0800)
+ {
+ pos = (Bit8u *) ( ( ( (Bit32u)(*(Bit16u*)pos & 0x0fff) ) << 1 ) + ((Bit32u)pos + 4) );
+ }
+ }
+
+#ifdef DRC_FLAGS_INVALIDATION_DCODE
+ if (((Bit32u)pos & 0x03) == 0)
+ {
+ // try to avoid function calls but rather directly fill in code
+ switch (flags_type) {
+ case t_ADDb:
+ case t_ADDw:
+ case t_ADDd:
+ *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_SUBb:
+ case t_SUBw:
+ case t_SUBd:
+ *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_CMPb:
+ case t_CMPw:
+ case t_CMPd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ *(Bit16u*)pos=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_INCb:
+ case t_INCw:
+ case t_INCd:
+ *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1
+ *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_DECb:
+ case t_DECw:
+ case t_DECd:
+ *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1
+ *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_SHLb:
+ case t_SHLw:
+ case t_SHLd:
+ *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_SHRb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24
+ *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_SHRw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16
+ *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_SHRd:
+ *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_SARb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24
+ *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_SARw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16
+ *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_SARd:
+ *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_RORb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8
+ *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+6)=NOP; // nop
+ *(Bit16u*)(pos+8)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+10)=NOP; // nop
+ *(Bit16u*)(pos+12)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+14)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ break;
+ case t_RORw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+8)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_RORd:
+ *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_ROLb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8
+ *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+10)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+12)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+14)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ break;
+ case t_ROLw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+10)=NOP; // nop
+ *(Bit16u*)(pos+12)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+14)=NOP; // nop
+ break;
+ case t_ROLd:
+ *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_NEGb:
+ case t_NEGw:
+ case t_NEGd:
+ *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1
+ *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10)
+ break;
+ default:
+ *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 4) ) = (Bit32u)fct_ptr; // simple_func
+ break;
+ }
+ }
+ else
+ {
+ // try to avoid function calls but rather directly fill in code
+ switch (flags_type) {
+ case t_ADDb:
+ case t_ADDw:
+ case t_ADDd:
+ *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_SUBb:
+ case t_SUBw:
+ case t_SUBd:
+ *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_CMPb:
+ case t_CMPw:
+ case t_CMPd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ *(Bit16u*)pos=B_FWD(14); // b after_call (pc+14)
+ break;
+ case t_INCb:
+ case t_INCw:
+ case t_INCd:
+ *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1
+ *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_DECb:
+ case t_DECw:
+ case t_DECd:
+ *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1
+ *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_SHLb:
+ case t_SHLw:
+ case t_SHLd:
+ *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_SHRb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24
+ *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8)
+ break;
+ case t_SHRw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16
+ *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8)
+ break;
+ case t_SHRd:
+ *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_SARb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24
+ *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8)
+ break;
+ case t_SARw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16
+ *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8)
+ break;
+ case t_SARd:
+ *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_RORb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8
+ *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+6)=NOP; // nop
+ *(Bit16u*)(pos+8)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+10)=NOP; // nop
+ *(Bit16u*)(pos+12)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+14)=NOP; // nop
+ *(Bit16u*)(pos+16)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ break;
+ case t_RORw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+8)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_RORd:
+ *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_ROLb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8
+ *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+10)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+12)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+14)=NOP; // nop
+ *(Bit16u*)(pos+16)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ break;
+ case t_ROLw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+10)=NOP; // nop
+ *(Bit16u*)(pos+12)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+14)=NOP; // nop
+ *(Bit16u*)(pos+16)=NOP; // nop
+ break;
+ case t_ROLd:
+ *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8)
+ break;
+ case t_NEGb:
+ case t_NEGw:
+ case t_NEGd:
+ *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1
+ *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12)
+ break;
+ default:
+ *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 2) ) = (Bit32u)fct_ptr; // simple_func
+ break;
+ }
+
+ }
+#else
+ if (((Bit32u)pos & 0x03) == 0)
+ {
+ *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 4) ) = (Bit32u)fct_ptr; // simple_func
+ }
+ else
+ {
+ *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 2) ) = (Bit32u)fct_ptr; // simple_func
+ }
+#endif
+}
+#endif
+
+#ifdef DRC_USE_SEGS_ADDR
+
+// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR
+ cache_addw( LDRH_IMM(dest_reg, templo1, index) ); // ldrh dest_reg, [templo1, #index]
+}
+
+// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR
+ cache_addw( LDR_IMM(dest_reg, templo1, index) ); // ldr dest_reg, [templo1, #index]
+}
+
+// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero)
+static void gen_add_seg32_to_reg(HostReg reg,Bitu index) {
+ cache_checkinstr(6);
+ cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR
+ cache_addw( LDR_IMM(templo2, templo1, index) ); // ldr templo2, [templo1, #index]
+ cache_addw( ADD_REG(reg, reg, templo2) ); // add reg, reg, templo2
+}
+
+#endif
+
+#ifdef DRC_USE_REGS_ADDR
+
+// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index]
+}
+
+// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index]
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ if (dword) {
+ cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index]
+ } else {
+ cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index]
+ }
+}
+
+// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index]
+}
+
+// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index]
+}
+
+
+// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_add_regval32_to_reg(HostReg reg,Bitu index) {
+ cache_checkinstr(6);
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDR_IMM(templo1, templo2, index) ); // ldr templo1, [templo2, #index]
+ cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1
+}
+
+
+// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero)
+static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR
+ cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index]
+}
+
+// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR
+ cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index]
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
+static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR
+ if (dword) {
+ cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index]
+ } else {
+ cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index]
+ }
+}
+
+// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR
+static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) {
+ cache_checkinstr(4);
+ cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR
+ cache_addw( STRB_IMM(src_reg, templo1, index) ); // strb src_reg, [templo1, #index]
+}
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+/* ARMv4 (little endian) backend by M-HT (thumb version) */
+
+
+// temporary "lo" registers
+#define templo1 HOST_v3
+#define templo2 HOST_v4
+#define templo3 HOST_v2
+
+// register that holds function return values
+#define FC_RETOP HOST_a1
+
+// register used for address calculations,
+#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG
+
+// register that holds the first parameter
+#define FC_OP1 HOST_a1
+
+// register that holds the second parameter
+#define FC_OP2 HOST_a2
+
+// special register that holds the third parameter for _R3 calls (byte accessible)
+#define FC_OP3 HOST_a4
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA1 HOST_a1
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA2 HOST_a2
+
+// temporary register for LEA
+#define TEMP_REG_DRC HOST_a4
+
+// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code
+#define FC_REGS_ADDR HOST_v7
+
+// used to hold the address of "Segs" - preferably filled in function gen_run_code
+#define FC_SEGS_ADDR HOST_v8
+
+// used to hold the address of "core_dynrec.readdata" - filled in function gen_run_code
+#define readdata_addr HOST_v5
+
+
+// instruction encodings
+
+// move
+// mov dst, #imm @ 0 <= imm <= 255
+#define MOV_IMM(dst, imm) (0x2000 + ((dst) << 8) + (imm) )
+// mov dst, src
+#define MOV_REG(dst, src) ADD_IMM3(dst, src, 0)
+// mov dst, src
+#define MOV_LO_HI(dst, src) (0x4640 + (dst) + (((src) - HOST_r8) << 3) )
+// mov dst, src
+#define MOV_HI_LO(dst, src) (0x4680 + ((dst) - HOST_r8) + ((src) << 3) )
+
+// arithmetic
+// add dst, src, #imm @ 0 <= imm <= 7
+#define ADD_IMM3(dst, src, imm) (0x1c00 + (dst) + ((src) << 3) + ((imm) << 6) )
+// add dst, #imm @ 0 <= imm <= 255
+#define ADD_IMM8(dst, imm) (0x3000 + ((dst) << 8) + (imm) )
+// add dst, src1, src2
+#define ADD_REG(dst, src1, src2) (0x1800 + (dst) + ((src1) << 3) + ((src2) << 6) )
+// add dst, pc, #imm @ 0 <= imm < 1024 & imm mod 4 = 0
+#define ADD_LO_PC_IMM(dst, imm) (0xa000 + ((dst) << 8) + ((imm) >> 2) )
+// sub dst, src1, src2
+#define SUB_REG(dst, src1, src2) (0x1a00 + (dst) + ((src1) << 3) + ((src2) << 6) )
+// sub dst, src, #imm @ 0 <= imm <= 7
+#define SUB_IMM3(dst, src, imm) (0x1e00 + (dst) + ((src) << 3) + ((imm) << 6) )
+// sub dst, #imm @ 0 <= imm <= 255
+#define SUB_IMM8(dst, imm) (0x3800 + ((dst) << 8) + (imm) )
+// neg dst, src
+#define NEG(dst, src) (0x4240 + (dst) + ((src) << 3) )
+// cmp dst, #imm @ 0 <= imm <= 255
+#define CMP_IMM(dst, imm) (0x2800 + ((dst) << 8) + (imm) )
+// nop
+#define NOP (0x46c0)
+
+// logical
+// and dst, src
+#define AND(dst, src) (0x4000 + (dst) + ((src) << 3) )
+// bic dst, src
+#define BIC(dst, src) (0x4380 + (dst) + ((src) << 3) )
+// eor dst, src
+#define EOR(dst, src) (0x4040 + (dst) + ((src) << 3) )
+// orr dst, src
+#define ORR(dst, src) (0x4300 + (dst) + ((src) << 3) )
+// mvn dst, src
+#define MVN(dst, src) (0x43c0 + (dst) + ((src) << 3) )
+
+// shift/rotate
+// lsl dst, src, #imm
+#define LSL_IMM(dst, src, imm) (0x0000 + (dst) + ((src) << 3) + ((imm) << 6) )
+// lsl dst, reg
+#define LSL_REG(dst, reg) (0x4080 + (dst) + ((reg) << 3) )
+// lsr dst, src, #imm
+#define LSR_IMM(dst, src, imm) (0x0800 + (dst) + ((src) << 3) + ((imm) << 6) )
+// lsr dst, reg
+#define LSR_REG(dst, reg) (0x40c0 + (dst) + ((reg) << 3) )
+// asr dst, src, #imm
+#define ASR_IMM(dst, src, imm) (0x1000 + (dst) + ((src) << 3) + ((imm) << 6) )
+// asr dst, reg
+#define ASR_REG(dst, reg) (0x4100 + (dst) + ((reg) << 3) )
+// ror dst, reg
+#define ROR_REG(dst, reg) (0x41c0 + (dst) + ((reg) << 3) )
+
+// load
+// ldr reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0
+#define LDR_IMM(reg, addr, imm) (0x6800 + (reg) + ((addr) << 3) + ((imm) << 4) )
+// ldrh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0
+#define LDRH_IMM(reg, addr, imm) (0x8800 + (reg) + ((addr) << 3) + ((imm) << 5) )
+// ldrb reg, [addr, #imm] @ 0 <= imm < 32
+#define LDRB_IMM(reg, addr, imm) (0x7800 + (reg) + ((addr) << 3) + ((imm) << 6) )
+// ldr reg, [pc, #imm] @ 0 <= imm < 1024 & imm mod 4 = 0
+#define LDR_PC_IMM(reg, imm) (0x4800 + ((reg) << 8) + ((imm) >> 2) )
+// ldr reg, [addr1, addr2]
+#define LDR_REG(reg, addr1, addr2) (0x5800 + (reg) + ((addr1) << 3) + ((addr2) << 6) )
+
+// store
+// str reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0
+#define STR_IMM(reg, addr, imm) (0x6000 + (reg) + ((addr) << 3) + ((imm) << 4) )
+// strh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0
+#define STRH_IMM(reg, addr, imm) (0x8000 + (reg) + ((addr) << 3) + ((imm) << 5) )
+// strb reg, [addr, #imm] @ 0 <= imm < 32
+#define STRB_IMM(reg, addr, imm) (0x7000 + (reg) + ((addr) << 3) + ((imm) << 6) )
+
+// branch
+// beq pc+imm @ 0 <= imm < 256 & imm mod 2 = 0
+#define BEQ_FWD(imm) (0xd000 + ((imm) >> 1) )
+// bne pc+imm @ 0 <= imm < 256 & imm mod 2 = 0
+#define BNE_FWD(imm) (0xd100 + ((imm) >> 1) )
+// bgt pc+imm @ 0 <= imm < 256 & imm mod 2 = 0
+#define BGT_FWD(imm) (0xdc00 + ((imm) >> 1) )
+// b pc+imm @ 0 <= imm < 2048 & imm mod 2 = 0
+#define B_FWD(imm) (0xe000 + ((imm) >> 1) )
+// bx reg
+#define BX(reg) (0x4700 + ((reg) << 3) )
+
+
+// arm instructions
+
+// arithmetic
+// add dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0
+#define ARM_ADD_IMM(dst, src, imm, rimm) (0xe2800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) )
+
+// load
+// ldr reg, [addr, #imm] @ 0 <= imm < 4096
+#define ARM_LDR_IMM(reg, addr, imm) (0xe5900000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+
+// store
+// str reg, [addr, #-(imm)]! @ 0 <= imm < 4096
+#define ARM_STR_IMM_M_W(reg, addr, imm) (0xe5200000 + ((reg) << 12) + ((addr) << 16) + (imm) )
+
+// branch
+// bx reg
+#define ARM_BX(reg) (0xe12fff10 + (reg) )
+
+
+// move a full register from reg_src to reg_dst
+static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) {
+ if(reg_src == reg_dst) return;
+ cache_addw( MOV_REG(reg_dst, reg_src) ); // mov reg_dst, reg_src
+}
+
+// helper function
+static bool val_single_shift(Bit32u value, Bit32u *val_shift) {
+ Bit32u shift;
+
+ if (GCC_UNLIKELY(value == 0)) {
+ *val_shift = 0;
+ return true;
+ }
+
+ shift = 0;
+ while ((value & 1) == 0) {
+ value>>=1;
+ shift+=1;
+ }
+
+ if ((value >> 8) != 0) return false;
+
+ *val_shift = shift;
+ return true;
+}
+
+// move a 32bit constant value into dest_reg
+static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) {
+ Bit32u scale;
+
+ if (imm < 256) {
+ cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #imm
+ } else if ((~imm) < 256) {
+ cache_addw( MOV_IMM(dest_reg, ~imm) ); // mov dest_reg, #(~imm)
+ cache_addw( MVN(dest_reg, dest_reg) ); // mvn dest_reg, dest_reg
+ } else if (val_single_shift(imm, &scale)) {
+ cache_addw( MOV_IMM(dest_reg, imm >> scale) ); // mov dest_reg, #(imm >> scale)
+ cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #scale
+ } else {
+ Bit32u diff;
+
+ diff = imm - ((Bit32u)cache.pos+4);
+
+ if ((diff < 1024) && ((imm & 0x03) == 0)) {
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( ADD_LO_PC_IMM(dest_reg, diff) ); // add dest_reg, pc, #(diff >> 2)
+ } else {
+ cache_addw( NOP ); // nop
+ cache_addw( ADD_LO_PC_IMM(dest_reg, diff - 2) ); // add dest_reg, pc, #((diff - 2) >> 2)
+ }
+ } else {
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( LDR_PC_IMM(dest_reg, 0) ); // ldr dest_reg, [pc, #0]
+ cache_addw( B_FWD(2) ); // b next_code (pc+2)
+ cache_addd(imm); // .int imm
+ // next_code:
+ } else {
+ cache_addw( LDR_PC_IMM(dest_reg, 4) ); // ldr dest_reg, [pc, #4]
+ cache_addw( B_FWD(4) ); // b next_code (pc+4)
+ cache_addw( NOP ); // nop
+ cache_addd(imm); // .int imm
+ // next_code:
+ }
+ }
+ }
+}
+
+// helper function
+static bool gen_mov_memval_to_reg_helper(HostReg dest_reg, Bit32u data, Bitu size, HostReg addr_reg, Bit32u addr_data) {
+ switch (size) {
+ case 4:
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((data & 3) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 128) && (((data - addr_data) & 3) == 0)) {
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( LDR_IMM(dest_reg, templo2, data - addr_data) ); // ldr dest_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ }
+ break;
+ case 2:
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((data & 1) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 64) && (((data - addr_data) & 1) == 0)) {
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( LDRH_IMM(dest_reg, templo2, data - addr_data) ); // ldrh dest_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ }
+ break;
+ case 1:
+ if ((data >= addr_data) && (data < addr_data + 32)) {
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( LDRB_IMM(dest_reg, templo2, data - addr_data) ); // ldrb dest_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+// helper function
+static bool gen_mov_memval_to_reg(HostReg dest_reg, void *data, Bitu size) {
+ if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, FC_REGS_ADDR, (Bit32u)&cpu_regs)) return true;
+ if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, readdata_addr, (Bit32u)&core_dynrec.readdata)) return true;
+ if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, FC_SEGS_ADDR, (Bit32u)&Segs)) return true;
+ return false;
+}
+
+// helper function for gen_mov_word_to_reg
+static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) {
+ // alignment....
+ if (dword) {
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((Bit32u)data & 3) {
+ if ( ((Bit32u)data & 3) == 2 ) {
+ cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg]
+ cache_addw( LDRH_IMM(templo1, data_reg, 2) ); // ldrh templo1, [data_reg, #2]
+ cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16
+ cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1
+ } else {
+ cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg]
+ cache_addw( ADD_IMM3(templo1, data_reg, 1) ); // add templo1, data_reg, #1
+ cache_addw( LDRH_IMM(templo1, templo1, 0) ); // ldrh templo1, [templo1]
+ cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8
+ cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1
+ cache_addw( LDRB_IMM(templo1, data_reg, 3) ); // ldrb templo1, [data_reg, #3]
+ cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24
+ cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1
+ }
+ } else
+#endif
+ {
+ cache_addw( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg]
+ }
+ } else {
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((Bit32u)data & 1) {
+ cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg]
+ cache_addw( LDRB_IMM(templo1, data_reg, 1) ); // ldrb templo1, [data_reg, #1]
+ cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8
+ cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1
+ } else
+#endif
+ {
+ cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg]
+ }
+ }
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) {
+ if (!gen_mov_memval_to_reg(dest_reg, data, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(templo2, (Bit32u)data);
+ gen_mov_word_to_reg_helper(dest_reg, data, dword, templo2);
+ }
+}
+
+// move a 16bit constant value into dest_reg
+// the upper 16bit of the destination register may be destroyed
+static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) {
+ gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm);
+}
+
+// helper function
+static bool gen_mov_memval_from_reg_helper(HostReg src_reg, Bit32u data, Bitu size, HostReg addr_reg, Bit32u addr_data) {
+ switch (size) {
+ case 4:
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((data & 3) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 128) && (((data - addr_data) & 3) == 0)) {
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( STR_IMM(src_reg, templo2, data - addr_data) ); // str src_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ }
+ break;
+ case 2:
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((data & 1) == 0)
+#endif
+ {
+ if ((data >= addr_data) && (data < addr_data + 64) && (((data - addr_data) & 1) == 0)) {
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( STRH_IMM(src_reg, templo2, data - addr_data) ); // strh src_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ }
+ break;
+ case 1:
+ if ((data >= addr_data) && (data < addr_data + 32)) {
+ cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg
+ cache_addw( STRB_IMM(src_reg, templo2, data - addr_data) ); // strb src_reg, [templo2, #(data - addr_data)]
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+// helper function
+static bool gen_mov_memval_from_reg(HostReg src_reg, void *dest, Bitu size) {
+ if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, FC_REGS_ADDR, (Bit32u)&cpu_regs)) return true;
+ if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, readdata_addr, (Bit32u)&core_dynrec.readdata)) return true;
+ if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, FC_SEGS_ADDR, (Bit32u)&Segs)) return true;
+ return false;
+}
+
+// helper function for gen_mov_word_from_reg
+static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) {
+ // alignment....
+ if (dword) {
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((Bit32u)dest & 3) {
+ if ( ((Bit32u)dest & 3) == 2 ) {
+ cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16
+ cache_addw( STRH_IMM(templo1, data_reg, 2) ); // strh templo1, [data_reg, #2]
+ } else {
+ cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8
+ cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16
+ cache_addw( STRB_IMM(templo1, data_reg, 2) ); // strb templo1, [data_reg, #2]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 24) ); // lsr templo1, templo1, #24
+ cache_addw( STRB_IMM(templo1, data_reg, 3) ); // strb templo1, [data_reg, #3]
+ }
+ } else
+#endif
+ {
+ cache_addw( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg]
+ }
+ } else {
+#if !defined(C_UNALIGNED_MEMORY)
+ if ((Bit32u)dest & 1) {
+ cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg]
+ cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg
+ cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8
+ cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1]
+ } else
+#endif
+ {
+ cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg]
+ }
+ }
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into memory
+static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) {
+ if (!gen_mov_memval_from_reg(src_reg, dest, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest);
+ gen_mov_word_from_reg_helper(src_reg, dest, dword, templo2);
+ }
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) {
+ if (!gen_mov_memval_to_reg(dest_reg, data, 1)) {
+ gen_mov_dword_to_reg_imm(templo1, (Bit32u)data);
+ cache_addw( LDRB_IMM(dest_reg, templo1, 0) ); // ldrb dest_reg, [templo1]
+ }
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) {
+ gen_mov_byte_to_reg_low(dest_reg, data);
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) {
+ cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm)
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) {
+ gen_mov_byte_to_reg_low_imm(dest_reg, imm);
+}
+
+// move the lowest 8bit of a register into memory
+static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) {
+ if (!gen_mov_memval_from_reg(src_reg, dest, 1)) {
+ gen_mov_dword_to_reg_imm(templo1, (Bit32u)dest);
+ cache_addw( STRB_IMM(src_reg, templo1, 0) ); // strb src_reg, [templo1]
+ }
+}
+
+
+
+// convert an 8bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_byte(bool sign,HostReg reg) {
+ cache_addw( LSL_IMM(reg, reg, 24) ); // lsl reg, reg, #24
+
+ if (sign) {
+ cache_addw( ASR_IMM(reg, reg, 24) ); // asr reg, reg, #24
+ } else {
+ cache_addw( LSR_IMM(reg, reg, 24) ); // lsr reg, reg, #24
+ }
+}
+
+// convert a 16bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_word(bool sign,HostReg reg) {
+ cache_addw( LSL_IMM(reg, reg, 16) ); // lsl reg, reg, #16
+
+ if (sign) {
+ cache_addw( ASR_IMM(reg, reg, 16) ); // asr reg, reg, #16
+ } else {
+ cache_addw( LSR_IMM(reg, reg, 16) ); // lsr reg, reg, #16
+ }
+}
+
+// add a 32bit value from memory to a full register
+static void gen_add(HostReg reg,void* op) {
+ gen_mov_word_to_reg(templo3, op, 1);
+ cache_addw( ADD_REG(reg, reg, templo3) ); // add reg, reg, templo3
+}
+
+// add a 32bit constant value to a full register
+static void gen_add_imm(HostReg reg,Bit32u imm) {
+ Bit32u imm2, scale;
+
+ if(!imm) return;
+
+ imm2 = (Bit32u) (-((Bit32s)imm));
+
+ if (imm <= 255) {
+ cache_addw( ADD_IMM8(reg, imm) ); // add reg, #imm
+ } else if (imm2 <= 255) {
+ cache_addw( SUB_IMM8(reg, imm2) ); // sub reg, #(-imm)
+ } else {
+ if (val_single_shift(imm2, &scale)) {
+ cache_addw( MOV_IMM(templo1, imm2 >> scale) ); // mov templo1, #(~imm >> scale)
+ if (scale) {
+ cache_addw( LSL_IMM(templo1, templo1, scale) ); // lsl templo1, templo1, #scale
+ }
+ cache_addw( SUB_REG(reg, reg, templo1) ); // sub reg, reg, templo1
+ } else {
+ gen_mov_dword_to_reg_imm(templo1, imm);
+ cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1
+ }
+ }
+}
+
+// and a 32bit constant value with a full register
+static void gen_and_imm(HostReg reg,Bit32u imm) {
+ Bit32u imm2, scale;
+
+ imm2 = ~imm;
+ if(!imm2) return;
+
+ if (!imm) {
+ cache_addw( MOV_IMM(reg, 0) ); // mov reg, #0
+ } else {
+ if (val_single_shift(imm2, &scale)) {
+ cache_addw( MOV_IMM(templo1, imm2 >> scale) ); // mov templo1, #(~imm >> scale)
+ if (scale) {
+ cache_addw( LSL_IMM(templo1, templo1, scale) ); // lsl templo1, templo1, #scale
+ }
+ cache_addw( BIC(reg, templo1) ); // bic reg, templo1
+ } else {
+ gen_mov_dword_to_reg_imm(templo1, imm);
+ cache_addw( AND(reg, templo1) ); // and reg, templo1
+ }
+ }
+}
+
+
+// move a 32bit constant value into memory
+static void gen_mov_direct_dword(void* dest,Bit32u imm) {
+ gen_mov_dword_to_reg_imm(templo3, imm);
+ gen_mov_word_from_reg(templo3, dest, 1);
+}
+
+// move an address into memory
+static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) {
+ gen_mov_direct_dword(dest,(Bit32u)imm);
+}
+
+// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value
+static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) {
+ if (!dword) imm &= 0xffff;
+ if(!imm) return;
+
+ if (!gen_mov_memval_to_reg(templo3, dest, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest);
+ gen_mov_word_to_reg_helper(templo3, dest, dword, templo2);
+ }
+ gen_add_imm(templo3, imm);
+ if (!gen_mov_memval_from_reg(templo3, dest, (dword)?4:2)) {
+ gen_mov_word_from_reg_helper(templo3, dest, dword, templo2);
+ }
+}
+
+// add an 8bit constant value to a dword memory value
+static void gen_add_direct_byte(void* dest,Bit8s imm) {
+ gen_add_direct_word(dest, (Bit32s)imm, 1);
+}
+
+// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value
+static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) {
+ Bit32u imm2, scale;
+
+ if (!dword) imm &= 0xffff;
+ if(!imm) return;
+
+ if (!gen_mov_memval_to_reg(templo3, dest, (dword)?4:2)) {
+ gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest);
+ gen_mov_word_to_reg_helper(templo3, dest, dword, templo2);
+ }
+
+ imm2 = (Bit32u) (-((Bit32s)imm));
+
+ if (imm <= 255) {
+ cache_addw( SUB_IMM8(templo3, imm) ); // sub templo3, #imm
+ } else if (imm2 <= 255) {
+ cache_addw( ADD_IMM8(templo3, imm2) ); // add templo3, #(-imm)
+ } else {
+ if (val_single_shift(imm2, &scale)) {
+ cache_addw( MOV_IMM(templo1, imm2 >> scale) ); // mov templo1, #(~imm >> scale)
+ if (scale) {
+ cache_addw( LSL_IMM(templo1, templo1, scale) ); // lsl templo1, templo1, #scale
+ }
+ cache_addw( ADD_REG(templo3, templo3, templo1) ); // add templo3, templo3, templo1
+ } else {
+ gen_mov_dword_to_reg_imm(templo1, imm);
+ cache_addw( SUB_REG(templo3, templo3, templo1) ); // sub templo3, templo3, templo1
+ }
+ }
+
+ if (!gen_mov_memval_from_reg(templo3, dest, (dword)?4:2)) {
+ gen_mov_word_from_reg_helper(templo3, dest, dword, templo2);
+ }
+}
+
+// subtract an 8bit constant value from a dword memory value
+static void gen_sub_direct_byte(void* dest,Bit8s imm) {
+ gen_sub_direct_word(dest, (Bit32s)imm, 1);
+}
+
+// effective address calculation, destination is dest_reg
+// scale_reg is scaled by scale (scale_reg*(2^scale)) and
+// added to dest_reg, then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) {
+ if (scale) {
+ cache_addw( LSL_IMM(templo1, scale_reg, scale) ); // lsl templo1, scale_reg, #(scale)
+ cache_addw( ADD_REG(dest_reg, dest_reg, templo1) ); // add dest_reg, dest_reg, templo1
+ } else {
+ cache_addw( ADD_REG(dest_reg, dest_reg, scale_reg) ); // add dest_reg, dest_reg, scale_reg
+ }
+ gen_add_imm(dest_reg, imm);
+}
+
+// effective address calculation, destination is dest_reg
+// dest_reg is scaled by scale (dest_reg*(2^scale)),
+// then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) {
+ if (scale) {
+ cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #(scale)
+ }
+ gen_add_imm(dest_reg, imm);
+}
+
+// generate a call to a parameterless function
+static void INLINE gen_call_function_raw(void * func) {
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( LDR_PC_IMM(templo1, 4) ); // ldr templo1, [pc, #4]
+ cache_addw( ADD_LO_PC_IMM(templo2, 8) ); // adr templo2, after_call (add templo2, pc, #8)
+ cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2
+ cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state
+ } else {
+ cache_addw( LDR_PC_IMM(templo1, 8) ); // ldr templo1, [pc, #8]
+ cache_addw( ADD_LO_PC_IMM(templo2, 8) ); // adr templo2, after_call (add templo2, pc, #8)
+ cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2
+ cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state
+ cache_addw( NOP ); // nop
+ }
+ cache_addd((Bit32u)func); // .int func
+ // after_call:
+
+ // switch from arm to thumb state
+ cache_addd(0xe2800000 + (templo1 << 12) + (HOST_pc << 16) + (1)); // add templo1, pc, #1
+ cache_addd(0xe12fff10 + (templo1)); // bx templo1
+
+ // thumb state from now on
+}
+
+// generate a call to a function with paramcount parameters
+// note: the parameters are loaded in the architecture specific way
+// using the gen_load_param_ functions below
+static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) {
+ Bit32u proc_addr = (Bit32u)cache.pos;
+ gen_call_function_raw(func);
+ return proc_addr;
+ // if proc_addr is on word boundary ((proc_addr & 0x03) == 0)
+ // then length of generated code is 20 bytes
+ // otherwise length of generated code is 22 bytes
+}
+
+#if (1)
+// max of 4 parameters in a1-a4
+
+// load an immediate value as param'th function parameter
+static void INLINE gen_load_param_imm(Bitu imm,Bitu param) {
+ gen_mov_dword_to_reg_imm(param, imm);
+}
+
+// load an address as param'th function parameter
+static void INLINE gen_load_param_addr(Bitu addr,Bitu param) {
+ gen_mov_dword_to_reg_imm(param, addr);
+}
+
+// load a host-register as param'th function parameter
+static void INLINE gen_load_param_reg(Bitu reg,Bitu param) {
+ gen_mov_regs(param, reg);
+}
+
+// load a value from memory as param'th function parameter
+static void INLINE gen_load_param_mem(Bitu mem,Bitu param) {
+ gen_mov_word_to_reg(param, (void *)mem, 1);
+}
+#else
+ other arm abis
+#endif
+
+// jump to an address pointed at by ptr, offset is in imm
+static void gen_jmp_ptr(void * ptr,Bits imm=0) {
+ gen_mov_word_to_reg(templo3, ptr, 1);
+
+#if !defined(C_UNALIGNED_MEMORY)
+// (*ptr) should be word aligned
+ if ((imm & 0x03) == 0) {
+#endif
+ if ((imm >= 0) && (imm < 128) && ((imm & 3) == 0)) {
+ cache_addw( LDR_IMM(templo2, templo3, imm) ); // ldr templo2, [templo3, #imm]
+ } else {
+ gen_mov_dword_to_reg_imm(templo2, imm);
+ cache_addw( LDR_REG(templo2, templo3, templo2) ); // ldr templo2, [templo3, templo2]
+ }
+#if !defined(C_UNALIGNED_MEMORY)
+ } else {
+ gen_add_imm(templo3, imm);
+
+ cache_addw( LDRB_IMM(templo2, templo3, 0) ); // ldrb templo2, [templo3]
+ cache_addw( LDRB_IMM(templo1, templo3, 1) ); // ldrb templo1, [templo3, #1]
+ cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8
+ cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1
+ cache_addw( LDRB_IMM(templo1, templo3, 2) ); // ldrb templo1, [templo3, #2]
+ cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16
+ cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1
+ cache_addw( LDRB_IMM(templo1, templo3, 3) ); // ldrb templo1, [templo3, #3]
+ cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24
+ cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1
+ }
+#endif
+
+ // increase jmp address to keep thumb state
+ cache_addw( ADD_IMM3(templo2, templo2, 1) ); // add templo2, templo2, #1
+
+ cache_addw( BX(templo2) ); // bx templo2
+}
+
+// short conditional jump (+-127 bytes) if register is zero
+// the destination is set by gen_fill_branch() later
+static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) {
+ if (dword) {
+ cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0
+ } else {
+ cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16
+ }
+ cache_addw( BEQ_FWD(0) ); // beq j
+ return ((Bit32u)cache.pos-2);
+}
+
+// short conditional jump (+-127 bytes) if register is nonzero
+// the destination is set by gen_fill_branch() later
+static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) {
+ if (dword) {
+ cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0
+ } else {
+ cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16
+ }
+ cache_addw( BNE_FWD(0) ); // bne j
+ return ((Bit32u)cache.pos-2);
+}
+
+// calculate relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) {
+#if C_DEBUG
+ Bits len=(Bit32u)cache.pos-(data+4);
+ if (len<0) len=-len;
+ if (len>252) LOG_MSG("Big jump %d",len);
+#endif
+ *(Bit8u*)data=(Bit8u)( ((Bit32u)cache.pos-(data+4)) >> 1 );
+}
+
+// conditional jump if register is nonzero
+// for isdword==true the 32bit of the register are tested
+// for isdword==false the lowest 8bit of the register are tested
+static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) {
+ if (isdword) {
+ cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0
+ } else {
+ cache_addw( LSL_IMM(templo2, reg, 24) ); // lsl templo2, reg, #24
+ }
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( BEQ_FWD(8) ); // beq nobranch (pc+8)
+ cache_addw( LDR_PC_IMM(templo1, 4) ); // ldr templo1, [pc, #4]
+ cache_addw( BX(templo1) ); // bx templo1
+ cache_addw( NOP ); // nop
+ } else {
+ cache_addw( BEQ_FWD(6) ); // beq nobranch (pc+6)
+ cache_addw( LDR_PC_IMM(templo1, 0) ); // ldr templo1, [pc, #0]
+ cache_addw( BX(templo1) ); // bx templo1
+ }
+ cache_addd(0); // fill j
+ // nobranch:
+ return ((Bit32u)cache.pos-4);
+}
+
+// compare 32bit-register against zero and jump if value less/equal than zero
+static Bit32u gen_create_branch_long_leqzero(HostReg reg) {
+ cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0
+ if (((Bit32u)cache.pos & 0x03) == 0) {
+ cache_addw( BGT_FWD(8) ); // bgt nobranch (pc+8)
+ cache_addw( LDR_PC_IMM(templo1, 4) ); // ldr templo1, [pc, #4]
+ cache_addw( BX(templo1) ); // bx templo1
+ cache_addw( NOP ); // nop
+ } else {
+ cache_addw( BGT_FWD(6) ); // bgt nobranch (pc+6)
+ cache_addw( LDR_PC_IMM(templo1, 0) ); // ldr templo1, [pc, #0]
+ cache_addw( BX(templo1) ); // bx templo1
+ }
+ cache_addd(0); // fill j
+ // nobranch:
+ return ((Bit32u)cache.pos-4);
+}
+
+// calculate long relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch_long(Bit32u data) {
+ // this is an absolute branch
+ *(Bit32u*)data=((Bit32u)cache.pos) + 1; // add 1 to keep processor in thumb state
+}
+
+static void gen_run_code(void) {
+ Bit8u *pos1, *pos2, *pos3;
+
+#if (__ARM_EABI__)
+ // 8-byte stack alignment
+ cache_addd(0xe92d4ff0); // stmfd sp!, {v1-v8,lr}
+#else
+ cache_addd(0xe92d4df0); // stmfd sp!, {v1-v5,v7,v8,lr}
+#endif
+
+ cache_addd( ARM_ADD_IMM(HOST_r0, HOST_r0, 1, 0) ); // add r0, r0, #1
+
+ pos1 = cache.pos;
+ cache_addd( 0 );
+ pos2 = cache.pos;
+ cache_addd( 0 );
+ pos3 = cache.pos;
+ cache_addd( 0 );
+
+ cache_addd( ARM_ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4
+ cache_addd( ARM_STR_IMM_M_W(HOST_lr, HOST_sp, 4) ); // str lr, [sp, #-4]!
+ cache_addd( ARM_BX(HOST_r0) ); // bx r0
+
+#if (__ARM_EABI__)
+ cache_addd(0xe8bd4ff0); // ldmfd sp!, {v1-v8,lr}
+#else
+ cache_addd(0xe8bd4df0); // ldmfd sp!, {v1-v5,v7,v8,lr}
+#endif
+ cache_addd( ARM_BX(HOST_lr) ); // bx lr
+
+ // align cache.pos to 32 bytes
+ if ((((Bitu)cache.pos) & 0x1f) != 0) {
+ cache.pos = cache.pos + (32 - (((Bitu)cache.pos) & 0x1f));
+ }
+
+ *(Bit32u*)pos1 = ARM_LDR_IMM(FC_SEGS_ADDR, HOST_pc, cache.pos - (pos1 + 8)); // ldr FC_SEGS_ADDR, [pc, #(&Segs)]
+ cache_addd((Bit32u)&Segs); // address of "Segs"
+
+ *(Bit32u*)pos2 = ARM_LDR_IMM(FC_REGS_ADDR, HOST_pc, cache.pos - (pos2 + 8)); // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)]
+ cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs"
+
+ *(Bit32u*)pos3 = ARM_LDR_IMM(readdata_addr, HOST_pc, cache.pos - (pos3 + 8)); // ldr readdata_addr, [pc, #(&core_dynrec.readdata)]
+ cache_addd((Bit32u)&core_dynrec.readdata); // address of "core_dynrec.readdata"
+
+ // align cache.pos to 32 bytes
+ if ((((Bitu)cache.pos) & 0x1f) != 0) {
+ cache.pos = cache.pos + (32 - (((Bitu)cache.pos) & 0x1f));
+ }
+}
+
+// return from a function
+static void gen_return_function(void) {
+ cache_addw(0xbc08); // pop {r3}
+ cache_addw( BX(HOST_r3) ); // bx r3
+}
+
+#ifdef DRC_FLAGS_INVALIDATION
+
+// called when a call to a function can be replaced by a
+// call to a simpler function
+static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) {
+#ifdef DRC_FLAGS_INVALIDATION_DCODE
+ if (((Bit32u)pos & 0x03) == 0)
+ {
+ // try to avoid function calls but rather directly fill in code
+ switch (flags_type) {
+ case t_ADDb:
+ case t_ADDw:
+ case t_ADDd:
+ *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14)
+ break;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14)
+ break;
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14)
+ break;
+ case t_SUBb:
+ case t_SUBw:
+ case t_SUBd:
+ *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14)
+ break;
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14)
+ break;
+ case t_CMPb:
+ case t_CMPw:
+ case t_CMPd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ *(Bit16u*)pos=B_FWD(16); // b after_call (pc+16)
+ break;
+ case t_INCb:
+ case t_INCw:
+ case t_INCd:
+ *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1
+ *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14)
+ break;
+ case t_DECb:
+ case t_DECw:
+ case t_DECd:
+ *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1
+ *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14)
+ break;
+ case t_SHLb:
+ case t_SHLw:
+ case t_SHLd:
+ *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14)
+ break;
+ case t_SHRb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24
+ *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_SHRw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16
+ *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_SHRd:
+ *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14)
+ break;
+ case t_SARb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24
+ *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_SARw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16
+ *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_SARd:
+ *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14)
+ break;
+ case t_RORb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8
+ *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+6)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+12)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_RORw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+8)=B_FWD(8); // b after_call (pc+8)
+ break;
+ case t_RORd:
+ *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14)
+ break;
+ case t_ROLb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8
+ *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+10)=NOP; // nop
+ *(Bit16u*)(pos+12)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+14)=NOP; // nop
+ *(Bit16u*)(pos+16)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+18)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ break;
+ case t_ROLw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+12)=B_FWD(4); // b after_call (pc+4)
+ break;
+ case t_ROLd:
+ *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_NEGb:
+ case t_NEGw:
+ case t_NEGd:
+ *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1
+ *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14)
+ break;
+ default:
+ *(Bit32u*)(pos+8)=(Bit32u)fct_ptr; // simple_func
+ break;
+ }
+ }
+ else
+ {
+ // try to avoid function calls but rather directly fill in code
+ switch (flags_type) {
+ case t_ADDb:
+ case t_ADDw:
+ case t_ADDd:
+ *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16)
+ break;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16)
+ break;
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16)
+ break;
+ case t_SUBb:
+ case t_SUBw:
+ case t_SUBd:
+ *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16)
+ break;
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16)
+ break;
+ case t_CMPb:
+ case t_CMPw:
+ case t_CMPd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ *(Bit16u*)pos=B_FWD(18); // b after_call (pc+18)
+ break;
+ case t_INCb:
+ case t_INCw:
+ case t_INCd:
+ *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1
+ *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16)
+ break;
+ case t_DECb:
+ case t_DECw:
+ case t_DECd:
+ *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1
+ *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16)
+ break;
+ case t_SHLb:
+ case t_SHLw:
+ case t_SHLd:
+ *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16)
+ break;
+ case t_SHRb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24
+ *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_SHRw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16
+ *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_SHRd:
+ *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16)
+ break;
+ case t_SARb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24
+ *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_SARw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16
+ *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_SARd:
+ *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16)
+ break;
+ case t_RORb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8
+ *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+6)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+12)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_RORw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+8)=B_FWD(10); // b after_call (pc+10)
+ break;
+ case t_RORd:
+ *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16)
+ break;
+ case t_ROLb:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24
+ *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8
+ *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+10)=NOP; // nop
+ *(Bit16u*)(pos+12)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+14)=NOP; // nop
+ *(Bit16u*)(pos+16)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+18)=NOP; // nop
+ *(Bit16u*)(pos+20)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ break;
+ case t_ROLw:
+ *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16
+ *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16
+ *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1
+ *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+12)=B_FWD(6); // b after_call (pc+6)
+ break;
+ case t_ROLd:
+ *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2
+ *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32
+ *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2
+ *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12)
+ break;
+ case t_NEGb:
+ case t_NEGw:
+ case t_NEGd:
+ *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1
+ *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16)
+ break;
+ default:
+ *(Bit32u*)(pos+10)=(Bit32u)fct_ptr; // simple_func
+ break;
+ }
+
+ }
+#else
+ if (((Bit32u)pos & 0x03) == 0)
+ {
+ *(Bit32u*)(pos+8)=(Bit32u)fct_ptr; // simple_func
+ }
+ else
+ {
+ *(Bit32u*)(pos+10)=(Bit32u)fct_ptr; // simple_func
+ }
+#endif
+}
+#endif
+
+static void cache_block_before_close(void) {
+ if ((((Bit32u)cache.pos) & 3) != 0) {
+ cache_addw( NOP ); // nop
+ }
+}
+
+#ifdef DRC_USE_SEGS_ADDR
+
+// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) {
+ cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR
+ cache_addw( LDRH_IMM(dest_reg, templo1, index) ); // ldrh dest_reg, [templo1, #index]
+}
+
+// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) {
+ cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR
+ cache_addw( LDR_IMM(dest_reg, templo1, index) ); // ldr dest_reg, [templo1, #index]
+}
+
+// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero)
+static void gen_add_seg32_to_reg(HostReg reg,Bitu index) {
+ cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR
+ cache_addw( LDR_IMM(templo2, templo1, index) ); // ldr templo2, [templo1, #index]
+ cache_addw( ADD_REG(reg, reg, templo2) ); // add reg, reg, templo2
+}
+
+#endif
+
+#ifdef DRC_USE_REGS_ADDR
+
+// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) {
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index]
+}
+
+// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) {
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index]
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) {
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ if (dword) {
+ cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index]
+ } else {
+ cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index]
+ }
+}
+
+// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) {
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index]
+}
+
+// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) {
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index]
+}
+
+
+// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_add_regval32_to_reg(HostReg reg,Bitu index) {
+ cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR
+ cache_addw( LDR_IMM(templo1, templo2, index) ); // ldr templo1, [templo2, #index]
+ cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1
+}
+
+
+// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero)
+static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) {
+ cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR
+ cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index]
+}
+
+// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) {
+ cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR
+ cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index]
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
+static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) {
+ cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR
+ if (dword) {
+ cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index]
+ } else {
+ cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index]
+ }
+}
+
+// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR
+static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) {
+ cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR
+ cache_addw( STRB_IMM(src_reg, templo1, index) ); // strb src_reg, [templo1, #index]
+}
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+/* ARMv4/ARMv7 (little endian) backend (switcher) by M-HT */
+
+#include "risc_armv4le-common.h"
+
+// choose your destiny:
+#if C_TARGETCPU == ARMV7LE
+ #include "risc_armv4le-o3.h"
+#else
+ #if defined(__THUMB_INTERWORK__)
+ #include "risc_armv4le-thumb-iw.h"
+ #else
+ #include "risc_armv4le-o3.h"
+// #include "risc_armv4le-thumb-niw.h"
+// #include "risc_armv4le-thumb.h"
+ #endif
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+/* MIPS32 (little endian) backend by crazyc */
+
+
+// some configuring defines that specify the capabilities of this architecture
+// or aspects of the recompiling
+
+// protect FC_ADDR over function calls if necessaray
+// #define DRC_PROTECT_ADDR_REG
+
+// try to use non-flags generating functions if possible
+#define DRC_FLAGS_INVALIDATION
+// try to replace _simple functions by code
+#define DRC_FLAGS_INVALIDATION_DCODE
+
+// type with the same size as a pointer
+#define DRC_PTR_SIZE_IM Bit32u
+
+// calling convention modifier
+#define DRC_CALL_CONV /* nothing */
+#define DRC_FC /* nothing */
+
+// use FC_REGS_ADDR to hold the address of "cpu_regs" and to access it using FC_REGS_ADDR
+//#define DRC_USE_REGS_ADDR
+// use FC_SEGS_ADDR to hold the address of "Segs" and to access it using FC_SEGS_ADDR
+//#define DRC_USE_SEGS_ADDR
+
+// register mapping
+typedef Bit8u HostReg;
+
+#define HOST_v0 2
+#define HOST_v1 3
+#define HOST_a0 4
+#define HOST_a1 5
+#define HOST_t4 12
+#define HOST_t5 13
+#define HOST_t6 14
+#define HOST_t7 15
+#define HOST_s0 16
+#define HOST_t8 24
+#define HOST_t9 25
+#define temp1 HOST_v1
+#define temp2 HOST_t9
+
+// register that holds function return values
+#define FC_RETOP HOST_v0
+
+// register used for address calculations,
+#define FC_ADDR HOST_s0 // has to be saved across calls, see DRC_PROTECT_ADDR_REG
+
+// register that holds the first parameter
+#define FC_OP1 HOST_a0
+
+// register that holds the second parameter
+#define FC_OP2 HOST_a1
+
+// special register that holds the third parameter for _R3 calls (byte accessible)
+#define FC_OP3 HOST_???
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA1 HOST_t5
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA2 HOST_t6
+
+// temporary register for LEA
+#define TEMP_REG_DRC HOST_t7
+
+#ifdef DRC_USE_REGS_ADDR
+// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code
+#define FC_REGS_ADDR HOST_???
+#endif
+
+#ifdef DRC_USE_SEGS_ADDR
+// used to hold the address of "Segs" - preferably filled in function gen_run_code
+#define FC_SEGS_ADDR HOST_???
+#endif
+
+// save some state to improve code gen
+static bool temp1_valid = false;
+static Bit32u temp1_value;
+
+// move a full register from reg_src to reg_dst
+static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) {
+ if(reg_src == reg_dst) return;
+ cache_addw((reg_dst<<11)+0x21); // addu reg_dst, $0, reg_src
+ cache_addw(reg_src);
+}
+
+// move a 32bit constant value into dest_reg
+static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) {
+ if(imm < 65536) {
+ cache_addw((Bit16u)imm); // ori dest_reg, $0, imm
+ cache_addw(0x3400+dest_reg);
+ } else if(((Bit32s)imm < 0) && ((Bit32s)imm >= -32768)) {
+ cache_addw((Bit16u)imm); // addiu dest_reg, $0, imm
+ cache_addw(0x2400+dest_reg);
+ } else if(!(imm & 0xffff)) {
+ cache_addw((Bit16u)(imm >> 16)); // lui dest_reg, %hi(imm)
+ cache_addw(0x3c00+dest_reg);
+ } else {
+ cache_addw((Bit16u)(imm >> 16)); // lui dest_reg, %hi(imm)
+ cache_addw(0x3c00+dest_reg);
+ cache_addw((Bit16u)imm); // ori dest_reg, dest_reg, %lo(imm)
+ cache_addw(0x3400+(dest_reg<<5)+dest_reg);
+ }
+}
+
+// this is the only place temp1 should be modified
+static void INLINE mov_imm_to_temp1(Bit32u imm) {
+ if (temp1_valid && (temp1_value == imm)) return;
+ gen_mov_dword_to_reg_imm(temp1, imm);
+ temp1_valid = true;
+ temp1_value = imm;
+}
+
+static Bit16s gen_addr_temp1(Bit32u addr) {
+ Bit32u hihalf = addr & 0xffff0000;
+ Bit16s lohalf = addr & 0xffff;
+ if (lohalf > 32764) { // [l,s]wl will overflow
+ hihalf = addr;
+ lohalf = 0;
+ } else if(lohalf < 0) hihalf += 0x10000;
+ mov_imm_to_temp1(hihalf);
+ return lohalf;
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) {
+ Bit16s lohalf = gen_addr_temp1((Bit32u)data);
+ // alignment....
+ if (dword) {
+ if ((Bit32u)data & 3) {
+ cache_addw(lohalf+3); // lwl dest_reg, 3(temp1)
+ cache_addw(0x8800+(temp1<<5)+dest_reg);
+ cache_addw(lohalf); // lwr dest_reg, 0(temp1)
+ cache_addw(0x9800+(temp1<<5)+dest_reg);
+ } else {
+ cache_addw(lohalf); // lw dest_reg, 0(temp1)
+ cache_addw(0x8C00+(temp1<<5)+dest_reg);
+ }
+ } else {
+ if ((Bit32u)data & 1) {
+ cache_addw(lohalf); // lbu dest_reg, 0(temp1)
+ cache_addw(0x9000+(temp1<<5)+dest_reg);
+ cache_addw(lohalf+1); // lbu temp2, 1(temp1)
+ cache_addw(0x9000+(temp1<<5)+temp2);
+#if (_MIPS_ISA==MIPS32R2) || defined(PSP)
+ cache_addw(0x7a04); // ins dest_reg, temp2, 8, 8
+ cache_addw(0x7c00+(temp2<<5)+dest_reg);
+#else
+ cache_addw((temp2<<11)+0x200); // sll temp2, temp2, 8
+ cache_addw(temp2);
+ cache_addw((dest_reg<<11)+0x25); // or dest_reg, temp2, dest_reg
+ cache_addw((temp2<<5)+dest_reg);
+#endif
+ } else {
+ cache_addw(lohalf); // lhu dest_reg, 0(temp1);
+ cache_addw(0x9400+(temp1<<5)+dest_reg);
+ }
+ }
+}
+
+// move a 16bit constant value into dest_reg
+// the upper 16bit of the destination register may be destroyed
+static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) {
+ cache_addw(imm); // ori dest_reg, $0, imm
+ cache_addw(0x3400+dest_reg);
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into memory
+static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) {
+ Bit16s lohalf = gen_addr_temp1((Bit32u)dest);
+ // alignment....
+ if (dword) {
+ if ((Bit32u)dest & 3) {
+ cache_addw(lohalf+3); // swl src_reg, 3(temp1)
+ cache_addw(0xA800+(temp1<<5)+src_reg);
+ cache_addw(lohalf); // swr src_reg, 0(temp1)
+ cache_addw(0xB800+(temp1<<5)+src_reg);
+ } else {
+ cache_addw(lohalf); // sw src_reg, 0(temp1)
+ cache_addw(0xAC00+(temp1<<5)+src_reg);
+ }
+ } else {
+ if((Bit32u)dest & 1) {
+ cache_addw(lohalf); // sb src_reg, 0(temp1)
+ cache_addw(0xA000+(temp1<<5)+src_reg);
+ cache_addw((temp2<<11)+0x202); // srl temp2, src_reg, 8
+ cache_addw(src_reg);
+ cache_addw(lohalf+1); // sb temp2, 1(temp1)
+ cache_addw(0xA000+(temp1<<5)+temp2);
+ } else {
+ cache_addw(lohalf); // sh src_reg, 0(temp1);
+ cache_addw(0xA400+(temp1<<5)+src_reg);
+ }
+ }
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) {
+ Bit16s lohalf = gen_addr_temp1((Bit32u)data);
+ cache_addw(lohalf); // lbu dest_reg, 0(temp1)
+ cache_addw(0x9000+(temp1<<5)+dest_reg);
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) {
+ gen_mov_byte_to_reg_low(dest_reg, data);
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) {
+ gen_mov_word_to_reg_imm(dest_reg, imm);
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) {
+ gen_mov_byte_to_reg_low_imm(dest_reg, imm);
+}
+
+// move the lowest 8bit of a register into memory
+static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) {
+ Bit16s lohalf = gen_addr_temp1((Bit32u)dest);
+ cache_addw(lohalf); // sb src_reg, 0(temp1)
+ cache_addw(0xA000+(temp1<<5)+src_reg);
+}
+
+
+
+// convert an 8bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_byte(bool sign,HostReg reg) {
+ if (sign) {
+#if (_MIPS_ISA==MIPS32R2) || defined(PSP)
+ cache_addw((reg<<11)+0x420); // seb reg, reg
+ cache_addw(0x7c00+reg);
+#else
+ arch that lacks seb
+#endif
+ } else {
+ cache_addw(0xff); // andi reg, reg, 0xff
+ cache_addw(0x3000+(reg<<5)+reg);
+ }
+}
+
+// convert a 16bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_word(bool sign,HostReg reg) {
+ if (sign) {
+#if (_MIPS_ISA==MIPS32R2) || defined(PSP)
+ cache_addw((reg<<11)+0x620); // seh reg, reg
+ cache_addw(0x7c00+reg);
+#else
+ arch that lacks seh
+#endif
+ } else {
+ cache_addw(0xffff); // andi reg, reg, 0xffff
+ cache_addw(0x3000+(reg<<5)+reg);
+ }
+}
+
+// add a 32bit value from memory to a full register
+static void gen_add(HostReg reg,void* op) {
+ gen_mov_word_to_reg(temp2, op, 1);
+ cache_addw((reg<<11)+0x21); // addu reg, reg, temp2
+ cache_addw((reg<<5)+temp2);
+}
+
+// add a 32bit constant value to a full register
+static void gen_add_imm(HostReg reg,Bit32u imm) {
+ if(!imm) return;
+ if(((Bit32s)imm >= -32768) && ((Bit32s)imm < 32768)) {
+ cache_addw((Bit16u)imm); // addiu reg, reg, imm
+ cache_addw(0x2400+(reg<<5)+reg);
+ } else {
+ mov_imm_to_temp1(imm);
+ cache_addw((reg<<11)+0x21); // addu reg, reg, temp1
+ cache_addw((reg<<5)+temp1);
+ }
+}
+
+// and a 32bit constant value with a full register
+static void gen_and_imm(HostReg reg,Bit32u imm) {
+ if(imm < 65536) {
+ cache_addw((Bit16u)imm); // andi reg, reg, imm
+ cache_addw(0x3000+(reg<<5)+reg);
+ } else {
+ mov_imm_to_temp1((Bit32u)imm);
+ cache_addw((reg<<11)+0x24); // and reg, temp1, reg
+ cache_addw((temp1<<5)+reg);
+ }
+}
+
+
+// move a 32bit constant value into memory
+static void INLINE gen_mov_direct_dword(void* dest,Bit32u imm) {
+ gen_mov_dword_to_reg_imm(temp2, imm);
+ gen_mov_word_from_reg(temp2, dest, 1);
+}
+
+// move an address into memory
+static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) {
+ gen_mov_direct_dword(dest,(Bit32u)imm);
+}
+
+// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value
+static void INLINE gen_add_direct_word(void* dest,Bit32u imm,bool dword) {
+ if(!imm) return;
+ gen_mov_word_to_reg(temp2, dest, dword);
+ gen_add_imm(temp2, imm);
+ gen_mov_word_from_reg(temp2, dest, dword);
+}
+
+// add an 8bit constant value to a dword memory value
+static void INLINE gen_add_direct_byte(void* dest,Bit8s imm) {
+ gen_add_direct_word(dest, (Bit32s)imm, 1);
+}
+
+// subtract an 8bit constant value from a dword memory value
+static void INLINE gen_sub_direct_byte(void* dest,Bit8s imm) {
+ gen_add_direct_word(dest, -((Bit32s)imm), 1);
+}
+
+// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value
+static void INLINE gen_sub_direct_word(void* dest,Bit32u imm,bool dword) {
+ gen_add_direct_word(dest, -(Bit32s)imm, dword);
+}
+
+// effective address calculation, destination is dest_reg
+// scale_reg is scaled by scale (scale_reg*(2^scale)) and
+// added to dest_reg, then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) {
+ if (scale) {
+ cache_addw((scale_reg<<11)+(scale<<6)); // sll scale_reg, scale_reg, scale
+ cache_addw(scale_reg);
+ }
+ cache_addw((dest_reg<<11)+0x21); // addu dest_reg, dest_reg, scale_reg
+ cache_addw((dest_reg<<5)+scale_reg);
+ gen_add_imm(dest_reg, imm);
+}
+
+// effective address calculation, destination is dest_reg
+// dest_reg is scaled by scale (dest_reg*(2^scale)),
+// then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) {
+ if (scale) {
+ cache_addw((dest_reg<<11)+(scale<<6)); // sll dest_reg, dest_reg, scale
+ cache_addw(dest_reg);
+ }
+ gen_add_imm(dest_reg, imm);
+}
+
+#define DELAY cache_addd(0) // nop
+
+// generate a call to a parameterless function
+static void INLINE gen_call_function_raw(void * func) {
+#if C_DEBUG
+ if ((cache.pos ^ func) & 0xf0000000) LOG_MSG("jump overflow\n");
+#endif
+ temp1_valid = false;
+ cache_addd(0x0c000000+(((Bit32u)func>>2)&0x3ffffff)); // jal func
+ DELAY;
+}
+
+// generate a call to a function with paramcount parameters
+// note: the parameters are loaded in the architecture specific way
+// using the gen_load_param_ functions below
+static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) {
+ Bit32u proc_addr = (Bit32u)cache.pos;
+ gen_call_function_raw(func);
+ return proc_addr;
+}
+
+#ifdef __mips_eabi
+// max of 8 parameters in $a0-$a3 and $t0-$t3
+
+// load an immediate value as param'th function parameter
+static void INLINE gen_load_param_imm(Bitu imm,Bitu param) {
+ gen_mov_dword_to_reg_imm(param+4, imm);
+}
+
+// load an address as param'th function parameter
+static void INLINE gen_load_param_addr(Bitu addr,Bitu param) {
+ gen_mov_dword_to_reg_imm(param+4, addr);
+}
+
+// load a host-register as param'th function parameter
+static void INLINE gen_load_param_reg(Bitu reg,Bitu param) {
+ gen_mov_regs(param+4, reg);
+}
+
+// load a value from memory as param'th function parameter
+static void INLINE gen_load_param_mem(Bitu mem,Bitu param) {
+ gen_mov_word_to_reg(param+4, (void *)mem, 1);
+}
+#else
+ other mips abis
+#endif
+
+// jump to an address pointed at by ptr, offset is in imm
+static void INLINE gen_jmp_ptr(void * ptr,Bits imm=0) {
+ gen_mov_word_to_reg(temp2, ptr, 1);
+ if((imm < -32768) || (imm >= 32768)) {
+ gen_add_imm(temp2, imm);
+ imm = 0;
+ }
+ temp1_valid = false;
+ cache_addw((Bit16u)imm); // lw temp2, imm(temp2)
+ cache_addw(0x8C00+(temp2<<5)+temp2);
+ cache_addd((temp2<<21)+8); // jr temp2
+ DELAY;
+}
+
+// short conditional jump (+-127 bytes) if register is zero
+// the destination is set by gen_fill_branch() later
+static Bit32u INLINE gen_create_branch_on_zero(HostReg reg,bool dword) {
+ temp1_valid = false;
+ if(!dword) {
+ cache_addw(0xffff); // andi temp1, reg, 0xffff
+ cache_addw(0x3000+(reg<<5)+temp1);
+ }
+ cache_addw(0); // beq $0, reg, 0
+ cache_addw(0x1000+(dword?reg:temp1));
+ DELAY;
+ return ((Bit32u)cache.pos-8);
+}
+
+// short conditional jump (+-127 bytes) if register is nonzero
+// the destination is set by gen_fill_branch() later
+static Bit32u INLINE gen_create_branch_on_nonzero(HostReg reg,bool dword) {
+ temp1_valid = false;
+ if(!dword) {
+ cache_addw(0xffff); // andi temp1, reg, 0xffff
+ cache_addw(0x3000+(reg<<5)+temp1);
+ }
+ cache_addw(0); // bne $0, reg, 0
+ cache_addw(0x1400+(dword?reg:temp1));
+ DELAY;
+ return ((Bit32u)cache.pos-8);
+}
+
+// calculate relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) {
+#if C_DEBUG
+ Bits len=(Bit32u)cache.pos-data;
+ if (len<0) len=-len;
+ if (len>126) LOG_MSG("Big jump %d",len);
+#endif
+ temp1_valid = false; // this is a branch target
+ *(Bit16u*)data=((Bit16u)((Bit32u)cache.pos-data-4)>>2);
+}
+
+#if 0 // assume for the moment no branch will go farther then +/- 128KB
+
+// conditional jump if register is nonzero
+// for isdword==true the 32bit of the register are tested
+// for isdword==false the lowest 8bit of the register are tested
+static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) {
+ temp1_valid = false;
+ if (!isdword) {
+ cache_addw(0xff); // andi temp1, reg, 0xff
+ cache_addw(0x3000+(reg<<5)+temp1);
+ }
+ cache_addw(3); // beq $0, reg, +12
+ cache_addw(0x1000+(isdword?reg:temp1));
+ DELAY;
+ cache_addd(0x00000000); // fill j
+ DELAY;
+ return ((Bit32u)cache.pos-8);
+}
+
+// compare 32bit-register against zero and jump if value less/equal than zero
+static Bit32u INLINE gen_create_branch_long_leqzero(HostReg reg) {
+ temp1_valid = false;
+ cache_addw(3); // bgtz reg, +12
+ cache_addw(0x1c00+(reg<<5));
+ DELAY;
+ cache_addd(0x00000000); // fill j
+ DELAY;
+ return ((Bit32u)cache.pos-8);
+}
+
+// calculate long relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch_long(Bit32u data) {
+ temp1_valid = false;
+ // this is an absolute branch
+ *(Bit32u*)data=0x08000000+(((Bit32u)cache.pos>>2)&0x3ffffff);
+}
+#else
+// conditional jump if register is nonzero
+// for isdword==true the 32bit of the register are tested
+// for isdword==false the lowest 8bit of the register are tested
+static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) {
+ temp1_valid = false;
+ if (!isdword) {
+ cache_addw(0xff); // andi temp1, reg, 0xff
+ cache_addw(0x3000+(reg<<5)+temp1);
+ }
+ cache_addw(0); // bne $0, reg, 0
+ cache_addw(0x1400+(isdword?reg:temp1));
+ DELAY;
+ return ((Bit32u)cache.pos-8);
+}
+
+// compare 32bit-register against zero and jump if value less/equal than zero
+static Bit32u INLINE gen_create_branch_long_leqzero(HostReg reg) {
+ temp1_valid = false;
+ cache_addw(0); // blez reg, 0
+ cache_addw(0x1800+(reg<<5));
+ DELAY;
+ return ((Bit32u)cache.pos-8);
+}
+
+// calculate long relative offset and fill it into the location pointed to by data
+static void INLINE gen_fill_branch_long(Bit32u data) {
+ gen_fill_branch(data);
+}
+#endif
+
+static void gen_run_code(void) {
+ temp1_valid = false;
+ cache_addd(0x27bdfff0); // addiu $sp, $sp, -16
+ cache_addd(0xafb00004); // sw $s0, 4($sp)
+ cache_addd(0x00800008); // jr $a0
+ cache_addd(0xafbf0000); // sw $ra, 0($sp)
+}
+
+// return from a function
+static void gen_return_function(void) {
+ temp1_valid = false;
+ cache_addd(0x8fbf0000); // lw $ra, 0($sp)
+ cache_addd(0x8fb00004); // lw $s0, 4($sp)
+ cache_addd(0x03e00008); // jr $ra
+ cache_addd(0x27bd0010); // addiu $sp, $sp, 16
+}
+
+#ifdef DRC_FLAGS_INVALIDATION
+// called when a call to a function can be replaced by a
+// call to a simpler function
+static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) {
+#ifdef DRC_FLAGS_INVALIDATION_DCODE
+ // try to avoid function calls but rather directly fill in code
+ switch (flags_type) {
+ case t_ADDb:
+ case t_ADDw:
+ case t_ADDd:
+ *(Bit32u*)pos=0x00851021; // addu $v0, $a0, $a1
+ break;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ *(Bit32u*)pos=0x00851025; // or $v0, $a0, $a1
+ break;
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ *(Bit32u*)pos=0x00851024; // and $v0, $a0, $a1
+ break;
+ case t_SUBb:
+ case t_SUBw:
+ case t_SUBd:
+ *(Bit32u*)pos=0x00851023; // subu $v0, $a0, $a1
+ break;
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ *(Bit32u*)pos=0x00851026; // xor $v0, $a0, $a1
+ break;
+ case t_CMPb:
+ case t_CMPw:
+ case t_CMPd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ *(Bit32u*)pos=0; // nop
+ break;
+ case t_INCb:
+ case t_INCw:
+ case t_INCd:
+ *(Bit32u*)pos=0x24820001; // addiu $v0, $a0, 1
+ break;
+ case t_DECb:
+ case t_DECw:
+ case t_DECd:
+ *(Bit32u*)pos=0x2482ffff; // addiu $v0, $a0, -1
+ break;
+ case t_SHLb:
+ case t_SHLw:
+ case t_SHLd:
+ *(Bit32u*)pos=0x00a41004; // sllv $v0, $a0, $a1
+ break;
+ case t_SHRb:
+ case t_SHRw:
+ case t_SHRd:
+ *(Bit32u*)pos=0x00a41006; // srlv $v0, $a0, $a1
+ break;
+ case t_SARd:
+ *(Bit32u*)pos=0x00a41007; // srav $v0, $a0, $a1
+ break;
+#if (_MIPS_ISA==MIPS32R2) || defined(PSP)
+ case t_RORd:
+ *(Bit32u*)pos=0x00a41046; // rotr $v0, $a0, $a1
+ break;
+#endif
+ case t_NEGb:
+ case t_NEGw:
+ case t_NEGd:
+ *(Bit32u*)pos=0x00041023; // subu $v0, $0, $a0
+ break;
+ default:
+ *(Bit32u*)pos=0x0c000000+((((Bit32u)fct_ptr)>>2)&0x3ffffff); // jal simple_func
+ break;
+ }
+#else
+ *(Bit32u*)pos=0x0c000000+(((Bit32u)fct_ptr)>>2)&0x3ffffff); // jal simple_func
+#endif
+}
+#endif
+
+static void cache_block_closing(Bit8u* block_start,Bitu block_size) {
+#ifdef PSP
+// writeback dcache and invalidate icache
+ Bit32u inval_start = ((Bit32u)block_start) & ~63;
+ Bit32u inval_end = (((Bit32u)block_start) + block_size + 64) & ~63;
+ for (;inval_start < inval_end; inval_start+=64) {
+ __builtin_allegrex_cache(0x1a, inval_start);
+ __builtin_allegrex_cache(0x08, inval_start);
+ }
+#endif
+}
+
+static void cache_block_before_close(void) { }
+
+
+#ifdef DRC_USE_SEGS_ADDR
+
+// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) {
+// stub
+}
+
+// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) {
+// stub
+}
+
+// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero)
+static void gen_add_seg32_to_reg(HostReg reg,Bitu index) {
+// stub
+}
+
+#endif
+
+#ifdef DRC_USE_REGS_ADDR
+
+// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) {
+// stub
+}
+
+// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) {
+// stub
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) {
+// stub
+}
+
+// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) {
+// stub
+}
+
+// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) {
+// stub
+}
+
+
+// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_add_regval32_to_reg(HostReg reg,Bitu index) {
+// stub
+}
+
+
+// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero)
+static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) {
+// stub
+}
+
+// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero)
+static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) {
+// stub
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
+static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) {
+// stub
+}
+
+// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR
+static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) {
+// stub
+}
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+// some configuring defines that specify the capabilities of this architecture
+// or aspects of the recompiling
+
+// protect FC_ADDR over function calls if necessaray
+// #define DRC_PROTECT_ADDR_REG
+
+// try to use non-flags generating functions if possible
+#define DRC_FLAGS_INVALIDATION
+// try to replace _simple functions by code
+#define DRC_FLAGS_INVALIDATION_DCODE
+
+// type with the same size as a pointer
+#define DRC_PTR_SIZE_IM Bit64u
+
+// calling convention modifier
+#define DRC_CALL_CONV /* nothing */
+#define DRC_FC /* nothing */
+
+
+// register mapping
+typedef Bit8u HostReg;
+
+#define HOST_EAX 0
+#define HOST_ECX 1
+#define HOST_EDX 2
+#define HOST_EBX 3
+#define HOST_ESI 6
+#define HOST_EDI 7
+
+
+// register that holds function return values
+#define FC_RETOP HOST_EAX
+
+// register used for address calculations, if the ABI does not
+// state that this register is preserved across function calls
+// then define DRC_PROTECT_ADDR_REG above
+#define FC_ADDR HOST_EBX
+
+// register that holds the first parameter
+#define FC_OP1 HOST_EDI
+
+// register that holds the second parameter
+#define FC_OP2 HOST_ESI
+
+// special register that holds the third parameter for _R3 calls (byte accessible)
+#define FC_OP3 HOST_EAX
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA1 HOST_ECX
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA2 HOST_EDX
+
+
+// temporary register for LEA
+#define TEMP_REG_DRC HOST_ESI
+
+
+// move a full register from reg_src to reg_dst
+static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) {
+ cache_addb(0x8b); // mov reg_dst,reg_src
+ cache_addb(0xc0+(reg_dst<<3)+reg_src);
+}
+
+// move a 64bit constant value into a full register
+static void gen_mov_reg_qword(HostReg dest_reg,Bit64u imm) {
+ cache_addb(0x48);
+ cache_addb(0xb8+dest_reg); // mov dest_reg,imm
+ cache_addq(imm);
+}
+
+
+// This function generates an instruction with register addressing and a memory location
+static INLINE void gen_reg_memaddr(HostReg reg,void* data,Bit8u op,Bit8u prefix=0) {
+ Bit64s diff = (Bit64s)data-((Bit64s)cache.pos+(prefix?7:6));
+// if ((diff<0x80000000LL) && (diff>-0x80000000LL)) { //clang messes itself up on this...
+ if ( (diff>>63) == (diff>>31) ) { //signed bit extend, test to see if value fits in a Bit32s
+ // mov reg,[rip+diff] (or similar, depending on the op) to fetch *data
+ if(prefix) cache_addb(prefix);
+ cache_addb(op);
+ cache_addb(0x05+(reg<<3));
+ // RIP-relative addressing is offset after the instruction
+ cache_addd((Bit32u)(((Bit64u)diff)&0xffffffffLL));
+ } else if ((Bit64u)data<0x100000000LL) {
+ // mov reg,[data] (or similar, depending on the op) when absolute address of data is <4GB
+ if(prefix) cache_addb(prefix);
+ cache_addb(op);
+ cache_addw(0x2504+(reg<<3));
+ cache_addd((Bit32u)(((Bit64u)data)&0xffffffffLL));
+ } else {
+ // load 64-bit data into tmp_reg and do mov reg,[tmp_reg] (or similar, depending on the op)
+ HostReg tmp_reg = HOST_EAX;
+ if(reg == HOST_EAX) tmp_reg = HOST_ECX;
+
+ cache_addb(0x50+tmp_reg); // push rax/rcx
+ gen_mov_reg_qword(tmp_reg,(Bit64u)data);
+
+ if(prefix) cache_addb(prefix);
+ cache_addb(op);
+ cache_addb(tmp_reg+(reg<<3));
+
+ cache_addb(0x58+tmp_reg); // pop rax/rcx
+ }
+}
+
+// Same as above, but with immediate addressing and a memory location
+static INLINE void gen_memaddr(Bitu modreg,void* data,Bitu off,Bitu imm,Bit8u op,Bit8u prefix=0) {
+ Bit64s diff = (Bit64s)data-((Bit64s)cache.pos+off+(prefix?7:6));
+// if ((diff<0x80000000LL) && (diff>-0x80000000LL)) {
+ if ( (diff>>63) == (diff>>31) ) {
+ // RIP-relative addressing is offset after the instruction
+ if(prefix) cache_addb(prefix);
+ cache_addw(op+((modreg+1)<<8));
+ cache_addd((Bit32u)(((Bit64u)diff)&0xffffffffLL));
+
+ switch(off) {
+ case 1: cache_addb(((Bit8u)imm&0xff)); break;
+ case 2: cache_addw(((Bit16u)imm&0xffff)); break;
+ case 4: cache_addd(((Bit32u)imm&0xffffffff)); break;
+ }
+
+ } else if ((Bit64u)data<0x100000000LL) {
+ if(prefix) cache_addb(prefix);
+ cache_addw(op+(modreg<<8));
+ cache_addb(0x25);
+ cache_addd((Bit32u)(((Bit64u)data)&0xffffffffLL));
+
+ switch(off) {
+ case 1: cache_addb(((Bit8u)imm&0xff)); break;
+ case 2: cache_addw(((Bit16u)imm&0xffff)); break;
+ case 4: cache_addd(((Bit32u)imm&0xffffffff)); break;
+ }
+
+ } else {
+ HostReg tmp_reg = HOST_EAX;
+
+ cache_addb(0x50+tmp_reg); // push rax
+ gen_mov_reg_qword(tmp_reg,(Bit64u)data);
+
+ if(prefix) cache_addb(prefix);
+ cache_addw(op+((modreg-4+tmp_reg)<<8));
+
+ switch(off) {
+ case 1: cache_addb(((Bit8u)imm&0xff)); break;
+ case 2: cache_addw(((Bit16u)imm&0xffff)); break;
+ case 4: cache_addd(((Bit32u)imm&0xffffffff)); break;
+ }
+
+ cache_addb(0x58+tmp_reg); // pop rax
+ }
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword,Bit8u prefix=0) {
+ if (!dword) gen_reg_memaddr(dest_reg,data,0xb7,0x0f); // movzx reg,[data] - zero extend data, fixes LLVM compile where the called function does not extend the parameters
+ else gen_reg_memaddr(dest_reg,data,0x8b,prefix); // mov reg,[data]
+}
+
+// move a 16bit constant value into dest_reg
+// the upper 16bit of the destination register may be destroyed
+static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) {
+ cache_addb(0xb8+dest_reg); // mov reg,imm
+ cache_addd((Bit32u)imm);
+}
+
+// move a 32bit constant value into dest_reg
+static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) {
+ cache_addb(0xb8+dest_reg); // mov reg,imm
+ cache_addd(imm);
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into memory
+static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword,Bit8u prefix=0) {
+ gen_reg_memaddr(src_reg,dest,0x89,(dword?prefix:0x66)); // mov [data],reg
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) {
+ gen_reg_memaddr(dest_reg,data,0xb6,0x0f); // movzx reg,[data]
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) {
+ gen_reg_memaddr(dest_reg,data,0xb6,0x0f); // movzx reg,[data]
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) {
+ cache_addb(0xb8+dest_reg); // mov reg,imm
+ cache_addd((Bit32u)imm);
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) {
+ cache_addb(0xb8+dest_reg); // mov reg,imm
+ cache_addd((Bit32u)imm);
+}
+
+// move the lowest 8bit of a register into memory
+static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) {
+ gen_reg_memaddr(src_reg,dest,0x88); // mov byte [data],reg
+}
+
+
+
+// convert an 8bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_byte(bool sign,HostReg reg) {
+ cache_addw(0xb60f+(sign?0x800:0)); // movsx/movzx
+ cache_addb(0xc0+(reg<<3)+reg);
+}
+
+// convert a 16bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_word(bool sign,HostReg reg) {
+ cache_addw(0xb70f+(sign?0x800:0)); // movsx/movzx
+ cache_addb(0xc0+(reg<<3)+reg);
+}
+
+
+
+// add a 32bit value from memory to a full register
+static void gen_add(HostReg reg,void* op) {
+ gen_reg_memaddr(reg,op,0x03); // add reg,[data]
+}
+
+// add a 32bit constant value to a full register
+static void gen_add_imm(HostReg reg,Bit32u imm) {
+ cache_addw(0xc081+(reg<<8)); // add reg,imm
+ cache_addd(imm);
+}
+
+// and a 32bit constant value with a full register
+static void gen_and_imm(HostReg reg,Bit32u imm) {
+ cache_addw(0xe081+(reg<<8)); // and reg,imm
+ cache_addd(imm);
+}
+
+
+
+// move a 32bit constant value into memory
+static void gen_mov_direct_dword(void* dest,Bit32u imm) {
+ gen_memaddr(0x4,dest,4,imm,0xc7); // mov [data],imm
+}
+
+
+// move an address into memory
+static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) {
+ gen_mov_reg_qword(HOST_EAX,imm);
+ gen_mov_word_from_reg(HOST_EAX,dest,true,0x48); // 0x48 prefixes full 64-bit mov
+}
+
+
+// add an 8bit constant value to a memory value
+static void gen_add_direct_byte(void* dest,Bit8s imm) {
+ gen_memaddr(0x4,dest,1,imm,0x83); // add [data],imm
+}
+
+// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value
+static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) {
+ if ((imm<128) && dword) {
+ gen_add_direct_byte(dest,(Bit8s)imm);
+ return;
+ }
+ gen_memaddr(0x4,dest,(dword?4:2),imm,0x81,(dword?0:0x66)); // add [data],imm
+}
+
+// subtract an 8bit constant value from a memory value
+static void gen_sub_direct_byte(void* dest,Bit8s imm) {
+ gen_memaddr(0x2c,dest,1,imm,0x83);
+}
+
+// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value
+static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) {
+ if ((imm<128) && dword) {
+ gen_sub_direct_byte(dest,(Bit8s)imm);
+ return;
+ }
+ gen_memaddr(0x2c,dest,(dword?4:2),imm,0x81,(dword?0:0x66)); // sub [data],imm
+}
+
+
+
+// effective address calculation, destination is dest_reg
+// scale_reg is scaled by scale (scale_reg*(2^scale)) and
+// added to dest_reg, then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) {
+ Bit8u rm_base;
+ Bitu imm_size;
+ if (!imm) {
+ imm_size=0; rm_base=0x0; //no imm
+ } else if ((imm>=-128 && imm<=127)) {
+ imm_size=1; rm_base=0x40; //Signed byte imm
+ } else {
+ imm_size=4; rm_base=0x80; //Signed dword imm
+ }
+
+ // ea_reg := ea_reg+scale_reg*(2^scale)+imm
+ cache_addb(0x48);
+ cache_addb(0x8d); //LEA
+ cache_addb(0x04+(dest_reg << 3)+rm_base); //The sib indicator
+ cache_addb(dest_reg+(scale_reg<<3)+(scale<<6));
+
+ switch (imm_size) {
+ case 0: break;
+ case 1:cache_addb(imm);break;
+ case 4:cache_addd(imm);break;
+ }
+}
+
+// effective address calculation, destination is dest_reg
+// dest_reg is scaled by scale (dest_reg*(2^scale)),
+// then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) {
+ // ea_reg := ea_reg*(2^scale)+imm
+ // ea_reg := op2 *(2^scale)+imm
+ cache_addb(0x48);
+ cache_addb(0x8d); //LEA
+ cache_addb(0x04+(dest_reg<<3));
+ cache_addb(0x05+(dest_reg<<3)+(scale<<6));
+
+ cache_addd(imm); // always add dword immediate
+}
+
+
+
+// generate a call to a parameterless function
+static void INLINE gen_call_function_raw(void * func) {
+ cache_addb(0x48);
+ cache_addw(0xec83);
+ cache_addb(0x08); // sub rsp,0x08 (align stack to 16 byte boundary)
+
+ cache_addb(0x48);
+ cache_addb(0xb8); // mov reg,imm64
+ cache_addq((Bit64u)func);
+ cache_addw(0xd0ff);
+
+ cache_addb(0x48);
+ cache_addw(0xc483);
+ cache_addb(0x08); // add rsp,0x08 (reset alignment)
+}
+
+// generate a call to a function with paramcount parameters
+// note: the parameters are loaded in the architecture specific way
+// using the gen_load_param_ functions below
+static Bit64u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) {
+ // align the stack
+ cache_addb(0x48);
+ cache_addw(0xc48b); // mov rax,rsp
+
+ cache_addb(0x48);
+ cache_addw(0xec83); // sub rsp,0x08
+ cache_addb(0x08); // 0x08==return address pushed onto stack by call
+
+ cache_addb(0x48);
+ cache_addw(0xe483); // and esp,0xfffffffffffffff0
+ cache_addb(0xf0);
+
+ cache_addb(0x48);
+ cache_addw(0xc483); // add rsp,0x08
+ cache_addb(0x08);
+
+ // stack is 16 byte aligned now
+
+
+ cache_addb(0x50); // push rax (==old rsp)
+
+ // returned address relates to where the address is stored in gen_call_function_raw
+ Bit64u proc_addr=(Bit64u)cache.pos-4;
+
+ // Do the actual call to the procedure
+ cache_addb(0x48);
+ cache_addb(0xb8); // mov reg,imm64
+ cache_addq((Bit64u)func);
+
+ cache_addw(0xd0ff);
+
+ // restore stack
+ cache_addb(0x5c); // pop rsp
+
+ return proc_addr;
+}
+
+
+// load an immediate value as param'th function parameter
+static void INLINE gen_load_param_imm(Bitu imm,Bitu param) {
+ // move an immediate 32bit value into a 64bit param reg
+ switch (param) {
+ case 0: // mov param1,imm32
+ gen_mov_dword_to_reg_imm(FC_OP1,(Bit32u)imm);
+ break;
+ case 1: // mov param2,imm32
+ gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)imm);
+ break;
+#if defined (_MSC_VER)
+ case 2: // mov r8,imm32
+ cache_addw(0xb849);
+ cache_addq((Bit32u)imm);
+ break;
+ case 3: // mov r9,imm32
+ cache_addw(0xb949);
+ cache_addq((Bit32u)imm);
+ break;
+#else
+ case 2: // mov rdx,imm32
+ gen_mov_dword_to_reg_imm(HOST_EDX,(Bit32u)imm);
+ break;
+ case 3: // mov rcx,imm32
+ gen_mov_dword_to_reg_imm(HOST_ECX,(Bit32u)imm);
+ break;
+#endif
+ default:
+ E_Exit("I(mm) >4 params unsupported");
+ break;
+ }
+}
+
+// load an address as param'th function parameter
+static void INLINE gen_load_param_addr(DRC_PTR_SIZE_IM addr,Bitu param) {
+ // move an immediate 64bit value into a 64bit param reg
+ switch (param) {
+ case 0: // mov param1,addr64
+ gen_mov_reg_qword(FC_OP1,addr);
+ break;
+ case 1: // mov param2,addr64
+ gen_mov_reg_qword(FC_OP2,addr);
+ break;
+#if defined (_MSC_VER)
+ case 2: // mov r8,addr64
+ cache_addw(0xb849);
+ cache_addq(addr);
+ break;
+ case 3: // mov r9,addr64
+ cache_addw(0xb949);
+ cache_addq(addr);
+ break;
+#else
+ case 2: // mov rdx,addr64
+ gen_mov_reg_qword(HOST_EDX,addr);
+ break;
+ case 3: // mov rcx,addr64
+ gen_mov_reg_qword(HOST_ECX,addr);
+ break;
+#endif
+ default:
+ E_Exit("A(ddr) >4 params unsupported");
+ break;
+ }
+}
+
+// load a host-register as param'th function parameter
+static void INLINE gen_load_param_reg(Bitu reg,Bitu param) {
+ // move a register into a 64bit param reg, {inputregs}!={outputregs}
+ switch (param) {
+ case 0: // mov param1,reg&7
+ gen_mov_regs(FC_OP1,reg&7);
+ break;
+ case 1: // mov param2,reg&7
+ gen_mov_regs(FC_OP2,reg&7);
+ break;
+#if defined (_MSC_VER)
+ case 2: // mov r8,reg&7
+ cache_addb(0x49);
+ gen_mov_regs(0,reg&7);
+ break;
+ case 3: // mov r9,reg&7
+ cache_addb(0x49);
+ gen_mov_regs(1,reg&7);
+ break;
+#else
+ case 2: // mov rdx,reg&7
+ gen_mov_regs(HOST_EDX,reg&7);
+ break;
+ case 3: // mov rcx,reg&7
+ gen_mov_regs(HOST_ECX,reg&7);
+ break;
+#endif
+ default:
+ E_Exit("R(eg) >4 params unsupported");
+ break;
+ }
+}
+
+// load a value from memory as param'th function parameter
+static void INLINE gen_load_param_mem(Bitu mem,Bitu param) {
+ // move memory content into a 64bit param reg
+ switch (param) {
+ case 0: // mov param1,[mem]
+ gen_mov_word_to_reg(FC_OP1,(void*)mem,true);
+ break;
+ case 1: // mov param2,[mem]
+ gen_mov_word_to_reg(FC_OP2,(void*)mem,true);
+ break;
+#if defined (_MSC_VER)
+ case 2: // mov r8,[mem]
+ gen_mov_word_to_reg(0,(void*)mem,true,0x49); // 0x49, use x64 rX regs
+ break;
+ case 3: // mov r9,[mem]
+ gen_mov_word_to_reg(1,(void*)mem,true,0x49); // 0x49, use x64 rX regs
+ break;
+#else
+ case 2: // mov rdx,[mem]
+ gen_mov_word_to_reg(HOST_EDX,(void*)mem,true);
+ break;
+ case 3: // mov rcx,[mem]
+ gen_mov_word_to_reg(HOST_ECX,(void*)mem,true);
+ break;
+#endif
+ default:
+ E_Exit("R(eg) >4 params unsupported");
+ break;
+ }
+}
+
+
+
+// jump to an address pointed at by ptr, offset is in imm
+static void gen_jmp_ptr(void * ptr,Bits imm=0) {
+ cache_addw(0xa148); // mov rax,[data]
+ cache_addq((Bit64u)ptr);
+
+ cache_addb(0xff); // jmp [rax+imm]
+ if (!imm) {
+ cache_addb(0x20);
+ } else if ((imm>=-128 && imm<=127)) {
+ cache_addb(0x60);
+ cache_addb(imm);
+ } else {
+ cache_addb(0xa0);
+ cache_addd(imm);
+ }
+}
+
+
+// short conditional jump (+-127 bytes) if register is zero
+// the destination is set by gen_fill_branch() later
+static Bit64u gen_create_branch_on_zero(HostReg reg,bool dword) {
+ if (!dword) cache_addb(0x66);
+ cache_addb(0x0b); // or reg,reg
+ cache_addb(0xc0+reg+(reg<<3));
+
+ cache_addw(0x0074); // jz addr
+ return ((Bit64u)cache.pos-1);
+}
+
+// short conditional jump (+-127 bytes) if register is nonzero
+// the destination is set by gen_fill_branch() later
+static Bit64u gen_create_branch_on_nonzero(HostReg reg,bool dword) {
+ if (!dword) cache_addb(0x66);
+ cache_addb(0x0b); // or reg,reg
+ cache_addb(0xc0+reg+(reg<<3));
+
+ cache_addw(0x0075); // jnz addr
+ return ((Bit64u)cache.pos-1);
+}
+
+// calculate relative offset and fill it into the location pointed to by data
+static void gen_fill_branch(DRC_PTR_SIZE_IM data) {
+#if C_DEBUG
+ Bit64s len=(Bit64u)cache.pos-data;
+ if (len<0) len=-len;
+ if (len>126) LOG_MSG("Big jump %d",len);
+#endif
+ *(Bit8u*)data=(Bit8u)((Bit64u)cache.pos-data-1);
+}
+
+// conditional jump if register is nonzero
+// for isdword==true the 32bit of the register are tested
+// for isdword==false the lowest 8bit of the register are tested
+static Bit64u gen_create_branch_long_nonzero(HostReg reg,bool isdword) {
+ // isdword: cmp reg32,0
+ // not isdword: cmp reg8,0
+ cache_addb(0x0a+(isdword?1:0)); // or reg,reg
+ cache_addb(0xc0+reg+(reg<<3));
+
+ cache_addw(0x850f); // jnz
+ cache_addd(0);
+ return ((Bit64u)cache.pos-4);
+}
+
+// compare 32bit-register against zero and jump if value less/equal than zero
+static Bit64u gen_create_branch_long_leqzero(HostReg reg) {
+ cache_addw(0xf883+(reg<<8));
+ cache_addb(0x00); // cmp reg,0
+
+ cache_addw(0x8e0f); // jle
+ cache_addd(0);
+ return ((Bit64u)cache.pos-4);
+}
+
+// calculate long relative offset and fill it into the location pointed to by data
+static void gen_fill_branch_long(Bit64u data) {
+ *(Bit32u*)data=(Bit32u)((Bit64u)cache.pos-data-4);
+}
+
+
+static void gen_run_code(void) {
+ cache_addb(0x53); // push rbx
+ cache_addw(0xd0ff+(FC_OP1<<8)); // call rdi
+ cache_addb(0x5b); // pop rbx
+}
+
+// return from a function
+static void gen_return_function(void) {
+ cache_addb(0xc3); // ret
+}
+
+#ifdef DRC_FLAGS_INVALIDATION
+// called when a call to a function can be replaced by a
+// call to a simpler function
+// check gen_call_function_raw and gen_call_function_setup
+// for the targeted code
+static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) {
+#ifdef DRC_FLAGS_INVALIDATION_DCODE
+ // try to avoid function calls but rather directly fill in code
+ switch (flags_type) {
+ case t_ADDb:
+ case t_ADDw:
+ case t_ADDd:
+ *(Bit32u*)(pos+0)=0xf001f889; // mov eax,edi; add eax,esi
+ *(Bit32u*)(pos+4)=0x90900eeb; // skip
+ *(Bit32u*)(pos+8)=0x90909090;
+ *(Bit32u*)(pos+12)=0x90909090;
+ *(Bit32u*)(pos+16)=0x90909090;
+ break;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ *(Bit32u*)(pos+0)=0xf009f889; // mov eax,edi; or eax,esi
+ *(Bit32u*)(pos+4)=0x90900eeb; // skip
+ *(Bit32u*)(pos+8)=0x90909090;
+ *(Bit32u*)(pos+12)=0x90909090;
+ *(Bit32u*)(pos+16)=0x90909090;
+ break;
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ *(Bit32u*)(pos+0)=0xf021f889; // mov eax,edi; and eax,esi
+ *(Bit32u*)(pos+4)=0x90900eeb; // skip
+ *(Bit32u*)(pos+8)=0x90909090;
+ *(Bit32u*)(pos+12)=0x90909090;
+ *(Bit32u*)(pos+16)=0x90909090;
+ break;
+ case t_SUBb:
+ case t_SUBw:
+ case t_SUBd:
+ *(Bit32u*)(pos+0)=0xf029f889; // mov eax,edi; sub eax,esi
+ *(Bit32u*)(pos+4)=0x90900eeb; // skip
+ *(Bit32u*)(pos+8)=0x90909090;
+ *(Bit32u*)(pos+12)=0x90909090;
+ *(Bit32u*)(pos+16)=0x90909090;
+ break;
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ *(Bit32u*)(pos+0)=0xf031f889; // mov eax,edi; xor eax,esi
+ *(Bit32u*)(pos+4)=0x90900eeb; // skip
+ *(Bit32u*)(pos+8)=0x90909090;
+ *(Bit32u*)(pos+12)=0x90909090;
+ *(Bit32u*)(pos+16)=0x90909090;
+ break;
+ case t_CMPb:
+ case t_CMPw:
+ case t_CMPd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ *(Bit32u*)(pos+0)=0x909012eb; // skip
+ *(Bit32u*)(pos+4)=0x90909090;
+ *(Bit32u*)(pos+8)=0x90909090;
+ *(Bit32u*)(pos+12)=0x90909090;
+ *(Bit32u*)(pos+16)=0x90909090;
+ break;
+ case t_INCb:
+ case t_INCw:
+ case t_INCd:
+ *(Bit32u*)(pos+0)=0xc0fff889; // mov eax,edi; inc eax
+ *(Bit32u*)(pos+4)=0x90900eeb; // skip
+ *(Bit32u*)(pos+8)=0x90909090;
+ *(Bit32u*)(pos+12)=0x90909090;
+ *(Bit32u*)(pos+16)=0x90909090;
+ break;
+ case t_DECb:
+ case t_DECw:
+ case t_DECd:
+ *(Bit32u*)(pos+0)=0xc8fff889; // mov eax,edi; dec eax
+ *(Bit32u*)(pos+4)=0x90900eeb; // skip
+ *(Bit32u*)(pos+8)=0x90909090;
+ *(Bit32u*)(pos+12)=0x90909090;
+ *(Bit32u*)(pos+16)=0x90909090;
+ break;
+ case t_NEGb:
+ case t_NEGw:
+ case t_NEGd:
+ *(Bit32u*)(pos+0)=0xd8f7f889; // mov eax,edi; neg eax
+ *(Bit32u*)(pos+4)=0x90900eeb; // skip
+ *(Bit32u*)(pos+8)=0x90909090;
+ *(Bit32u*)(pos+12)=0x90909090;
+ *(Bit32u*)(pos+16)=0x90909090;
+ break;
+ default:
+ *(Bit64u*)(pos+6)=(Bit64u)fct_ptr; // fill function pointer
+ break;
+ }
+#else
+ *(Bit64u*)(pos+6)=(Bit64u)fct_ptr; // fill function pointer
+#endif
+}
+#endif
+
+static void cache_block_closing(Bit8u* block_start,Bitu block_size) { }
+
+static void cache_block_before_close(void) { }
--- /dev/null
+/*
+ * 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.
+ */
+
+
+
+// some configuring defines that specify the capabilities of this architecture
+// or aspects of the recompiling
+
+// protect FC_ADDR over function calls if necessaray
+// #define DRC_PROTECT_ADDR_REG
+
+// try to use non-flags generating functions if possible
+#define DRC_FLAGS_INVALIDATION
+// try to replace _simple functions by code
+#define DRC_FLAGS_INVALIDATION_DCODE
+
+// type with the same size as a pointer
+#define DRC_PTR_SIZE_IM Bit32u
+
+// calling convention modifier
+#if defined (WIN32)
+#define DRC_CALL_CONV _fastcall
+#define DRC_FC /* nothing */
+#else
+#define DRC_CALL_CONV /* nothing */
+#define DRC_FC GCC_ATTRIBUTE(fastcall)
+#endif
+
+
+// register mapping
+enum HostReg {
+ HOST_EAX=0,
+ HOST_ECX,
+ HOST_EDX,
+ HOST_EBX,
+ HOST_ESP,
+ HOST_EBP,
+ HOST_ESI,
+ HOST_EDI
+};
+
+
+// register that holds function return values
+#define FC_RETOP HOST_EAX
+
+// register used for address calculations, if the ABI does not
+// state that this register is preserved across function calls
+// then define DRC_PROTECT_ADDR_REG above
+#define FC_ADDR HOST_EBX
+
+// register that holds the first parameter
+#define FC_OP1 HOST_ECX
+
+// register that holds the second parameter
+#define FC_OP2 HOST_EDX
+
+// special register that holds the third parameter for _R3 calls (byte accessible)
+#define FC_OP3 HOST_EAX
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA1 HOST_ECX
+
+// register that holds byte-accessible temporary values
+#define FC_TMP_BA2 HOST_EDX
+
+
+// temporary register for LEA
+#define TEMP_REG_DRC HOST_ESI
+
+
+// move a full register from reg_src to reg_dst
+static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) {
+ cache_addb(0x8b); // mov reg_dst,reg_src
+ cache_addb(0xc0+(reg_dst<<3)+reg_src);
+}
+
+// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg
+// 16bit moves may destroy the upper 16bit of the destination register
+static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) {
+ if (!dword) cache_addb(0x66);
+ cache_addw(0x058b+(dest_reg<<11)); // mov reg,[data]
+ cache_addd((Bit32u)data);
+}
+
+// move a 16bit constant value into dest_reg
+// the upper 16bit of the destination register may be destroyed
+static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) {
+ cache_addb(0x66);
+ cache_addb(0xb8+dest_reg); // mov reg,imm
+ cache_addw(imm);
+}
+
+// move a 32bit constant value into dest_reg
+static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) {
+ cache_addb(0xb8+dest_reg); // mov reg,imm
+ cache_addd(imm);
+}
+
+// move 32bit (dword==true) or 16bit (dword==false) of a register into memory
+static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) {
+ if (!dword) cache_addb(0x66);
+ cache_addw(0x0589+(src_reg<<11)); // mov [data],reg
+ cache_addd((Bit32u)dest);
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) {
+ cache_addw(0x058a+(dest_reg<<11)); // mov reg,[data]
+ cache_addd((Bit32u)data);
+}
+
+// move an 8bit value from memory into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) {
+ cache_addb(0x66);
+ cache_addw(0x058b+(dest_reg<<11)); // mov reg,[data]
+ cache_addd((Bit32u)data);
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function does not use FC_OP1/FC_OP2 as dest_reg as these
+// registers might not be directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) {
+ cache_addb(0xb0+dest_reg); // mov reg,imm
+ cache_addb(imm);
+}
+
+// move an 8bit constant value into dest_reg
+// the upper 24bit of the destination register can be destroyed
+// this function can use FC_OP1/FC_OP2 as dest_reg which are
+// not directly byte-accessible on some architectures
+static void gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) {
+ cache_addb(0x66);
+ cache_addb(0xb8+dest_reg); // mov reg,imm
+ cache_addw(imm);
+}
+
+// move the lowest 8bit of a register into memory
+static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) {
+ cache_addw(0x0588+(src_reg<<11)); // mov [data],reg
+ cache_addd((Bit32u)dest);
+}
+
+
+
+// convert an 8bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_byte(bool sign,HostReg reg) {
+ cache_addw(0xb60f+(sign?0x800:0)); // movsx/movzx
+ cache_addb(0xc0+(reg<<3)+reg);
+}
+
+// convert a 16bit word to a 32bit dword
+// the register is zero-extended (sign==false) or sign-extended (sign==true)
+static void gen_extend_word(bool sign,HostReg reg) {
+ cache_addw(0xb70f+(sign?0x800:0)); // movsx/movzx
+ cache_addb(0xc0+(reg<<3)+reg);
+}
+
+
+
+// add a 32bit value from memory to a full register
+static void gen_add(HostReg reg,void* op) {
+ cache_addw(0x0503+(reg<<11)); // add reg,[data]
+ cache_addd((Bit32u)op);
+}
+
+// add a 32bit constant value to a full register
+static void gen_add_imm(HostReg reg,Bit32u imm) {
+ cache_addw(0xc081+(reg<<8)); // add reg,imm
+ cache_addd(imm);
+}
+
+// and a 32bit constant value with a full register
+static void gen_and_imm(HostReg reg,Bit32u imm) {
+ cache_addw(0xe081+(reg<<8)); // and reg,imm
+ cache_addd(imm);
+}
+
+
+
+// move a 32bit constant value into memory
+static void gen_mov_direct_dword(void* dest,Bit32u imm) {
+ cache_addw(0x05c7); // mov [data],imm
+ cache_addd((Bit32u)dest);
+ cache_addd(imm);
+}
+
+// move an address into memory
+static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) {
+ gen_mov_direct_dword(dest,(Bit32u)imm);
+}
+
+
+// add an 8bit constant value to a memory value
+static void gen_add_direct_byte(void* dest,Bit8s imm) {
+ cache_addw(0x0583); // add [data],imm
+ cache_addd((Bit32u)dest);
+ cache_addb(imm);
+}
+
+// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value
+static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) {
+ if ((imm<128) && dword) {
+ gen_add_direct_byte(dest,(Bit8s)imm);
+ return;
+ }
+ if (!dword) cache_addb(0x66);
+ cache_addw(0x0581); // add [data],imm
+ cache_addd((Bit32u)dest);
+ if (dword) cache_addd((Bit32u)imm);
+ else cache_addw((Bit16u)imm);
+}
+
+// subtract an 8bit constant value from a memory value
+static void gen_sub_direct_byte(void* dest,Bit8s imm) {
+ cache_addw(0x2d83); // sub [data],imm
+ cache_addd((Bit32u)dest);
+ cache_addb(imm);
+}
+
+// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value
+static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) {
+ if ((imm<128) && dword) {
+ gen_sub_direct_byte(dest,(Bit8s)imm);
+ return;
+ }
+ if (!dword) cache_addb(0x66);
+ cache_addw(0x2d81); // sub [data],imm
+ cache_addd((Bit32u)dest);
+ if (dword) cache_addd((Bit32u)imm);
+ else cache_addw((Bit16u)imm);
+}
+
+
+
+// effective address calculation, destination is dest_reg
+// scale_reg is scaled by scale (scale_reg*(2^scale)) and
+// added to dest_reg, then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) {
+ Bit8u rm_base;
+ Bitu imm_size;
+ if (!imm) {
+ imm_size=0; rm_base=0x0; //no imm
+ } else if ((imm>=-128 && imm<=127)) {
+ imm_size=1; rm_base=0x40; //Signed byte imm
+ } else {
+ imm_size=4; rm_base=0x80; //Signed dword imm
+ }
+
+ // ea_reg := ea_reg+scale_reg*(2^scale)+imm
+ cache_addb(0x8d); //LEA
+ cache_addb(0x04+(dest_reg << 3)+rm_base); //The sib indicator
+ cache_addb(dest_reg+(scale_reg<<3)+(scale<<6));
+
+ switch (imm_size) {
+ case 0: break;
+ case 1:cache_addb(imm);break;
+ case 4:cache_addd(imm);break;
+ }
+}
+
+// effective address calculation, destination is dest_reg
+// dest_reg is scaled by scale (dest_reg*(2^scale)),
+// then the immediate value is added
+static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) {
+ // ea_reg := ea_reg*(2^scale)+imm
+ // ea_reg := op2 *(2^scale)+imm
+ cache_addb(0x8d); //LEA
+ cache_addb(0x04+(dest_reg<<3));
+ cache_addb(0x05+(dest_reg<<3)+(scale<<6));
+
+ cache_addd(imm); // always add dword immediate
+}
+
+
+
+// generate a call to a parameterless function
+static void INLINE gen_call_function_raw(void * func) {
+ cache_addb(0xe8);
+ cache_addd((Bit32u)func - (Bit32u)cache.pos-4);
+}
+
+// generate a call to a function with paramcount parameters
+// note: the parameters are loaded in the architecture specific way
+// using the gen_load_param_ functions below
+static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) {
+ Bit32u proc_addr=(Bit32u)cache.pos;
+ // Do the actual call to the procedure
+ cache_addb(0xe8);
+ cache_addd((Bit32u)func - (Bit32u)cache.pos-4);
+
+ // Restore the params of the stack
+ if (paramcount) {
+ cache_addw(0xc483); //add ESP,imm byte
+ cache_addb((!fastcall)?paramcount*4:0);
+ }
+ return proc_addr;
+}
+
+
+// load an immediate value as param'th function parameter
+static void INLINE gen_load_param_imm(Bitu imm,Bitu param) {
+ cache_addb(0x68); // push immediate
+ cache_addd(imm);
+}
+
+// load an address as param'th function parameter
+static void INLINE gen_load_param_addr(Bitu addr,Bitu param) {
+ cache_addb(0x68); // push immediate (address)
+ cache_addd(addr);
+}
+
+// load a host-register as param'th function parameter
+static void INLINE gen_load_param_reg(Bitu reg,Bitu param) {
+ cache_addb(0x50+(reg&7)); // push reg
+}
+
+// load a value from memory as param'th function parameter
+static void INLINE gen_load_param_mem(Bitu mem,Bitu param) {
+ cache_addw(0x35ff); // push []
+ cache_addd(mem);
+}
+
+
+
+// jump to an address pointed at by ptr, offset is in imm
+static void gen_jmp_ptr(void * ptr,Bits imm=0) {
+ gen_mov_word_to_reg(HOST_EAX,ptr,true);
+ cache_addb(0xff); // jmp [eax+imm]
+ if (!imm) {
+ cache_addb(0x20);
+ } else if ((imm>=-128 && imm<=127)) {
+ cache_addb(0x60);
+ cache_addb(imm);
+ } else {
+ cache_addb(0xa0);
+ cache_addd(imm);
+ }
+}
+
+
+// short conditional jump (+-127 bytes) if register is zero
+// the destination is set by gen_fill_branch() later
+static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) {
+ if (!dword) cache_addb(0x66);
+ cache_addb(0x0b); // or reg,reg
+ cache_addb(0xc0+reg+(reg<<3));
+
+ cache_addw(0x0074); // jz addr
+ return ((Bit32u)cache.pos-1);
+}
+
+// short conditional jump (+-127 bytes) if register is nonzero
+// the destination is set by gen_fill_branch() later
+static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) {
+ if (!dword) cache_addb(0x66);
+ cache_addb(0x0b); // or reg,reg
+ cache_addb(0xc0+reg+(reg<<3));
+
+ cache_addw(0x0075); // jnz addr
+ return ((Bit32u)cache.pos-1);
+}
+
+// calculate relative offset and fill it into the location pointed to by data
+static void gen_fill_branch(DRC_PTR_SIZE_IM data) {
+#if C_DEBUG
+ Bits len=(Bit32u)cache.pos-data;
+ if (len<0) len=-len;
+ if (len>126) LOG_MSG("Big jump %d",len);
+#endif
+ *(Bit8u*)data=(Bit8u)((Bit32u)cache.pos-data-1);
+}
+
+// conditional jump if register is nonzero
+// for isdword==true the 32bit of the register are tested
+// for isdword==false the lowest 8bit of the register are tested
+static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) {
+ // isdword: cmp reg32,0
+ // not isdword: cmp reg8,0
+ cache_addb(0x0a+(isdword?1:0)); // or reg,reg
+ cache_addb(0xc0+reg+(reg<<3));
+
+ cache_addw(0x850f); // jnz
+ cache_addd(0);
+ return ((Bit32u)cache.pos-4);
+}
+
+// compare 32bit-register against zero and jump if value less/equal than zero
+static Bit32u gen_create_branch_long_leqzero(HostReg reg) {
+ cache_addw(0xf883+(reg<<8));
+ cache_addb(0x00); // cmp reg,0
+
+ cache_addw(0x8e0f); // jle
+ cache_addd(0);
+ return ((Bit32u)cache.pos-4);
+}
+
+// calculate long relative offset and fill it into the location pointed to by data
+static void gen_fill_branch_long(Bit32u data) {
+ *(Bit32u*)data=((Bit32u)cache.pos-data-4);
+}
+
+
+static void gen_run_code(void) {
+ cache_addd(0x0424448b); // mov eax,[esp+4]
+ cache_addb(0x53); // push ebx
+ cache_addb(0x56); // push esi
+ cache_addw(0xd0ff); // call eax
+ cache_addb(0x5e); // pop esi
+ cache_addb(0x5b); // pop ebx
+}
+
+// return from a function
+static void gen_return_function(void) {
+ cache_addb(0xc3); // ret
+}
+
+#ifdef DRC_FLAGS_INVALIDATION
+// called when a call to a function can be replaced by a
+// call to a simpler function
+static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) {
+#ifdef DRC_FLAGS_INVALIDATION_DCODE
+ // try to avoid function calls but rather directly fill in code
+ switch (flags_type) {
+ case t_ADDb:
+ case t_ADDw:
+ case t_ADDd:
+ *(Bit32u*)pos=0xc203c18b; // mov eax,ecx; add eax,edx
+ *(pos+4)=0x90;
+ break;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ *(Bit32u*)pos=0xc20bc18b; // mov eax,ecx; or eax,edx
+ *(pos+4)=0x90;
+ break;
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ *(Bit32u*)pos=0xc223c18b; // mov eax,ecx; and eax,edx
+ *(pos+4)=0x90;
+ break;
+ case t_SUBb:
+ case t_SUBw:
+ case t_SUBd:
+ *(Bit32u*)pos=0xc22bc18b; // mov eax,ecx; sub eax,edx
+ *(pos+4)=0x90;
+ break;
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ *(Bit32u*)pos=0xc233c18b; // mov eax,ecx; xor eax,edx
+ *(pos+4)=0x90;
+ break;
+ case t_CMPb:
+ case t_CMPw:
+ case t_CMPd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ *(Bit32u*)pos=0x909003eb; // skip
+ *(pos+4)=0x90;
+ break;
+ case t_INCb:
+ case t_INCw:
+ case t_INCd:
+ *(Bit32u*)pos=0x9040c18b; // mov eax,ecx; inc eax
+ *(pos+4)=0x90;
+ break;
+ case t_DECb:
+ case t_DECw:
+ case t_DECd:
+ *(Bit32u*)pos=0x9048c18b; // mov eax,ecx; dec eax
+ *(pos+4)=0x90;
+ break;
+ case t_NEGb:
+ case t_NEGw:
+ case t_NEGd:
+ *(Bit32u*)pos=0xd8f7c18b; // mov eax,ecx; neg eax
+ *(pos+4)=0x90;
+ break;
+ default:
+ *(Bit32u*)(pos+1)=(Bit32u)((Bit8u*)fct_ptr - (pos+1+4)); // fill function pointer
+ break;
+ }
+#else
+ *(Bit32u*)(pos+1)=(Bit32u)((Bit8u*)fct_ptr - (pos+1+4)); // fill function pointer
+#endif
+}
+#endif
+
+static void cache_block_closing(Bit8u* block_start,Bitu block_size) { }
+
+static void cache_block_before_close(void) { }
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "dosbox.h"
+
+#include "pic.h"
+#include "regs.h"
+#include "cpu.h"
+#include "lazyflags.h"
+#include "paging.h"
+#include "fpu.h"
+#include "debug.h"
+#include "inout.h"
+#include "callback.h"
+
+
+typedef PhysPt EAPoint;
+#define SegBase(c) SegPhys(c)
+
+#define LoadMb(off) mem_readb_inline(off)
+#define LoadMw(off) mem_readw_inline(off)
+#define LoadMd(off) mem_readd_inline(off)
+
+#define LoadMbs(off) (Bit8s)(LoadMb(off))
+#define LoadMws(off) (Bit16s)(LoadMw(off))
+#define LoadMds(off) (Bit32s)(LoadMd(off))
+
+#define SaveMb(off,val) mem_writeb_inline(off,val)
+#define SaveMw(off,val) mem_writew_inline(off,val)
+#define SaveMd(off,val) mem_writed_inline(off,val)
+
+#define LoadD(reg) reg
+#define SaveD(reg,val) reg=val
+
+
+
+#include "core_full/loadwrite.h"
+#include "core_full/support.h"
+#include "core_full/optable.h"
+#include "instructions.h"
+
+#define EXCEPTION(blah) \
+ { \
+ Bit8u new_num=blah; \
+ CPU_Exception(new_num,0); \
+ continue; \
+ }
+
+Bits CPU_Core_Full_Run(void) {
+ FullData inst;
+ while (CPU_Cycles-->0) {
+#if C_DEBUG
+ cycle_count++;
+#if C_HEAVY_DEBUG
+ if (DEBUG_HeavyIsBreakpoint()) {
+ FillFlags();
+ return debugCallback;
+ };
+#endif
+#endif
+ LoadIP();
+ inst.entry=cpu.code.big*0x200;
+ inst.prefix=cpu.code.big;
+restartopcode:
+ inst.entry=(inst.entry & 0xffffff00) | Fetchb();
+ inst.code=OpCodeTable[inst.entry];
+ #include "core_full/load.h"
+ #include "core_full/op.h"
+ #include "core_full/save.h"
+nextopcode:;
+ SaveIP();
+ continue;
+illegalopcode:
+ LOG(LOG_CPU,LOG_NORMAL)("Illegal opcode");
+ CPU_Exception(0x6,0);
+ }
+ FillFlags();
+ return CBRET_NONE;
+}
+
+
+void CPU_Core_Full_Init(void) {
+
+}
--- /dev/null
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# src/cpu/core_full/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/dosbox
+pkgincludedir = $(includedir)/dosbox
+pkglibdir = $(libdir)/dosbox
+pkglibexecdir = $(libexecdir)/dosbox
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = src/cpu/core_full
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = aclocal-1.16
+ALSA_CFLAGS =
+ALSA_LIBS = -lasound -lm -ldl -lpthread
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+AUTOCONF = autoconf
+AUTOHEADER = autoheader
+AUTOMAKE = automake-1.16
+AWK = gawk
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS = -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
+CXX = g++
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+ECHO_C =
+ECHO_N = -n
+ECHO_T =
+EGREP = /bin/grep -E
+EXEEXT =
+GREP = /bin/grep
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LDFLAGS =
+LIBOBJS =
+LIBS = -lasound -lm -ldl -lpthread -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL -lXfont2 -lXi -lpng -lz -lX11 -lGL
+LTLIBOBJS =
+MAKEINFO = makeinfo
+MKDIR_P = /bin/mkdir -p
+OBJEXT = o
+PACKAGE = dosbox
+PACKAGE_BUGREPORT =
+PACKAGE_NAME = dosbox
+PACKAGE_STRING = dosbox 0.74
+PACKAGE_TARNAME = dosbox
+PACKAGE_URL =
+PACKAGE_VERSION = 0.74
+PATH_SEPARATOR = :
+RANLIB = ranlib
+SDL_CFLAGS = -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
+SDL_CONFIG = /usr/local/bin/sdl-config
+SDL_LIBS = -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL -lXfont2 -lXi -lpthread
+SET_MAKE =
+SHELL = /bin/bash
+STRIP =
+VERSION = 0.74
+WINDRES = :
+abs_builddir = /home/whatisthis/src/DOSVAXJ3/src/cpu/core_full
+abs_srcdir = /home/whatisthis/src/DOSVAXJ3/src/cpu/core_full
+abs_top_builddir = /home/whatisthis/src/DOSVAXJ3
+abs_top_srcdir = /home/whatisthis/src/DOSVAXJ3
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = $${TAR-tar} chof - "$$tardir"
+am__untar = $${TAR-tar} xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias =
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = x86_64-pc-linux-gnu
+host_alias =
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/whatisthis/src/DOSVAXJ3/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+runstatedir = ${localstatedir}/run
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target_alias =
+top_build_prefix = ../../../
+top_builddir = ../../..
+top_srcdir = ../../..
+noinst_HEADERS = ea_lookup.h load.h loadwrite.h op.h optable.h save.h \
+ string.h support.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/cpu/core_full/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/cpu/core_full/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+
+noinst_HEADERS = ea_lookup.h load.h loadwrite.h op.h optable.h save.h \
+ string.h support.h
--- /dev/null
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/cpu/core_full
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WINDRES = @WINDRES@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = ea_lookup.h load.h loadwrite.h op.h optable.h save.h \
+ string.h support.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/cpu/core_full/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/cpu/core_full/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+/*
+ * 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.
+ */
+
+{
+ EAPoint seg_base;
+ Bit16u off;
+ switch ((inst.rm_mod<<3)|inst.rm_eai) {
+ case 0x00:
+ off=reg_bx+reg_si;
+ seg_base=SegBase(ds);
+ break;
+ case 0x01:
+ off=reg_bx+reg_di;
+ seg_base=SegBase(ds);
+ break;
+ case 0x02:
+ off=reg_bp+reg_si;
+ seg_base=SegBase(ss);
+ break;
+ case 0x03:
+ off=reg_bp+reg_di;
+ seg_base=SegBase(ss);
+ break;
+ case 0x04:
+ off=reg_si;
+ seg_base=SegBase(ds);
+ break;
+ case 0x05:
+ off=reg_di;
+ seg_base=SegBase(ds);
+ break;
+ case 0x06:
+ off=Fetchw();
+ seg_base=SegBase(ds);
+ break;
+ case 0x07:
+ off=reg_bx;
+ seg_base=SegBase(ds);
+ break;
+
+ case 0x08:
+ off=reg_bx+reg_si+Fetchbs();
+ seg_base=SegBase(ds);
+ break;
+ case 0x09:
+ off=reg_bx+reg_di+Fetchbs();
+ seg_base=SegBase(ds);
+ break;
+ case 0x0a:
+ off=reg_bp+reg_si+Fetchbs();
+ seg_base=SegBase(ss);
+ break;
+ case 0x0b:
+ off=reg_bp+reg_di+Fetchbs();
+ seg_base=SegBase(ss);
+ break;
+ case 0x0c:
+ off=reg_si+Fetchbs();
+ seg_base=SegBase(ds);
+ break;
+ case 0x0d:
+ off=reg_di+Fetchbs();
+ seg_base=SegBase(ds);
+ break;
+ case 0x0e:
+ off=reg_bp+Fetchbs();
+ seg_base=SegBase(ss);
+ break;
+ case 0x0f:
+ off=reg_bx+Fetchbs();
+ seg_base=SegBase(ds);
+ break;
+
+ case 0x10:
+ off=reg_bx+reg_si+Fetchws();
+ seg_base=SegBase(ds);
+ break;
+ case 0x11:
+ off=reg_bx+reg_di+Fetchws();
+ seg_base=SegBase(ds);
+ break;
+ case 0x12:
+ off=reg_bp+reg_si+Fetchws();
+ seg_base=SegBase(ss);
+ break;
+ case 0x13:
+ off=reg_bp+reg_di+Fetchws();
+ seg_base=SegBase(ss);
+ break;
+ case 0x14:
+ off=reg_si+Fetchws();
+ seg_base=SegBase(ds);
+ break;
+ case 0x15:
+ off=reg_di+Fetchws();
+ seg_base=SegBase(ds);
+ break;
+ case 0x16:
+ off=reg_bp+Fetchws();
+ seg_base=SegBase(ss);
+ break;
+ case 0x17:
+ off=reg_bx+Fetchws();
+ seg_base=SegBase(ds);
+ break;
+ }
+ inst.rm_off=off;
+ if (inst.prefix & PREFIX_SEG) {
+ inst.rm_eaa=inst.seg.base+off;
+ } else {
+ inst.rm_eaa=seg_base+off;
+ }
+} else {
+
+
+#define SIB(MODE) { \
+ Bitu sib=Fetchb(); \
+ switch (sib&7) { \
+ case 0:seg_base=SegBase(ds);off=reg_eax;break; \
+ case 1:seg_base=SegBase(ds);off=reg_ecx;break; \
+ case 2:seg_base=SegBase(ds);off=reg_edx;break; \
+ case 3:seg_base=SegBase(ds);off=reg_ebx;break; \
+ case 4:seg_base=SegBase(ss);off=reg_esp;break; \
+ case 5:if (!MODE) { seg_base=SegBase(ds);off=Fetchd();break; \
+ } else { seg_base=SegBase(ss);off=reg_ebp;break;} \
+ case 6:seg_base=SegBase(ds);off=reg_esi;break; \
+ case 7:seg_base=SegBase(ds);off=reg_edi;break; \
+ } \
+ off+=*SIBIndex[(sib >> 3) &7] << (sib >> 6); \
+};
+ static Bit32u SIBZero=0;
+ static Bit32u * SIBIndex[8]= { ®_eax,®_ecx,®_edx,®_ebx,&SIBZero,®_ebp,®_esi,®_edi };
+ EAPoint seg_base;
+ Bit32u off;
+ switch ((inst.rm_mod<<3)|inst.rm_eai) {
+ case 0x00:
+ off=reg_eax;
+ seg_base=SegBase(ds);
+ break;
+ case 0x01:
+ off=reg_ecx;
+ seg_base=SegBase(ds);
+ break;
+ case 0x02:
+ off=reg_edx;
+ seg_base=SegBase(ds);
+ break;
+ case 0x03:
+ off=reg_ebx;
+ seg_base=SegBase(ds);
+ break;
+ case 0x04:
+ SIB(0);
+ break;
+ case 0x05:
+ off=Fetchd();
+ seg_base=SegBase(ds);
+ break;
+ case 0x06:
+ off=reg_esi;
+ seg_base=SegBase(ds);
+ break;
+ case 0x07:
+ off=reg_edi;
+ seg_base=SegBase(ds);
+ break;
+
+ case 0x08:
+ off=reg_eax+Fetchbs();
+ seg_base=SegBase(ds);
+ break;
+ case 0x09:
+ off=reg_ecx+Fetchbs();
+ seg_base=SegBase(ds);
+ break;
+ case 0x0a:
+ off=reg_edx+Fetchbs();
+ seg_base=SegBase(ds);
+ break;
+ case 0x0b:
+ off=reg_ebx+Fetchbs();
+ seg_base=SegBase(ds);
+ break;
+ case 0x0c:
+ SIB(1);
+ off+=Fetchbs();
+ break;
+ case 0x0d:
+ off=reg_ebp+Fetchbs();
+ seg_base=SegBase(ss);
+ break;
+ case 0x0e:
+ off=reg_esi+Fetchbs();
+ seg_base=SegBase(ds);
+ break;
+ case 0x0f:
+ off=reg_edi+Fetchbs();
+ seg_base=SegBase(ds);
+ break;
+
+ case 0x10:
+ off=reg_eax+Fetchds();
+ seg_base=SegBase(ds);
+ break;
+ case 0x11:
+ off=reg_ecx+Fetchds();
+ seg_base=SegBase(ds);
+ break;
+ case 0x12:
+ off=reg_edx+Fetchds();
+ seg_base=SegBase(ds);
+ break;
+ case 0x13:
+ off=reg_ebx+Fetchds();
+ seg_base=SegBase(ds);
+ break;
+ case 0x14:
+ SIB(1);
+ off+=Fetchds();
+ break;
+ case 0x15:
+ off=reg_ebp+Fetchds();
+ seg_base=SegBase(ss);
+ break;
+ case 0x16:
+ off=reg_esi+Fetchds();
+ seg_base=SegBase(ds);
+ break;
+ case 0x17:
+ off=reg_edi+Fetchds();
+ seg_base=SegBase(ds);
+ break;
+ }
+ inst.rm_off=off;
+ if (inst.prefix & PREFIX_SEG) {
+ inst.rm_eaa=inst.seg.base+off;
+ } else {
+ inst.rm_eaa=seg_base+off;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+switch (inst.code.load) {
+/* General loading */
+ case L_POPwRM:
+ inst_op1_w = Pop_16();
+ goto case_L_MODRM;
+ case L_POPdRM:
+ inst_op1_d = Pop_32();
+ goto case_L_MODRM;
+ case L_MODRM_NVM:
+ if ((reg_flags & FLAG_VM) || !cpu.pmode) goto illegalopcode;
+ goto case_L_MODRM;
+case_L_MODRM:
+ case L_MODRM:
+ inst.rm=Fetchb();
+ inst.rm_index=(inst.rm >> 3) & 7;
+ inst.rm_eai=inst.rm&07;
+ inst.rm_mod=inst.rm>>6;
+ /* Decode address of mod/rm if needed */
+ if (inst.rm<0xc0) {
+ if (!(inst.prefix & PREFIX_ADDR))
+ #include "ea_lookup.h"
+ }
+l_MODRMswitch:
+ switch (inst.code.extra) {
+/* Byte */
+ case M_Ib:
+ inst_op1_d=Fetchb();
+ break;
+ case M_Ebx:
+ if (inst.rm<0xc0) inst_op1_ds=(Bit8s)LoadMb(inst.rm_eaa);
+ else inst_op1_ds=(Bit8s)reg_8(inst.rm_eai);
+ break;
+ case M_EbIb:
+ inst_op2_d=Fetchb();
+ case M_Eb:
+ if (inst.rm<0xc0) inst_op1_d=LoadMb(inst.rm_eaa);
+ else inst_op1_d=reg_8(inst.rm_eai);
+ break;
+ case M_EbGb:
+ if (inst.rm<0xc0) inst_op1_d=LoadMb(inst.rm_eaa);
+ else inst_op1_d=reg_8(inst.rm_eai);
+ inst_op2_d=reg_8(inst.rm_index);
+ break;
+ case M_GbEb:
+ if (inst.rm<0xc0) inst_op2_d=LoadMb(inst.rm_eaa);
+ else inst_op2_d=reg_8(inst.rm_eai);
+ case M_Gb:
+ inst_op1_d=reg_8(inst.rm_index);;
+ break;
+/* Word */
+ case M_Iw:
+ inst_op1_d=Fetchw();
+ break;
+ case M_EwxGwx:
+ inst_op2_ds=(Bit16s)reg_16(inst.rm_index);
+ goto l_M_Ewx;
+ case M_EwxIbx:
+ inst_op2_ds=Fetchbs();
+ goto l_M_Ewx;
+ case M_EwxIwx:
+ inst_op2_ds=Fetchws();
+l_M_Ewx:
+ case M_Ewx:
+ if (inst.rm<0xc0) inst_op1_ds=(Bit16s)LoadMw(inst.rm_eaa);
+ else inst_op1_ds=(Bit16s)reg_16(inst.rm_eai);
+ break;
+ case M_EwIb:
+ inst_op2_d=Fetchb();
+ goto l_M_Ew;
+ case M_EwIbx:
+ inst_op2_ds=Fetchbs();
+ goto l_M_Ew;
+ case M_EwIw:
+ inst_op2_d=Fetchw();
+ goto l_M_Ew;
+ case M_EwGwCL:
+ inst_imm_d=reg_cl;
+ goto l_M_EwGw;
+ case M_EwGwIb:
+ inst_imm_d=Fetchb();
+ goto l_M_EwGw;
+ case M_EwGwt:
+ inst_op2_d=reg_16(inst.rm_index);
+ inst.rm_eaa+=((Bit16s)inst_op2_d >> 4) * 2;
+ goto l_M_Ew;
+l_M_EwGw:
+ case M_EwGw:
+ inst_op2_d=reg_16(inst.rm_index);
+l_M_Ew:
+ case M_Ew:
+ if (inst.rm<0xc0) inst_op1_d=LoadMw(inst.rm_eaa);
+ else inst_op1_d=reg_16(inst.rm_eai);
+ break;
+ case M_GwEw:
+ if (inst.rm<0xc0) inst_op2_d=LoadMw(inst.rm_eaa);
+ else inst_op2_d=reg_16(inst.rm_eai);
+ case M_Gw:
+ inst_op1_d=reg_16(inst.rm_index);;
+ break;
+/* DWord */
+ case M_Id:
+ inst_op1_d=Fetchd();
+ break;
+ case M_EdxGdx:
+ inst_op2_ds=(Bit32s)reg_32(inst.rm_index);
+ case M_Edx:
+ if (inst.rm<0xc0) inst_op1_d=(Bit32s)LoadMd(inst.rm_eaa);
+ else inst_op1_d=(Bit32s)reg_32(inst.rm_eai);
+ break;
+ case M_EdIb:
+ inst_op2_d=Fetchb();
+ goto l_M_Ed;
+ case M_EdIbx:
+ inst_op2_ds=Fetchbs();
+ goto l_M_Ed;
+ case M_EdId:
+ inst_op2_d=Fetchd();
+ goto l_M_Ed;
+ case M_EdGdCL:
+ inst_imm_d=reg_cl;
+ goto l_M_EdGd;
+ case M_EdGdt:
+ inst_op2_d=reg_32(inst.rm_index);
+ inst.rm_eaa+=((Bit32s)inst_op2_d >> 5) * 4;
+ goto l_M_Ed;
+ case M_EdGdIb:
+ inst_imm_d=Fetchb();
+ goto l_M_EdGd;
+l_M_EdGd:
+ case M_EdGd:
+ inst_op2_d=reg_32(inst.rm_index);
+l_M_Ed:
+ case M_Ed:
+ if (inst.rm<0xc0) inst_op1_d=LoadMd(inst.rm_eaa);
+ else inst_op1_d=reg_32(inst.rm_eai);
+ break;
+ case M_GdEd:
+ if (inst.rm<0xc0) inst_op2_d=LoadMd(inst.rm_eaa);
+ else inst_op2_d=reg_32(inst.rm_eai);
+ case M_Gd:
+ inst_op1_d=reg_32(inst.rm_index);
+ break;
+/* Others */
+
+ case M_SEG:
+ //TODO Check for limit
+ inst_op1_d=SegValue((SegNames)inst.rm_index);
+ break;
+ case M_Efw:
+ if (inst.rm>=0xc0) goto illegalopcode;
+ inst_op1_d=LoadMw(inst.rm_eaa);
+ inst_op2_d=LoadMw(inst.rm_eaa+2);
+ break;
+ case M_Efd:
+ if (inst.rm>=0xc0) goto illegalopcode;
+ inst_op1_d=LoadMd(inst.rm_eaa);
+ inst_op2_d=LoadMw(inst.rm_eaa+4);
+ break;
+ case M_EA:
+ inst_op1_d=inst.rm_off;
+ break;
+ case M_POPw:
+ inst_op1_d = Pop_16();
+ break;
+ case M_POPd:
+ inst_op1_d = Pop_32();
+ break;
+ case M_GRP:
+ inst.code=Groups[inst.code.op][inst.rm_index];
+ goto l_MODRMswitch;
+ case M_GRP_Ib:
+ inst_op2_d=Fetchb();
+ inst.code=Groups[inst.code.op][inst.rm_index];
+ goto l_MODRMswitch;
+ case M_GRP_CL:
+ inst_op2_d=reg_cl;
+ inst.code=Groups[inst.code.op][inst.rm_index];
+ goto l_MODRMswitch;
+ case M_GRP_1:
+ inst_op2_d=1;
+ inst.code=Groups[inst.code.op][inst.rm_index];
+ goto l_MODRMswitch;
+ case 0:
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("MODRM:Unhandled load %d entry %x",inst.code.extra,inst.entry);
+ break;
+ }
+ break;
+ case L_POPw:
+ inst_op1_d = Pop_16();
+ break;
+ case L_POPd:
+ inst_op1_d = Pop_32();
+ break;
+ case L_POPfw:
+ inst_op1_d = Pop_16();
+ inst_op2_d = Pop_16();
+ break;
+ case L_POPfd:
+ inst_op1_d = Pop_32();
+ inst_op2_d = Pop_16();
+ break;
+ case L_Ib:
+ inst_op1_d=Fetchb();
+ break;
+ case L_Ibx:
+ inst_op1_ds=Fetchbs();
+ break;
+ case L_Iw:
+ inst_op1_d=Fetchw();
+ break;
+ case L_Iwx:
+ inst_op1_ds=Fetchws();
+ break;
+ case L_Idx:
+ case L_Id:
+ inst_op1_d=Fetchd();
+ break;
+ case L_Ifw:
+ inst_op1_d=Fetchw();
+ inst_op2_d=Fetchw();
+ break;
+ case L_Ifd:
+ inst_op1_d=Fetchd();
+ inst_op2_d=Fetchw();
+ break;
+/* Direct load of registers */
+ case L_REGbIb:
+ inst_op2_d=Fetchb();
+ case L_REGb:
+ inst_op1_d=reg_8(inst.code.extra);
+ break;
+ case L_REGwIw:
+ inst_op2_d=Fetchw();
+ case L_REGw:
+ inst_op1_d=reg_16(inst.code.extra);
+ break;
+ case L_REGdId:
+ inst_op2_d=Fetchd();
+ case L_REGd:
+ inst_op1_d=reg_32(inst.code.extra);
+ break;
+ case L_SEG:
+ inst_op1_d=SegValue((SegNames)inst.code.extra);
+ break;
+/* Depending on addressize */
+ case L_OP:
+ if (inst.prefix & PREFIX_ADDR) {
+ inst.rm_eaa=Fetchd();
+ } else {
+ inst.rm_eaa=Fetchw();
+ }
+ if (inst.prefix & PREFIX_SEG) {
+ inst.rm_eaa+=inst.seg.base;
+ } else {
+ inst.rm_eaa+=SegBase(ds);
+ }
+ break;
+ /* Special cases */
+ case L_DOUBLE:
+ inst.entry|=0x100;
+ goto restartopcode;
+ case L_PRESEG:
+ inst.prefix|=PREFIX_SEG;
+ inst.seg.base=SegBase((SegNames)inst.code.extra);
+ goto restartopcode;
+ case L_PREREPNE:
+ inst.prefix|=PREFIX_REP;
+ inst.repz=false;
+ goto restartopcode;
+ case L_PREREP:
+ inst.prefix|=PREFIX_REP;
+ inst.repz=true;
+ goto restartopcode;
+ case L_PREOP:
+ inst.entry=(cpu.code.big ^1) * 0x200;
+ goto restartopcode;
+ case L_PREADD:
+ inst.prefix=(inst.prefix & ~1) | (cpu.code.big ^ 1);
+ goto restartopcode;
+ case L_VAL:
+ inst_op1_d=inst.code.extra;
+ break;
+ case L_INTO:
+ if (!get_OF()) goto nextopcode;
+ inst_op1_d=4;
+ break;
+ case D_IRETw:
+ CPU_IRET(false,GetIP());
+ if (GETFLAG(IF) && PIC_IRQCheck) {
+ return CBRET_NONE;
+ }
+ continue;
+ case D_IRETd:
+ CPU_IRET(true,GetIP());
+ if (GETFLAG(IF) && PIC_IRQCheck)
+ return CBRET_NONE;
+ continue;
+ case D_RETFwIw:
+ {
+ Bitu words=Fetchw();
+ FillFlags();
+ CPU_RET(false,words,GetIP());
+ continue;
+ }
+ case D_RETFw:
+ FillFlags();
+ CPU_RET(false,0,GetIP());
+ continue;
+ case D_RETFdIw:
+ {
+ Bitu words=Fetchw();
+ FillFlags();
+ CPU_RET(true,words,GetIP());
+ continue;
+ }
+ case D_RETFd:
+ FillFlags();
+ CPU_RET(true,0,GetIP());
+ continue;
+/* Direct operations */
+ case L_STRING:
+ #include "string.h"
+ goto nextopcode;
+ case D_PUSHAw:
+ {
+ Bit16u old_sp=reg_sp;
+ Push_16(reg_ax);Push_16(reg_cx);Push_16(reg_dx);Push_16(reg_bx);
+ Push_16(old_sp);Push_16(reg_bp);Push_16(reg_si);Push_16(reg_di);
+ }
+ goto nextopcode;
+ case D_PUSHAd:
+ {
+ Bit32u old_esp=reg_esp;
+ Push_32(reg_eax);Push_32(reg_ecx);Push_32(reg_edx);Push_32(reg_ebx);
+ Push_32(old_esp);Push_32(reg_ebp);Push_32(reg_esi);Push_32(reg_edi);
+ }
+ goto nextopcode;
+ case D_POPAw:
+ reg_di=Pop_16();reg_si=Pop_16();reg_bp=Pop_16();Pop_16();//Don't save SP
+ reg_bx=Pop_16();reg_dx=Pop_16();reg_cx=Pop_16();reg_ax=Pop_16();
+ goto nextopcode;
+ case D_POPAd:
+ reg_edi=Pop_32();reg_esi=Pop_32();reg_ebp=Pop_32();Pop_32();//Don't save ESP
+ reg_ebx=Pop_32();reg_edx=Pop_32();reg_ecx=Pop_32();reg_eax=Pop_32();
+ goto nextopcode;
+ case D_POPSEGw:
+ if (CPU_PopSeg((SegNames)inst.code.extra,false)) RunException();
+ goto nextopcode;
+ case D_POPSEGd:
+ if (CPU_PopSeg((SegNames)inst.code.extra,true)) RunException();
+ goto nextopcode;
+ case D_SETALC:
+ reg_al = get_CF() ? 0xFF : 0;
+ goto nextopcode;
+ case D_XLAT:
+ if (inst.prefix & PREFIX_SEG) {
+ if (inst.prefix & PREFIX_ADDR) {
+ reg_al=LoadMb(inst.seg.base+(Bit32u)(reg_ebx+reg_al));
+ } else {
+ reg_al=LoadMb(inst.seg.base+(Bit16u)(reg_bx+reg_al));
+ }
+ } else {
+ if (inst.prefix & PREFIX_ADDR) {
+ reg_al=LoadMb(SegBase(ds)+(Bit32u)(reg_ebx+reg_al));
+ } else {
+ reg_al=LoadMb(SegBase(ds)+(Bit16u)(reg_bx+reg_al));
+ }
+ }
+ goto nextopcode;
+ case D_CBW:
+ reg_ax=(Bit8s)reg_al;
+ goto nextopcode;
+ case D_CWDE:
+ reg_eax=(Bit16s)reg_ax;
+ goto nextopcode;
+ case D_CWD:
+ if (reg_ax & 0x8000) reg_dx=0xffff;
+ else reg_dx=0;
+ goto nextopcode;
+ case D_CDQ:
+ if (reg_eax & 0x80000000) reg_edx=0xffffffff;
+ else reg_edx=0;
+ goto nextopcode;
+ case D_CLI:
+ if (CPU_CLI()) RunException();
+ goto nextopcode;
+ case D_STI:
+ if (CPU_STI()) RunException();
+ goto nextopcode;
+ case D_STC:
+ FillFlags();SETFLAGBIT(CF,true);
+ goto nextopcode;
+ case D_CLC:
+ FillFlags();SETFLAGBIT(CF,false);
+ goto nextopcode;
+ case D_CMC:
+ FillFlags();
+ SETFLAGBIT(CF,!(reg_flags & FLAG_CF));
+ goto nextopcode;
+ case D_CLD:
+ SETFLAGBIT(DF,false);
+ cpu.direction=1;
+ goto nextopcode;
+ case D_STD:
+ SETFLAGBIT(DF,true);
+ cpu.direction=-1;
+ goto nextopcode;
+ case D_PUSHF:
+ if (CPU_PUSHF(inst.code.extra)) RunException();
+ goto nextopcode;
+ case D_POPF:
+ if (CPU_POPF(inst.code.extra)) RunException();
+ if (GETFLAG(IF) && PIC_IRQCheck) {
+ SaveIP();
+ return CBRET_NONE;
+ }
+ goto nextopcode;
+ case D_SAHF:
+ SETFLAGSb(reg_ah);
+ goto nextopcode;
+ case D_LAHF:
+ FillFlags();
+ reg_ah=reg_flags&0xff;
+ goto nextopcode;
+ case D_WAIT:
+ case D_NOP:
+ goto nextopcode;
+ case D_LOCK: /* FIXME: according to intel, LOCK should raise an exception if it's not followed by one of a small set of instructions;
+ probably doesn't matter for our purposes as it is a pentium prefix anyhow */
+ LOG(LOG_CPU,LOG_NORMAL)("CPU:LOCK");
+ goto nextopcode;
+ case D_ENTERw:
+ {
+ Bitu bytes=Fetchw();
+ Bitu level=Fetchb();
+ CPU_ENTER(false,bytes,level);
+ goto nextopcode;
+ }
+ case D_ENTERd:
+ {
+ Bitu bytes=Fetchw();
+ Bitu level=Fetchb();
+ CPU_ENTER(true,bytes,level);
+ goto nextopcode;
+ }
+ case D_LEAVEw:
+ reg_esp&=cpu.stack.notmask;
+ reg_esp|=(reg_ebp&cpu.stack.mask);
+ reg_bp=Pop_16();
+ goto nextopcode;
+ case D_LEAVEd:
+ reg_esp&=cpu.stack.notmask;
+ reg_esp|=(reg_ebp&cpu.stack.mask);
+ reg_ebp=Pop_32();
+ goto nextopcode;
+ case D_DAA:
+ DAA();
+ goto nextopcode;
+ case D_DAS:
+ DAS();
+ goto nextopcode;
+ case D_AAA:
+ AAA();
+ goto nextopcode;
+ case D_AAS:
+ AAS();
+ goto nextopcode;
+ case D_CPUID:
+ if (!CPU_CPUID()) goto illegalopcode;
+ goto nextopcode;
+ case D_HLT:
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ FillFlags();
+ CPU_HLT(GetIP());
+ return CBRET_NONE;
+ case D_CLTS:
+ if (cpu.pmode && cpu.cpl) goto illegalopcode;
+ cpu.cr0&=(~CR0_TASKSWITCH);
+ goto nextopcode;
+ case D_ICEBP:
+ CPU_SW_Interrupt_NoIOPLCheck(1,GetIP());
+ continue;
+ case D_RDTSC: {
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_PENTIUMSLOW) goto illegalopcode;
+ Bit64s tsc=(Bit64s)(PIC_FullIndex()*(double)(CPU_CycleAutoAdjust?70000:CPU_CycleMax));
+ reg_edx=(Bit32u)(tsc>>32);
+ reg_eax=(Bit32u)(tsc&0xffffffff);
+ break;
+ }
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("LOAD:Unhandled code %d opcode %X",inst.code.load,inst.entry);
+ goto illegalopcode;
+}
+
--- /dev/null
+/*
+ * 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.
+ */
+
+#define SaveIP() reg_eip=(Bit32u)(inst.cseip-SegBase(cs));
+#define LoadIP() inst.cseip=SegBase(cs)+reg_eip;
+#define GetIP() (inst.cseip-SegBase(cs))
+
+#define RunException() { \
+ CPU_Exception(cpu.exception.which,cpu.exception.error); \
+ continue; \
+}
+
+static INLINE Bit8u the_Fetchb(EAPoint & loc) {
+ Bit8u temp=LoadMb(loc);
+ loc+=1;
+ return temp;
+}
+
+static INLINE Bit16u the_Fetchw(EAPoint & loc) {
+ Bit16u temp=LoadMw(loc);
+ loc+=2;
+ return temp;
+}
+static INLINE Bit32u the_Fetchd(EAPoint & loc) {
+ Bit32u temp=LoadMd(loc);
+ loc+=4;
+ return temp;
+}
+
+#define Fetchb() the_Fetchb(inst.cseip)
+#define Fetchw() the_Fetchw(inst.cseip)
+#define Fetchd() the_Fetchd(inst.cseip)
+
+#define Fetchbs() (Bit8s)the_Fetchb(inst.cseip)
+#define Fetchws() (Bit16s)the_Fetchw(inst.cseip)
+#define Fetchds() (Bit32s)the_Fetchd(inst.cseip)
+
+#define Push_16 CPU_Push16
+#define Push_32 CPU_Push32
+#define Pop_16 CPU_Pop16
+#define Pop_32 CPU_Pop32
+
--- /dev/null
+/*
+ * 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.
+ */
+
+/* Do the actual opcode */
+switch (inst.code.op) {
+ case t_ADDb: case t_ADDw: case t_ADDd:
+ lf_var1d=inst_op1_d;
+ lf_var2d=inst_op2_d;
+ inst_op1_d=lf_resd=lf_var1d + lf_var2d;
+ lflags.type=inst.code.op;
+ break;
+ case t_CMPb: case t_CMPw: case t_CMPd:
+ case t_SUBb: case t_SUBw: case t_SUBd:
+ lf_var1d=inst_op1_d;
+ lf_var2d=inst_op2_d;
+ inst_op1_d=lf_resd=lf_var1d - lf_var2d;
+ lflags.type=inst.code.op;
+ break;
+ case t_ORb: case t_ORw: case t_ORd:
+ lf_var1d=inst_op1_d;
+ lf_var2d=inst_op2_d;
+ inst_op1_d=lf_resd=lf_var1d | lf_var2d;
+ lflags.type=inst.code.op;
+ break;
+ case t_XORb: case t_XORw: case t_XORd:
+ lf_var1d=inst_op1_d;
+ lf_var2d=inst_op2_d;
+ inst_op1_d=lf_resd=lf_var1d ^ lf_var2d;
+ lflags.type=inst.code.op;
+ break;
+ case t_TESTb: case t_TESTw: case t_TESTd:
+ case t_ANDb: case t_ANDw: case t_ANDd:
+ lf_var1d=inst_op1_d;
+ lf_var2d=inst_op2_d;
+ inst_op1_d=lf_resd=lf_var1d & lf_var2d;
+ lflags.type=inst.code.op;
+ break;
+ case t_ADCb: case t_ADCw: case t_ADCd:
+ lflags.oldcf=(get_CF()!=0);
+ lf_var1d=inst_op1_d;
+ lf_var2d=inst_op2_d;
+ inst_op1_d=lf_resd=lf_var1d + lf_var2d + lflags.oldcf;
+ lflags.type=inst.code.op;
+ break;
+ case t_SBBb: case t_SBBw: case t_SBBd:
+ lflags.oldcf=(get_CF()!=0);
+ lf_var1d=inst_op1_d;
+ lf_var2d=inst_op2_d;
+ inst_op1_d=lf_resd=lf_var1d - lf_var2d - lflags.oldcf;
+ lflags.type=inst.code.op;
+ break;
+ case t_INCb: case t_INCw: case t_INCd:
+ LoadCF;
+ lf_var1d=inst_op1_d;
+ inst_op1_d=lf_resd=inst_op1_d+1;
+ lflags.type=inst.code.op;
+ break;
+ case t_DECb: case t_DECw: case t_DECd:
+ LoadCF;
+ lf_var1d=inst_op1_d;
+ inst_op1_d=lf_resd=inst_op1_d-1;
+ lflags.type=inst.code.op;
+ break;
+/* Using the instructions.h defines */
+ case t_ROLb:
+ ROLB(inst_op1_b,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_ROLw:
+ ROLW(inst_op1_w,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_ROLd:
+ ROLD(inst_op1_d,inst_op2_b,LoadD,SaveD);
+ break;
+
+ case t_RORb:
+ RORB(inst_op1_b,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_RORw:
+ RORW(inst_op1_w,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_RORd:
+ RORD(inst_op1_d,inst_op2_b,LoadD,SaveD);
+ break;
+
+ case t_RCLb:
+ RCLB(inst_op1_b,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_RCLw:
+ RCLW(inst_op1_w,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_RCLd:
+ RCLD(inst_op1_d,inst_op2_b,LoadD,SaveD);
+ break;
+
+ case t_RCRb:
+ RCRB(inst_op1_b,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_RCRw:
+ RCRW(inst_op1_w,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_RCRd:
+ RCRD(inst_op1_d,inst_op2_b,LoadD,SaveD);
+ break;
+
+ case t_SHLb:
+ SHLB(inst_op1_b,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_SHLw:
+ SHLW(inst_op1_w,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_SHLd:
+ SHLD(inst_op1_d,inst_op2_b,LoadD,SaveD);
+ break;
+
+ case t_SHRb:
+ SHRB(inst_op1_b,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_SHRw:
+ SHRW(inst_op1_w,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_SHRd:
+ SHRD(inst_op1_d,inst_op2_b,LoadD,SaveD);
+ break;
+
+ case t_SARb:
+ SARB(inst_op1_b,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_SARw:
+ SARW(inst_op1_w,inst_op2_b,LoadD,SaveD);
+ break;
+ case t_SARd:
+ SARD(inst_op1_d,inst_op2_b,LoadD,SaveD);
+ break;
+
+ case O_DSHLw:
+ {
+ DSHLW(inst_op1_w,inst_op2_w,inst_imm_b,LoadD,SaveD);
+ break;
+ }
+ case O_DSHRw:
+ {
+ DSHRW(inst_op1_w,inst_op2_w,inst_imm_b,LoadD,SaveD);
+ break;
+ }
+ case O_DSHLd:
+ {
+ DSHLD(inst_op1_d,inst_op2_d,inst_imm_b,LoadD,SaveD);
+ break;
+ }
+ case O_DSHRd:
+ {
+ DSHRD(inst_op1_d,inst_op2_d,inst_imm_b,LoadD,SaveD);
+ break;
+ }
+
+ case t_NEGb:
+ lf_var1b=inst_op1_b;
+ inst_op1_b=lf_resb=0-inst_op1_b;
+ lflags.type=t_NEGb;
+ break;
+ case t_NEGw:
+ lf_var1w=inst_op1_w;
+ inst_op1_w=lf_resw=0-inst_op1_w;
+ lflags.type=t_NEGw;
+ break;
+ case t_NEGd:
+ lf_var1d=inst_op1_d;
+ inst_op1_d=lf_resd=0-inst_op1_d;
+ lflags.type=t_NEGd;
+ break;
+
+ case O_NOT:
+ inst_op1_d=~inst_op1_d;
+ break;
+
+ /* Special instructions */
+ case O_IMULRw:
+ DIMULW(inst_op1_ws,inst_op1_ws,inst_op2_ws,LoadD,SaveD);
+ break;
+ case O_IMULRd:
+ DIMULD(inst_op1_ds,inst_op1_ds,inst_op2_ds,LoadD,SaveD);
+ break;
+ case O_MULb:
+ MULB(inst_op1_b,LoadD,0);
+ goto nextopcode;
+ case O_MULw:
+ MULW(inst_op1_w,LoadD,0);
+ goto nextopcode;
+ case O_MULd:
+ MULD(inst_op1_d,LoadD,0);
+ goto nextopcode;
+ case O_IMULb:
+ IMULB(inst_op1_b,LoadD,0);
+ goto nextopcode;
+ case O_IMULw:
+ IMULW(inst_op1_w,LoadD,0);
+ goto nextopcode;
+ case O_IMULd:
+ IMULD(inst_op1_d,LoadD,0);
+ goto nextopcode;
+ case O_DIVb:
+ DIVB(inst_op1_b,LoadD,0);
+ goto nextopcode;
+ case O_DIVw:
+ DIVW(inst_op1_w,LoadD,0);
+ goto nextopcode;
+ case O_DIVd:
+ DIVD(inst_op1_d,LoadD,0);
+ goto nextopcode;
+ case O_IDIVb:
+ IDIVB(inst_op1_b,LoadD,0);
+ goto nextopcode;
+ case O_IDIVw:
+ IDIVW(inst_op1_w,LoadD,0);
+ goto nextopcode;
+ case O_IDIVd:
+ IDIVD(inst_op1_d,LoadD,0);
+ goto nextopcode;
+ case O_AAM:
+ AAM(inst_op1_b);
+ goto nextopcode;
+ case O_AAD:
+ AAD(inst_op1_b);
+ goto nextopcode;
+
+ case O_C_O: inst.cond=TFLG_O; break;
+ case O_C_NO: inst.cond=TFLG_NO; break;
+ case O_C_B: inst.cond=TFLG_B; break;
+ case O_C_NB: inst.cond=TFLG_NB; break;
+ case O_C_Z: inst.cond=TFLG_Z; break;
+ case O_C_NZ: inst.cond=TFLG_NZ; break;
+ case O_C_BE: inst.cond=TFLG_BE; break;
+ case O_C_NBE: inst.cond=TFLG_NBE; break;
+ case O_C_S: inst.cond=TFLG_S; break;
+ case O_C_NS: inst.cond=TFLG_NS; break;
+ case O_C_P: inst.cond=TFLG_P; break;
+ case O_C_NP: inst.cond=TFLG_NP; break;
+ case O_C_L: inst.cond=TFLG_L; break;
+ case O_C_NL: inst.cond=TFLG_NL; break;
+ case O_C_LE: inst.cond=TFLG_LE; break;
+ case O_C_NLE: inst.cond=TFLG_NLE; break;
+
+ case O_ALOP:
+ reg_al=LoadMb(inst.rm_eaa);
+ goto nextopcode;
+ case O_AXOP:
+ reg_ax=LoadMw(inst.rm_eaa);
+ goto nextopcode;
+ case O_EAXOP:
+ reg_eax=LoadMd(inst.rm_eaa);
+ goto nextopcode;
+ case O_OPAL:
+ SaveMb(inst.rm_eaa,reg_al);
+ goto nextopcode;
+ case O_OPAX:
+ SaveMw(inst.rm_eaa,reg_ax);
+ goto nextopcode;
+ case O_OPEAX:
+ SaveMd(inst.rm_eaa,reg_eax);
+ goto nextopcode;
+ case O_SEGDS:
+ inst.code.extra=ds;
+ break;
+ case O_SEGES:
+ inst.code.extra=es;
+ break;
+ case O_SEGFS:
+ inst.code.extra=fs;
+ break;
+ case O_SEGGS:
+ inst.code.extra=gs;
+ break;
+ case O_SEGSS:
+ inst.code.extra=ss;
+ break;
+
+ case O_LOOP:
+ if (inst.prefix & PREFIX_ADDR) {
+ if (--reg_ecx) break;
+ } else {
+ if (--reg_cx) break;
+ }
+ goto nextopcode;
+ case O_LOOPZ:
+ if (inst.prefix & PREFIX_ADDR) {
+ if (--reg_ecx && get_ZF()) break;
+ } else {
+ if (--reg_cx && get_ZF()) break;
+ }
+ goto nextopcode;
+ case O_LOOPNZ:
+ if (inst.prefix & PREFIX_ADDR) {
+ if (--reg_ecx && !get_ZF()) break;
+ } else {
+ if (--reg_cx && !get_ZF()) break;
+ }
+ goto nextopcode;
+ case O_JCXZ:
+ if (inst.prefix & PREFIX_ADDR) {
+ if (reg_ecx) goto nextopcode;
+ } else {
+ if (reg_cx) goto nextopcode;
+ }
+ break;
+ case O_XCHG_AX:
+ {
+ Bit16u temp=reg_ax;
+ reg_ax=inst_op1_w;
+ inst_op1_w=temp;
+ break;
+ }
+ case O_XCHG_EAX:
+ {
+ Bit32u temp=reg_eax;
+ reg_eax=inst_op1_d;
+ inst_op1_d=temp;
+ break;
+ }
+ case O_CALLNw:
+ SaveIP();
+ Push_16(reg_ip);
+ break;
+ case O_CALLNd:
+ SaveIP();
+ Push_32(reg_eip);
+ break;
+ case O_CALLFw:
+ FillFlags();
+ CPU_CALL(false,inst_op2_d,inst_op1_d,GetIP());
+ continue;
+ case O_CALLFd:
+ FillFlags();
+ CPU_CALL(true,inst_op2_d,inst_op1_d,GetIP());
+ continue;
+ case O_JMPFw:
+ FillFlags();
+ CPU_JMP(false,inst_op2_d,inst_op1_d,GetIP());
+ continue;
+ case O_JMPFd:
+ FillFlags();
+ CPU_JMP(true,inst_op2_d,inst_op1_d,GetIP());
+ continue;
+ case O_INT:
+#if C_DEBUG
+ FillFlags();
+ if (((inst.entry & 0xFF)==0xcc) && DEBUG_Breakpoint())
+ return debugCallback;
+ else if (DEBUG_IntBreakpoint(inst_op1_b))
+ return debugCallback;
+#endif
+ CPU_SW_Interrupt(inst_op1_b,GetIP());
+ continue;
+ case O_INb:
+ if (CPU_IO_Exception(inst_op1_d,1)) RunException();
+ reg_al=IO_ReadB(inst_op1_d);
+ goto nextopcode;
+ case O_INw:
+ if (CPU_IO_Exception(inst_op1_d,2)) RunException();
+ reg_ax=IO_ReadW(inst_op1_d);
+ goto nextopcode;
+ case O_INd:
+ if (CPU_IO_Exception(inst_op1_d,4)) RunException();
+ reg_eax=IO_ReadD(inst_op1_d);
+ goto nextopcode;
+ case O_OUTb:
+ if (CPU_IO_Exception(inst_op1_d,1)) RunException();
+ IO_WriteB(inst_op1_d,reg_al);
+ goto nextopcode;
+ case O_OUTw:
+ if (CPU_IO_Exception(inst_op1_d,2)) RunException();
+ IO_WriteW(inst_op1_d,reg_ax);
+ goto nextopcode;
+ case O_OUTd:
+ if (CPU_IO_Exception(inst_op1_d,4)) RunException();
+ IO_WriteD(inst_op1_d,reg_eax);
+ goto nextopcode;
+ case O_CBACK:
+ FillFlags();SaveIP();
+ return inst_op1_d;
+ case O_GRP6w:
+ case O_GRP6d:
+ if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode;
+ switch (inst.rm_index) {
+ case 0x00: /* SLDT */
+ inst_op1_d=(Bit32u)CPU_SLDT();
+ break;
+ case 0x01: /* STR */
+ inst_op1_d=(Bit32u)CPU_STR();
+ break;
+ case 0x02: /* LLDT */
+ if (cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ if (CPU_LLDT(inst_op1_d)) RunException();
+ goto nextopcode; /* Else value will saved */
+ case 0x03: /* LTR */
+ if (cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ if (CPU_LTR(inst_op1_d)) RunException();
+ goto nextopcode; /* Else value will saved */
+ case 0x04: /* VERR */
+ CPU_VERR(inst_op1_d);
+ goto nextopcode; /* Else value will saved */
+ case 0x05: /* VERW */
+ CPU_VERW(inst_op1_d);
+ goto nextopcode; /* Else value will saved */
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Group 6 Illegal subfunction %X",inst.rm_index);
+ goto illegalopcode;
+ }
+ break;
+ case O_GRP7w:
+ case O_GRP7d:
+ switch (inst.rm_index) {
+ case 0: /* SGDT */
+ SaveMw(inst.rm_eaa,CPU_SGDT_limit());
+ SaveMd(inst.rm_eaa+2,CPU_SGDT_base());
+ goto nextopcode;
+ case 1: /* SIDT */
+ SaveMw(inst.rm_eaa,CPU_SIDT_limit());
+ SaveMd(inst.rm_eaa+2,CPU_SIDT_base());
+ goto nextopcode;
+ case 2: /* LGDT */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ CPU_LGDT(LoadMw(inst.rm_eaa),LoadMd(inst.rm_eaa+2)&((inst.code.op == O_GRP7w) ? 0xFFFFFF : 0xFFFFFFFF));
+ goto nextopcode;
+ case 3: /* LIDT */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ CPU_LIDT(LoadMw(inst.rm_eaa),LoadMd(inst.rm_eaa+2)&((inst.code.op == O_GRP7w) ? 0xFFFFFF : 0xFFFFFFFF));
+ goto nextopcode;
+ case 4: /* SMSW */
+ inst_op1_d=CPU_SMSW();
+ break;
+ case 6: /* LMSW */
+ FillFlags();
+ if (CPU_LMSW(inst_op1_w)) RunException();
+ goto nextopcode;
+ case 7: /* INVLPG */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ FillFlags();
+ PAGING_ClearTLB();
+ goto nextopcode;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Group 7 Illegal subfunction %X",inst.rm_index);
+ goto illegalopcode;
+ }
+ break;
+ case O_M_CRx_Rd:
+ if (CPU_WRITE_CRX(inst.rm_index,inst_op1_d)) RunException();
+ break;
+ case O_M_Rd_CRx:
+ if (CPU_READ_CRX(inst.rm_index,inst_op1_d)) RunException();
+ break;
+ case O_M_DRx_Rd:
+ if (CPU_WRITE_DRX(inst.rm_index,inst_op1_d)) RunException();
+ break;
+ case O_M_Rd_DRx:
+ if (CPU_READ_DRX(inst.rm_index,inst_op1_d)) RunException();
+ break;
+ case O_M_TRx_Rd:
+ if (CPU_WRITE_TRX(inst.rm_index,inst_op1_d)) RunException();
+ break;
+ case O_M_Rd_TRx:
+ if (CPU_READ_TRX(inst.rm_index,inst_op1_d)) RunException();
+ break;
+ case O_LAR:
+ {
+ Bitu ar=inst_op2_d;
+ CPU_LAR(inst_op1_w,ar);
+ inst_op1_d=(Bit32u)ar;
+ }
+ break;
+ case O_LSL:
+ {
+ Bitu limit=inst_op2_d;
+ CPU_LSL(inst_op1_w,limit);
+ inst_op1_d=(Bit32u)limit;
+ }
+ break;
+ case O_ARPL:
+ {
+ Bitu new_sel=inst_op1_d;
+ CPU_ARPL(new_sel,inst_op2_d);
+ inst_op1_d=(Bit32u)new_sel;
+ }
+ break;
+ case O_BSFw:
+ {
+ FillFlags();
+ if (!inst_op1_w) {
+ SETFLAGBIT(ZF,true);
+ goto nextopcode;
+ } else {
+ Bitu count=0;
+ while (1) {
+ if (inst_op1_w & 0x1) break;
+ count++;inst_op1_w>>=1;
+ }
+ inst_op1_d=count;
+ SETFLAGBIT(ZF,false);
+ }
+ }
+ break;
+ case O_BSFd:
+ {
+ FillFlags();
+ if (!inst_op1_d) {
+ SETFLAGBIT(ZF,true);
+ goto nextopcode;
+ } else {
+ Bitu count=0;
+ while (1) {
+ if (inst_op1_d & 0x1) break;
+ count++;inst_op1_d>>=1;
+ }
+ inst_op1_d=count;
+ SETFLAGBIT(ZF,false);
+ }
+ }
+ break;
+ case O_BSRw:
+ {
+ FillFlags();
+ if (!inst_op1_w) {
+ SETFLAGBIT(ZF,true);
+ goto nextopcode;
+ } else {
+ Bitu count=15;
+ while (1) {
+ if (inst_op1_w & 0x8000) break;
+ count--;inst_op1_w<<=1;
+ }
+ inst_op1_d=count;
+ SETFLAGBIT(ZF,false);
+ }
+ }
+ break;
+ case O_BSRd:
+ {
+ FillFlags();
+ if (!inst_op1_d) {
+ SETFLAGBIT(ZF,true);
+ goto nextopcode;
+ } else {
+ Bitu count=31;
+ while (1) {
+ if (inst_op1_d & 0x80000000) break;
+ count--;inst_op1_d<<=1;
+ }
+ inst_op1_d=count;
+ SETFLAGBIT(ZF,false);
+ }
+ }
+ break;
+ case O_BTw:
+ FillFlags();
+ SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15))));
+ break;
+ case O_BTSw:
+ FillFlags();
+ SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15))));
+ inst_op1_d|=(1 << (inst_op2_d & 15));
+ break;
+ case O_BTCw:
+ FillFlags();
+ SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15))));
+ inst_op1_d^=(1 << (inst_op2_d & 15));
+ break;
+ case O_BTRw:
+ FillFlags();
+ SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15))));
+ inst_op1_d&=~(1 << (inst_op2_d & 15));
+ break;
+ case O_BTd:
+ FillFlags();
+ SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31))));
+ break;
+ case O_BTSd:
+ FillFlags();
+ SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31))));
+ inst_op1_d|=(1 << (inst_op2_d & 31));
+ break;
+ case O_BTCd:
+ FillFlags();
+ SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31))));
+ inst_op1_d^=(1 << (inst_op2_d & 31));
+ break;
+ case O_BTRd:
+ FillFlags();
+ SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31))));
+ inst_op1_d&=~(1 << (inst_op2_d & 31));
+ break;
+ case O_BSWAPw:
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegalopcode;
+ BSWAPW(inst_op1_w);
+ break;
+ case O_BSWAPd:
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegalopcode;
+ BSWAPD(inst_op1_d);
+ break;
+ case O_CMPXCHG:
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486NEWSLOW) goto illegalopcode;
+ FillFlags();
+ if (inst_op1_d==reg_eax) {
+ inst_op1_d=reg_32(inst.rm_index);
+ if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d); // early write-pf
+ SETFLAGBIT(ZF,1);
+ } else {
+ if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d); // early write-pf
+ reg_eax=inst_op1_d;
+ SETFLAGBIT(ZF,0);
+ }
+ break;
+ case O_FPU:
+#if C_FPU
+ switch (((inst.rm>=0xc0) << 3) | inst.code.save) {
+ case 0x00: FPU_ESC0_EA(inst.rm,inst.rm_eaa);break;
+ case 0x01: FPU_ESC1_EA(inst.rm,inst.rm_eaa);break;
+ case 0x02: FPU_ESC2_EA(inst.rm,inst.rm_eaa);break;
+ case 0x03: FPU_ESC3_EA(inst.rm,inst.rm_eaa);break;
+ case 0x04: FPU_ESC4_EA(inst.rm,inst.rm_eaa);break;
+ case 0x05: FPU_ESC5_EA(inst.rm,inst.rm_eaa);break;
+ case 0x06: FPU_ESC6_EA(inst.rm,inst.rm_eaa);break;
+ case 0x07: FPU_ESC7_EA(inst.rm,inst.rm_eaa);break;
+
+ case 0x08: FPU_ESC0_Normal(inst.rm);break;
+ case 0x09: FPU_ESC1_Normal(inst.rm);break;
+ case 0x0a: FPU_ESC2_Normal(inst.rm);break;
+ case 0x0b: FPU_ESC3_Normal(inst.rm);break;
+ case 0x0c: FPU_ESC4_Normal(inst.rm);break;
+ case 0x0d: FPU_ESC5_Normal(inst.rm);break;
+ case 0x0e: FPU_ESC6_Normal(inst.rm);break;
+ case 0x0f: FPU_ESC7_Normal(inst.rm);break;
+ }
+ goto nextopcode;
+#else
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled FPU ESCAPE %d",inst.code.save);
+ goto nextopcode;
+#endif
+ case O_BOUNDw:
+ {
+ Bit16s bound_min, bound_max;
+ bound_min=LoadMw(inst.rm_eaa);
+ bound_max=LoadMw(inst.rm_eaa+2);
+ if ( (((Bit16s)inst_op1_w) < bound_min) || (((Bit16s)inst_op1_w) > bound_max) ) {
+ EXCEPTION(5);
+ }
+ }
+ break;
+ case 0:
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("OP:Unhandled code %d entry %X",inst.code.op,inst.entry);
+
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+/* Big ass opcode table normal,double, 66 normal, 66 double */
+static OpCode OpCodeTable[1024]={
+/* 0x00 - 0x07 */
+{L_MODRM ,t_ADDb ,S_Eb ,M_EbGb },{L_MODRM ,t_ADDw ,S_Ew ,M_EwGw },
+{L_MODRM ,t_ADDb ,S_Gb ,M_GbEb },{L_MODRM ,t_ADDw ,S_Gw ,M_GwEw },
+{L_REGbIb ,t_ADDb ,S_REGb ,REGI_AL },{L_REGwIw ,t_ADDw ,S_REGw ,REGI_AX },
+{L_SEG ,0 ,S_PUSHw,es },{D_POPSEGw,0 ,0 ,es },
+/* 0x08 - 0x0f */
+{L_MODRM ,t_ORb ,S_Eb ,M_EbGb },{L_MODRM ,t_ORw ,S_Ew ,M_EwGw },
+{L_MODRM ,t_ORb ,S_Gb ,M_GbEb },{L_MODRM ,t_ORw ,S_Gw ,M_GwEw },
+{L_REGbIb ,t_ORb ,S_REGb ,REGI_AL },{L_REGwIw ,t_ORw ,S_REGw ,REGI_AX },
+{L_SEG ,0 ,S_PUSHw,cs },{L_DOUBLE ,0 ,0 ,0 },
+
+/* 0x10 - 0x17 */
+{L_MODRM ,t_ADCb ,S_Eb ,M_EbGb },{L_MODRM ,t_ADCw ,S_Ew ,M_EwGw },
+{L_MODRM ,t_ADCb ,S_Gb ,M_GbEb },{L_MODRM ,t_ADCw ,S_Gw ,M_GwEw },
+{L_REGbIb ,t_ADCb ,S_REGb ,REGI_AL },{L_REGwIw ,t_ADCw ,S_REGw ,REGI_AX },
+{L_SEG ,0 ,S_PUSHw,ss },{D_POPSEGw,0 ,0 ,ss },
+/* 0x18 - 0x1f */
+{L_MODRM ,t_SBBb ,S_Eb ,M_EbGb },{L_MODRM ,t_SBBw ,S_Ew ,M_EwGw },
+{L_MODRM ,t_SBBb ,S_Gb ,M_GbEb },{L_MODRM ,t_SBBw ,S_Gw ,M_GwEw },
+{L_REGbIb ,t_SBBb ,S_REGb ,REGI_AL },{L_REGwIw ,t_SBBw ,S_REGw ,REGI_AX },
+{L_SEG ,0 ,S_PUSHw,ds },{D_POPSEGw,0 ,0 ,ds },
+
+/* 0x20 - 0x27 */
+{L_MODRM ,t_ANDb ,S_Eb ,M_EbGb },{L_MODRM ,t_ANDw ,S_Ew ,M_EwGw },
+{L_MODRM ,t_ANDb ,S_Gb ,M_GbEb },{L_MODRM ,t_ANDw ,S_Gw ,M_GwEw },
+{L_REGbIb ,t_ANDb ,S_REGb ,REGI_AL },{L_REGwIw ,t_ANDw ,S_REGw ,REGI_AX },
+{L_PRESEG ,0 ,0 ,es },{D_DAA ,0 ,0 ,0 },
+/* 0x28 - 0x2f */
+{L_MODRM ,t_SUBb ,S_Eb ,M_EbGb },{L_MODRM ,t_SUBw ,S_Ew ,M_EwGw },
+{L_MODRM ,t_SUBb ,S_Gb ,M_GbEb },{L_MODRM ,t_SUBw ,S_Gw ,M_GwEw },
+{L_REGbIb ,t_SUBb ,S_REGb ,REGI_AL },{L_REGwIw ,t_SUBw ,S_REGw ,REGI_AX },
+{L_PRESEG ,0 ,0 ,cs },{D_DAS ,0 ,0 ,0 },
+
+/* 0x30 - 0x37 */
+{L_MODRM ,t_XORb ,S_Eb ,M_EbGb },{L_MODRM ,t_XORw ,S_Ew ,M_EwGw },
+{L_MODRM ,t_XORb ,S_Gb ,M_GbEb },{L_MODRM ,t_XORw ,S_Gw ,M_GwEw },
+{L_REGbIb ,t_XORb ,S_REGb ,REGI_AL },{L_REGwIw ,t_XORw ,S_REGw ,REGI_AX },
+{L_PRESEG ,0 ,0 ,ss },{D_AAA ,0 ,0 ,0 },
+/* 0x38 - 0x3f */
+{L_MODRM ,t_CMPb ,0 ,M_EbGb },{L_MODRM ,t_CMPw ,0 ,M_EwGw },
+{L_MODRM ,t_CMPb ,0 ,M_GbEb },{L_MODRM ,t_CMPw ,0 ,M_GwEw },
+{L_REGbIb ,t_CMPb ,0 ,REGI_AL },{L_REGwIw ,t_CMPw ,0 ,REGI_AX },
+{L_PRESEG ,0 ,0 ,ds },{D_AAS ,0 ,0 ,0 },
+
+/* 0x40 - 0x47 */
+{L_REGw ,t_INCw ,S_REGw ,REGI_AX},{L_REGw ,t_INCw ,S_REGw ,REGI_CX},
+{L_REGw ,t_INCw ,S_REGw ,REGI_DX},{L_REGw ,t_INCw ,S_REGw ,REGI_BX},
+{L_REGw ,t_INCw ,S_REGw ,REGI_SP},{L_REGw ,t_INCw ,S_REGw ,REGI_BP},
+{L_REGw ,t_INCw ,S_REGw ,REGI_SI},{L_REGw ,t_INCw ,S_REGw ,REGI_DI},
+/* 0x48 - 0x4f */
+{L_REGw ,t_DECw ,S_REGw ,REGI_AX},{L_REGw ,t_DECw ,S_REGw ,REGI_CX},
+{L_REGw ,t_DECw ,S_REGw ,REGI_DX},{L_REGw ,t_DECw ,S_REGw ,REGI_BX},
+{L_REGw ,t_DECw ,S_REGw ,REGI_SP},{L_REGw ,t_DECw ,S_REGw ,REGI_BP},
+{L_REGw ,t_DECw ,S_REGw ,REGI_SI},{L_REGw ,t_DECw ,S_REGw ,REGI_DI},
+
+/* 0x50 - 0x57 */
+{L_REGw ,0 ,S_PUSHw,REGI_AX},{L_REGw ,0 ,S_PUSHw,REGI_CX},
+{L_REGw ,0 ,S_PUSHw,REGI_DX},{L_REGw ,0 ,S_PUSHw,REGI_BX},
+{L_REGw ,0 ,S_PUSHw,REGI_SP},{L_REGw ,0 ,S_PUSHw,REGI_BP},
+{L_REGw ,0 ,S_PUSHw,REGI_SI},{L_REGw ,0 ,S_PUSHw,REGI_DI},
+/* 0x58 - 0x5f */
+{L_POPw ,0 ,S_REGw ,REGI_AX},{L_POPw ,0 ,S_REGw ,REGI_CX},
+{L_POPw ,0 ,S_REGw ,REGI_DX},{L_POPw ,0 ,S_REGw ,REGI_BX},
+{L_POPw ,0 ,S_REGw ,REGI_SP},{L_POPw ,0 ,S_REGw ,REGI_BP},
+{L_POPw ,0 ,S_REGw ,REGI_SI},{L_POPw ,0 ,S_REGw ,REGI_DI},
+
+
+/* 0x60 - 0x67 */
+{D_PUSHAw ,0 ,0 ,0 },{D_POPAw ,0 ,0 ,0 },
+{L_MODRM ,O_BOUNDw ,0 ,M_Gw },{L_MODRM_NVM ,O_ARPL ,S_Ew ,M_EwGw },
+{L_PRESEG ,0 ,0 ,fs },{L_PRESEG ,0 ,0 ,gs },
+{L_PREOP ,0 ,0 ,0 },{L_PREADD ,0 ,0 ,0 },
+/* 0x68 - 0x6f */
+{L_Iw ,0 ,S_PUSHw,0 },{L_MODRM ,O_IMULRw ,S_Gw ,M_EwxIwx},
+{L_Ibx ,0 ,S_PUSHw,0 },{L_MODRM ,O_IMULRw ,S_Gw ,M_EwxIbx},
+{L_STRING ,R_INSB ,0 ,0 },{L_STRING ,R_INSW ,0 ,0 },
+{L_STRING ,R_OUTSB ,0 ,0 },{L_STRING ,R_OUTSW ,0 ,0 },
+
+
+/* 0x70 - 0x77 */
+{L_Ibx ,O_C_O ,S_C_AIPw,0 },{L_Ibx ,O_C_NO ,S_C_AIPw,0 },
+{L_Ibx ,O_C_B ,S_C_AIPw,0 },{L_Ibx ,O_C_NB ,S_C_AIPw,0 },
+{L_Ibx ,O_C_Z ,S_C_AIPw,0 },{L_Ibx ,O_C_NZ ,S_C_AIPw,0 },
+{L_Ibx ,O_C_BE ,S_C_AIPw,0 },{L_Ibx ,O_C_NBE ,S_C_AIPw,0 },
+/* 0x78 - 0x7f */
+{L_Ibx ,O_C_S ,S_C_AIPw,0 },{L_Ibx ,O_C_NS ,S_C_AIPw,0 },
+{L_Ibx ,O_C_P ,S_C_AIPw,0 },{L_Ibx ,O_C_NP ,S_C_AIPw,0 },
+{L_Ibx ,O_C_L ,S_C_AIPw,0 },{L_Ibx ,O_C_NL ,S_C_AIPw,0 },
+{L_Ibx ,O_C_LE ,S_C_AIPw,0 },{L_Ibx ,O_C_NLE ,S_C_AIPw,0 },
+
+
+/* 0x80 - 0x87 */
+{L_MODRM ,0 ,0 ,M_GRP },{L_MODRM ,1 ,0 ,M_GRP },
+{L_MODRM ,0 ,0 ,M_GRP },{L_MODRM ,3 ,0 ,M_GRP },
+{L_MODRM ,t_TESTb ,0 ,M_EbGb },{L_MODRM ,t_TESTw ,0 ,M_EwGw },
+{L_MODRM ,0 ,S_EbGb ,M_GbEb },{L_MODRM ,0 ,S_EwGw ,M_GwEw },
+/* 0x88 - 0x8f */
+{L_MODRM ,0 ,S_Eb ,M_Gb },{L_MODRM ,0 ,S_Ew ,M_Gw },
+{L_MODRM ,0 ,S_Gb ,M_Eb },{L_MODRM ,0 ,S_Gw ,M_Ew },
+{L_MODRM ,0 ,S_Ew ,M_SEG },{L_MODRM ,0 ,S_Gw ,M_EA },
+{L_MODRM ,0 ,S_SEGm ,M_Ew },{L_POPwRM ,0 ,S_Ew ,M_None },
+
+/* 0x90 - 0x97 */
+{D_NOP ,0 ,0 ,0 },{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_CX},
+{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_DX},{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_BX},
+{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_SP},{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_BP},
+{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_SI},{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_DI},
+/* 0x98 - 0x9f */
+{D_CBW ,0 ,0 ,0 },{D_CWD ,0 ,0 ,0 },
+{L_Ifw ,O_CALLFw ,0 ,0 },{D_WAIT ,0 ,0 ,0 },
+{D_PUSHF ,0 ,0 ,0 },{D_POPF ,0 ,0 ,0 },
+{D_SAHF ,0 ,0 ,0 },{D_LAHF ,0 ,0 ,0 },
+
+
+/* 0xa0 - 0xa7 */
+{L_OP ,O_ALOP ,0 ,0 },{L_OP ,O_AXOP ,0 ,0 },
+{L_OP ,O_OPAL ,0 ,0 },{L_OP ,O_OPAX ,0 ,0 },
+{L_STRING ,R_MOVSB ,0 ,0 },{L_STRING ,R_MOVSW ,0 ,0 },
+{L_STRING ,R_CMPSB ,0 ,0 },{L_STRING ,R_CMPSW ,0 ,0 },
+/* 0xa8 - 0xaf */
+{L_REGbIb ,t_TESTb ,0 ,REGI_AL},{L_REGwIw ,t_TESTw ,0 ,REGI_AX},
+{L_STRING ,R_STOSB ,0 ,0 },{L_STRING ,R_STOSW ,0 ,0 },
+{L_STRING ,R_LODSB ,0 ,0 },{L_STRING ,R_LODSW ,0 ,0 },
+{L_STRING ,R_SCASB ,0 ,0 },{L_STRING ,R_SCASW ,0 ,0 },
+
+/* 0xb0 - 0xb7 */
+{L_Ib ,0 ,S_REGb ,REGI_AL},{L_Ib ,0 ,S_REGb ,REGI_CL},
+{L_Ib ,0 ,S_REGb ,REGI_DL},{L_Ib ,0 ,S_REGb ,REGI_BL},
+{L_Ib ,0 ,S_REGb ,REGI_AH},{L_Ib ,0 ,S_REGb ,REGI_CH},
+{L_Ib ,0 ,S_REGb ,REGI_DH},{L_Ib ,0 ,S_REGb ,REGI_BH},
+/* 0xb8 - 0xbf */
+{L_Iw ,0 ,S_REGw ,REGI_AX},{L_Iw ,0 ,S_REGw ,REGI_CX},
+{L_Iw ,0 ,S_REGw ,REGI_DX},{L_Iw ,0 ,S_REGw ,REGI_BX},
+{L_Iw ,0 ,S_REGw ,REGI_SP},{L_Iw ,0 ,S_REGw ,REGI_BP},
+{L_Iw ,0 ,S_REGw ,REGI_SI},{L_Iw ,0 ,S_REGw ,REGI_DI},
+
+/* 0xc0 - 0xc7 */
+{L_MODRM ,5 ,0 ,M_GRP_Ib },{L_MODRM ,6 ,0 ,M_GRP_Ib },
+{L_POPw ,0 ,S_IPIw ,0 },{L_POPw ,0 ,S_IP ,0 },
+{L_MODRM ,O_SEGES ,S_SEGGw,M_Efw },{L_MODRM ,O_SEGDS ,S_SEGGw,M_Efw },
+{L_MODRM ,0 ,S_Eb ,M_Ib },{L_MODRM ,0 ,S_Ew ,M_Iw },
+/* 0xc8 - 0xcf */
+{D_ENTERw ,0 ,0 ,0 },{D_LEAVEw ,0 ,0 ,0 },
+{D_RETFwIw ,0 ,0 ,0 },{D_RETFw ,0 ,0 ,0 },
+{L_VAL ,O_INT ,0 ,3 },{L_Ib ,O_INT ,0 ,0 },
+{L_INTO ,O_INT ,0 ,0 },{D_IRETw ,0 ,0 ,0 },
+
+/* 0xd0 - 0xd7 */
+{L_MODRM ,5 ,0 ,M_GRP_1 },{L_MODRM ,6 ,0 ,M_GRP_1 },
+{L_MODRM ,5 ,0 ,M_GRP_CL },{L_MODRM ,6 ,0 ,M_GRP_CL },
+{L_Ib ,O_AAM ,0 ,0 },{L_Ib ,O_AAD ,0 ,0 },
+{D_SETALC ,0 ,0 ,0 },{D_XLAT ,0 ,0 ,0 },
+//TODO FPU
+/* 0xd8 - 0xdf */
+{L_MODRM ,O_FPU ,0 ,0 },{L_MODRM ,O_FPU ,1 ,0 },
+{L_MODRM ,O_FPU ,2 ,0 },{L_MODRM ,O_FPU ,3 ,0 },
+{L_MODRM ,O_FPU ,4 ,0 },{L_MODRM ,O_FPU ,5 ,0 },
+{L_MODRM ,O_FPU ,6 ,0 },{L_MODRM ,O_FPU ,7 ,0 },
+
+/* 0xe0 - 0xe7 */
+{L_Ibx ,O_LOOPNZ ,S_AIPw ,0 },{L_Ibx ,O_LOOPZ ,S_AIPw ,0 },
+{L_Ibx ,O_LOOP ,S_AIPw ,0 },{L_Ibx ,O_JCXZ ,S_AIPw ,0 },
+{L_Ib ,O_INb ,0 ,0 },{L_Ib ,O_INw ,0 ,0 },
+{L_Ib ,O_OUTb ,0 ,0 },{L_Ib ,O_OUTw ,0 ,0 },
+/* 0xe8 - 0xef */
+{L_Iw ,O_CALLNw ,S_AIPw ,0 },{L_Iwx ,0 ,S_AIPw ,0 },
+{L_Ifw ,O_JMPFw ,0 ,0 },{L_Ibx ,0 ,S_AIPw ,0 },
+{L_REGw ,O_INb ,0 ,REGI_DX},{L_REGw ,O_INw ,0 ,REGI_DX},
+{L_REGw ,O_OUTb ,0 ,REGI_DX},{L_REGw ,O_OUTw ,0 ,REGI_DX},
+
+/* 0xf0 - 0xf7 */
+{D_LOCK ,0 ,0 ,0 },{D_ICEBP ,0 ,0 ,0 },
+{L_PREREPNE ,0 ,0 ,0 },{L_PREREP ,0 ,0 ,0 },
+{D_HLT ,0 ,0 ,0 },{D_CMC ,0 ,0 ,0 },
+{L_MODRM ,8 ,0 ,M_GRP },{L_MODRM ,9 ,0 ,M_GRP },
+/* 0xf8 - 0xff */
+{D_CLC ,0 ,0 ,0 },{D_STC ,0 ,0 ,0 },
+{D_CLI ,0 ,0 ,0 },{D_STI ,0 ,0 ,0 },
+{D_CLD ,0 ,0 ,0 },{D_STD ,0 ,0 ,0 },
+{L_MODRM ,0xb ,0 ,M_GRP },{L_MODRM ,0xc ,0 ,M_GRP },
+
+/* 0x100 - 0x107 */
+{L_MODRM ,O_GRP6w ,S_Ew ,M_Ew },{L_MODRM ,O_GRP7w ,S_Ew ,M_Ew },
+{L_MODRM_NVM ,O_LAR ,S_Gw ,M_EwGw },{L_MODRM_NVM ,O_LSL ,S_Gw ,M_EwGw },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{D_CLTS ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x108 - 0x10f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x110 - 0x117 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x118 - 0x11f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x120 - 0x127 */
+{L_MODRM ,O_M_Rd_CRx ,S_Ed ,0 },{L_MODRM ,O_M_Rd_DRx ,S_Ed ,0 },
+{L_MODRM ,O_M_CRx_Rd ,0 ,M_Ed },{L_MODRM ,O_M_DRx_Rd ,0 ,M_Ed },
+{L_MODRM ,O_M_Rd_TRx ,S_Ed ,0 },{0 ,0 ,0 ,0 },
+{L_MODRM ,O_M_TRx_Rd ,0 ,M_Ed },{0 ,0 ,0 ,0 },
+
+/* 0x128 - 0x12f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x130 - 0x137 */
+{0 ,0 ,0 ,0 },{D_RDTSC ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x138 - 0x13f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x140 - 0x147 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x148 - 0x14f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x150 - 0x157 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x158 - 0x15f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x160 - 0x167 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x168 - 0x16f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+
+/* 0x170 - 0x177 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x178 - 0x17f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x180 - 0x187 */
+{L_Iwx ,O_C_O ,S_C_AIPw,0 },{L_Iwx ,O_C_NO ,S_C_AIPw,0 },
+{L_Iwx ,O_C_B ,S_C_AIPw,0 },{L_Iwx ,O_C_NB ,S_C_AIPw,0 },
+{L_Iwx ,O_C_Z ,S_C_AIPw,0 },{L_Iwx ,O_C_NZ ,S_C_AIPw,0 },
+{L_Iwx ,O_C_BE ,S_C_AIPw,0 },{L_Iwx ,O_C_NBE ,S_C_AIPw,0 },
+/* 0x188 - 0x18f */
+{L_Iwx ,O_C_S ,S_C_AIPw,0 },{L_Iwx ,O_C_NS ,S_C_AIPw,0 },
+{L_Iwx ,O_C_P ,S_C_AIPw,0 },{L_Iwx ,O_C_NP ,S_C_AIPw,0 },
+{L_Iwx ,O_C_L ,S_C_AIPw,0 },{L_Iwx ,O_C_NL ,S_C_AIPw,0 },
+{L_Iwx ,O_C_LE ,S_C_AIPw,0 },{L_Iwx ,O_C_NLE ,S_C_AIPw,0 },
+
+/* 0x190 - 0x197 */
+{L_MODRM ,O_C_O ,S_C_Eb,0 },{L_MODRM ,O_C_NO ,S_C_Eb,0 },
+{L_MODRM ,O_C_B ,S_C_Eb,0 },{L_MODRM ,O_C_NB ,S_C_Eb,0 },
+{L_MODRM ,O_C_Z ,S_C_Eb,0 },{L_MODRM ,O_C_NZ ,S_C_Eb,0 },
+{L_MODRM ,O_C_BE ,S_C_Eb,0 },{L_MODRM ,O_C_NBE ,S_C_Eb,0 },
+/* 0x198 - 0x19f */
+{L_MODRM ,O_C_S ,S_C_Eb,0 },{L_MODRM ,O_C_NS ,S_C_Eb,0 },
+{L_MODRM ,O_C_P ,S_C_Eb,0 },{L_MODRM ,O_C_NP ,S_C_Eb,0 },
+{L_MODRM ,O_C_L ,S_C_Eb,0 },{L_MODRM ,O_C_NL ,S_C_Eb,0 },
+{L_MODRM ,O_C_LE ,S_C_Eb,0 },{L_MODRM ,O_C_NLE ,S_C_Eb,0 },
+
+/* 0x1a0 - 0x1a7 */
+{L_SEG ,0 ,S_PUSHw ,fs },{D_POPSEGw,0 ,0 ,fs },
+{D_CPUID ,0 ,0 ,0 },{L_MODRM ,O_BTw ,S_Ew ,M_EwGwt },
+{L_MODRM ,O_DSHLw ,S_Ew,M_EwGwIb },{L_MODRM ,O_DSHLw ,S_Ew ,M_EwGwCL },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x1a8 - 0x1af */
+{L_SEG ,0 ,S_PUSHw ,gs },{D_POPSEGw,0 ,0 ,gs },
+{0 ,0 ,0 ,0 },{L_MODRM ,O_BTSw ,S_Ew ,M_EwGwt },
+{L_MODRM ,O_DSHRw ,S_Ew,M_EwGwIb },{L_MODRM ,O_DSHRw ,S_Ew ,M_EwGwCL },
+{0 ,0 ,0 ,0 },{L_MODRM ,O_IMULRw ,S_Gw ,M_EwxGwx },
+
+/* 0x1b0 - 0x1b7 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{L_MODRM ,O_SEGSS ,S_SEGGw,M_Efw },{L_MODRM ,O_BTRw ,S_Ew ,M_EwGwt },
+{L_MODRM ,O_SEGFS ,S_SEGGw,M_Efw },{L_MODRM ,O_SEGGS ,S_SEGGw,M_Efw },
+{L_MODRM ,0 ,S_Gw ,M_Eb },{L_MODRM ,0 ,S_Gw ,M_Ew },
+/* 0x1b8 - 0x1bf */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{L_MODRM ,0xe ,0 ,M_GRP },{L_MODRM ,O_BTCw ,S_Ew ,M_EwGwt },
+{L_MODRM ,O_BSFw ,S_Gw ,M_Ew },{L_MODRM ,O_BSRw ,S_Gw ,M_Ew },
+{L_MODRM ,0 ,S_Gw ,M_Ebx },{L_MODRM ,0 ,S_Gw ,M_Ewx },
+
+/* 0x1c0 - 0x1cc */
+{L_MODRM ,t_ADDb ,S_EbGb ,M_GbEb },{L_MODRM ,t_ADDw ,S_EwGw ,M_GwEw },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x1c8 - 0x1cf */
+{L_REGw ,O_BSWAPw ,S_REGw ,REGI_AX},{L_REGw ,O_BSWAPw ,S_REGw ,REGI_CX},
+{L_REGw ,O_BSWAPw ,S_REGw ,REGI_DX},{L_REGw ,O_BSWAPw ,S_REGw ,REGI_BX},
+{L_REGw ,O_BSWAPw ,S_REGw ,REGI_SP},{L_REGw ,O_BSWAPw ,S_REGw ,REGI_BP},
+{L_REGw ,O_BSWAPw ,S_REGw ,REGI_SI},{L_REGw ,O_BSWAPw ,S_REGw ,REGI_DI},
+
+/* 0x1d0 - 0x1d7 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x1d8 - 0x1df */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x1e0 - 0x1ee */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x1e8 - 0x1ef */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x1f0 - 0x1fc */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x1f8 - 0x1ff */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+
+/* 0x200 - 0x207 */
+{L_MODRM ,t_ADDb ,S_Eb ,M_EbGb },{L_MODRM ,t_ADDd ,S_Ed ,M_EdGd },
+{L_MODRM ,t_ADDb ,S_Gb ,M_GbEb },{L_MODRM ,t_ADDd ,S_Gd ,M_GdEd },
+{L_REGbIb ,t_ADDb ,S_REGb ,REGI_AL },{L_REGdId ,t_ADDd ,S_REGd ,REGI_AX },
+{L_SEG ,0 ,S_PUSHd,es },{D_POPSEGd,0 ,0 ,es },
+/* 0x208 - 0x20f */
+{L_MODRM ,t_ORb ,S_Eb ,M_EbGb },{L_MODRM ,t_ORd ,S_Ed ,M_EdGd },
+{L_MODRM ,t_ORb ,S_Gb ,M_GbEb },{L_MODRM ,t_ORd ,S_Gd ,M_GdEd },
+{L_REGbIb ,t_ORb ,S_REGb ,REGI_AL },{L_REGdId ,t_ORd ,S_REGd ,REGI_AX },
+{L_SEG ,0 ,S_PUSHd,cs },{L_DOUBLE ,0 ,0 ,0 },
+
+/* 0x210 - 0x217 */
+{L_MODRM ,t_ADCb ,S_Eb ,M_EbGb },{L_MODRM ,t_ADCd ,S_Ed ,M_EdGd },
+{L_MODRM ,t_ADCb ,S_Gb ,M_GbEb },{L_MODRM ,t_ADCd ,S_Gd ,M_GdEd },
+{L_REGbIb ,t_ADCb ,S_REGb ,REGI_AL },{L_REGdId ,t_ADCd ,S_REGd ,REGI_AX },
+{L_SEG ,0 ,S_PUSHd,ss },{D_POPSEGd,0 ,0 ,ss },
+/* 0x218 - 0x21f */
+{L_MODRM ,t_SBBb ,S_Eb ,M_EbGb },{L_MODRM ,t_SBBd ,S_Ed ,M_EdGd },
+{L_MODRM ,t_SBBb ,S_Gb ,M_GbEb },{L_MODRM ,t_SBBd ,S_Gd ,M_GdEd },
+{L_REGbIb ,t_SBBb ,S_REGb ,REGI_AL },{L_REGdId ,t_SBBd ,S_REGd ,REGI_AX },
+{L_SEG ,0 ,S_PUSHd,ds },{D_POPSEGd,0 ,0 ,ds },
+
+/* 0x220 - 0x227 */
+{L_MODRM ,t_ANDb ,S_Eb ,M_EbGb },{L_MODRM ,t_ANDd ,S_Ed ,M_EdGd },
+{L_MODRM ,t_ANDb ,S_Gb ,M_GbEb },{L_MODRM ,t_ANDd ,S_Gd ,M_GdEd },
+{L_REGbIb ,t_ANDb ,S_REGb ,REGI_AL },{L_REGdId ,t_ANDd ,S_REGd ,REGI_AX },
+{L_PRESEG ,0 ,0 ,es },{D_DAA ,0 ,0 ,0 },
+/* 0x228 - 0x22f */
+{L_MODRM ,t_SUBb ,S_Eb ,M_EbGb },{L_MODRM ,t_SUBd ,S_Ed ,M_EdGd },
+{L_MODRM ,t_SUBb ,S_Gb ,M_GbEb },{L_MODRM ,t_SUBd ,S_Gd ,M_GdEd },
+{L_REGbIb ,t_SUBb ,S_REGb ,REGI_AL },{L_REGdId ,t_SUBd ,S_REGd ,REGI_AX },
+{L_PRESEG ,0 ,0 ,cs },{D_DAS ,0 ,0 ,0 },
+
+/* 0x230 - 0x237 */
+{L_MODRM ,t_XORb ,S_Eb ,M_EbGb },{L_MODRM ,t_XORd ,S_Ed ,M_EdGd },
+{L_MODRM ,t_XORb ,S_Gb ,M_GbEb },{L_MODRM ,t_XORd ,S_Gd ,M_GdEd },
+{L_REGbIb ,t_XORb ,S_REGb ,REGI_AL },{L_REGdId ,t_XORd ,S_REGd ,REGI_AX },
+{L_PRESEG ,0 ,0 ,ss },{D_AAA ,0 ,0 ,0 },
+/* 0x238 - 0x23f */
+{L_MODRM ,t_CMPb ,0 ,M_EbGb },{L_MODRM ,t_CMPd ,0 ,M_EdGd },
+{L_MODRM ,t_CMPb ,0 ,M_GbEb },{L_MODRM ,t_CMPd ,0 ,M_GdEd },
+{L_REGbIb ,t_CMPb ,0 ,REGI_AL },{L_REGdId ,t_CMPd ,0 ,REGI_AX },
+{L_PRESEG ,0 ,0 ,ds },{D_AAS ,0 ,0 ,0 },
+
+/* 0x240 - 0x247 */
+{L_REGd ,t_INCd ,S_REGd ,REGI_AX},{L_REGd ,t_INCd ,S_REGd ,REGI_CX},
+{L_REGd ,t_INCd ,S_REGd ,REGI_DX},{L_REGd ,t_INCd ,S_REGd ,REGI_BX},
+{L_REGd ,t_INCd ,S_REGd ,REGI_SP},{L_REGd ,t_INCd ,S_REGd ,REGI_BP},
+{L_REGd ,t_INCd ,S_REGd ,REGI_SI},{L_REGd ,t_INCd ,S_REGd ,REGI_DI},
+/* 0x248 - 0x24f */
+{L_REGd ,t_DECd ,S_REGd ,REGI_AX},{L_REGd ,t_DECd ,S_REGd ,REGI_CX},
+{L_REGd ,t_DECd ,S_REGd ,REGI_DX},{L_REGd ,t_DECd ,S_REGd ,REGI_BX},
+{L_REGd ,t_DECd ,S_REGd ,REGI_SP},{L_REGd ,t_DECd ,S_REGd ,REGI_BP},
+{L_REGd ,t_DECd ,S_REGd ,REGI_SI},{L_REGd ,t_DECd ,S_REGd ,REGI_DI},
+
+/* 0x250 - 0x257 */
+{L_REGd ,0 ,S_PUSHd,REGI_AX},{L_REGd ,0 ,S_PUSHd,REGI_CX},
+{L_REGd ,0 ,S_PUSHd,REGI_DX},{L_REGd ,0 ,S_PUSHd,REGI_BX},
+{L_REGd ,0 ,S_PUSHd,REGI_SP},{L_REGd ,0 ,S_PUSHd,REGI_BP},
+{L_REGd ,0 ,S_PUSHd,REGI_SI},{L_REGd ,0 ,S_PUSHd,REGI_DI},
+/* 0x258 - 0x25f */
+{L_POPd ,0 ,S_REGd ,REGI_AX},{L_POPd ,0 ,S_REGd ,REGI_CX},
+{L_POPd ,0 ,S_REGd ,REGI_DX},{L_POPd ,0 ,S_REGd ,REGI_BX},
+{L_POPd ,0 ,S_REGd ,REGI_SP},{L_POPd ,0 ,S_REGd ,REGI_BP},
+{L_POPd ,0 ,S_REGd ,REGI_SI},{L_POPd ,0 ,S_REGd ,REGI_DI},
+
+/* 0x260 - 0x267 */
+{D_PUSHAd ,0 ,0 ,0 },{D_POPAd ,0 ,0 ,0 },
+{L_MODRM ,O_BOUNDd ,0 ,0 },{0 ,0 ,0 ,0 },
+{L_PRESEG ,0 ,0 ,fs },{L_PRESEG ,0 ,0 ,gs },
+{L_PREOP ,0 ,0 ,0 },{L_PREADD ,0 ,0 ,0 },
+/* 0x268 - 0x26f */
+{L_Id ,0 ,S_PUSHd,0 },{L_MODRM ,O_IMULRd ,S_Gd ,M_EdId},
+{L_Ibx ,0 ,S_PUSHd,0 },{L_MODRM ,O_IMULRd ,S_Gd ,M_EdIbx},
+{L_STRING ,R_INSB ,0 ,0 },{L_STRING ,R_INSD ,0 ,0 },
+{L_STRING ,R_OUTSB ,0 ,0 },{L_STRING ,R_OUTSD ,0 ,0 },
+
+/* 0x270 - 0x277 */
+{L_Ibx ,O_C_O ,S_C_AIPd,0 },{L_Ibx ,O_C_NO ,S_C_AIPd,0 },
+{L_Ibx ,O_C_B ,S_C_AIPd,0 },{L_Ibx ,O_C_NB ,S_C_AIPd,0 },
+{L_Ibx ,O_C_Z ,S_C_AIPd,0 },{L_Ibx ,O_C_NZ ,S_C_AIPd,0 },
+{L_Ibx ,O_C_BE ,S_C_AIPd,0 },{L_Ibx ,O_C_NBE ,S_C_AIPd,0 },
+/* 0x278 - 0x27f */
+{L_Ibx ,O_C_S ,S_C_AIPd,0 },{L_Ibx ,O_C_NS ,S_C_AIPd,0 },
+{L_Ibx ,O_C_P ,S_C_AIPd,0 },{L_Ibx ,O_C_NP ,S_C_AIPd,0 },
+{L_Ibx ,O_C_L ,S_C_AIPd,0 },{L_Ibx ,O_C_NL ,S_C_AIPd,0 },
+{L_Ibx ,O_C_LE ,S_C_AIPd,0 },{L_Ibx ,O_C_NLE ,S_C_AIPd,0 },
+
+/* 0x280 - 0x287 */
+{L_MODRM ,0 ,0 ,M_GRP },{L_MODRM ,2 ,0 ,M_GRP },
+{L_MODRM ,0 ,0 ,M_GRP },{L_MODRM ,4 ,0 ,M_GRP },
+{L_MODRM ,t_TESTb ,0 ,M_EbGb },{L_MODRM ,t_TESTd ,0 ,M_EdGd },
+{L_MODRM ,0 ,S_EbGb ,M_GbEb },{L_MODRM ,0 ,S_EdGd ,M_GdEd },
+/* 0x288 - 0x28f */
+{L_MODRM ,0 ,S_Eb ,M_Gb },{L_MODRM ,0 ,S_Ed ,M_Gd },
+{L_MODRM ,0 ,S_Gb ,M_Eb },{L_MODRM ,0 ,S_Gd ,M_Ed },
+{L_MODRM ,0 ,S_EdMw ,M_SEG },{L_MODRM ,0 ,S_Gd ,M_EA },
+{L_MODRM ,0 ,S_SEGm ,M_Ew },{L_POPdRM ,0 ,S_Ed ,M_None },
+
+/* 0x290 - 0x297 */
+{D_NOP ,0 ,0 ,0 },{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_CX},
+{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_DX},{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_BX},
+{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_SP},{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_BP},
+{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_SI},{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_DI},
+/* 0x298 - 0x29f */
+{D_CWDE ,0 ,0 ,0 },{D_CDQ ,0 ,0 ,0 },
+{L_Ifd ,O_CALLFd ,0 ,0 },{D_WAIT ,0 ,0 ,0 },
+{D_PUSHF ,0 ,0 ,true },{D_POPF ,0 ,0 ,true },
+{D_SAHF ,0 ,0 ,0 },{D_LAHF ,0 ,0 ,0 },
+
+/* 0x2a0 - 0x2a7 */
+{L_OP ,O_ALOP ,0 ,0 },{L_OP ,O_EAXOP ,0 ,0 },
+{L_OP ,O_OPAL ,0 ,0 },{L_OP ,O_OPEAX ,0 ,0 },
+{L_STRING ,R_MOVSB ,0 ,0 },{L_STRING ,R_MOVSD ,0 ,0 },
+{L_STRING ,R_CMPSB ,0 ,0 },{L_STRING ,R_CMPSD ,0 ,0 },
+/* 0x2a8 - 0x2af */
+{L_REGbIb ,t_TESTb ,0 ,REGI_AL},{L_REGdId ,t_TESTd ,0 ,REGI_AX},
+{L_STRING ,R_STOSB ,0 ,0 },{L_STRING ,R_STOSD ,0 ,0 },
+{L_STRING ,R_LODSB ,0 ,0 },{L_STRING ,R_LODSD ,0 ,0 },
+{L_STRING ,R_SCASB ,0 ,0 },{L_STRING ,R_SCASD ,0 ,0 },
+
+/* 0x2b0 - 0x2b7 */
+{L_Ib ,0 ,S_REGb ,REGI_AL},{L_Ib ,0 ,S_REGb ,REGI_CL},
+{L_Ib ,0 ,S_REGb ,REGI_DL},{L_Ib ,0 ,S_REGb ,REGI_BL},
+{L_Ib ,0 ,S_REGb ,REGI_AH},{L_Ib ,0 ,S_REGb ,REGI_CH},
+{L_Ib ,0 ,S_REGb ,REGI_DH},{L_Ib ,0 ,S_REGb ,REGI_BH},
+/* 0x2b8 - 0x2bf */
+{L_Id ,0 ,S_REGd ,REGI_AX},{L_Id ,0 ,S_REGd ,REGI_CX},
+{L_Id ,0 ,S_REGd ,REGI_DX},{L_Id ,0 ,S_REGd ,REGI_BX},
+{L_Id ,0 ,S_REGd ,REGI_SP},{L_Id ,0 ,S_REGd ,REGI_BP},
+{L_Id ,0 ,S_REGd ,REGI_SI},{L_Id ,0 ,S_REGd ,REGI_DI},
+
+/* 0x2c0 - 0x2c7 */
+{L_MODRM ,5 ,0 ,M_GRP_Ib },{L_MODRM ,7 ,0 ,M_GRP_Ib },
+{L_POPd ,0 ,S_IPIw ,0 },{L_POPd ,0 ,S_IP ,0 },
+{L_MODRM ,O_SEGES ,S_SEGGd,M_Efd },{L_MODRM ,O_SEGDS ,S_SEGGd,M_Efd },
+{L_MODRM ,0 ,S_Eb ,M_Ib },{L_MODRM ,0 ,S_Ed ,M_Id },
+/* 0x2c8 - 0x2cf */
+{D_ENTERd ,0 ,0 ,0 },{D_LEAVEd ,0 ,0 ,0 },
+{D_RETFdIw ,0 ,0 ,0 },{D_RETFd ,0 ,0 ,0 },
+{L_VAL ,O_INT ,0 ,3 },{L_Ib ,O_INT ,0 ,0 },
+{L_INTO ,O_INT ,0 ,0 },{D_IRETd ,0 ,0 ,0 },
+
+/* 0x2d0 - 0x2d7 */
+{L_MODRM ,5 ,0 ,M_GRP_1 },{L_MODRM ,7 ,0 ,M_GRP_1 },
+{L_MODRM ,5 ,0 ,M_GRP_CL },{L_MODRM ,7 ,0 ,M_GRP_CL },
+{L_Ib ,O_AAM ,0 ,0 },{L_Ib ,O_AAD ,0 ,0 },
+{D_SETALC ,0 ,0 ,0 },{D_XLAT ,0 ,0 ,0 },
+/* 0x2d8 - 0x2df */
+{L_MODRM ,O_FPU ,0 ,0 },{L_MODRM ,O_FPU ,1 ,0 },
+{L_MODRM ,O_FPU ,2 ,0 },{L_MODRM ,O_FPU ,3 ,0 },
+{L_MODRM ,O_FPU ,4 ,0 },{L_MODRM ,O_FPU ,5 ,0 },
+{L_MODRM ,O_FPU ,6 ,0 },{L_MODRM ,O_FPU ,7 ,0 },
+
+/* 0x2e0 - 0x2e7 */
+{L_Ibx ,O_LOOPNZ ,S_AIPd ,0 },{L_Ibx ,O_LOOPZ ,S_AIPd ,0 },
+{L_Ibx ,O_LOOP ,S_AIPd ,0 },{L_Ibx ,O_JCXZ ,S_AIPd ,0 },
+{L_Ib ,O_INb ,0 ,0 },{L_Ib ,O_INd ,0 ,0 },
+{L_Ib ,O_OUTb ,0 ,0 },{L_Ib ,O_OUTd ,0 ,0 },
+/* 0x2e8 - 0x2ef */
+{L_Id ,O_CALLNd ,S_AIPd ,0 },{L_Idx ,0 ,S_AIPd ,0 },
+{L_Ifd ,O_JMPFd ,0 ,0 },{L_Ibx ,0 ,S_AIPd ,0 },
+{L_REGw ,O_INb ,0 ,REGI_DX},{L_REGw ,O_INd ,0 ,REGI_DX},
+{L_REGw ,O_OUTb ,0 ,REGI_DX},{L_REGw ,O_OUTd ,0 ,REGI_DX},
+
+/* 0x2f0 - 0x2f7 */
+{D_LOCK ,0 ,0 ,0 },{D_ICEBP ,0 ,0 ,0 },
+{L_PREREPNE ,0 ,0 ,0 },{L_PREREP ,0 ,0 ,0 },
+{D_HLT ,0 ,0 ,0 },{D_CMC ,0 ,0 ,0 },
+{L_MODRM ,8 ,0 ,M_GRP },{L_MODRM ,0xa ,0 ,M_GRP },
+/* 0x2f8 - 0x2ff */
+{D_CLC ,0 ,0 ,0 },{D_STC ,0 ,0 ,0 },
+{D_CLI ,0 ,0 ,0 },{D_STI ,0 ,0 ,0 },
+{D_CLD ,0 ,0 ,0 },{D_STD ,0 ,0 ,0 },
+{L_MODRM ,0xb ,0 ,M_GRP },{L_MODRM ,0xd ,0 ,M_GRP },
+
+
+/* 0x300 - 0x307 */
+{L_MODRM ,O_GRP6d ,S_Ew ,M_Ew },{L_MODRM ,O_GRP7d ,S_Ew ,M_Ew },
+{L_MODRM_NVM ,O_LAR ,S_Gd ,M_EdGd },{L_MODRM_NVM ,O_LSL ,S_Gd ,M_EdGd },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{D_CLTS ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x308 - 0x30f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x310 - 0x317 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x318 - 0x31f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x320 - 0x327 */
+{L_MODRM ,O_M_Rd_CRx ,S_Ed ,0 },{L_MODRM ,O_M_Rd_DRx ,S_Ed ,0 },
+{L_MODRM ,O_M_CRx_Rd ,0 ,M_Ed },{L_MODRM ,O_M_DRx_Rd ,0 ,M_Ed },
+{L_MODRM ,O_M_Rd_TRx ,S_Ed ,0 },{0 ,0 ,0 ,0 },
+{L_MODRM ,O_M_TRx_Rd ,0 ,M_Ed },{0 ,0 ,0 ,0 },
+
+/* 0x328 - 0x32f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x330 - 0x337 */
+{0 ,0 ,0 ,0 },{D_RDTSC ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x338 - 0x33f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x340 - 0x347 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x348 - 0x34f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x350 - 0x357 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x358 - 0x35f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x360 - 0x367 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x368 - 0x36f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+
+/* 0x370 - 0x377 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x378 - 0x37f */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x380 - 0x387 */
+{L_Idx ,O_C_O ,S_C_AIPd,0 },{L_Idx ,O_C_NO ,S_C_AIPd,0 },
+{L_Idx ,O_C_B ,S_C_AIPd,0 },{L_Idx ,O_C_NB ,S_C_AIPd,0 },
+{L_Idx ,O_C_Z ,S_C_AIPd,0 },{L_Idx ,O_C_NZ ,S_C_AIPd,0 },
+{L_Idx ,O_C_BE ,S_C_AIPd,0 },{L_Idx ,O_C_NBE ,S_C_AIPd,0 },
+/* 0x388 - 0x38f */
+{L_Idx ,O_C_S ,S_C_AIPd,0 },{L_Idx ,O_C_NS ,S_C_AIPd,0 },
+{L_Idx ,O_C_P ,S_C_AIPd,0 },{L_Idx ,O_C_NP ,S_C_AIPd,0 },
+{L_Idx ,O_C_L ,S_C_AIPd,0 },{L_Idx ,O_C_NL ,S_C_AIPd,0 },
+{L_Idx ,O_C_LE ,S_C_AIPd,0 },{L_Idx ,O_C_NLE ,S_C_AIPd,0 },
+
+/* 0x390 - 0x397 */
+{L_MODRM ,O_C_O ,S_C_Eb,0 },{L_MODRM ,O_C_NO ,S_C_Eb,0 },
+{L_MODRM ,O_C_B ,S_C_Eb,0 },{L_MODRM ,O_C_NB ,S_C_Eb,0 },
+{L_MODRM ,O_C_Z ,S_C_Eb,0 },{L_MODRM ,O_C_NZ ,S_C_Eb,0 },
+{L_MODRM ,O_C_BE ,S_C_Eb,0 },{L_MODRM ,O_C_NBE ,S_C_Eb,0 },
+/* 0x398 - 0x39f */
+{L_MODRM ,O_C_S ,S_C_Eb,0 },{L_MODRM ,O_C_NS ,S_C_Eb,0 },
+{L_MODRM ,O_C_P ,S_C_Eb,0 },{L_MODRM ,O_C_NP ,S_C_Eb,0 },
+{L_MODRM ,O_C_L ,S_C_Eb,0 },{L_MODRM ,O_C_NL ,S_C_Eb,0 },
+{L_MODRM ,O_C_LE ,S_C_Eb,0 },{L_MODRM ,O_C_NLE ,S_C_Eb,0 },
+
+/* 0x3a0 - 0x3a7 */
+{L_SEG ,0 ,S_PUSHd ,fs },{D_POPSEGd,0 ,0 ,fs },
+{D_CPUID ,0 ,0 ,0 },{L_MODRM ,O_BTd ,S_Ed ,M_EdGdt },
+{L_MODRM ,O_DSHLd ,S_Ed,M_EdGdIb },{L_MODRM ,O_DSHLd ,S_Ed ,M_EdGdCL },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x3a8 - 0x3af */
+{L_SEG ,0 ,S_PUSHd ,gs },{D_POPSEGd,0 ,0 ,gs },
+{0 ,0 ,0 ,0 },{L_MODRM ,O_BTSd ,S_Ed ,M_EdGdt },
+{L_MODRM ,O_DSHRd ,S_Ed,M_EdGdIb },{L_MODRM ,O_DSHRd ,S_Ed ,M_EdGdCL },
+{0 ,0 ,0 ,0 },{L_MODRM ,O_IMULRd ,S_Gd ,M_EdxGdx },
+
+/* 0x3b0 - 0x3b7 */
+{0 ,0 ,0 ,0 },{L_MODRM ,O_CMPXCHG ,S_Ed ,M_Ed },
+{L_MODRM ,O_SEGSS ,S_SEGGd,M_Efd },{L_MODRM ,O_BTRd ,S_Ed ,M_EdGdt },
+{L_MODRM ,O_SEGFS ,S_SEGGd,M_Efd },{L_MODRM ,O_SEGGS ,S_SEGGd,M_Efd },
+{L_MODRM ,0 ,S_Gd ,M_Eb },{L_MODRM ,0 ,S_Gd ,M_Ew },
+/* 0x3b8 - 0x3bf */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{L_MODRM ,0xf ,0 ,M_GRP },{L_MODRM ,O_BTCd ,S_Ed ,M_EdGdt },
+{L_MODRM ,O_BSFd ,S_Gd ,M_Ed },{L_MODRM ,O_BSRd ,S_Gd ,M_Ed },
+{L_MODRM ,0 ,S_Gd ,M_Ebx },{L_MODRM ,0 ,S_Gd ,M_Ewx },
+
+/* 0x3c0 - 0x3cc */
+{L_MODRM ,t_ADDb ,S_EbGb ,M_GbEb },{L_MODRM ,t_ADDd ,S_EdGd ,M_GdEd },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x3c8 - 0x3cf */
+{L_REGd ,O_BSWAPd ,S_REGd ,REGI_AX},{L_REGd ,O_BSWAPd ,S_REGd ,REGI_CX},
+{L_REGd ,O_BSWAPd ,S_REGd ,REGI_DX},{L_REGd ,O_BSWAPd ,S_REGd ,REGI_BX},
+{L_REGd ,O_BSWAPd ,S_REGd ,REGI_SP},{L_REGd ,O_BSWAPd ,S_REGd ,REGI_BP},
+{L_REGd ,O_BSWAPd ,S_REGd ,REGI_SI},{L_REGd ,O_BSWAPd ,S_REGd ,REGI_DI},
+
+/* 0x3d0 - 0x3d7 */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x3d8 - 0x3df */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x3e0 - 0x3ee */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x3e8 - 0x3ef */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+/* 0x3f0 - 0x3fc */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+/* 0x3f8 - 0x3ff */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+
+};
+
+static OpCode Groups[16][8]={
+{ /* 0x00 Group 1 Eb,Ib */
+{0 ,t_ADDb ,S_Eb ,M_EbIb },{0 ,t_ORb ,S_Eb ,M_EbIb },
+{0 ,t_ADCb ,S_Eb ,M_EbIb },{0 ,t_SBBb ,S_Eb ,M_EbIb },
+{0 ,t_ANDb ,S_Eb ,M_EbIb },{0 ,t_SUBb ,S_Eb ,M_EbIb },
+{0 ,t_XORb ,S_Eb ,M_EbIb },{0 ,t_CMPb ,0 ,M_EbIb },
+},{ /* 0x01 Group 1 Ew,Iw */
+{0 ,t_ADDw ,S_Ew ,M_EwIw },{0 ,t_ORw ,S_Ew ,M_EwIw },
+{0 ,t_ADCw ,S_Ew ,M_EwIw },{0 ,t_SBBw ,S_Ew ,M_EwIw },
+{0 ,t_ANDw ,S_Ew ,M_EwIw },{0 ,t_SUBw ,S_Ew ,M_EwIw },
+{0 ,t_XORw ,S_Ew ,M_EwIw },{0 ,t_CMPw ,0 ,M_EwIw },
+},{ /* 0x02 Group 1 Ed,Id */
+{0 ,t_ADDd ,S_Ed ,M_EdId },{0 ,t_ORd ,S_Ed ,M_EdId },
+{0 ,t_ADCd ,S_Ed ,M_EdId },{0 ,t_SBBd ,S_Ed ,M_EdId },
+{0 ,t_ANDd ,S_Ed ,M_EdId },{0 ,t_SUBd ,S_Ed ,M_EdId },
+{0 ,t_XORd ,S_Ed ,M_EdId },{0 ,t_CMPd ,0 ,M_EdId },
+},{ /* 0x03 Group 1 Ew,Ibx */
+{0 ,t_ADDw ,S_Ew ,M_EwIbx },{0 ,t_ORw ,S_Ew ,M_EwIbx },
+{0 ,t_ADCw ,S_Ew ,M_EwIbx },{0 ,t_SBBw ,S_Ew ,M_EwIbx },
+{0 ,t_ANDw ,S_Ew ,M_EwIbx },{0 ,t_SUBw ,S_Ew ,M_EwIbx },
+{0 ,t_XORw ,S_Ew ,M_EwIbx },{0 ,t_CMPw ,0 ,M_EwIbx },
+},{ /* 0x04 Group 1 Ed,Ibx */
+{0 ,t_ADDd ,S_Ed ,M_EdIbx },{0 ,t_ORd ,S_Ed ,M_EdIbx },
+{0 ,t_ADCd ,S_Ed ,M_EdIbx },{0 ,t_SBBd ,S_Ed ,M_EdIbx },
+{0 ,t_ANDd ,S_Ed ,M_EdIbx },{0 ,t_SUBd ,S_Ed ,M_EdIbx },
+{0 ,t_XORd ,S_Ed ,M_EdIbx },{0 ,t_CMPd ,0 ,M_EdIbx },
+
+},{ /* 0x05 Group 2 Eb,XXX */
+{0 ,t_ROLb ,S_Eb ,M_Eb },{0 ,t_RORb ,S_Eb ,M_Eb },
+{0 ,t_RCLb ,S_Eb ,M_Eb },{0 ,t_RCRb ,S_Eb ,M_Eb },
+{0 ,t_SHLb ,S_Eb ,M_Eb },{0 ,t_SHRb ,S_Eb ,M_Eb },
+{0 ,t_SHLb ,S_Eb ,M_Eb },{0 ,t_SARb ,S_Eb ,M_Eb },
+},{ /* 0x06 Group 2 Ew,XXX */
+{0 ,t_ROLw ,S_Ew ,M_Ew },{0 ,t_RORw ,S_Ew ,M_Ew },
+{0 ,t_RCLw ,S_Ew ,M_Ew },{0 ,t_RCRw ,S_Ew ,M_Ew },
+{0 ,t_SHLw ,S_Ew ,M_Ew },{0 ,t_SHRw ,S_Ew ,M_Ew },
+{0 ,t_SHLw ,S_Ew ,M_Ew },{0 ,t_SARw ,S_Ew ,M_Ew },
+},{ /* 0x07 Group 2 Ed,XXX */
+{0 ,t_ROLd ,S_Ed ,M_Ed },{0 ,t_RORd ,S_Ed ,M_Ed },
+{0 ,t_RCLd ,S_Ed ,M_Ed },{0 ,t_RCRd ,S_Ed ,M_Ed },
+{0 ,t_SHLd ,S_Ed ,M_Ed },{0 ,t_SHRd ,S_Ed ,M_Ed },
+{0 ,t_SHLd ,S_Ed ,M_Ed },{0 ,t_SARd ,S_Ed ,M_Ed },
+
+
+},{ /* 0x08 Group 3 Eb */
+{0 ,t_TESTb ,0 ,M_EbIb },{0 ,t_TESTb ,0 ,M_EbIb },
+{0 ,O_NOT ,S_Eb ,M_Eb },{0 ,t_NEGb ,S_Eb ,M_Eb },
+{0 ,O_MULb ,0 ,M_Eb },{0 ,O_IMULb ,0 ,M_Eb },
+{0 ,O_DIVb ,0 ,M_Eb },{0 ,O_IDIVb ,0 ,M_Eb },
+},{ /* 0x09 Group 3 Ew */
+{0 ,t_TESTw ,0 ,M_EwIw },{0 ,t_TESTw ,0 ,M_EwIw },
+{0 ,O_NOT ,S_Ew ,M_Ew },{0 ,t_NEGw ,S_Ew ,M_Ew },
+{0 ,O_MULw ,0 ,M_Ew },{0 ,O_IMULw ,0 ,M_Ew },
+{0 ,O_DIVw ,0 ,M_Ew },{0 ,O_IDIVw ,0 ,M_Ew },
+},{ /* 0x0a Group 3 Ed */
+{0 ,t_TESTd ,0 ,M_EdId },{0 ,t_TESTd ,0 ,M_EdId },
+{0 ,O_NOT ,S_Ed ,M_Ed },{0 ,t_NEGd ,S_Ed ,M_Ed },
+{0 ,O_MULd ,0 ,M_Ed },{0 ,O_IMULd ,0 ,M_Ed },
+{0 ,O_DIVd ,0 ,M_Ed },{0 ,O_IDIVd ,0 ,M_Ed },
+
+},{ /* 0x0b Group 4 Eb */
+{0 ,t_INCb ,S_Eb ,M_Eb },{0 ,t_DECb ,S_Eb ,M_Eb },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,O_CBACK ,0 ,M_Iw },
+},{ /* 0x0c Group 5 Ew */
+{0 ,t_INCw ,S_Ew ,M_Ew },{0 ,t_DECw ,S_Ew ,M_Ew },
+{0 ,O_CALLNw ,S_IP ,M_Ew },{0 ,O_CALLFw ,0 ,M_Efw },
+{0 ,0 ,S_IP ,M_Ew },{0 ,O_JMPFw ,0 ,M_Efw },
+{0 ,0 ,S_PUSHw,M_Ew },{0 ,0 ,0 ,0 },
+},{ /* 0x0d Group 5 Ed */
+{0 ,t_INCd ,S_Ed ,M_Ed },{0 ,t_DECd ,S_Ed ,M_Ed },
+{0 ,O_CALLNd ,S_IP ,M_Ed },{0 ,O_CALLFd ,0 ,M_Efd },
+{0 ,0 ,S_IP ,M_Ed },{0 ,O_JMPFd ,0 ,M_Efd },
+{0 ,0 ,S_PUSHd,M_Ed },{0 ,0 ,0 ,0 },
+
+
+},{ /* 0x0e Group 8 Ew */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,O_BTw ,S_Ew ,M_EwIb },{0 ,O_BTSw ,S_Ew ,M_EwIb },
+{0 ,O_BTRw ,S_Ew ,M_EwIb },{0 ,O_BTCw ,S_Ew ,M_EwIb },
+},{ /* 0x0f Group 8 Ed */
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
+{0 ,O_BTd ,S_Ed ,M_EdIb },{0 ,O_BTSd ,S_Ed ,M_EdIb },
+{0 ,O_BTRd ,S_Ed ,M_EdIb },{0 ,O_BTCd ,S_Ed ,M_EdIb },
+
+
+
+}
+};
+
+
+
--- /dev/null
+/*
+ * 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.
+ */
+
+/* Write the data from the opcode */
+switch (inst.code.save) {
+/* Byte */
+ case S_C_Eb:
+ inst_op1_b=inst.cond ? 1 : 0;
+ case S_Eb:
+ if (inst.rm<0xc0) SaveMb(inst.rm_eaa,inst_op1_b);
+ else reg_8(inst.rm_eai)=inst_op1_b;
+ break;
+ case S_Gb:
+ reg_8(inst.rm_index)=inst_op1_b;
+ break;
+ case S_EbGb:
+ if (inst.rm<0xc0) SaveMb(inst.rm_eaa,inst_op1_b);
+ else reg_8(inst.rm_eai)=inst_op1_b;
+ reg_8(inst.rm_index)=inst_op2_b;
+ break;
+/* Word */
+ case S_Ew:
+ if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst_op1_w);
+ else reg_16(inst.rm_eai)=inst_op1_w;
+ break;
+ case S_Gw:
+ reg_16(inst.rm_index)=inst_op1_w;
+ break;
+ case S_EwGw:
+ if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst_op1_w);
+ else reg_16(inst.rm_eai)=inst_op1_w;
+ reg_16(inst.rm_index)=inst_op2_w;
+ break;
+/* Dword */
+ case S_Ed:
+ if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d);
+ else reg_32(inst.rm_eai)=inst_op1_d;
+ break;
+ case S_EdMw: /* Special one 16 to memory, 32 zero extend to reg */
+ if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst_op1_w);
+ else reg_32(inst.rm_eai)=inst_op1_d;
+ break;
+ case S_Gd:
+ reg_32(inst.rm_index)=inst_op1_d;
+ break;
+ case S_EdGd:
+ if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d);
+ else reg_32(inst.rm_eai)=inst_op1_d;
+ reg_32(inst.rm_index)=inst_op2_d;
+ break;
+
+ case S_REGb:
+ reg_8(inst.code.extra)=inst_op1_b;
+ break;
+ case S_REGw:
+ reg_16(inst.code.extra)=inst_op1_w;
+ break;
+ case S_REGd:
+ reg_32(inst.code.extra)=inst_op1_d;
+ break;
+ case S_SEGm:
+ if (CPU_SetSegGeneral((SegNames)inst.rm_index,inst_op1_w)) RunException();
+ break;
+ case S_SEGGw:
+ if (CPU_SetSegGeneral((SegNames)inst.code.extra,inst_op2_w)) RunException();
+ reg_16(inst.rm_index)=inst_op1_w;
+ break;
+ case S_SEGGd:
+ if (CPU_SetSegGeneral((SegNames)inst.code.extra,inst_op2_w)) RunException();
+ reg_32(inst.rm_index)=inst_op1_d;
+ break;
+ case S_PUSHw:
+ Push_16(inst_op1_w);
+ break;
+ case S_PUSHd:
+ Push_32(inst_op1_d);
+ break;
+
+ case S_C_AIPw:
+ if (!inst.cond) goto nextopcode;
+ case S_AIPw:
+ SaveIP();
+ reg_eip+=inst_op1_d;
+ reg_eip&=0xffff;
+ continue;
+ case S_C_AIPd:
+ if (!inst.cond) goto nextopcode;
+ case S_AIPd:
+ SaveIP();
+ reg_eip+=inst_op1_d;
+ continue;
+ case S_IPIw:
+ reg_esp+=Fetchw();
+ case S_IP:
+ SaveIP();
+ reg_eip=inst_op1_d;
+ continue;
+ case 0:
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("SAVE:Unhandled code %d entry %X",inst.code.save,inst.entry);
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+{
+ EAPoint si_base,di_base;
+ Bitu si_index,di_index;
+ Bitu add_mask;
+ Bitu count,count_left;
+ Bits add_index;
+
+ if (inst.prefix & PREFIX_SEG) si_base=inst.seg.base;
+ else si_base=SegBase(ds);
+ di_base=SegBase(es);
+ if (inst.prefix & PREFIX_ADDR) {
+ add_mask=0xFFFFFFFF;
+ si_index=reg_esi;
+ di_index=reg_edi;
+ count=reg_ecx;
+ } else {
+ add_mask=0xFFFF;
+ si_index=reg_si;
+ di_index=reg_di;
+ count=reg_cx;
+ }
+ if (!(inst.prefix & PREFIX_REP)) {
+ count=1;
+ } else {
+ /* Calculate amount of ops to do before cycles run out */
+ CPU_Cycles++;
+ if ((count>(Bitu)CPU_Cycles) && (inst.code.op<R_SCASB)) {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ LoadIP();
+ } else {
+ /* Won't interrupt scas and cmps instruction since they can interrupt themselves */
+ if (inst.code.op<R_SCASB) CPU_Cycles-=count;
+ count_left=0;
+ }
+ }
+ add_index=cpu.direction;
+ if (count) switch (inst.code.op) {
+ case R_OUTSB:
+ for (;count>0;count--) {
+ IO_WriteB(reg_dx,LoadMb(si_base+si_index));
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_OUTSW:
+ add_index<<=1;
+ for (;count>0;count--) {
+ IO_WriteW(reg_dx,LoadMw(si_base+si_index));
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_OUTSD:
+ add_index<<=2;
+ for (;count>0;count--) {
+ IO_WriteD(reg_dx,LoadMd(si_base+si_index));
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_INSB:
+ for (;count>0;count--) {
+ SaveMb(di_base+di_index,IO_ReadB(reg_dx));
+ di_index=(di_index+add_index) & add_mask;
+ }
+ break;
+ case R_INSW:
+ add_index<<=1;
+ for (;count>0;count--) {
+ SaveMw(di_base+di_index,IO_ReadW(reg_dx));
+ di_index=(di_index+add_index) & add_mask;
+ }
+ break;
+ case R_INSD:
+ add_index<<=2;
+ for (;count>0;count--) {
+ SaveMd(di_base+di_index,IO_ReadD(reg_dx));
+ di_index=(di_index+add_index) & add_mask;
+ }
+ break;
+ case R_STOSB:
+ for (;count>0;count--) {
+ SaveMb(di_base+di_index,reg_al);
+ di_index=(di_index+add_index) & add_mask;
+ }
+ break;
+ case R_STOSW:
+ add_index<<=1;
+ for (;count>0;count--) {
+ SaveMw(di_base+di_index,reg_ax);
+ di_index=(di_index+add_index) & add_mask;
+ }
+ break;
+ case R_STOSD:
+ add_index<<=2;
+ for (;count>0;count--) {
+ SaveMd(di_base+di_index,reg_eax);
+ di_index=(di_index+add_index) & add_mask;
+ }
+ break;
+ case R_MOVSB:
+ for (;count>0;count--) {
+ SaveMb(di_base+di_index,LoadMb(si_base+si_index));
+ di_index=(di_index+add_index) & add_mask;
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_MOVSW:
+ add_index<<=1;
+ for (;count>0;count--) {
+ SaveMw(di_base+di_index,LoadMw(si_base+si_index));
+ di_index=(di_index+add_index) & add_mask;
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_MOVSD:
+ add_index<<=2;
+ for (;count>0;count--) {
+ SaveMd(di_base+di_index,LoadMd(si_base+si_index));
+ di_index=(di_index+add_index) & add_mask;
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_LODSB:
+ for (;count>0;count--) {
+ reg_al=LoadMb(si_base+si_index);
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_LODSW:
+ add_index<<=1;
+ for (;count>0;count--) {
+ reg_ax=LoadMw(si_base+si_index);
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_LODSD:
+ add_index<<=2;
+ for (;count>0;count--) {
+ reg_eax=LoadMd(si_base+si_index);
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_SCASB:
+ {
+ Bit8u val2;
+ for (;count>0;) {
+ count--;CPU_Cycles--;
+ val2=LoadMb(di_base+di_index);
+ di_index=(di_index+add_index) & add_mask;
+ if ((reg_al==val2)!=inst.repz) break;
+ }
+ CMPB(reg_al,val2,LoadD,0);
+ }
+ break;
+ case R_SCASW:
+ {
+ add_index<<=1;Bit16u val2;
+ for (;count>0;) {
+ count--;CPU_Cycles--;
+ val2=LoadMw(di_base+di_index);
+ di_index=(di_index+add_index) & add_mask;
+ if ((reg_ax==val2)!=inst.repz) break;
+ }
+ CMPW(reg_ax,val2,LoadD,0);
+ }
+ break;
+ case R_SCASD:
+ {
+ add_index<<=2;Bit32u val2;
+ for (;count>0;) {
+ count--;CPU_Cycles--;
+ val2=LoadMd(di_base+di_index);
+ di_index=(di_index+add_index) & add_mask;
+ if ((reg_eax==val2)!=inst.repz) break;
+ }
+ CMPD(reg_eax,val2,LoadD,0);
+ }
+ break;
+ case R_CMPSB:
+ {
+ Bit8u val1,val2;
+ for (;count>0;) {
+ count--;CPU_Cycles--;
+ val1=LoadMb(si_base+si_index);
+ val2=LoadMb(di_base+di_index);
+ si_index=(si_index+add_index) & add_mask;
+ di_index=(di_index+add_index) & add_mask;
+ if ((val1==val2)!=inst.repz) break;
+ }
+ CMPB(val1,val2,LoadD,0);
+ }
+ break;
+ case R_CMPSW:
+ {
+ add_index<<=1;Bit16u val1,val2;
+ for (;count>0;) {
+ count--;CPU_Cycles--;
+ val1=LoadMw(si_base+si_index);
+ val2=LoadMw(di_base+di_index);
+ si_index=(si_index+add_index) & add_mask;
+ di_index=(di_index+add_index) & add_mask;
+ if ((val1==val2)!=inst.repz) break;
+ }
+ CMPW(val1,val2,LoadD,0);
+ }
+ break;
+ case R_CMPSD:
+ {
+ add_index<<=2;Bit32u val1,val2;
+ for (;count>0;) {
+ count--;CPU_Cycles--;
+ val1=LoadMd(si_base+si_index);
+ val2=LoadMd(di_base+di_index);
+ si_index=(si_index+add_index) & add_mask;
+ di_index=(di_index+add_index) & add_mask;
+ if ((val1==val2)!=inst.repz) break;
+ }
+ CMPD(val1,val2,LoadD,0);
+ }
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled string %d entry %X",inst.code.op,inst.entry);
+ }
+ /* Clean up after certain amount of instructions */
+ reg_esi&=(~add_mask);
+ reg_esi|=(si_index & add_mask);
+ reg_edi&=(~add_mask);
+ reg_edi|=(di_index & add_mask);
+ if (inst.prefix & PREFIX_REP) {
+ count+=count_left;
+ reg_ecx&=(~add_mask);
+ reg_ecx|=(count & add_mask);
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+enum {
+ L_N=0,
+ L_SKIP,
+ /* Grouped ones using MOD/RM */
+ L_MODRM,L_MODRM_NVM,L_POPwRM,L_POPdRM,
+
+ L_Ib,L_Iw,L_Id,
+ L_Ibx,L_Iwx,L_Idx, //Sign extend
+ L_Ifw,L_Ifd,
+ L_OP,
+
+ L_REGb,L_REGw,L_REGd,
+ L_REGbIb,L_REGwIw,L_REGdId,
+ L_POPw,L_POPd,
+ L_POPfw,L_POPfd,
+ L_SEG,
+
+ L_INTO,
+
+ L_VAL,
+ L_PRESEG,
+ L_DOUBLE,
+ L_PREOP,L_PREADD,L_PREREP,L_PREREPNE,
+ L_STRING,
+
+/* Direct ones */
+ D_IRETw,D_IRETd,
+ D_PUSHAw,D_PUSHAd,
+ D_POPAw,D_POPAd,
+ D_POPSEGw,D_POPSEGd,
+ D_DAA,D_DAS,
+ D_AAA,D_AAS,
+ D_CBW,D_CWDE,
+ D_CWD,D_CDQ,
+ D_SETALC,
+ D_XLAT,
+ D_CLI,D_STI,D_STC,D_CLC,D_CMC,D_CLD,D_STD,
+ D_NOP,D_WAIT,
+ D_ENTERw,D_ENTERd,
+ D_LEAVEw,D_LEAVEd,
+
+ D_RETFw,D_RETFd,
+ D_RETFwIw,D_RETFdIw,
+ D_POPF,D_PUSHF,
+ D_SAHF,D_LAHF,
+ D_CPUID,
+ D_HLT,D_CLTS,
+ D_LOCK,D_ICEBP,
+ D_RDTSC,
+ L_ERROR
+};
+
+
+enum {
+ O_N=t_LASTFLAG,
+ O_COND,
+ O_XCHG_AX,O_XCHG_EAX,
+ O_IMULRw,O_IMULRd,
+ O_BOUNDw,O_BOUNDd,
+ O_CALLNw,O_CALLNd,
+ O_CALLFw,O_CALLFd,
+ O_JMPFw,O_JMPFd,
+
+ O_OPAL,O_ALOP,
+ O_OPAX,O_AXOP,
+ O_OPEAX,O_EAXOP,
+ O_INT,
+ O_SEGDS,O_SEGES,O_SEGFS,O_SEGGS,O_SEGSS,
+ O_LOOP,O_LOOPZ,O_LOOPNZ,O_JCXZ,
+ O_INb,O_INw,O_INd,
+ O_OUTb,O_OUTw,O_OUTd,
+
+ O_NOT,O_AAM,O_AAD,
+ O_MULb,O_MULw,O_MULd,
+ O_IMULb,O_IMULw,O_IMULd,
+ O_DIVb,O_DIVw,O_DIVd,
+ O_IDIVb,O_IDIVw,O_IDIVd,
+ O_CBACK,
+
+
+ O_DSHLw,O_DSHLd,
+ O_DSHRw,O_DSHRd,
+ O_C_O ,O_C_NO ,O_C_B ,O_C_NB ,O_C_Z ,O_C_NZ ,O_C_BE ,O_C_NBE,
+ O_C_S ,O_C_NS ,O_C_P ,O_C_NP ,O_C_L ,O_C_NL ,O_C_LE ,O_C_NLE,
+
+ O_GRP6w,O_GRP6d,
+ O_GRP7w,O_GRP7d,
+ O_M_CRx_Rd,O_M_Rd_CRx,
+ O_M_DRx_Rd,O_M_Rd_DRx,
+ O_M_TRx_Rd,O_M_Rd_TRx,
+ O_LAR,O_LSL,
+ O_ARPL,
+
+ O_BTw,O_BTSw,O_BTRw,O_BTCw,
+ O_BTd,O_BTSd,O_BTRd,O_BTCd,
+ O_BSFw,O_BSRw,O_BSFd,O_BSRd,
+
+ O_BSWAPw, O_BSWAPd,
+ O_CMPXCHG,
+ O_FPU
+
+
+};
+
+enum {
+ S_N=0,
+ S_C_Eb,
+ S_Eb,S_Gb,S_EbGb,
+ S_Ew,S_Gw,S_EwGw,
+ S_Ed,S_Gd,S_EdGd,S_EdMw,
+
+
+ S_REGb,S_REGw,S_REGd,
+ S_PUSHw,S_PUSHd,
+ S_SEGm,
+ S_SEGGw,S_SEGGd,
+
+
+ S_AIPw,S_C_AIPw,
+ S_AIPd,S_C_AIPd,
+
+ S_IP,S_IPIw
+};
+
+enum {
+ R_OUTSB,R_OUTSW,R_OUTSD,
+ R_INSB,R_INSW,R_INSD,
+ R_MOVSB,R_MOVSW,R_MOVSD,
+ R_LODSB,R_LODSW,R_LODSD,
+ R_STOSB,R_STOSW,R_STOSD,
+ R_SCASB,R_SCASW,R_SCASD,
+ R_CMPSB,R_CMPSW,R_CMPSD
+};
+
+enum {
+ M_None=0,
+ M_Ebx,M_Eb,M_Gb,M_EbGb,M_GbEb,
+ M_Ewx,M_Ew,M_Gw,M_EwGw,M_GwEw,M_EwxGwx,M_EwGwt,
+ M_Edx,M_Ed,M_Gd,M_EdGd,M_GdEd,M_EdxGdx,M_EdGdt,
+
+ M_EbIb,M_EwIb,M_EdIb,
+ M_EwIw,M_EwIbx,M_EwxIbx,M_EwxIwx,M_EwGwIb,M_EwGwCL,
+ M_EdId,M_EdIbx,M_EdGdIb,M_EdGdCL,
+
+ M_Efw,M_Efd,
+
+ M_Ib,M_Iw,M_Id,
+
+
+ M_SEG,M_EA,
+ M_GRP,
+ M_GRP_Ib,M_GRP_CL,M_GRP_1,
+
+ M_POPw,M_POPd
+};
+
+struct OpCode {
+ Bit8u load,op,save,extra;
+};
+
+struct FullData {
+ Bitu entry;
+ Bitu rm;
+ EAPoint rm_eaa;
+ Bitu rm_off;
+ Bitu rm_eai;
+ Bitu rm_index;
+ Bitu rm_mod;
+ OpCode code;
+ EAPoint cseip;
+#ifdef WORDS_BIGENDIAN
+ union {
+ Bit32u dword[1];
+ Bit32s dwords[1];
+ Bit16u word[2];
+ Bit16s words[2];
+ Bit8u byte[4];
+ Bit8s bytes[4];
+ } blah1,blah2,blah_imm;
+#else
+ union {
+ Bit8u b;Bit8s bs;
+ Bit16u w;Bit16s ws;
+ Bit32u d;Bit32s ds;
+ } op1,op2,imm;
+#endif
+ Bitu new_flags;
+ struct {
+ EAPoint base;
+ } seg;
+ Bitu cond;
+ bool repz;
+ Bitu prefix;
+};
+
+/* Some defines to get the names correct. */
+#ifdef WORDS_BIGENDIAN
+
+#define inst_op1_b inst.blah1.byte[3]
+#define inst_op1_bs inst.blah1.bytes[3]
+#define inst_op1_w inst.blah1.word[1]
+#define inst_op1_ws inst.blah1.words[1]
+#define inst_op1_d inst.blah1.dword[0]
+#define inst_op1_ds inst.blah1.dwords[0]
+
+#define inst_op2_b inst.blah2.byte[3]
+#define inst_op2_bs inst.blah2.bytes[3]
+#define inst_op2_w inst.blah2.word[1]
+#define inst_op2_ws inst.blah2.words[1]
+#define inst_op2_d inst.blah2.dword[0]
+#define inst_op2_ds inst.blah2.dwords[0]
+
+#define inst_imm_b inst.blah_imm.byte[3]
+#define inst_imm_bs inst.blah_imm.bytes[3]
+#define inst_imm_w inst.blah_imm.word[1]
+#define inst_imm_ws inst.blah_imm.words[1]
+#define inst_imm_d inst.blah_imm.dword[0]
+#define inst_imm_ds inst.blah_imm.dwords[0]
+
+#else
+
+#define inst_op1_b inst.op1.b
+#define inst_op1_bs inst.op1.bs
+#define inst_op1_w inst.op1.w
+#define inst_op1_ws inst.op1.ws
+#define inst_op1_d inst.op1.d
+#define inst_op1_ds inst.op1.ds
+
+#define inst_op2_b inst.op2.b
+#define inst_op2_bs inst.op2.bs
+#define inst_op2_w inst.op2.w
+#define inst_op2_ws inst.op2.ws
+#define inst_op2_d inst.op2.d
+#define inst_op2_ds inst.op2.ds
+
+#define inst_imm_b inst.imm.b
+#define inst_imm_bs inst.imm.bs
+#define inst_imm_w inst.imm.w
+#define inst_imm_ws inst.imm.ws
+#define inst_imm_d inst.imm.d
+#define inst_imm_ds inst.imm.ds
+
+#endif
+
+
+#define PREFIX_NONE 0x0
+#define PREFIX_ADDR 0x1
+#define PREFIX_SEG 0x2
+#define PREFIX_REP 0x4
+
--- /dev/null
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+
+#include "dosbox.h"
+#include "mem.h"
+#include "cpu.h"
+#include "lazyflags.h"
+#include "inout.h"
+#include "callback.h"
+#include "pic.h"
+#include "fpu.h"
+#include "paging.h"
+
+#if C_DEBUG
+#include "debug.h"
+#endif
+
+#if (!C_CORE_INLINE)
+#define LoadMb(off) mem_readb(off)
+#define LoadMw(off) mem_readw(off)
+#define LoadMd(off) mem_readd(off)
+#define SaveMb(off,val) mem_writeb(off,val)
+#define SaveMw(off,val) mem_writew(off,val)
+#define SaveMd(off,val) mem_writed(off,val)
+#else
+#include "paging.h"
+#define LoadMb(off) mem_readb_inline(off)
+#define LoadMw(off) mem_readw_inline(off)
+#define LoadMd(off) mem_readd_inline(off)
+#define SaveMb(off,val) mem_writeb_inline(off,val)
+#define SaveMw(off,val) mem_writew_inline(off,val)
+#define SaveMd(off,val) mem_writed_inline(off,val)
+#endif
+
+extern Bitu cycle_count;
+
+#if C_FPU
+#define CPU_FPU 1 //Enable FPU escape instructions
+#endif
+
+#define CPU_PIC_CHECK 1
+#define CPU_TRAP_CHECK 1
+
+#define OPCODE_NONE 0x000
+#define OPCODE_0F 0x100
+#define OPCODE_SIZE 0x200
+
+#define PREFIX_ADDR 0x1
+#define PREFIX_REP 0x2
+
+#define TEST_PREFIX_ADDR (core.prefixes & PREFIX_ADDR)
+#define TEST_PREFIX_REP (core.prefixes & PREFIX_REP)
+
+#define DO_PREFIX_SEG(_SEG) \
+ BaseDS=SegBase(_SEG); \
+ BaseSS=SegBase(_SEG); \
+ core.base_val_ds=_SEG; \
+ goto restart_opcode;
+
+#define DO_PREFIX_ADDR() \
+ core.prefixes=(core.prefixes & ~PREFIX_ADDR) | \
+ (cpu.code.big ^ PREFIX_ADDR); \
+ core.ea_table=&EATable[(core.prefixes&1) * 256]; \
+ goto restart_opcode;
+
+#define DO_PREFIX_REP(_ZERO) \
+ core.prefixes|=PREFIX_REP; \
+ core.rep_zero=_ZERO; \
+ goto restart_opcode;
+
+typedef PhysPt (*GetEAHandler)(void);
+
+static const Bit32u AddrMaskTable[2]={0x0000ffff,0xffffffff};
+
+static struct {
+ Bitu opcode_index;
+ PhysPt cseip;
+ PhysPt base_ds,base_ss;
+ SegNames base_val_ds;
+ bool rep_zero;
+ Bitu prefixes;
+ GetEAHandler * ea_table;
+} core;
+
+#define GETIP (core.cseip-SegBase(cs))
+#define SAVEIP reg_eip=GETIP;
+#define LOADIP core.cseip=(SegBase(cs)+reg_eip);
+
+#define SegBase(c) SegPhys(c)
+#define BaseDS core.base_ds
+#define BaseSS core.base_ss
+
+static INLINE Bit8u Fetchb() {
+ Bit8u temp=LoadMb(core.cseip);
+ core.cseip+=1;
+ return temp;
+}
+
+static INLINE Bit16u Fetchw() {
+ Bit16u temp=LoadMw(core.cseip);
+ core.cseip+=2;
+ return temp;
+}
+static INLINE Bit32u Fetchd() {
+ Bit32u temp=LoadMd(core.cseip);
+ core.cseip+=4;
+ return temp;
+}
+
+#define Push_16 CPU_Push16
+#define Push_32 CPU_Push32
+#define Pop_16 CPU_Pop16
+#define Pop_32 CPU_Pop32
+
+#include "instructions.h"
+#include "core_normal/support.h"
+#include "core_normal/string.h"
+
+
+#define EALookupTable (core.ea_table)
+
+Bits CPU_Core_Normal_Run(void) {
+ while (CPU_Cycles-->0) {
+ LOADIP;
+ core.opcode_index=cpu.code.big*0x200;
+ core.prefixes=cpu.code.big;
+ core.ea_table=&EATable[cpu.code.big*256];
+ BaseDS=SegBase(ds);
+ BaseSS=SegBase(ss);
+ core.base_val_ds=ds;
+#if C_DEBUG
+#if C_HEAVY_DEBUG
+ if (DEBUG_HeavyIsBreakpoint()) {
+ FillFlags();
+ return debugCallback;
+ };
+#endif
+ cycle_count++;
+#endif
+restart_opcode:
+ switch (core.opcode_index+Fetchb()) {
+ #include "core_normal/prefix_none.h"
+ #include "core_normal/prefix_0f.h"
+ #include "core_normal/prefix_66.h"
+ #include "core_normal/prefix_66_0f.h"
+ default:
+ illegal_opcode:
+#if C_DEBUG
+ {
+ Bitu len=(GETIP-reg_eip);
+ LOADIP;
+ if (len>16) len=16;
+ char tempcode[16*2+1];char * writecode=tempcode;
+ for (;len>0;len--) {
+ sprintf(writecode,"%02X",mem_readb(core.cseip++));
+ writecode+=2;
+ }
+ LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode);
+ }
+#endif
+ CPU_Exception(6,0);
+ continue;
+ }
+ SAVEIP;
+ }
+ FillFlags();
+ return CBRET_NONE;
+decode_end:
+ SAVEIP;
+ FillFlags();
+ return CBRET_NONE;
+}
+
+Bits CPU_Core_Normal_Trap_Run(void) {
+ Bits oldCycles = CPU_Cycles;
+ CPU_Cycles = 1;
+ cpu.trap_skip = false;
+
+ Bits ret=CPU_Core_Normal_Run();
+ if (!cpu.trap_skip) CPU_HW_Interrupt(1);
+ CPU_Cycles = oldCycles-1;
+ cpudecoder = &CPU_Core_Normal_Run;
+
+ return ret;
+}
+
+
+
+void CPU_Core_Normal_Init(void) {
+
+}
+
--- /dev/null
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# src/cpu/core_normal/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/dosbox
+pkgincludedir = $(includedir)/dosbox
+pkglibdir = $(libdir)/dosbox
+pkglibexecdir = $(libexecdir)/dosbox
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = src/cpu/core_normal
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = aclocal-1.16
+ALSA_CFLAGS =
+ALSA_LIBS = -lasound -lm -ldl -lpthread
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+AUTOCONF = autoconf
+AUTOHEADER = autoheader
+AUTOMAKE = automake-1.16
+AWK = gawk
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS = -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
+CXX = g++
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+ECHO_C =
+ECHO_N = -n
+ECHO_T =
+EGREP = /bin/grep -E
+EXEEXT =
+GREP = /bin/grep
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LDFLAGS =
+LIBOBJS =
+LIBS = -lasound -lm -ldl -lpthread -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL -lXfont2 -lXi -lpng -lz -lX11 -lGL
+LTLIBOBJS =
+MAKEINFO = makeinfo
+MKDIR_P = /bin/mkdir -p
+OBJEXT = o
+PACKAGE = dosbox
+PACKAGE_BUGREPORT =
+PACKAGE_NAME = dosbox
+PACKAGE_STRING = dosbox 0.74
+PACKAGE_TARNAME = dosbox
+PACKAGE_URL =
+PACKAGE_VERSION = 0.74
+PATH_SEPARATOR = :
+RANLIB = ranlib
+SDL_CFLAGS = -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
+SDL_CONFIG = /usr/local/bin/sdl-config
+SDL_LIBS = -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL -lXfont2 -lXi -lpthread
+SET_MAKE =
+SHELL = /bin/bash
+STRIP =
+VERSION = 0.74
+WINDRES = :
+abs_builddir = /home/whatisthis/src/DOSVAXJ3/src/cpu/core_normal
+abs_srcdir = /home/whatisthis/src/DOSVAXJ3/src/cpu/core_normal
+abs_top_builddir = /home/whatisthis/src/DOSVAXJ3
+abs_top_srcdir = /home/whatisthis/src/DOSVAXJ3
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = $${TAR-tar} chof - "$$tardir"
+am__untar = $${TAR-tar} xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias =
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = x86_64-pc-linux-gnu
+host_alias =
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/whatisthis/src/DOSVAXJ3/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+runstatedir = ${localstatedir}/run
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target_alias =
+top_build_prefix = ../../../
+top_builddir = ../../..
+top_srcdir = ../../..
+noinst_HEADERS = helpers.h prefix_none.h prefix_66.h prefix_0f.h support.h table_ea.h \
+ prefix_66_0f.h string.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/cpu/core_normal/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/cpu/core_normal/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+
+noinst_HEADERS = helpers.h prefix_none.h prefix_66.h prefix_0f.h support.h table_ea.h \
+ prefix_66_0f.h string.h
--- /dev/null
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = src/cpu/core_normal
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WINDRES = @WINDRES@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = helpers.h prefix_none.h prefix_66.h prefix_0f.h support.h table_ea.h \
+ prefix_66_0f.h string.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/cpu/core_normal/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/cpu/core_normal/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#define GetEAa \
+ PhysPt eaa=EALookupTable[rm]();
+
+#define GetRMEAa \
+ GetRM; \
+ GetEAa;
+
+
+#define RMEbGb(inst) \
+ { \
+ GetRMrb; \
+ if (rm >= 0xc0 ) {GetEArb;inst(*earb,*rmrb,LoadRb,SaveRb);} \
+ else {GetEAa;inst(eaa,*rmrb,LoadMb,SaveMb);} \
+ }
+
+#define RMGbEb(inst) \
+ { \
+ GetRMrb; \
+ if (rm >= 0xc0 ) {GetEArb;inst(*rmrb,*earb,LoadRb,SaveRb);} \
+ else {GetEAa;inst(*rmrb,LoadMb(eaa),LoadRb,SaveRb);} \
+ }
+
+#define RMEb(inst) \
+ { \
+ if (rm >= 0xc0 ) {GetEArb;inst(*earb,LoadRb,SaveRb);} \
+ else {GetEAa;inst(eaa,LoadMb,SaveMb);} \
+ }
+
+#define RMEwGw(inst) \
+ { \
+ GetRMrw; \
+ if (rm >= 0xc0 ) {GetEArw;inst(*earw,*rmrw,LoadRw,SaveRw);} \
+ else {GetEAa;inst(eaa,*rmrw,LoadMw,SaveMw);} \
+ }
+
+#define RMEwGwOp3(inst,op3) \
+ { \
+ GetRMrw; \
+ if (rm >= 0xc0 ) {GetEArw;inst(*earw,*rmrw,op3,LoadRw,SaveRw);} \
+ else {GetEAa;inst(eaa,*rmrw,op3,LoadMw,SaveMw);} \
+ }
+
+#define RMGwEw(inst) \
+ { \
+ GetRMrw; \
+ if (rm >= 0xc0 ) {GetEArw;inst(*rmrw,*earw,LoadRw,SaveRw);} \
+ else {GetEAa;inst(*rmrw,LoadMw(eaa),LoadRw,SaveRw);} \
+ }
+
+#define RMGwEwOp3(inst,op3) \
+ { \
+ GetRMrw; \
+ if (rm >= 0xc0 ) {GetEArw;inst(*rmrw,*earw,op3,LoadRw,SaveRw);} \
+ else {GetEAa;inst(*rmrw,LoadMw(eaa),op3,LoadRw,SaveRw);} \
+ }
+
+#define RMEw(inst) \
+ { \
+ if (rm >= 0xc0 ) {GetEArw;inst(*earw,LoadRw,SaveRw);} \
+ else {GetEAa;inst(eaa,LoadMw,SaveMw);} \
+ }
+
+#define RMEdGd(inst) \
+ { \
+ GetRMrd; \
+ if (rm >= 0xc0 ) {GetEArd;inst(*eard,*rmrd,LoadRd,SaveRd);} \
+ else {GetEAa;inst(eaa,*rmrd,LoadMd,SaveMd);} \
+ }
+
+#define RMEdGdOp3(inst,op3) \
+ { \
+ GetRMrd; \
+ if (rm >= 0xc0 ) {GetEArd;inst(*eard,*rmrd,op3,LoadRd,SaveRd);} \
+ else {GetEAa;inst(eaa,*rmrd,op3,LoadMd,SaveMd);} \
+ }
+
+
+#define RMGdEd(inst) \
+ { \
+ GetRMrd; \
+ if (rm >= 0xc0 ) {GetEArd;inst(*rmrd,*eard,LoadRd,SaveRd);} \
+ else {GetEAa;inst(*rmrd,LoadMd(eaa),LoadRd,SaveRd);} \
+ }
+
+#define RMGdEdOp3(inst,op3) \
+ { \
+ GetRMrd; \
+ if (rm >= 0xc0 ) {GetEArd;inst(*rmrd,*eard,op3,LoadRd,SaveRd);} \
+ else {GetEAa;inst(*rmrd,LoadMd(eaa),op3,LoadRd,SaveRd);} \
+ }
+
+
+
+
+#define RMEw(inst) \
+ { \
+ if (rm >= 0xc0 ) {GetEArw;inst(*earw,LoadRw,SaveRw);} \
+ else {GetEAa;inst(eaa,LoadMw,SaveMw);} \
+ }
+
+#define RMEd(inst) \
+ { \
+ if (rm >= 0xc0 ) {GetEArd;inst(*eard,LoadRd,SaveRd);} \
+ else {GetEAa;inst(eaa,LoadMd,SaveMd);} \
+ }
+
+#define ALIb(inst) \
+ { inst(reg_al,Fetchb(),LoadRb,SaveRb)}
+
+#define AXIw(inst) \
+ { inst(reg_ax,Fetchw(),LoadRw,SaveRw);}
+
+#define EAXId(inst) \
+ { inst(reg_eax,Fetchd(),LoadRd,SaveRd);}
+
+#define FPU_ESC(code) { \
+ Bit8u rm=Fetchb(); \
+ if (rm >= 0xc0) { \
+ FPU_ESC ## code ## _Normal(rm); \
+ } else { \
+ GetEAa;FPU_ESC ## code ## _EA(rm,eaa); \
+ } \
+}
+
+#define CASE_W(_WHICH) \
+ case (OPCODE_NONE+_WHICH):
+
+#define CASE_D(_WHICH) \
+ case (OPCODE_SIZE+_WHICH):
+
+#define CASE_B(_WHICH) \
+ CASE_W(_WHICH) \
+ CASE_D(_WHICH)
+
+#define CASE_0F_W(_WHICH) \
+ case ((OPCODE_0F|OPCODE_NONE)+_WHICH):
+
+#define CASE_0F_D(_WHICH) \
+ case ((OPCODE_0F|OPCODE_SIZE)+_WHICH):
+
+#define CASE_0F_B(_WHICH) \
+ CASE_0F_W(_WHICH) \
+ CASE_0F_D(_WHICH)
--- /dev/null
+/*
+ * 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.
+ */
+
+ CASE_0F_W(0x00) /* GRP 6 Exxx */
+ {
+ if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
+ GetRM;Bitu which=(rm>>3)&7;
+ switch (which) {
+ case 0x00: /* SLDT */
+ case 0x01: /* STR */
+ {
+ Bitu saveval;
+ if (!which) saveval=CPU_SLDT();
+ else saveval=CPU_STR();
+ if (rm >= 0xc0) {GetEArw;*earw=saveval;}
+ else {GetEAa;SaveMw(eaa,saveval);}
+ }
+ break;
+ case 0x02:case 0x03:case 0x04:case 0x05:
+ {
+ Bitu loadval;
+ if (rm >= 0xc0 ) {GetEArw;loadval=*earw;}
+ else {GetEAa;loadval=LoadMw(eaa);}
+ switch (which) {
+ case 0x02:
+ if (cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ if (CPU_LLDT(loadval)) RUNEXCEPTION();
+ break;
+ case 0x03:
+ if (cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ if (CPU_LTR(loadval)) RUNEXCEPTION();
+ break;
+ case 0x04:
+ CPU_VERR(loadval);
+ break;
+ case 0x05:
+ CPU_VERW(loadval);
+ break;
+ }
+ }
+ break;
+ default:
+ goto illegal_opcode;
+ }
+ }
+ break;
+ CASE_0F_W(0x01) /* Group 7 Ew */
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ if (rm < 0xc0) { //First ones all use EA
+ GetEAa;Bitu limit;
+ switch (which) {
+ case 0x00: /* SGDT */
+ SaveMw(eaa,CPU_SGDT_limit());
+ SaveMd(eaa+2,CPU_SGDT_base());
+ break;
+ case 0x01: /* SIDT */
+ SaveMw(eaa,CPU_SIDT_limit());
+ SaveMd(eaa+2,CPU_SIDT_base());
+ break;
+ case 0x02: /* LGDT */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ CPU_LGDT(LoadMw(eaa),LoadMd(eaa+2) & 0xFFFFFF);
+ break;
+ case 0x03: /* LIDT */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ CPU_LIDT(LoadMw(eaa),LoadMd(eaa+2) & 0xFFFFFF);
+ break;
+ case 0x04: /* SMSW */
+ SaveMw(eaa,CPU_SMSW());
+ break;
+ case 0x06: /* LMSW */
+ limit=LoadMw(eaa);
+ if (CPU_LMSW(limit)) RUNEXCEPTION();
+ break;
+ case 0x07: /* INVLPG */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ PAGING_ClearTLB();
+ break;
+ }
+ } else {
+ GetEArw;
+ switch (which) {
+ case 0x02: /* LGDT */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ goto illegal_opcode;
+ case 0x03: /* LIDT */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ goto illegal_opcode;
+ case 0x04: /* SMSW */
+ *earw=CPU_SMSW();
+ break;
+ case 0x06: /* LMSW */
+ if (CPU_LMSW(*earw)) RUNEXCEPTION();
+ break;
+ default:
+ goto illegal_opcode;
+ }
+ }
+ }
+ break;
+ CASE_0F_W(0x02) /* LAR Gw,Ew */
+ {
+ if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
+ GetRMrw;Bitu ar=*rmrw;
+ if (rm >= 0xc0) {
+ GetEArw;CPU_LAR(*earw,ar);
+ } else {
+ GetEAa;CPU_LAR(LoadMw(eaa),ar);
+ }
+ *rmrw=(Bit16u)ar;
+ }
+ break;
+ CASE_0F_W(0x03) /* LSL Gw,Ew */
+ {
+ if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
+ GetRMrw;Bitu limit=*rmrw;
+ if (rm >= 0xc0) {
+ GetEArw;CPU_LSL(*earw,limit);
+ } else {
+ GetEAa;CPU_LSL(LoadMw(eaa),limit);
+ }
+ *rmrw=(Bit16u)limit;
+ }
+ break;
+ CASE_0F_B(0x06) /* CLTS */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ cpu.cr0&=(~CR0_TASKSWITCH);
+ break;
+ CASE_0F_B(0x08) /* INVD */
+ CASE_0F_B(0x09) /* WBINVD */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ break;
+ CASE_0F_B(0x20) /* MOV Rd.CRx */
+ {
+ GetRM;
+ Bitu which=(rm >> 3) & 7;
+ if (rm < 0xc0 ) {
+ rm |= 0xc0;
+ LOG(LOG_CPU,LOG_ERROR)("MOV XXX,CR%u with non-register",which);
+ }
+ GetEArd;
+ Bit32u crx_value;
+ if (CPU_READ_CRX(which,crx_value)) RUNEXCEPTION();
+ *eard=crx_value;
+ }
+ break;
+ CASE_0F_B(0x21) /* MOV Rd,DRx */
+ {
+ GetRM;
+ Bitu which=(rm >> 3) & 7;
+ if (rm < 0xc0 ) {
+ rm |= 0xc0;
+ LOG(LOG_CPU,LOG_ERROR)("MOV XXX,DR%u with non-register",which);
+ }
+ GetEArd;
+ Bit32u drx_value;
+ if (CPU_READ_DRX(which,drx_value)) RUNEXCEPTION();
+ *eard=drx_value;
+ }
+ break;
+ CASE_0F_B(0x22) /* MOV CRx,Rd */
+ {
+ GetRM;
+ Bitu which=(rm >> 3) & 7;
+ if (rm < 0xc0 ) {
+ rm |= 0xc0;
+ LOG(LOG_CPU,LOG_ERROR)("MOV XXX,CR%u with non-register",which);
+ }
+ GetEArd;
+ if (CPU_WRITE_CRX(which,*eard)) RUNEXCEPTION();
+ }
+ break;
+ CASE_0F_B(0x23) /* MOV DRx,Rd */
+ {
+ GetRM;
+ Bitu which=(rm >> 3) & 7;
+ if (rm < 0xc0 ) {
+ rm |= 0xc0;
+ LOG(LOG_CPU,LOG_ERROR)("MOV DR%u,XXX with non-register",which);
+ }
+ GetEArd;
+ if (CPU_WRITE_DRX(which,*eard)) RUNEXCEPTION();
+ }
+ break;
+ CASE_0F_B(0x24) /* MOV Rd,TRx */
+ {
+ GetRM;
+ Bitu which=(rm >> 3) & 7;
+ if (rm < 0xc0 ) {
+ rm |= 0xc0;
+ LOG(LOG_CPU,LOG_ERROR)("MOV XXX,TR%u with non-register",which);
+ }
+ GetEArd;
+ Bit32u trx_value;
+ if (CPU_READ_TRX(which,trx_value)) RUNEXCEPTION();
+ *eard=trx_value;
+ }
+ break;
+ CASE_0F_B(0x26) /* MOV TRx,Rd */
+ {
+ GetRM;
+ Bitu which=(rm >> 3) & 7;
+ if (rm < 0xc0 ) {
+ rm |= 0xc0;
+ LOG(LOG_CPU,LOG_ERROR)("MOV TR%u,XXX with non-register",which);
+ }
+ GetEArd;
+ if (CPU_WRITE_TRX(which,*eard)) RUNEXCEPTION();
+ }
+ break;
+ CASE_0F_B(0x31) /* RDTSC */
+ {
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_PENTIUMSLOW) goto illegal_opcode;
+ /* Use a fixed number when in auto cycles mode as else the reported value changes constantly */
+ Bit64s tsc=(Bit64s)(PIC_FullIndex()*(double) (CPU_CycleAutoAdjust?70000:CPU_CycleMax));
+ reg_edx=(Bit32u)(tsc>>32);
+ reg_eax=(Bit32u)(tsc&0xffffffff);
+ }
+ break;
+ CASE_0F_W(0x80) /* JO */
+ JumpCond16_w(TFLG_O);break;
+ CASE_0F_W(0x81) /* JNO */
+ JumpCond16_w(TFLG_NO);break;
+ CASE_0F_W(0x82) /* JB */
+ JumpCond16_w(TFLG_B);break;
+ CASE_0F_W(0x83) /* JNB */
+ JumpCond16_w(TFLG_NB);break;
+ CASE_0F_W(0x84) /* JZ */
+ JumpCond16_w(TFLG_Z);break;
+ CASE_0F_W(0x85) /* JNZ */
+ JumpCond16_w(TFLG_NZ);break;
+ CASE_0F_W(0x86) /* JBE */
+ JumpCond16_w(TFLG_BE);break;
+ CASE_0F_W(0x87) /* JNBE */
+ JumpCond16_w(TFLG_NBE);break;
+ CASE_0F_W(0x88) /* JS */
+ JumpCond16_w(TFLG_S);break;
+ CASE_0F_W(0x89) /* JNS */
+ JumpCond16_w(TFLG_NS);break;
+ CASE_0F_W(0x8a) /* JP */
+ JumpCond16_w(TFLG_P);break;
+ CASE_0F_W(0x8b) /* JNP */
+ JumpCond16_w(TFLG_NP);break;
+ CASE_0F_W(0x8c) /* JL */
+ JumpCond16_w(TFLG_L);break;
+ CASE_0F_W(0x8d) /* JNL */
+ JumpCond16_w(TFLG_NL);break;
+ CASE_0F_W(0x8e) /* JLE */
+ JumpCond16_w(TFLG_LE);break;
+ CASE_0F_W(0x8f) /* JNLE */
+ JumpCond16_w(TFLG_NLE);break;
+ CASE_0F_B(0x90) /* SETO */
+ SETcc(TFLG_O);break;
+ CASE_0F_B(0x91) /* SETNO */
+ SETcc(TFLG_NO);break;
+ CASE_0F_B(0x92) /* SETB */
+ SETcc(TFLG_B);break;
+ CASE_0F_B(0x93) /* SETNB */
+ SETcc(TFLG_NB);break;
+ CASE_0F_B(0x94) /* SETZ */
+ SETcc(TFLG_Z);break;
+ CASE_0F_B(0x95) /* SETNZ */
+ SETcc(TFLG_NZ); break;
+ CASE_0F_B(0x96) /* SETBE */
+ SETcc(TFLG_BE);break;
+ CASE_0F_B(0x97) /* SETNBE */
+ SETcc(TFLG_NBE);break;
+ CASE_0F_B(0x98) /* SETS */
+ SETcc(TFLG_S);break;
+ CASE_0F_B(0x99) /* SETNS */
+ SETcc(TFLG_NS);break;
+ CASE_0F_B(0x9a) /* SETP */
+ SETcc(TFLG_P);break;
+ CASE_0F_B(0x9b) /* SETNP */
+ SETcc(TFLG_NP);break;
+ CASE_0F_B(0x9c) /* SETL */
+ SETcc(TFLG_L);break;
+ CASE_0F_B(0x9d) /* SETNL */
+ SETcc(TFLG_NL);break;
+ CASE_0F_B(0x9e) /* SETLE */
+ SETcc(TFLG_LE);break;
+ CASE_0F_B(0x9f) /* SETNLE */
+ SETcc(TFLG_NLE);break;
+
+ CASE_0F_W(0xa0) /* PUSH FS */
+ Push_16(SegValue(fs));break;
+ CASE_0F_W(0xa1) /* POP FS */
+ if (CPU_PopSeg(fs,false)) RUNEXCEPTION();
+ break;
+ CASE_0F_B(0xa2) /* CPUID */
+ if (!CPU_CPUID()) goto illegal_opcode;
+ break;
+ CASE_0F_W(0xa3) /* BT Ew,Gw */
+ {
+ FillFlags();GetRMrw;
+ Bit16u mask=1 << (*rmrw & 15);
+ if (rm >= 0xc0 ) {
+ GetEArw;
+ SETFLAGBIT(CF,(*earw & mask));
+ } else {
+ GetEAa;eaa+=(((Bit16s)*rmrw)>>4)*2;
+ Bit16u old=LoadMw(eaa);
+ SETFLAGBIT(CF,(old & mask));
+ }
+ break;
+ }
+ CASE_0F_W(0xa4) /* SHLD Ew,Gw,Ib */
+ RMEwGwOp3(DSHLW,Fetchb());
+ break;
+ CASE_0F_W(0xa5) /* SHLD Ew,Gw,CL */
+ RMEwGwOp3(DSHLW,reg_cl);
+ break;
+ CASE_0F_W(0xa8) /* PUSH GS */
+ Push_16(SegValue(gs));break;
+ CASE_0F_W(0xa9) /* POP GS */
+ if (CPU_PopSeg(gs,false)) RUNEXCEPTION();
+ break;
+ CASE_0F_W(0xab) /* BTS Ew,Gw */
+ {
+ FillFlags();GetRMrw;
+ Bit16u mask=1 << (*rmrw & 15);
+ if (rm >= 0xc0 ) {
+ GetEArw;
+ SETFLAGBIT(CF,(*earw & mask));
+ *earw|=mask;
+ } else {
+ GetEAa;eaa+=(((Bit16s)*rmrw)>>4)*2;
+ Bit16u old=LoadMw(eaa);
+ SETFLAGBIT(CF,(old & mask));
+ SaveMw(eaa,old | mask);
+ }
+ break;
+ }
+ CASE_0F_W(0xac) /* SHRD Ew,Gw,Ib */
+ RMEwGwOp3(DSHRW,Fetchb());
+ break;
+ CASE_0F_W(0xad) /* SHRD Ew,Gw,CL */
+ RMEwGwOp3(DSHRW,reg_cl);
+ break;
+ CASE_0F_W(0xaf) /* IMUL Gw,Ew */
+ RMGwEwOp3(DIMULW,*rmrw);
+ break;
+ CASE_0F_B(0xb0) /* cmpxchg Eb,Gb */
+ {
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ FillFlags();
+ GetRMrb;
+ if (rm >= 0xc0 ) {
+ GetEArb;
+ if (reg_al == *earb) {
+ *earb=*rmrb;
+ SETFLAGBIT(ZF,1);
+ } else {
+ reg_al = *earb;
+ SETFLAGBIT(ZF,0);
+ }
+ } else {
+ GetEAa;
+ Bit8u val = LoadMb(eaa);
+ if (reg_al == val) {
+ SaveMb(eaa,*rmrb);
+ SETFLAGBIT(ZF,1);
+ } else {
+ SaveMb(eaa,val); // cmpxchg always issues a write
+ reg_al = val;
+ SETFLAGBIT(ZF,0);
+ }
+ }
+ break;
+ }
+ CASE_0F_W(0xb1) /* cmpxchg Ew,Gw */
+ {
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ FillFlags();
+ GetRMrw;
+ if (rm >= 0xc0 ) {
+ GetEArw;
+ if(reg_ax == *earw) {
+ *earw = *rmrw;
+ SETFLAGBIT(ZF,1);
+ } else {
+ reg_ax = *earw;
+ SETFLAGBIT(ZF,0);
+ }
+ } else {
+ GetEAa;
+ Bit16u val = LoadMw(eaa);
+ if(reg_ax == val) {
+ SaveMw(eaa,*rmrw);
+ SETFLAGBIT(ZF,1);
+ } else {
+ SaveMw(eaa,val); // cmpxchg always issues a write
+ reg_ax = val;
+ SETFLAGBIT(ZF,0);
+ }
+ }
+ break;
+ }
+
+ CASE_0F_W(0xb2) /* LSS Ew */
+ {
+ GetRMrw;
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ if (CPU_SetSegGeneral(ss,LoadMw(eaa+2))) RUNEXCEPTION();
+ *rmrw=LoadMw(eaa);
+ break;
+ }
+ CASE_0F_W(0xb3) /* BTR Ew,Gw */
+ {
+ FillFlags();GetRMrw;
+ Bit16u mask=1 << (*rmrw & 15);
+ if (rm >= 0xc0 ) {
+ GetEArw;
+ SETFLAGBIT(CF,(*earw & mask));
+ *earw&= ~mask;
+ } else {
+ GetEAa;eaa+=(((Bit16s)*rmrw)>>4)*2;
+ Bit16u old=LoadMw(eaa);
+ SETFLAGBIT(CF,(old & mask));
+ SaveMw(eaa,old & ~mask);
+ }
+ break;
+ }
+ CASE_0F_W(0xb4) /* LFS Ew */
+ {
+ GetRMrw;
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ if (CPU_SetSegGeneral(fs,LoadMw(eaa+2))) RUNEXCEPTION();
+ *rmrw=LoadMw(eaa);
+ break;
+ }
+ CASE_0F_W(0xb5) /* LGS Ew */
+ {
+ GetRMrw;
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ if (CPU_SetSegGeneral(gs,LoadMw(eaa+2))) RUNEXCEPTION();
+ *rmrw=LoadMw(eaa);
+ break;
+ }
+ CASE_0F_W(0xb6) /* MOVZX Gw,Eb */
+ {
+ GetRMrw;
+ if (rm >= 0xc0 ) {GetEArb;*rmrw=*earb;}
+ else {GetEAa;*rmrw=LoadMb(eaa);}
+ break;
+ }
+ CASE_0F_W(0xb7) /* MOVZX Gw,Ew */
+ CASE_0F_W(0xbf) /* MOVSX Gw,Ew */
+ {
+ GetRMrw;
+ if (rm >= 0xc0 ) {GetEArw;*rmrw=*earw;}
+ else {GetEAa;*rmrw=LoadMw(eaa);}
+ break;
+ }
+ CASE_0F_W(0xba) /* GRP8 Ew,Ib */
+ {
+ FillFlags();GetRM;
+ if (rm >= 0xc0 ) {
+ GetEArw;
+ Bit16u mask=1 << (Fetchb() & 15);
+ SETFLAGBIT(CF,(*earw & mask));
+ switch (rm & 0x38) {
+ case 0x20: /* BT */
+ break;
+ case 0x28: /* BTS */
+ *earw|=mask;
+ break;
+ case 0x30: /* BTR */
+ *earw&= ~mask;
+ break;
+ case 0x38: /* BTC */
+ *earw^=mask;
+ break;
+ default:
+ E_Exit("CPU:0F:BA:Illegal subfunction %X",rm & 0x38);
+ }
+ } else {
+ GetEAa;Bit16u old=LoadMw(eaa);
+ Bit16u mask=1 << (Fetchb() & 15);
+ SETFLAGBIT(CF,(old & mask));
+ switch (rm & 0x38) {
+ case 0x20: /* BT */
+ break;
+ case 0x28: /* BTS */
+ SaveMw(eaa,old|mask);
+ break;
+ case 0x30: /* BTR */
+ SaveMw(eaa,old & ~mask);
+ break;
+ case 0x38: /* BTC */
+ SaveMw(eaa,old ^ mask);
+ break;
+ default:
+ E_Exit("CPU:0F:BA:Illegal subfunction %X",rm & 0x38);
+ }
+ }
+ break;
+ }
+ CASE_0F_W(0xbb) /* BTC Ew,Gw */
+ {
+ FillFlags();GetRMrw;
+ Bit16u mask=1 << (*rmrw & 15);
+ if (rm >= 0xc0 ) {
+ GetEArw;
+ SETFLAGBIT(CF,(*earw & mask));
+ *earw^=mask;
+ } else {
+ GetEAa;eaa+=(((Bit16s)*rmrw)>>4)*2;
+ Bit16u old=LoadMw(eaa);
+ SETFLAGBIT(CF,(old & mask));
+ SaveMw(eaa,old ^ mask);
+ }
+ break;
+ }
+ CASE_0F_W(0xbc) /* BSF Gw,Ew */
+ {
+ GetRMrw;
+ Bit16u result,value;
+ if (rm >= 0xc0) { GetEArw; value=*earw; }
+ else { GetEAa; value=LoadMw(eaa); }
+ if (value==0) {
+ SETFLAGBIT(ZF,true);
+ } else {
+ result = 0;
+ while ((value & 0x01)==0) { result++; value>>=1; }
+ SETFLAGBIT(ZF,false);
+ *rmrw = result;
+ }
+ lflags.type=t_UNKNOWN;
+ break;
+ }
+ CASE_0F_W(0xbd) /* BSR Gw,Ew */
+ {
+ GetRMrw;
+ Bit16u result,value;
+ if (rm >= 0xc0) { GetEArw; value=*earw; }
+ else { GetEAa; value=LoadMw(eaa); }
+ if (value==0) {
+ SETFLAGBIT(ZF,true);
+ } else {
+ result = 15; // Operandsize-1
+ while ((value & 0x8000)==0) { result--; value<<=1; }
+ SETFLAGBIT(ZF,false);
+ *rmrw = result;
+ }
+ lflags.type=t_UNKNOWN;
+ break;
+ }
+ CASE_0F_W(0xbe) /* MOVSX Gw,Eb */
+ {
+ GetRMrw;
+ if (rm >= 0xc0 ) {GetEArb;*rmrw=*(Bit8s *)earb;}
+ else {GetEAa;*rmrw=LoadMbs(eaa);}
+ break;
+ }
+ CASE_0F_B(0xc0) /* XADD Gb,Eb */
+ {
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ GetRMrb;Bit8u oldrmrb=*rmrb;
+ if (rm >= 0xc0 ) {GetEArb;*rmrb=*earb;*earb+=oldrmrb;}
+ else {GetEAa;*rmrb=LoadMb(eaa);SaveMb(eaa,LoadMb(eaa)+oldrmrb);}
+ break;
+ }
+ CASE_0F_W(0xc1) /* XADD Gw,Ew */
+ {
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ GetRMrw;Bit16u oldrmrw=*rmrw;
+ if (rm >= 0xc0 ) {GetEArw;*rmrw=*earw;*earw+=oldrmrw;}
+ else {GetEAa;*rmrw=LoadMw(eaa);SaveMw(eaa,LoadMw(eaa)+oldrmrw);}
+ break;
+ }
+ CASE_0F_W(0xc8) /* BSWAP AX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_ax);break;
+ CASE_0F_W(0xc9) /* BSWAP CX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_cx);break;
+ CASE_0F_W(0xca) /* BSWAP DX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_dx);break;
+ CASE_0F_W(0xcb) /* BSWAP BX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_bx);break;
+ CASE_0F_W(0xcc) /* BSWAP SP */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_sp);break;
+ CASE_0F_W(0xcd) /* BSWAP BP */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_bp);break;
+ CASE_0F_W(0xce) /* BSWAP SI */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_si);break;
+ CASE_0F_W(0xcf) /* BSWAP DI */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_di);break;
+
--- /dev/null
+/*
+ * 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.
+ */
+
+ CASE_D(0x01) /* ADD Ed,Gd */
+ RMEdGd(ADDD);break;
+ CASE_D(0x03) /* ADD Gd,Ed */
+ RMGdEd(ADDD);break;
+ CASE_D(0x05) /* ADD EAX,Id */
+ EAXId(ADDD);break;
+ CASE_D(0x06) /* PUSH ES */
+ Push_32(SegValue(es));break;
+ CASE_D(0x07) /* POP ES */
+ if (CPU_PopSeg(es,true)) RUNEXCEPTION();
+ break;
+ CASE_D(0x09) /* OR Ed,Gd */
+ RMEdGd(ORD);break;
+ CASE_D(0x0b) /* OR Gd,Ed */
+ RMGdEd(ORD);break;
+ CASE_D(0x0d) /* OR EAX,Id */
+ EAXId(ORD);break;
+ CASE_D(0x0e) /* PUSH CS */
+ Push_32(SegValue(cs));break;
+ CASE_D(0x11) /* ADC Ed,Gd */
+ RMEdGd(ADCD);break;
+ CASE_D(0x13) /* ADC Gd,Ed */
+ RMGdEd(ADCD);break;
+ CASE_D(0x15) /* ADC EAX,Id */
+ EAXId(ADCD);break;
+ CASE_D(0x16) /* PUSH SS */
+ Push_32(SegValue(ss));break;
+ CASE_D(0x17) /* POP SS */
+ if (CPU_PopSeg(ss,true)) RUNEXCEPTION();
+ CPU_Cycles++;
+ break;
+ CASE_D(0x19) /* SBB Ed,Gd */
+ RMEdGd(SBBD);break;
+ CASE_D(0x1b) /* SBB Gd,Ed */
+ RMGdEd(SBBD);break;
+ CASE_D(0x1d) /* SBB EAX,Id */
+ EAXId(SBBD);break;
+ CASE_D(0x1e) /* PUSH DS */
+ Push_32(SegValue(ds));break;
+ CASE_D(0x1f) /* POP DS */
+ if (CPU_PopSeg(ds,true)) RUNEXCEPTION();
+ break;
+ CASE_D(0x21) /* AND Ed,Gd */
+ RMEdGd(ANDD);break;
+ CASE_D(0x23) /* AND Gd,Ed */
+ RMGdEd(ANDD);break;
+ CASE_D(0x25) /* AND EAX,Id */
+ EAXId(ANDD);break;
+ CASE_D(0x29) /* SUB Ed,Gd */
+ RMEdGd(SUBD);break;
+ CASE_D(0x2b) /* SUB Gd,Ed */
+ RMGdEd(SUBD);break;
+ CASE_D(0x2d) /* SUB EAX,Id */
+ EAXId(SUBD);break;
+ CASE_D(0x31) /* XOR Ed,Gd */
+ RMEdGd(XORD);break;
+ CASE_D(0x33) /* XOR Gd,Ed */
+ RMGdEd(XORD);break;
+ CASE_D(0x35) /* XOR EAX,Id */
+ EAXId(XORD);break;
+ CASE_D(0x39) /* CMP Ed,Gd */
+ RMEdGd(CMPD);break;
+ CASE_D(0x3b) /* CMP Gd,Ed */
+ RMGdEd(CMPD);break;
+ CASE_D(0x3d) /* CMP EAX,Id */
+ EAXId(CMPD);break;
+ CASE_D(0x40) /* INC EAX */
+ INCD(reg_eax,LoadRd,SaveRd);break;
+ CASE_D(0x41) /* INC ECX */
+ INCD(reg_ecx,LoadRd,SaveRd);break;
+ CASE_D(0x42) /* INC EDX */
+ INCD(reg_edx,LoadRd,SaveRd);break;
+ CASE_D(0x43) /* INC EBX */
+ INCD(reg_ebx,LoadRd,SaveRd);break;
+ CASE_D(0x44) /* INC ESP */
+ INCD(reg_esp,LoadRd,SaveRd);break;
+ CASE_D(0x45) /* INC EBP */
+ INCD(reg_ebp,LoadRd,SaveRd);break;
+ CASE_D(0x46) /* INC ESI */
+ INCD(reg_esi,LoadRd,SaveRd);break;
+ CASE_D(0x47) /* INC EDI */
+ INCD(reg_edi,LoadRd,SaveRd);break;
+ CASE_D(0x48) /* DEC EAX */
+ DECD(reg_eax,LoadRd,SaveRd);break;
+ CASE_D(0x49) /* DEC ECX */
+ DECD(reg_ecx,LoadRd,SaveRd);break;
+ CASE_D(0x4a) /* DEC EDX */
+ DECD(reg_edx,LoadRd,SaveRd);break;
+ CASE_D(0x4b) /* DEC EBX */
+ DECD(reg_ebx,LoadRd,SaveRd);break;
+ CASE_D(0x4c) /* DEC ESP */
+ DECD(reg_esp,LoadRd,SaveRd);break;
+ CASE_D(0x4d) /* DEC EBP */
+ DECD(reg_ebp,LoadRd,SaveRd);break;
+ CASE_D(0x4e) /* DEC ESI */
+ DECD(reg_esi,LoadRd,SaveRd);break;
+ CASE_D(0x4f) /* DEC EDI */
+ DECD(reg_edi,LoadRd,SaveRd);break;
+ CASE_D(0x50) /* PUSH EAX */
+ Push_32(reg_eax);break;
+ CASE_D(0x51) /* PUSH ECX */
+ Push_32(reg_ecx);break;
+ CASE_D(0x52) /* PUSH EDX */
+ Push_32(reg_edx);break;
+ CASE_D(0x53) /* PUSH EBX */
+ Push_32(reg_ebx);break;
+ CASE_D(0x54) /* PUSH ESP */
+ Push_32(reg_esp);break;
+ CASE_D(0x55) /* PUSH EBP */
+ Push_32(reg_ebp);break;
+ CASE_D(0x56) /* PUSH ESI */
+ Push_32(reg_esi);break;
+ CASE_D(0x57) /* PUSH EDI */
+ Push_32(reg_edi);break;
+ CASE_D(0x58) /* POP EAX */
+ reg_eax=Pop_32();break;
+ CASE_D(0x59) /* POP ECX */
+ reg_ecx=Pop_32();break;
+ CASE_D(0x5a) /* POP EDX */
+ reg_edx=Pop_32();break;
+ CASE_D(0x5b) /* POP EBX */
+ reg_ebx=Pop_32();break;
+ CASE_D(0x5c) /* POP ESP */
+ reg_esp=Pop_32();break;
+ CASE_D(0x5d) /* POP EBP */
+ reg_ebp=Pop_32();break;
+ CASE_D(0x5e) /* POP ESI */
+ reg_esi=Pop_32();break;
+ CASE_D(0x5f) /* POP EDI */
+ reg_edi=Pop_32();break;
+ CASE_D(0x60) /* PUSHAD */
+ {
+ Bitu tmpesp = reg_esp;
+ Push_32(reg_eax);Push_32(reg_ecx);Push_32(reg_edx);Push_32(reg_ebx);
+ Push_32(tmpesp);Push_32(reg_ebp);Push_32(reg_esi);Push_32(reg_edi);
+ }; break;
+ CASE_D(0x61) /* POPAD */
+ reg_edi=Pop_32();reg_esi=Pop_32();reg_ebp=Pop_32();Pop_32();//Don't save ESP
+ reg_ebx=Pop_32();reg_edx=Pop_32();reg_ecx=Pop_32();reg_eax=Pop_32();
+ break;
+ CASE_D(0x62) /* BOUND Ed */
+ {
+ Bit32s bound_min, bound_max;
+ GetRMrd;GetEAa;
+ bound_min=LoadMd(eaa);
+ bound_max=LoadMd(eaa+4);
+ if ( (((Bit32s)*rmrd) < bound_min) || (((Bit32s)*rmrd) > bound_max) ) {
+ EXCEPTION(5);
+ }
+ }
+ break;
+ CASE_D(0x63) /* ARPL Ed,Rd */
+ {
+ if (((cpu.pmode) && (reg_flags & FLAG_VM)) || (!cpu.pmode)) goto illegal_opcode;
+ GetRMrw;
+ if (rm >= 0xc0 ) {
+ GetEArd;Bitu new_sel=(Bit16u)*eard;
+ CPU_ARPL(new_sel,*rmrw);
+ *eard=(Bit32u)new_sel;
+ } else {
+ GetEAa;Bitu new_sel=LoadMw(eaa);
+ CPU_ARPL(new_sel,*rmrw);
+ SaveMd(eaa,(Bit32u)new_sel);
+ }
+ }
+ break;
+ CASE_D(0x68) /* PUSH Id */
+ Push_32(Fetchd());break;
+ CASE_D(0x69) /* IMUL Gd,Ed,Id */
+ RMGdEdOp3(DIMULD,Fetchds());
+ break;
+ CASE_D(0x6a) /* PUSH Ib */
+ Push_32(Fetchbs());break;
+ CASE_D(0x6b) /* IMUL Gd,Ed,Ib */
+ RMGdEdOp3(DIMULD,Fetchbs());
+ break;
+ CASE_D(0x6d) /* INSD */
+ if (CPU_IO_Exception(reg_dx,4)) RUNEXCEPTION();
+ DoString(R_INSD);break;
+ CASE_D(0x6f) /* OUTSD */
+ if (CPU_IO_Exception(reg_dx,4)) RUNEXCEPTION();
+ DoString(R_OUTSD);break;
+ CASE_D(0x70) /* JO */
+ JumpCond32_b(TFLG_O);break;
+ CASE_D(0x71) /* JNO */
+ JumpCond32_b(TFLG_NO);break;
+ CASE_D(0x72) /* JB */
+ JumpCond32_b(TFLG_B);break;
+ CASE_D(0x73) /* JNB */
+ JumpCond32_b(TFLG_NB);break;
+ CASE_D(0x74) /* JZ */
+ JumpCond32_b(TFLG_Z);break;
+ CASE_D(0x75) /* JNZ */
+ JumpCond32_b(TFLG_NZ);break;
+ CASE_D(0x76) /* JBE */
+ JumpCond32_b(TFLG_BE);break;
+ CASE_D(0x77) /* JNBE */
+ JumpCond32_b(TFLG_NBE);break;
+ CASE_D(0x78) /* JS */
+ JumpCond32_b(TFLG_S);break;
+ CASE_D(0x79) /* JNS */
+ JumpCond32_b(TFLG_NS);break;
+ CASE_D(0x7a) /* JP */
+ JumpCond32_b(TFLG_P);break;
+ CASE_D(0x7b) /* JNP */
+ JumpCond32_b(TFLG_NP);break;
+ CASE_D(0x7c) /* JL */
+ JumpCond32_b(TFLG_L);break;
+ CASE_D(0x7d) /* JNL */
+ JumpCond32_b(TFLG_NL);break;
+ CASE_D(0x7e) /* JLE */
+ JumpCond32_b(TFLG_LE);break;
+ CASE_D(0x7f) /* JNLE */
+ JumpCond32_b(TFLG_NLE);break;
+ CASE_D(0x81) /* Grpl Ed,Id */
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ if (rm >= 0xc0) {
+ GetEArd;Bit32u id=Fetchd();
+ switch (which) {
+ case 0x00:ADDD(*eard,id,LoadRd,SaveRd);break;
+ case 0x01: ORD(*eard,id,LoadRd,SaveRd);break;
+ case 0x02:ADCD(*eard,id,LoadRd,SaveRd);break;
+ case 0x03:SBBD(*eard,id,LoadRd,SaveRd);break;
+ case 0x04:ANDD(*eard,id,LoadRd,SaveRd);break;
+ case 0x05:SUBD(*eard,id,LoadRd,SaveRd);break;
+ case 0x06:XORD(*eard,id,LoadRd,SaveRd);break;
+ case 0x07:CMPD(*eard,id,LoadRd,SaveRd);break;
+ }
+ } else {
+ GetEAa;Bit32u id=Fetchd();
+ switch (which) {
+ case 0x00:ADDD(eaa,id,LoadMd,SaveMd);break;
+ case 0x01: ORD(eaa,id,LoadMd,SaveMd);break;
+ case 0x02:ADCD(eaa,id,LoadMd,SaveMd);break;
+ case 0x03:SBBD(eaa,id,LoadMd,SaveMd);break;
+ case 0x04:ANDD(eaa,id,LoadMd,SaveMd);break;
+ case 0x05:SUBD(eaa,id,LoadMd,SaveMd);break;
+ case 0x06:XORD(eaa,id,LoadMd,SaveMd);break;
+ case 0x07:CMPD(eaa,id,LoadMd,SaveMd);break;
+ }
+ }
+ }
+ break;
+ CASE_D(0x83) /* Grpl Ed,Ix */
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ if (rm >= 0xc0) {
+ GetEArd;Bit32u id=(Bit32s)Fetchbs();
+ switch (which) {
+ case 0x00:ADDD(*eard,id,LoadRd,SaveRd);break;
+ case 0x01: ORD(*eard,id,LoadRd,SaveRd);break;
+ case 0x02:ADCD(*eard,id,LoadRd,SaveRd);break;
+ case 0x03:SBBD(*eard,id,LoadRd,SaveRd);break;
+ case 0x04:ANDD(*eard,id,LoadRd,SaveRd);break;
+ case 0x05:SUBD(*eard,id,LoadRd,SaveRd);break;
+ case 0x06:XORD(*eard,id,LoadRd,SaveRd);break;
+ case 0x07:CMPD(*eard,id,LoadRd,SaveRd);break;
+ }
+ } else {
+ GetEAa;Bit32u id=(Bit32s)Fetchbs();
+ switch (which) {
+ case 0x00:ADDD(eaa,id,LoadMd,SaveMd);break;
+ case 0x01: ORD(eaa,id,LoadMd,SaveMd);break;
+ case 0x02:ADCD(eaa,id,LoadMd,SaveMd);break;
+ case 0x03:SBBD(eaa,id,LoadMd,SaveMd);break;
+ case 0x04:ANDD(eaa,id,LoadMd,SaveMd);break;
+ case 0x05:SUBD(eaa,id,LoadMd,SaveMd);break;
+ case 0x06:XORD(eaa,id,LoadMd,SaveMd);break;
+ case 0x07:CMPD(eaa,id,LoadMd,SaveMd);break;
+ }
+ }
+ }
+ break;
+ CASE_D(0x85) /* TEST Ed,Gd */
+ RMEdGd(TESTD);break;
+ CASE_D(0x87) /* XCHG Ed,Gd */
+ {
+ GetRMrd;Bit32u oldrmrd=*rmrd;
+ if (rm >= 0xc0 ) {GetEArd;*rmrd=*eard;*eard=oldrmrd;}
+ else {GetEAa;*rmrd=LoadMd(eaa);SaveMd(eaa,oldrmrd);}
+ break;
+ }
+ CASE_D(0x89) /* MOV Ed,Gd */
+ {
+ GetRMrd;
+ if (rm >= 0xc0 ) {GetEArd;*eard=*rmrd;}
+ else {GetEAa;SaveMd(eaa,*rmrd);}
+ break;
+ }
+ CASE_D(0x8b) /* MOV Gd,Ed */
+ {
+ GetRMrd;
+ if (rm >= 0xc0 ) {GetEArd;*rmrd=*eard;}
+ else {GetEAa;*rmrd=LoadMd(eaa);}
+ break;
+ }
+ CASE_D(0x8c) /* Mov Ew,Sw */
+ {
+ GetRM;Bit16u val;Bitu which=(rm>>3)&7;
+ switch (which) {
+ case 0x00: /* MOV Ew,ES */
+ val=SegValue(es);break;
+ case 0x01: /* MOV Ew,CS */
+ val=SegValue(cs);break;
+ case 0x02: /* MOV Ew,SS */
+ val=SegValue(ss);break;
+ case 0x03: /* MOV Ew,DS */
+ val=SegValue(ds);break;
+ case 0x04: /* MOV Ew,FS */
+ val=SegValue(fs);break;
+ case 0x05: /* MOV Ew,GS */
+ val=SegValue(gs);break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("CPU:8c:Illegal RM Byte");
+ goto illegal_opcode;
+ }
+ if (rm >= 0xc0 ) {GetEArd;*eard=val;}
+ else {GetEAa;SaveMw(eaa,val);}
+ break;
+ }
+ CASE_D(0x8d) /* LEA Gd */
+ {
+ //Little hack to always use segprefixed version
+ GetRMrd;
+ BaseDS=BaseSS=0;
+ if (TEST_PREFIX_ADDR) {
+ *rmrd=(Bit32u)(*EATable[256+rm])();
+ } else {
+ *rmrd=(Bit32u)(*EATable[rm])();
+ }
+ break;
+ }
+ CASE_D(0x8f) /* POP Ed */
+ {
+ Bit32u val=Pop_32();
+ GetRM;
+ if (rm >= 0xc0 ) {GetEArd;*eard=val;}
+ else {GetEAa;SaveMd(eaa,val);}
+ break;
+ }
+ CASE_D(0x91) /* XCHG ECX,EAX */
+ { Bit32u temp=reg_eax;reg_eax=reg_ecx;reg_ecx=temp;break;}
+ CASE_D(0x92) /* XCHG EDX,EAX */
+ { Bit32u temp=reg_eax;reg_eax=reg_edx;reg_edx=temp;break;}
+ break;
+ CASE_D(0x93) /* XCHG EBX,EAX */
+ { Bit32u temp=reg_eax;reg_eax=reg_ebx;reg_ebx=temp;break;}
+ break;
+ CASE_D(0x94) /* XCHG ESP,EAX */
+ { Bit32u temp=reg_eax;reg_eax=reg_esp;reg_esp=temp;break;}
+ break;
+ CASE_D(0x95) /* XCHG EBP,EAX */
+ { Bit32u temp=reg_eax;reg_eax=reg_ebp;reg_ebp=temp;break;}
+ break;
+ CASE_D(0x96) /* XCHG ESI,EAX */
+ { Bit32u temp=reg_eax;reg_eax=reg_esi;reg_esi=temp;break;}
+ break;
+ CASE_D(0x97) /* XCHG EDI,EAX */
+ { Bit32u temp=reg_eax;reg_eax=reg_edi;reg_edi=temp;break;}
+ break;
+ CASE_D(0x98) /* CWDE */
+ reg_eax=(Bit16s)reg_ax;break;
+ CASE_D(0x99) /* CDQ */
+ if (reg_eax & 0x80000000) reg_edx=0xffffffff;
+ else reg_edx=0;
+ break;
+ CASE_D(0x9a) /* CALL FAR Ad */
+ {
+ Bit32u newip=Fetchd();Bit16u newcs=Fetchw();
+ FillFlags();
+ CPU_CALL(true,newcs,newip,GETIP);
+#if CPU_TRAP_CHECK
+ if (GETFLAG(TF)) {
+ cpudecoder=CPU_Core_Normal_Trap_Run;
+ return CBRET_NONE;
+ }
+#endif
+ continue;
+ }
+ CASE_D(0x9c) /* PUSHFD */
+ if (CPU_PUSHF(true)) RUNEXCEPTION();
+ break;
+ CASE_D(0x9d) /* POPFD */
+ if (CPU_POPF(true)) RUNEXCEPTION();
+#if CPU_TRAP_CHECK
+ if (GETFLAG(TF)) {
+ cpudecoder=CPU_Core_Normal_Trap_Run;
+ goto decode_end;
+ }
+#endif
+#if CPU_PIC_CHECK
+ if (GETFLAG(IF) && PIC_IRQCheck) goto decode_end;
+#endif
+ break;
+ CASE_D(0xa1) /* MOV EAX,Od */
+ {
+ GetEADirect;
+ reg_eax=LoadMd(eaa);
+ }
+ break;
+ CASE_D(0xa3) /* MOV Od,EAX */
+ {
+ GetEADirect;
+ SaveMd(eaa,reg_eax);
+ }
+ break;
+ CASE_D(0xa5) /* MOVSD */
+ DoString(R_MOVSD);break;
+ CASE_D(0xa7) /* CMPSD */
+ DoString(R_CMPSD);break;
+ CASE_D(0xa9) /* TEST EAX,Id */
+ EAXId(TESTD);break;
+ CASE_D(0xab) /* STOSD */
+ DoString(R_STOSD);break;
+ CASE_D(0xad) /* LODSD */
+ DoString(R_LODSD);break;
+ CASE_D(0xaf) /* SCASD */
+ DoString(R_SCASD);break;
+ CASE_D(0xb8) /* MOV EAX,Id */
+ reg_eax=Fetchd();break;
+ CASE_D(0xb9) /* MOV ECX,Id */
+ reg_ecx=Fetchd();break;
+ CASE_D(0xba) /* MOV EDX,Iw */
+ reg_edx=Fetchd();break;
+ CASE_D(0xbb) /* MOV EBX,Id */
+ reg_ebx=Fetchd();break;
+ CASE_D(0xbc) /* MOV ESP,Id */
+ reg_esp=Fetchd();break;
+ CASE_D(0xbd) /* MOV EBP.Id */
+ reg_ebp=Fetchd();break;
+ CASE_D(0xbe) /* MOV ESI,Id */
+ reg_esi=Fetchd();break;
+ CASE_D(0xbf) /* MOV EDI,Id */
+ reg_edi=Fetchd();break;
+ CASE_D(0xc1) /* GRP2 Ed,Ib */
+ GRP2D(Fetchb());break;
+ CASE_D(0xc2) /* RETN Iw */
+ reg_eip=Pop_32();
+ reg_esp+=Fetchw();
+ continue;
+ CASE_D(0xc3) /* RETN */
+ reg_eip=Pop_32();
+ continue;
+ CASE_D(0xc4) /* LES */
+ {
+ GetRMrd;
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ if (CPU_SetSegGeneral(es,LoadMw(eaa+4))) RUNEXCEPTION();
+ *rmrd=LoadMd(eaa);
+ break;
+ }
+ CASE_D(0xc5) /* LDS */
+ {
+ GetRMrd;
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ if (CPU_SetSegGeneral(ds,LoadMw(eaa+4))) RUNEXCEPTION();
+ *rmrd=LoadMd(eaa);
+ break;
+ }
+ CASE_D(0xc7) /* MOV Ed,Id */
+ {
+ GetRM;
+ if (rm >= 0xc0) {GetEArd;*eard=Fetchd();}
+ else {GetEAa;SaveMd(eaa,Fetchd());}
+ break;
+ }
+ CASE_D(0xc8) /* ENTER Iw,Ib */
+ {
+ Bitu bytes=Fetchw();
+ Bitu level=Fetchb();
+ CPU_ENTER(true,bytes,level);
+ }
+ break;
+ CASE_D(0xc9) /* LEAVE */
+ reg_esp&=cpu.stack.notmask;
+ reg_esp|=(reg_ebp&cpu.stack.mask);
+ reg_ebp=Pop_32();
+ break;
+ CASE_D(0xca) /* RETF Iw */
+ {
+ Bitu words=Fetchw();
+ FillFlags();
+ CPU_RET(true,words,GETIP);
+ continue;
+ }
+ CASE_D(0xcb) /* RETF */
+ {
+ FillFlags();
+ CPU_RET(true,0,GETIP);
+ continue;
+ }
+ CASE_D(0xcf) /* IRET */
+ {
+ CPU_IRET(true,GETIP);
+#if CPU_TRAP_CHECK
+ if (GETFLAG(TF)) {
+ cpudecoder=CPU_Core_Normal_Trap_Run;
+ return CBRET_NONE;
+ }
+#endif
+#if CPU_PIC_CHECK
+ if (GETFLAG(IF) && PIC_IRQCheck) return CBRET_NONE;
+#endif
+ continue;
+ }
+ CASE_D(0xd1) /* GRP2 Ed,1 */
+ GRP2D(1);break;
+ CASE_D(0xd3) /* GRP2 Ed,CL */
+ GRP2D(reg_cl);break;
+ CASE_D(0xe0) /* LOOPNZ */
+ if (TEST_PREFIX_ADDR) {
+ JumpCond32_b(--reg_ecx && !get_ZF());
+ } else {
+ JumpCond32_b(--reg_cx && !get_ZF());
+ }
+ break;
+ CASE_D(0xe1) /* LOOPZ */
+ if (TEST_PREFIX_ADDR) {
+ JumpCond32_b(--reg_ecx && get_ZF());
+ } else {
+ JumpCond32_b(--reg_cx && get_ZF());
+ }
+ break;
+ CASE_D(0xe2) /* LOOP */
+ if (TEST_PREFIX_ADDR) {
+ JumpCond32_b(--reg_ecx);
+ } else {
+ JumpCond32_b(--reg_cx);
+ }
+ break;
+ CASE_D(0xe3) /* JCXZ */
+ JumpCond32_b(!(reg_ecx & AddrMaskTable[core.prefixes& PREFIX_ADDR]));
+ break;
+ CASE_D(0xe5) /* IN EAX,Ib */
+ {
+ Bitu port=Fetchb();
+ if (CPU_IO_Exception(port,4)) RUNEXCEPTION();
+ reg_eax=IO_ReadD(port);
+ break;
+ }
+ CASE_D(0xe7) /* OUT Ib,EAX */
+ {
+ Bitu port=Fetchb();
+ if (CPU_IO_Exception(port,4)) RUNEXCEPTION();
+ IO_WriteD(port,reg_eax);
+ break;
+ }
+ CASE_D(0xe8) /* CALL Jd */
+ {
+ Bit32s addip=Fetchds();
+ SAVEIP;
+ Push_32(reg_eip);
+ reg_eip+=addip;
+ continue;
+ }
+ CASE_D(0xe9) /* JMP Jd */
+ {
+ Bit32s addip=Fetchds();
+ SAVEIP;
+ reg_eip+=addip;
+ continue;
+ }
+ CASE_D(0xea) /* JMP Ad */
+ {
+ Bit32u newip=Fetchd();
+ Bit16u newcs=Fetchw();
+ FillFlags();
+ CPU_JMP(true,newcs,newip,GETIP);
+#if CPU_TRAP_CHECK
+ if (GETFLAG(TF)) {
+ cpudecoder=CPU_Core_Normal_Trap_Run;
+ return CBRET_NONE;
+ }
+#endif
+ continue;
+ }
+ CASE_D(0xeb) /* JMP Jb */
+ {
+ Bit32s addip=Fetchbs();
+ SAVEIP;
+ reg_eip+=addip;
+ continue;
+ }
+ CASE_D(0xed) /* IN EAX,DX */
+ reg_eax=IO_ReadD(reg_dx);
+ break;
+ CASE_D(0xef) /* OUT DX,EAX */
+ IO_WriteD(reg_dx,reg_eax);
+ break;
+ CASE_D(0xf7) /* GRP3 Ed(,Id) */
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ switch (which) {
+ case 0x00: /* TEST Ed,Id */
+ case 0x01: /* TEST Ed,Id Undocumented*/
+ {
+ if (rm >= 0xc0 ) {GetEArd;TESTD(*eard,Fetchd(),LoadRd,SaveRd);}
+ else {GetEAa;TESTD(eaa,Fetchd(),LoadMd,SaveMd);}
+ break;
+ }
+ case 0x02: /* NOT Ed */
+ {
+ if (rm >= 0xc0 ) {GetEArd;*eard=~*eard;}
+ else {GetEAa;SaveMd(eaa,~LoadMd(eaa));}
+ break;
+ }
+ case 0x03: /* NEG Ed */
+ {
+ lflags.type=t_NEGd;
+ if (rm >= 0xc0 ) {
+ GetEArd;lf_var1d=*eard;lf_resd=0-lf_var1d;
+ *eard=lf_resd;
+ } else {
+ GetEAa;lf_var1d=LoadMd(eaa);lf_resd=0-lf_var1d;
+ SaveMd(eaa,lf_resd);
+ }
+ break;
+ }
+ case 0x04: /* MUL EAX,Ed */
+ RMEd(MULD);
+ break;
+ case 0x05: /* IMUL EAX,Ed */
+ RMEd(IMULD);
+ break;
+ case 0x06: /* DIV Ed */
+ RMEd(DIVD);
+ break;
+ case 0x07: /* IDIV Ed */
+ RMEd(IDIVD);
+ break;
+ }
+ break;
+ }
+ CASE_D(0xff) /* GRP 5 Ed */
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ switch (which) {
+ case 0x00: /* INC Ed */
+ RMEd(INCD);
+ break;
+ case 0x01: /* DEC Ed */
+ RMEd(DECD);
+ break;
+ case 0x02: /* CALL NEAR Ed */
+ if (rm >= 0xc0 ) {GetEArd;reg_eip=*eard;}
+ else {GetEAa;reg_eip=LoadMd(eaa);}
+ Push_32(GETIP);
+ continue;
+ case 0x03: /* CALL FAR Ed */
+ {
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ Bit32u newip=LoadMd(eaa);
+ Bit16u newcs=LoadMw(eaa+4);
+ FillFlags();
+ CPU_CALL(true,newcs,newip,GETIP);
+#if CPU_TRAP_CHECK
+ if (GETFLAG(TF)) {
+ cpudecoder=CPU_Core_Normal_Trap_Run;
+ return CBRET_NONE;
+ }
+#endif
+ continue;
+ }
+ case 0x04: /* JMP NEAR Ed */
+ if (rm >= 0xc0 ) {GetEArd;reg_eip=*eard;}
+ else {GetEAa;reg_eip=LoadMd(eaa);}
+ continue;
+ case 0x05: /* JMP FAR Ed */
+ {
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ Bit32u newip=LoadMd(eaa);
+ Bit16u newcs=LoadMw(eaa+4);
+ FillFlags();
+ CPU_JMP(true,newcs,newip,GETIP);
+#if CPU_TRAP_CHECK
+ if (GETFLAG(TF)) {
+ cpudecoder=CPU_Core_Normal_Trap_Run;
+ return CBRET_NONE;
+ }
+#endif
+ continue;
+ }
+ break;
+ case 0x06: /* Push Ed */
+ if (rm >= 0xc0 ) {GetEArd;Push_32(*eard);}
+ else {GetEAa;Push_32(LoadMd(eaa));}
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("CPU:66:GRP5:Illegal call %2X",which);
+ goto illegal_opcode;
+ }
+ break;
+ }
+
+
--- /dev/null
+/*
+ * 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.
+ */
+
+ CASE_0F_D(0x00) /* GRP 6 Exxx */
+ {
+ if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
+ GetRM;Bitu which=(rm>>3)&7;
+ switch (which) {
+ case 0x00: /* SLDT */
+ case 0x01: /* STR */
+ {
+ Bitu saveval;
+ if (!which) saveval=CPU_SLDT();
+ else saveval=CPU_STR();
+ if (rm >= 0xc0) {GetEArw;*earw=(Bit16u)saveval;}
+ else {GetEAa;SaveMw(eaa,saveval);}
+ }
+ break;
+ case 0x02:case 0x03:case 0x04:case 0x05:
+ {
+ /* Just use 16-bit loads since were only using selectors */
+ Bitu loadval;
+ if (rm >= 0xc0 ) {GetEArw;loadval=*earw;}
+ else {GetEAa;loadval=LoadMw(eaa);}
+ switch (which) {
+ case 0x02:
+ if (cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ if (CPU_LLDT(loadval)) RUNEXCEPTION();
+ break;
+ case 0x03:
+ if (cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ if (CPU_LTR(loadval)) RUNEXCEPTION();
+ break;
+ case 0x04:
+ CPU_VERR(loadval);
+ break;
+ case 0x05:
+ CPU_VERW(loadval);
+ break;
+ }
+ }
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("GRP6:Illegal call %2X",which);
+ goto illegal_opcode;
+ }
+ }
+ break;
+ CASE_0F_D(0x01) /* Group 7 Ed */
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ if (rm < 0xc0) { //First ones all use EA
+ GetEAa;Bitu limit;
+ switch (which) {
+ case 0x00: /* SGDT */
+ SaveMw(eaa,(Bit16u)CPU_SGDT_limit());
+ SaveMd(eaa+2,(Bit32u)CPU_SGDT_base());
+ break;
+ case 0x01: /* SIDT */
+ SaveMw(eaa,(Bit16u)CPU_SIDT_limit());
+ SaveMd(eaa+2,(Bit32u)CPU_SIDT_base());
+ break;
+ case 0x02: /* LGDT */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ CPU_LGDT(LoadMw(eaa),LoadMd(eaa+2));
+ break;
+ case 0x03: /* LIDT */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ CPU_LIDT(LoadMw(eaa),LoadMd(eaa+2));
+ break;
+ case 0x04: /* SMSW */
+ SaveMw(eaa,(Bit16u)CPU_SMSW());
+ break;
+ case 0x06: /* LMSW */
+ limit=LoadMw(eaa);
+ if (CPU_LMSW((Bit16u)limit)) RUNEXCEPTION();
+ break;
+ case 0x07: /* INVLPG */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ PAGING_ClearTLB();
+ break;
+ }
+ } else {
+ GetEArd;
+ switch (which) {
+ case 0x02: /* LGDT */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ goto illegal_opcode;
+ case 0x03: /* LIDT */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ goto illegal_opcode;
+ case 0x04: /* SMSW */
+ *eard=(Bit32u)CPU_SMSW();
+ break;
+ case 0x06: /* LMSW */
+ if (CPU_LMSW(*eard)) RUNEXCEPTION();
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Illegal group 7 RM subfunction %d",which);
+ goto illegal_opcode;
+ break;
+ }
+
+ }
+ }
+ break;
+ CASE_0F_D(0x02) /* LAR Gd,Ed */
+ {
+ if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
+ GetRMrd;Bitu ar=*rmrd;
+ if (rm >= 0xc0) {
+ GetEArw;CPU_LAR(*earw,ar);
+ } else {
+ GetEAa;CPU_LAR(LoadMw(eaa),ar);
+ }
+ *rmrd=(Bit32u)ar;
+ }
+ break;
+ CASE_0F_D(0x03) /* LSL Gd,Ew */
+ {
+ if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
+ GetRMrd;Bitu limit=*rmrd;
+ /* Just load 16-bit values for selectors */
+ if (rm >= 0xc0) {
+ GetEArw;CPU_LSL(*earw,limit);
+ } else {
+ GetEAa;CPU_LSL(LoadMw(eaa),limit);
+ }
+ *rmrd=(Bit32u)limit;
+ }
+ break;
+ CASE_0F_D(0x80) /* JO */
+ JumpCond32_d(TFLG_O);break;
+ CASE_0F_D(0x81) /* JNO */
+ JumpCond32_d(TFLG_NO);break;
+ CASE_0F_D(0x82) /* JB */
+ JumpCond32_d(TFLG_B);break;
+ CASE_0F_D(0x83) /* JNB */
+ JumpCond32_d(TFLG_NB);break;
+ CASE_0F_D(0x84) /* JZ */
+ JumpCond32_d(TFLG_Z);break;
+ CASE_0F_D(0x85) /* JNZ */
+ JumpCond32_d(TFLG_NZ);break;
+ CASE_0F_D(0x86) /* JBE */
+ JumpCond32_d(TFLG_BE);break;
+ CASE_0F_D(0x87) /* JNBE */
+ JumpCond32_d(TFLG_NBE);break;
+ CASE_0F_D(0x88) /* JS */
+ JumpCond32_d(TFLG_S);break;
+ CASE_0F_D(0x89) /* JNS */
+ JumpCond32_d(TFLG_NS);break;
+ CASE_0F_D(0x8a) /* JP */
+ JumpCond32_d(TFLG_P);break;
+ CASE_0F_D(0x8b) /* JNP */
+ JumpCond32_d(TFLG_NP);break;
+ CASE_0F_D(0x8c) /* JL */
+ JumpCond32_d(TFLG_L);break;
+ CASE_0F_D(0x8d) /* JNL */
+ JumpCond32_d(TFLG_NL);break;
+ CASE_0F_D(0x8e) /* JLE */
+ JumpCond32_d(TFLG_LE);break;
+ CASE_0F_D(0x8f) /* JNLE */
+ JumpCond32_d(TFLG_NLE);break;
+
+ CASE_0F_D(0xa0) /* PUSH FS */
+ Push_32(SegValue(fs));break;
+ CASE_0F_D(0xa1) /* POP FS */
+ if (CPU_PopSeg(fs,true)) RUNEXCEPTION();
+ break;
+ CASE_0F_D(0xa3) /* BT Ed,Gd */
+ {
+ FillFlags();GetRMrd;
+ Bit32u mask=1 << (*rmrd & 31);
+ if (rm >= 0xc0 ) {
+ GetEArd;
+ SETFLAGBIT(CF,(*eard & mask));
+ } else {
+ GetEAa;eaa+=(((Bit32s)*rmrd)>>5)*4;
+ Bit32u old=LoadMd(eaa);
+ SETFLAGBIT(CF,(old & mask));
+ }
+ break;
+ }
+ CASE_0F_D(0xa4) /* SHLD Ed,Gd,Ib */
+ RMEdGdOp3(DSHLD,Fetchb());
+ break;
+ CASE_0F_D(0xa5) /* SHLD Ed,Gd,CL */
+ RMEdGdOp3(DSHLD,reg_cl);
+ break;
+ CASE_0F_D(0xa8) /* PUSH GS */
+ Push_32(SegValue(gs));break;
+ CASE_0F_D(0xa9) /* POP GS */
+ if (CPU_PopSeg(gs,true)) RUNEXCEPTION();
+ break;
+ CASE_0F_D(0xab) /* BTS Ed,Gd */
+ {
+ FillFlags();GetRMrd;
+ Bit32u mask=1 << (*rmrd & 31);
+ if (rm >= 0xc0 ) {
+ GetEArd;
+ SETFLAGBIT(CF,(*eard & mask));
+ *eard|=mask;
+ } else {
+ GetEAa;eaa+=(((Bit32s)*rmrd)>>5)*4;
+ Bit32u old=LoadMd(eaa);
+ SETFLAGBIT(CF,(old & mask));
+ SaveMd(eaa,old | mask);
+ }
+ break;
+ }
+
+ CASE_0F_D(0xac) /* SHRD Ed,Gd,Ib */
+ RMEdGdOp3(DSHRD,Fetchb());
+ break;
+ CASE_0F_D(0xad) /* SHRD Ed,Gd,CL */
+ RMEdGdOp3(DSHRD,reg_cl);
+ break;
+ CASE_0F_D(0xaf) /* IMUL Gd,Ed */
+ {
+ RMGdEdOp3(DIMULD,*rmrd);
+ break;
+ }
+ CASE_0F_D(0xb1) /* CMPXCHG Ed,Gd */
+ {
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486NEWSLOW) goto illegal_opcode;
+ FillFlags();
+ GetRMrd;
+ if (rm >= 0xc0) {
+ GetEArd;
+ if (*eard==reg_eax) {
+ *eard=*rmrd;
+ SETFLAGBIT(ZF,1);
+ } else {
+ reg_eax=*eard;
+ SETFLAGBIT(ZF,0);
+ }
+ } else {
+ GetEAa;
+ Bit32u val=LoadMd(eaa);
+ if (val==reg_eax) {
+ SaveMd(eaa,*rmrd);
+ SETFLAGBIT(ZF,1);
+ } else {
+ SaveMd(eaa,val); // cmpxchg always issues a write
+ reg_eax=val;
+ SETFLAGBIT(ZF,0);
+ }
+ }
+ break;
+ }
+ CASE_0F_D(0xb2) /* LSS Ed */
+ {
+ GetRMrd;
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ if (CPU_SetSegGeneral(ss,LoadMw(eaa+4))) RUNEXCEPTION();
+ *rmrd=LoadMd(eaa);
+ break;
+ }
+ CASE_0F_D(0xb3) /* BTR Ed,Gd */
+ {
+ FillFlags();GetRMrd;
+ Bit32u mask=1 << (*rmrd & 31);
+ if (rm >= 0xc0 ) {
+ GetEArd;
+ SETFLAGBIT(CF,(*eard & mask));
+ *eard&= ~mask;
+ } else {
+ GetEAa;eaa+=(((Bit32s)*rmrd)>>5)*4;
+ Bit32u old=LoadMd(eaa);
+ SETFLAGBIT(CF,(old & mask));
+ SaveMd(eaa,old & ~mask);
+ }
+ break;
+ }
+ CASE_0F_D(0xb4) /* LFS Ed */
+ {
+ GetRMrd;
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ if (CPU_SetSegGeneral(fs,LoadMw(eaa+4))) RUNEXCEPTION();
+ *rmrd=LoadMd(eaa);
+ break;
+ }
+ CASE_0F_D(0xb5) /* LGS Ed */
+ {
+ GetRMrd;
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ if (CPU_SetSegGeneral(gs,LoadMw(eaa+4))) RUNEXCEPTION();
+ *rmrd=LoadMd(eaa);
+ break;
+ }
+ CASE_0F_D(0xb6) /* MOVZX Gd,Eb */
+ {
+ GetRMrd;
+ if (rm >= 0xc0 ) {GetEArb;*rmrd=*earb;}
+ else {GetEAa;*rmrd=LoadMb(eaa);}
+ break;
+ }
+ CASE_0F_D(0xb7) /* MOVXZ Gd,Ew */
+ {
+ GetRMrd;
+ if (rm >= 0xc0 ) {GetEArw;*rmrd=*earw;}
+ else {GetEAa;*rmrd=LoadMw(eaa);}
+ break;
+ }
+ CASE_0F_D(0xba) /* GRP8 Ed,Ib */
+ {
+ FillFlags();GetRM;
+ if (rm >= 0xc0 ) {
+ GetEArd;
+ Bit32u mask=1 << (Fetchb() & 31);
+ SETFLAGBIT(CF,(*eard & mask));
+ switch (rm & 0x38) {
+ case 0x20: /* BT */
+ break;
+ case 0x28: /* BTS */
+ *eard|=mask;
+ break;
+ case 0x30: /* BTR */
+ *eard&=~mask;
+ break;
+ case 0x38: /* BTC */
+ if (GETFLAG(CF)) *eard&=~mask;
+ else *eard|=mask;
+ break;
+ default:
+ E_Exit("CPU:66:0F:BA:Illegal subfunction %X",rm & 0x38);
+ }
+ } else {
+ GetEAa;Bit32u old=LoadMd(eaa);
+ Bit32u mask=1 << (Fetchb() & 31);
+ SETFLAGBIT(CF,(old & mask));
+ switch (rm & 0x38) {
+ case 0x20: /* BT */
+ break;
+ case 0x28: /* BTS */
+ SaveMd(eaa,old|mask);
+ break;
+ case 0x30: /* BTR */
+ SaveMd(eaa,old & ~mask);
+ break;
+ case 0x38: /* BTC */
+ if (GETFLAG(CF)) old&=~mask;
+ else old|=mask;
+ SaveMd(eaa,old);
+ break;
+ default:
+ E_Exit("CPU:66:0F:BA:Illegal subfunction %X",rm & 0x38);
+ }
+ }
+ break;
+ }
+ CASE_0F_D(0xbb) /* BTC Ed,Gd */
+ {
+ FillFlags();GetRMrd;
+ Bit32u mask=1 << (*rmrd & 31);
+ if (rm >= 0xc0 ) {
+ GetEArd;
+ SETFLAGBIT(CF,(*eard & mask));
+ *eard^=mask;
+ } else {
+ GetEAa;eaa+=(((Bit32s)*rmrd)>>5)*4;
+ Bit32u old=LoadMd(eaa);
+ SETFLAGBIT(CF,(old & mask));
+ SaveMd(eaa,old ^ mask);
+ }
+ break;
+ }
+ CASE_0F_D(0xbc) /* BSF Gd,Ed */
+ {
+ GetRMrd;
+ Bit32u result,value;
+ if (rm >= 0xc0) { GetEArd; value=*eard; }
+ else { GetEAa; value=LoadMd(eaa); }
+ if (value==0) {
+ SETFLAGBIT(ZF,true);
+ } else {
+ result = 0;
+ while ((value & 0x01)==0) { result++; value>>=1; }
+ SETFLAGBIT(ZF,false);
+ *rmrd = result;
+ }
+ lflags.type=t_UNKNOWN;
+ break;
+ }
+ CASE_0F_D(0xbd) /* BSR Gd,Ed */
+ {
+ GetRMrd;
+ Bit32u result,value;
+ if (rm >= 0xc0) { GetEArd; value=*eard; }
+ else { GetEAa; value=LoadMd(eaa); }
+ if (value==0) {
+ SETFLAGBIT(ZF,true);
+ } else {
+ result = 31; // Operandsize-1
+ while ((value & 0x80000000)==0) { result--; value<<=1; }
+ SETFLAGBIT(ZF,false);
+ *rmrd = result;
+ }
+ lflags.type=t_UNKNOWN;
+ break;
+ }
+ CASE_0F_D(0xbe) /* MOVSX Gd,Eb */
+ {
+ GetRMrd;
+ if (rm >= 0xc0 ) {GetEArb;*rmrd=*(Bit8s *)earb;}
+ else {GetEAa;*rmrd=LoadMbs(eaa);}
+ break;
+ }
+ CASE_0F_D(0xbf) /* MOVSX Gd,Ew */
+ {
+ GetRMrd;
+ if (rm >= 0xc0 ) {GetEArw;*rmrd=*(Bit16s *)earw;}
+ else {GetEAa;*rmrd=LoadMws(eaa);}
+ break;
+ }
+ CASE_0F_D(0xc1) /* XADD Gd,Ed */
+ {
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ GetRMrd;Bit32u oldrmrd=*rmrd;
+ if (rm >= 0xc0 ) {GetEArd;*rmrd=*eard;*eard+=oldrmrd;}
+ else {GetEAa;*rmrd=LoadMd(eaa);SaveMd(eaa,LoadMd(eaa)+oldrmrd);}
+ break;
+ }
+ CASE_0F_D(0xc8) /* BSWAP EAX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_eax);break;
+ CASE_0F_D(0xc9) /* BSWAP ECX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_ecx);break;
+ CASE_0F_D(0xca) /* BSWAP EDX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_edx);break;
+ CASE_0F_D(0xcb) /* BSWAP EBX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_ebx);break;
+ CASE_0F_D(0xcc) /* BSWAP ESP */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_esp);break;
+ CASE_0F_D(0xcd) /* BSWAP EBP */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_ebp);break;
+ CASE_0F_D(0xce) /* BSWAP ESI */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_esi);break;
+ CASE_0F_D(0xcf) /* BSWAP EDI */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_edi);break;
--- /dev/null
+/*
+ * 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.
+ */
+
+ CASE_B(0x00) /* ADD Eb,Gb */
+ RMEbGb(ADDB);break;
+ CASE_W(0x01) /* ADD Ew,Gw */
+ RMEwGw(ADDW);break;
+ CASE_B(0x02) /* ADD Gb,Eb */
+ RMGbEb(ADDB);break;
+ CASE_W(0x03) /* ADD Gw,Ew */
+ RMGwEw(ADDW);break;
+ CASE_B(0x04) /* ADD AL,Ib */
+ ALIb(ADDB);break;
+ CASE_W(0x05) /* ADD AX,Iw */
+ AXIw(ADDW);break;
+ CASE_W(0x06) /* PUSH ES */
+ Push_16(SegValue(es));break;
+ CASE_W(0x07) /* POP ES */
+ if (CPU_PopSeg(es,false)) RUNEXCEPTION();
+ break;
+ CASE_B(0x08) /* OR Eb,Gb */
+ RMEbGb(ORB);break;
+ CASE_W(0x09) /* OR Ew,Gw */
+ RMEwGw(ORW);break;
+ CASE_B(0x0a) /* OR Gb,Eb */
+ RMGbEb(ORB);break;
+ CASE_W(0x0b) /* OR Gw,Ew */
+ RMGwEw(ORW);break;
+ CASE_B(0x0c) /* OR AL,Ib */
+ ALIb(ORB);break;
+ CASE_W(0x0d) /* OR AX,Iw */
+ AXIw(ORW);break;
+ CASE_W(0x0e) /* PUSH CS */
+ Push_16(SegValue(cs));break;
+ CASE_B(0x0f) /* 2 byte opcodes*/
+ core.opcode_index|=OPCODE_0F;
+ goto restart_opcode;
+ break;
+ CASE_B(0x10) /* ADC Eb,Gb */
+ RMEbGb(ADCB);break;
+ CASE_W(0x11) /* ADC Ew,Gw */
+ RMEwGw(ADCW);break;
+ CASE_B(0x12) /* ADC Gb,Eb */
+ RMGbEb(ADCB);break;
+ CASE_W(0x13) /* ADC Gw,Ew */
+ RMGwEw(ADCW);break;
+ CASE_B(0x14) /* ADC AL,Ib */
+ ALIb(ADCB);break;
+ CASE_W(0x15) /* ADC AX,Iw */
+ AXIw(ADCW);break;
+ CASE_W(0x16) /* PUSH SS */
+ Push_16(SegValue(ss));break;
+ CASE_W(0x17) /* POP SS */
+ if (CPU_PopSeg(ss,false)) RUNEXCEPTION();
+ CPU_Cycles++; //Always do another instruction
+ break;
+ CASE_B(0x18) /* SBB Eb,Gb */
+ RMEbGb(SBBB);break;
+ CASE_W(0x19) /* SBB Ew,Gw */
+ RMEwGw(SBBW);break;
+ CASE_B(0x1a) /* SBB Gb,Eb */
+ RMGbEb(SBBB);break;
+ CASE_W(0x1b) /* SBB Gw,Ew */
+ RMGwEw(SBBW);break;
+ CASE_B(0x1c) /* SBB AL,Ib */
+ ALIb(SBBB);break;
+ CASE_W(0x1d) /* SBB AX,Iw */
+ AXIw(SBBW);break;
+ CASE_W(0x1e) /* PUSH DS */
+ Push_16(SegValue(ds));break;
+ CASE_W(0x1f) /* POP DS */
+ if (CPU_PopSeg(ds,false)) RUNEXCEPTION();
+ break;
+ CASE_B(0x20) /* AND Eb,Gb */
+ RMEbGb(ANDB);break;
+ CASE_W(0x21) /* AND Ew,Gw */
+ RMEwGw(ANDW);break;
+ CASE_B(0x22) /* AND Gb,Eb */
+ RMGbEb(ANDB);break;
+ CASE_W(0x23) /* AND Gw,Ew */
+ RMGwEw(ANDW);break;
+ CASE_B(0x24) /* AND AL,Ib */
+ ALIb(ANDB);break;
+ CASE_W(0x25) /* AND AX,Iw */
+ AXIw(ANDW);break;
+ CASE_B(0x26) /* SEG ES: */
+ DO_PREFIX_SEG(es);break;
+ CASE_B(0x27) /* DAA */
+ DAA();break;
+ CASE_B(0x28) /* SUB Eb,Gb */
+ RMEbGb(SUBB);break;
+ CASE_W(0x29) /* SUB Ew,Gw */
+ RMEwGw(SUBW);break;
+ CASE_B(0x2a) /* SUB Gb,Eb */
+ RMGbEb(SUBB);break;
+ CASE_W(0x2b) /* SUB Gw,Ew */
+ RMGwEw(SUBW);break;
+ CASE_B(0x2c) /* SUB AL,Ib */
+ ALIb(SUBB);break;
+ CASE_W(0x2d) /* SUB AX,Iw */
+ AXIw(SUBW);break;
+ CASE_B(0x2e) /* SEG CS: */
+ DO_PREFIX_SEG(cs);break;
+ CASE_B(0x2f) /* DAS */
+ DAS();break;
+ CASE_B(0x30) /* XOR Eb,Gb */
+ RMEbGb(XORB);break;
+ CASE_W(0x31) /* XOR Ew,Gw */
+ RMEwGw(XORW);break;
+ CASE_B(0x32) /* XOR Gb,Eb */
+ RMGbEb(XORB);break;
+ CASE_W(0x33) /* XOR Gw,Ew */
+ RMGwEw(XORW);break;
+ CASE_B(0x34) /* XOR AL,Ib */
+ ALIb(XORB);break;
+ CASE_W(0x35) /* XOR AX,Iw */
+ AXIw(XORW);break;
+ CASE_B(0x36) /* SEG SS: */
+ DO_PREFIX_SEG(ss);break;
+ CASE_B(0x37) /* AAA */
+ AAA();break;
+ CASE_B(0x38) /* CMP Eb,Gb */
+ RMEbGb(CMPB);break;
+ CASE_W(0x39) /* CMP Ew,Gw */
+ RMEwGw(CMPW);break;
+ CASE_B(0x3a) /* CMP Gb,Eb */
+ RMGbEb(CMPB);break;
+ CASE_W(0x3b) /* CMP Gw,Ew */
+ RMGwEw(CMPW);break;
+ CASE_B(0x3c) /* CMP AL,Ib */
+ ALIb(CMPB);break;
+ CASE_W(0x3d) /* CMP AX,Iw */
+ AXIw(CMPW);break;
+ CASE_B(0x3e) /* SEG DS: */
+ DO_PREFIX_SEG(ds);break;
+ CASE_B(0x3f) /* AAS */
+ AAS();break;
+ CASE_W(0x40) /* INC AX */
+ INCW(reg_ax,LoadRw,SaveRw);break;
+ CASE_W(0x41) /* INC CX */
+ INCW(reg_cx,LoadRw,SaveRw);break;
+ CASE_W(0x42) /* INC DX */
+ INCW(reg_dx,LoadRw,SaveRw);break;
+ CASE_W(0x43) /* INC BX */
+ INCW(reg_bx,LoadRw,SaveRw);break;
+ CASE_W(0x44) /* INC SP */
+ INCW(reg_sp,LoadRw,SaveRw);break;
+ CASE_W(0x45) /* INC BP */
+ INCW(reg_bp,LoadRw,SaveRw);break;
+ CASE_W(0x46) /* INC SI */
+ INCW(reg_si,LoadRw,SaveRw);break;
+ CASE_W(0x47) /* INC DI */
+ INCW(reg_di,LoadRw,SaveRw);break;
+ CASE_W(0x48) /* DEC AX */
+ DECW(reg_ax,LoadRw,SaveRw);break;
+ CASE_W(0x49) /* DEC CX */
+ DECW(reg_cx,LoadRw,SaveRw);break;
+ CASE_W(0x4a) /* DEC DX */
+ DECW(reg_dx,LoadRw,SaveRw);break;
+ CASE_W(0x4b) /* DEC BX */
+ DECW(reg_bx,LoadRw,SaveRw);break;
+ CASE_W(0x4c) /* DEC SP */
+ DECW(reg_sp,LoadRw,SaveRw);break;
+ CASE_W(0x4d) /* DEC BP */
+ DECW(reg_bp,LoadRw,SaveRw);break;
+ CASE_W(0x4e) /* DEC SI */
+ DECW(reg_si,LoadRw,SaveRw);break;
+ CASE_W(0x4f) /* DEC DI */
+ DECW(reg_di,LoadRw,SaveRw);break;
+ CASE_W(0x50) /* PUSH AX */
+ Push_16(reg_ax);break;
+ CASE_W(0x51) /* PUSH CX */
+ Push_16(reg_cx);break;
+ CASE_W(0x52) /* PUSH DX */
+ Push_16(reg_dx);break;
+ CASE_W(0x53) /* PUSH BX */
+ Push_16(reg_bx);break;
+ CASE_W(0x54) /* PUSH SP */
+ Push_16(reg_sp);break;
+ CASE_W(0x55) /* PUSH BP */
+ Push_16(reg_bp);break;
+ CASE_W(0x56) /* PUSH SI */
+ Push_16(reg_si);break;
+ CASE_W(0x57) /* PUSH DI */
+ Push_16(reg_di);break;
+ CASE_W(0x58) /* POP AX */
+ reg_ax=Pop_16();break;
+ CASE_W(0x59) /* POP CX */
+ reg_cx=Pop_16();break;
+ CASE_W(0x5a) /* POP DX */
+ reg_dx=Pop_16();break;
+ CASE_W(0x5b) /* POP BX */
+ reg_bx=Pop_16();break;
+ CASE_W(0x5c) /* POP SP */
+ reg_sp=Pop_16();break;
+ CASE_W(0x5d) /* POP BP */
+ reg_bp=Pop_16();break;
+ CASE_W(0x5e) /* POP SI */
+ reg_si=Pop_16();break;
+ CASE_W(0x5f) /* POP DI */
+ reg_di=Pop_16();break;
+ CASE_W(0x60) /* PUSHA */
+ {
+ Bit16u old_sp=reg_sp;
+ Push_16(reg_ax);Push_16(reg_cx);Push_16(reg_dx);Push_16(reg_bx);
+ Push_16(old_sp);Push_16(reg_bp);Push_16(reg_si);Push_16(reg_di);
+ }
+ break;
+ CASE_W(0x61) /* POPA */
+ reg_di=Pop_16();reg_si=Pop_16();reg_bp=Pop_16();Pop_16();//Don't save SP
+ reg_bx=Pop_16();reg_dx=Pop_16();reg_cx=Pop_16();reg_ax=Pop_16();
+ break;
+ CASE_W(0x62) /* BOUND */
+ {
+ Bit16s bound_min, bound_max;
+ GetRMrw;GetEAa;
+ bound_min=LoadMw(eaa);
+ bound_max=LoadMw(eaa+2);
+ if ( (((Bit16s)*rmrw) < bound_min) || (((Bit16s)*rmrw) > bound_max) ) {
+ EXCEPTION(5);
+ }
+ }
+ break;
+ CASE_W(0x63) /* ARPL Ew,Rw */
+ {
+ if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
+ GetRMrw;
+ if (rm >= 0xc0 ) {
+ GetEArw;Bitu new_sel=*earw;
+ CPU_ARPL(new_sel,*rmrw);
+ *earw=(Bit16u)new_sel;
+ } else {
+ GetEAa;Bitu new_sel=LoadMw(eaa);
+ CPU_ARPL(new_sel,*rmrw);
+ SaveMw(eaa,(Bit16u)new_sel);
+ }
+ }
+ break;
+ CASE_B(0x64) /* SEG FS: */
+ DO_PREFIX_SEG(fs);break;
+ CASE_B(0x65) /* SEG GS: */
+ DO_PREFIX_SEG(gs);break;
+ CASE_B(0x66) /* Operand Size Prefix */
+ core.opcode_index=(cpu.code.big^0x1)*0x200;
+ goto restart_opcode;
+ CASE_B(0x67) /* Address Size Prefix */
+ DO_PREFIX_ADDR();
+ CASE_W(0x68) /* PUSH Iw */
+ Push_16(Fetchw());break;
+ CASE_W(0x69) /* IMUL Gw,Ew,Iw */
+ RMGwEwOp3(DIMULW,Fetchws());
+ break;
+ CASE_W(0x6a) /* PUSH Ib */
+ Push_16(Fetchbs());
+ break;
+ CASE_W(0x6b) /* IMUL Gw,Ew,Ib */
+ RMGwEwOp3(DIMULW,Fetchbs());
+ break;
+ CASE_B(0x6c) /* INSB */
+ if (CPU_IO_Exception(reg_dx,1)) RUNEXCEPTION();
+ DoString(R_INSB);break;
+ CASE_W(0x6d) /* INSW */
+ if (CPU_IO_Exception(reg_dx,2)) RUNEXCEPTION();
+ DoString(R_INSW);break;
+ CASE_B(0x6e) /* OUTSB */
+ if (CPU_IO_Exception(reg_dx,1)) RUNEXCEPTION();
+ DoString(R_OUTSB);break;
+ CASE_W(0x6f) /* OUTSW */
+ if (CPU_IO_Exception(reg_dx,2)) RUNEXCEPTION();
+ DoString(R_OUTSW);break;
+ CASE_W(0x70) /* JO */
+ JumpCond16_b(TFLG_O);break;
+ CASE_W(0x71) /* JNO */
+ JumpCond16_b(TFLG_NO);break;
+ CASE_W(0x72) /* JB */
+ JumpCond16_b(TFLG_B);break;
+ CASE_W(0x73) /* JNB */
+ JumpCond16_b(TFLG_NB);break;
+ CASE_W(0x74) /* JZ */
+ JumpCond16_b(TFLG_Z);break;
+ CASE_W(0x75) /* JNZ */
+ JumpCond16_b(TFLG_NZ);break;
+ CASE_W(0x76) /* JBE */
+ JumpCond16_b(TFLG_BE);break;
+ CASE_W(0x77) /* JNBE */
+ JumpCond16_b(TFLG_NBE);break;
+ CASE_W(0x78) /* JS */
+ JumpCond16_b(TFLG_S);break;
+ CASE_W(0x79) /* JNS */
+ JumpCond16_b(TFLG_NS);break;
+ CASE_W(0x7a) /* JP */
+ JumpCond16_b(TFLG_P);break;
+ CASE_W(0x7b) /* JNP */
+ JumpCond16_b(TFLG_NP);break;
+ CASE_W(0x7c) /* JL */
+ JumpCond16_b(TFLG_L);break;
+ CASE_W(0x7d) /* JNL */
+ JumpCond16_b(TFLG_NL);break;
+ CASE_W(0x7e) /* JLE */
+ JumpCond16_b(TFLG_LE);break;
+ CASE_W(0x7f) /* JNLE */
+ JumpCond16_b(TFLG_NLE);break;
+ CASE_B(0x80) /* Grpl Eb,Ib */
+ CASE_B(0x82) /* Grpl Eb,Ib Mirror instruction*/
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ if (rm>= 0xc0) {
+ GetEArb;Bit8u ib=Fetchb();
+ switch (which) {
+ case 0x00:ADDB(*earb,ib,LoadRb,SaveRb);break;
+ case 0x01: ORB(*earb,ib,LoadRb,SaveRb);break;
+ case 0x02:ADCB(*earb,ib,LoadRb,SaveRb);break;
+ case 0x03:SBBB(*earb,ib,LoadRb,SaveRb);break;
+ case 0x04:ANDB(*earb,ib,LoadRb,SaveRb);break;
+ case 0x05:SUBB(*earb,ib,LoadRb,SaveRb);break;
+ case 0x06:XORB(*earb,ib,LoadRb,SaveRb);break;
+ case 0x07:CMPB(*earb,ib,LoadRb,SaveRb);break;
+ }
+ } else {
+ GetEAa;Bit8u ib=Fetchb();
+ switch (which) {
+ case 0x00:ADDB(eaa,ib,LoadMb,SaveMb);break;
+ case 0x01: ORB(eaa,ib,LoadMb,SaveMb);break;
+ case 0x02:ADCB(eaa,ib,LoadMb,SaveMb);break;
+ case 0x03:SBBB(eaa,ib,LoadMb,SaveMb);break;
+ case 0x04:ANDB(eaa,ib,LoadMb,SaveMb);break;
+ case 0x05:SUBB(eaa,ib,LoadMb,SaveMb);break;
+ case 0x06:XORB(eaa,ib,LoadMb,SaveMb);break;
+ case 0x07:CMPB(eaa,ib,LoadMb,SaveMb);break;
+ }
+ }
+ break;
+ }
+ CASE_W(0x81) /* Grpl Ew,Iw */
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ if (rm>= 0xc0) {
+ GetEArw;Bit16u iw=Fetchw();
+ switch (which) {
+ case 0x00:ADDW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x01: ORW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x02:ADCW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x03:SBBW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x04:ANDW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x05:SUBW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x06:XORW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x07:CMPW(*earw,iw,LoadRw,SaveRw);break;
+ }
+ } else {
+ GetEAa;Bit16u iw=Fetchw();
+ switch (which) {
+ case 0x00:ADDW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x01: ORW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x02:ADCW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x03:SBBW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x04:ANDW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x05:SUBW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x06:XORW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x07:CMPW(eaa,iw,LoadMw,SaveMw);break;
+ }
+ }
+ break;
+ }
+ CASE_W(0x83) /* Grpl Ew,Ix */
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ if (rm>= 0xc0) {
+ GetEArw;Bit16u iw=(Bit16s)Fetchbs();
+ switch (which) {
+ case 0x00:ADDW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x01: ORW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x02:ADCW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x03:SBBW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x04:ANDW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x05:SUBW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x06:XORW(*earw,iw,LoadRw,SaveRw);break;
+ case 0x07:CMPW(*earw,iw,LoadRw,SaveRw);break;
+ }
+ } else {
+ GetEAa;Bit16u iw=(Bit16s)Fetchbs();
+ switch (which) {
+ case 0x00:ADDW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x01: ORW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x02:ADCW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x03:SBBW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x04:ANDW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x05:SUBW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x06:XORW(eaa,iw,LoadMw,SaveMw);break;
+ case 0x07:CMPW(eaa,iw,LoadMw,SaveMw);break;
+ }
+ }
+ break;
+ }
+ CASE_B(0x84) /* TEST Eb,Gb */
+ RMEbGb(TESTB);
+ break;
+ CASE_W(0x85) /* TEST Ew,Gw */
+ RMEwGw(TESTW);
+ break;
+ CASE_B(0x86) /* XCHG Eb,Gb */
+ {
+ GetRMrb;Bit8u oldrmrb=*rmrb;
+ if (rm >= 0xc0 ) {GetEArb;*rmrb=*earb;*earb=oldrmrb;}
+ else {GetEAa;*rmrb=LoadMb(eaa);SaveMb(eaa,oldrmrb);}
+ break;
+ }
+ CASE_W(0x87) /* XCHG Ew,Gw */
+ {
+ GetRMrw;Bit16u oldrmrw=*rmrw;
+ if (rm >= 0xc0 ) {GetEArw;*rmrw=*earw;*earw=oldrmrw;}
+ else {GetEAa;*rmrw=LoadMw(eaa);SaveMw(eaa,oldrmrw);}
+ break;
+ }
+ CASE_B(0x88) /* MOV Eb,Gb */
+ {
+ GetRMrb;
+ if (rm >= 0xc0 ) {GetEArb;*earb=*rmrb;}
+ else {
+ if (cpu.pmode) {
+ if (GCC_UNLIKELY((rm==0x05) && (!cpu.code.big))) {
+ Descriptor desc;
+ cpu.gdt.GetDescriptor(SegValue(core.base_val_ds),desc);
+ if ((desc.Type()==DESC_CODE_R_NC_A) || (desc.Type()==DESC_CODE_R_NC_NA)) {
+ CPU_Exception(EXCEPTION_GP,SegValue(core.base_val_ds) & 0xfffc);
+ continue;
+ }
+ }
+ }
+ GetEAa;SaveMb(eaa,*rmrb);
+ }
+ break;
+ }
+ CASE_W(0x89) /* MOV Ew,Gw */
+ {
+ GetRMrw;
+ if (rm >= 0xc0 ) {GetEArw;*earw=*rmrw;}
+ else {GetEAa;SaveMw(eaa,*rmrw);}
+ break;
+ }
+ CASE_B(0x8a) /* MOV Gb,Eb */
+ {
+ GetRMrb;
+ if (rm >= 0xc0 ) {GetEArb;*rmrb=*earb;}
+ else {GetEAa;*rmrb=LoadMb(eaa);}
+ break;
+ }
+ CASE_W(0x8b) /* MOV Gw,Ew */
+ {
+ GetRMrw;
+ if (rm >= 0xc0 ) {GetEArw;*rmrw=*earw;}
+ else {GetEAa;*rmrw=LoadMw(eaa);}
+ break;
+ }
+ CASE_W(0x8c) /* Mov Ew,Sw */
+ {
+ GetRM;Bit16u val;Bitu which=(rm>>3)&7;
+ switch (which) {
+ case 0x00: /* MOV Ew,ES */
+ val=SegValue(es);break;
+ case 0x01: /* MOV Ew,CS */
+ val=SegValue(cs);break;
+ case 0x02: /* MOV Ew,SS */
+ val=SegValue(ss);break;
+ case 0x03: /* MOV Ew,DS */
+ val=SegValue(ds);break;
+ case 0x04: /* MOV Ew,FS */
+ val=SegValue(fs);break;
+ case 0x05: /* MOV Ew,GS */
+ val=SegValue(gs);break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("CPU:8c:Illegal RM Byte");
+ goto illegal_opcode;
+ }
+ if (rm >= 0xc0 ) {GetEArw;*earw=val;}
+ else {GetEAa;SaveMw(eaa,val);}
+ break;
+ }
+ CASE_W(0x8d) /* LEA Gw */
+ {
+ //Little hack to always use segprefixed version
+ BaseDS=BaseSS=0;
+ GetRMrw;
+ if (TEST_PREFIX_ADDR) {
+ *rmrw=(Bit16u)(*EATable[256+rm])();
+ } else {
+ *rmrw=(Bit16u)(*EATable[rm])();
+ }
+ break;
+ }
+ CASE_B(0x8e) /* MOV Sw,Ew */
+ {
+ GetRM;Bit16u val;Bitu which=(rm>>3)&7;
+ if (rm >= 0xc0 ) {GetEArw;val=*earw;}
+ else {GetEAa;val=LoadMw(eaa);}
+ switch (which) {
+ case 0x02: /* MOV SS,Ew */
+ CPU_Cycles++; //Always do another instruction
+ case 0x00: /* MOV ES,Ew */
+ case 0x03: /* MOV DS,Ew */
+ case 0x05: /* MOV GS,Ew */
+ case 0x04: /* MOV FS,Ew */
+ if (CPU_SetSegGeneral((SegNames)which,val)) RUNEXCEPTION();
+ break;
+ default:
+ goto illegal_opcode;
+ }
+ break;
+ }
+ CASE_W(0x8f) /* POP Ew */
+ {
+ Bit16u val=Pop_16();
+ GetRM;
+ if (rm >= 0xc0 ) {GetEArw;*earw=val;}
+ else {GetEAa;SaveMw(eaa,val);}
+ break;
+ }
+ CASE_B(0x90) /* NOP */
+ break;
+ CASE_W(0x91) /* XCHG CX,AX */
+ { Bit16u temp=reg_ax;reg_ax=reg_cx;reg_cx=temp; }
+ break;
+ CASE_W(0x92) /* XCHG DX,AX */
+ { Bit16u temp=reg_ax;reg_ax=reg_dx;reg_dx=temp; }
+ break;
+ CASE_W(0x93) /* XCHG BX,AX */
+ { Bit16u temp=reg_ax;reg_ax=reg_bx;reg_bx=temp; }
+ break;
+ CASE_W(0x94) /* XCHG SP,AX */
+ { Bit16u temp=reg_ax;reg_ax=reg_sp;reg_sp=temp; }
+ break;
+ CASE_W(0x95) /* XCHG BP,AX */
+ { Bit16u temp=reg_ax;reg_ax=reg_bp;reg_bp=temp; }
+ break;
+ CASE_W(0x96) /* XCHG SI,AX */
+ { Bit16u temp=reg_ax;reg_ax=reg_si;reg_si=temp; }
+ break;
+ CASE_W(0x97) /* XCHG DI,AX */
+ { Bit16u temp=reg_ax;reg_ax=reg_di;reg_di=temp; }
+ break;
+ CASE_W(0x98) /* CBW */
+ reg_ax=(Bit8s)reg_al;break;
+ CASE_W(0x99) /* CWD */
+ if (reg_ax & 0x8000) reg_dx=0xffff;else reg_dx=0;
+ break;
+ CASE_W(0x9a) /* CALL Ap */
+ {
+ FillFlags();
+ Bit16u newip=Fetchw();Bit16u newcs=Fetchw();
+ CPU_CALL(false,newcs,newip,GETIP);
+#if CPU_TRAP_CHECK
+ if (GETFLAG(TF)) {
+ cpudecoder=CPU_Core_Normal_Trap_Run;
+ return CBRET_NONE;
+ }
+#endif
+ continue;
+ }
+ CASE_B(0x9b) /* WAIT */
+ break; /* No waiting here */
+ CASE_W(0x9c) /* PUSHF */
+ if (CPU_PUSHF(false)) RUNEXCEPTION();
+ break;
+ CASE_W(0x9d) /* POPF */
+ if (CPU_POPF(false)) RUNEXCEPTION();
+#if CPU_TRAP_CHECK
+ if (GETFLAG(TF)) {
+ cpudecoder=CPU_Core_Normal_Trap_Run;
+ goto decode_end;
+ }
+#endif
+#if CPU_PIC_CHECK
+ if (GETFLAG(IF) && PIC_IRQCheck) goto decode_end;
+#endif
+ break;
+ CASE_B(0x9e) /* SAHF */
+ SETFLAGSb(reg_ah);
+ break;
+ CASE_B(0x9f) /* LAHF */
+ FillFlags();
+ reg_ah=reg_flags&0xff;
+ break;
+ CASE_B(0xa0) /* MOV AL,Ob */
+ {
+ GetEADirect;
+ reg_al=LoadMb(eaa);
+ }
+ break;
+ CASE_W(0xa1) /* MOV AX,Ow */
+ {
+ GetEADirect;
+ reg_ax=LoadMw(eaa);
+ }
+ break;
+ CASE_B(0xa2) /* MOV Ob,AL */
+ {
+ GetEADirect;
+ SaveMb(eaa,reg_al);
+ }
+ break;
+ CASE_W(0xa3) /* MOV Ow,AX */
+ {
+ GetEADirect;
+ SaveMw(eaa,reg_ax);
+ }
+ break;
+ CASE_B(0xa4) /* MOVSB */
+ DoString(R_MOVSB);break;
+ CASE_W(0xa5) /* MOVSW */
+ DoString(R_MOVSW);break;
+ CASE_B(0xa6) /* CMPSB */
+ DoString(R_CMPSB);break;
+ CASE_W(0xa7) /* CMPSW */
+ DoString(R_CMPSW);break;
+ CASE_B(0xa8) /* TEST AL,Ib */
+ ALIb(TESTB);break;
+ CASE_W(0xa9) /* TEST AX,Iw */
+ AXIw(TESTW);break;
+ CASE_B(0xaa) /* STOSB */
+ DoString(R_STOSB);break;
+ CASE_W(0xab) /* STOSW */
+ DoString(R_STOSW);break;
+ CASE_B(0xac) /* LODSB */
+ DoString(R_LODSB);break;
+ CASE_W(0xad) /* LODSW */
+ DoString(R_LODSW);break;
+ CASE_B(0xae) /* SCASB */
+ DoString(R_SCASB);break;
+ CASE_W(0xaf) /* SCASW */
+ DoString(R_SCASW);break;
+ CASE_B(0xb0) /* MOV AL,Ib */
+ reg_al=Fetchb();break;
+ CASE_B(0xb1) /* MOV CL,Ib */
+ reg_cl=Fetchb();break;
+ CASE_B(0xb2) /* MOV DL,Ib */
+ reg_dl=Fetchb();break;
+ CASE_B(0xb3) /* MOV BL,Ib */
+ reg_bl=Fetchb();break;
+ CASE_B(0xb4) /* MOV AH,Ib */
+ reg_ah=Fetchb();break;
+ CASE_B(0xb5) /* MOV CH,Ib */
+ reg_ch=Fetchb();break;
+ CASE_B(0xb6) /* MOV DH,Ib */
+ reg_dh=Fetchb();break;
+ CASE_B(0xb7) /* MOV BH,Ib */
+ reg_bh=Fetchb();break;
+ CASE_W(0xb8) /* MOV AX,Iw */
+ reg_ax=Fetchw();break;
+ CASE_W(0xb9) /* MOV CX,Iw */
+ reg_cx=Fetchw();break;
+ CASE_W(0xba) /* MOV DX,Iw */
+ reg_dx=Fetchw();break;
+ CASE_W(0xbb) /* MOV BX,Iw */
+ reg_bx=Fetchw();break;
+ CASE_W(0xbc) /* MOV SP,Iw */
+ reg_sp=Fetchw();break;
+ CASE_W(0xbd) /* MOV BP.Iw */
+ reg_bp=Fetchw();break;
+ CASE_W(0xbe) /* MOV SI,Iw */
+ reg_si=Fetchw();break;
+ CASE_W(0xbf) /* MOV DI,Iw */
+ reg_di=Fetchw();break;
+ CASE_B(0xc0) /* GRP2 Eb,Ib */
+ GRP2B(Fetchb());break;
+ CASE_W(0xc1) /* GRP2 Ew,Ib */
+ GRP2W(Fetchb());break;
+ CASE_W(0xc2) /* RETN Iw */
+ reg_eip=Pop_16();
+ reg_esp+=Fetchw();
+ continue;
+ CASE_W(0xc3) /* RETN */
+ reg_eip=Pop_16();
+ continue;
+ CASE_W(0xc4) /* LES */
+ {
+ GetRMrw;
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ if (CPU_SetSegGeneral(es,LoadMw(eaa+2))) RUNEXCEPTION();
+ *rmrw=LoadMw(eaa);
+ break;
+ }
+ CASE_W(0xc5) /* LDS */
+ {
+ GetRMrw;
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ if (CPU_SetSegGeneral(ds,LoadMw(eaa+2))) RUNEXCEPTION();
+ *rmrw=LoadMw(eaa);
+ break;
+ }
+ CASE_B(0xc6) /* MOV Eb,Ib */
+ {
+ GetRM;
+ if (rm >= 0xc0) {GetEArb;*earb=Fetchb();}
+ else {GetEAa;SaveMb(eaa,Fetchb());}
+ break;
+ }
+ CASE_W(0xc7) /* MOV EW,Iw */
+ {
+ GetRM;
+ if (rm >= 0xc0) {GetEArw;*earw=Fetchw();}
+ else {GetEAa;SaveMw(eaa,Fetchw());}
+ break;
+ }
+ CASE_W(0xc8) /* ENTER Iw,Ib */
+ {
+ Bitu bytes=Fetchw();
+ Bitu level=Fetchb();
+ CPU_ENTER(false,bytes,level);
+ }
+ break;
+ CASE_W(0xc9) /* LEAVE */
+ reg_esp&=cpu.stack.notmask;
+ reg_esp|=(reg_ebp&cpu.stack.mask);
+ reg_bp=Pop_16();
+ break;
+ CASE_W(0xca) /* RETF Iw */
+ {
+ Bitu words=Fetchw();
+ FillFlags();
+ CPU_RET(false,words,GETIP);
+ continue;
+ }
+ CASE_W(0xcb) /* RETF */
+ FillFlags();
+ CPU_RET(false,0,GETIP);
+ continue;
+ CASE_B(0xcc) /* INT3 */
+#if C_DEBUG
+ FillFlags();
+ if (DEBUG_Breakpoint())
+ return debugCallback;
+#endif
+ CPU_SW_Interrupt_NoIOPLCheck(3,GETIP);
+#if CPU_TRAP_CHECK
+ cpu.trap_skip=true;
+#endif
+ continue;
+ CASE_B(0xcd) /* INT Ib */
+ {
+ Bit8u num=Fetchb();
+#if C_DEBUG
+ FillFlags();
+ if (DEBUG_IntBreakpoint(num)) {
+ return debugCallback;
+ }
+#endif
+ CPU_SW_Interrupt(num,GETIP);
+#if CPU_TRAP_CHECK
+ cpu.trap_skip=true;
+#endif
+ continue;
+ }
+ CASE_B(0xce) /* INTO */
+ if (get_OF()) {
+ CPU_SW_Interrupt(4,GETIP);
+#if CPU_TRAP_CHECK
+ cpu.trap_skip=true;
+#endif
+ continue;
+ }
+ break;
+ CASE_W(0xcf) /* IRET */
+ {
+ CPU_IRET(false,GETIP);
+#if CPU_TRAP_CHECK
+ if (GETFLAG(TF)) {
+ cpudecoder=CPU_Core_Normal_Trap_Run;
+ return CBRET_NONE;
+ }
+#endif
+#if CPU_PIC_CHECK
+ if (GETFLAG(IF) && PIC_IRQCheck) return CBRET_NONE;
+#endif
+ continue;
+ }
+ CASE_B(0xd0) /* GRP2 Eb,1 */
+ GRP2B(1);break;
+ CASE_W(0xd1) /* GRP2 Ew,1 */
+ GRP2W(1);break;
+ CASE_B(0xd2) /* GRP2 Eb,CL */
+ GRP2B(reg_cl);break;
+ CASE_W(0xd3) /* GRP2 Ew,CL */
+ GRP2W(reg_cl);break;
+ CASE_B(0xd4) /* AAM Ib */
+ AAM(Fetchb());break;
+ CASE_B(0xd5) /* AAD Ib */
+ AAD(Fetchb());break;
+ CASE_B(0xd6) /* SALC */
+ reg_al = get_CF() ? 0xFF : 0;
+ break;
+ CASE_B(0xd7) /* XLAT */
+ if (TEST_PREFIX_ADDR) {
+ reg_al=LoadMb(BaseDS+(Bit32u)(reg_ebx+reg_al));
+ } else {
+ reg_al=LoadMb(BaseDS+(Bit16u)(reg_bx+reg_al));
+ }
+ break;
+#ifdef CPU_FPU
+ CASE_B(0xd8) /* FPU ESC 0 */
+ FPU_ESC(0);break;
+ CASE_B(0xd9) /* FPU ESC 1 */
+ FPU_ESC(1);break;
+ CASE_B(0xda) /* FPU ESC 2 */
+ FPU_ESC(2);break;
+ CASE_B(0xdb) /* FPU ESC 3 */
+ FPU_ESC(3);break;
+ CASE_B(0xdc) /* FPU ESC 4 */
+ FPU_ESC(4);break;
+ CASE_B(0xdd) /* FPU ESC 5 */
+ FPU_ESC(5);break;
+ CASE_B(0xde) /* FPU ESC 6 */
+ FPU_ESC(6);break;
+ CASE_B(0xdf) /* FPU ESC 7 */
+ FPU_ESC(7);break;
+#else
+ CASE_B(0xd8) /* FPU ESC 0 */
+ CASE_B(0xd9) /* FPU ESC 1 */
+ CASE_B(0xda) /* FPU ESC 2 */
+ CASE_B(0xdb) /* FPU ESC 3 */
+ CASE_B(0xdc) /* FPU ESC 4 */
+ CASE_B(0xdd) /* FPU ESC 5 */
+ CASE_B(0xde) /* FPU ESC 6 */
+ CASE_B(0xdf) /* FPU ESC 7 */
+ {
+ LOG(LOG_CPU,LOG_NORMAL)("FPU used");
+ Bit8u rm=Fetchb();
+ if (rm<0xc0) GetEAa;
+ }
+ break;
+#endif
+ CASE_W(0xe0) /* LOOPNZ */
+ if (TEST_PREFIX_ADDR) {
+ JumpCond16_b(--reg_ecx && !get_ZF());
+ } else {
+ JumpCond16_b(--reg_cx && !get_ZF());
+ }
+ break;
+ CASE_W(0xe1) /* LOOPZ */
+ if (TEST_PREFIX_ADDR) {
+ JumpCond16_b(--reg_ecx && get_ZF());
+ } else {
+ JumpCond16_b(--reg_cx && get_ZF());
+ }
+ break;
+ CASE_W(0xe2) /* LOOP */
+ if (TEST_PREFIX_ADDR) {
+ JumpCond16_b(--reg_ecx);
+ } else {
+ JumpCond16_b(--reg_cx);
+ }
+ break;
+ CASE_W(0xe3) /* JCXZ */
+ JumpCond16_b(!(reg_ecx & AddrMaskTable[core.prefixes& PREFIX_ADDR]));
+ break;
+ CASE_B(0xe4) /* IN AL,Ib */
+ {
+ Bitu port=Fetchb();
+ if (CPU_IO_Exception(port,1)) RUNEXCEPTION();
+ reg_al=IO_ReadB(port);
+ break;
+ }
+ CASE_W(0xe5) /* IN AX,Ib */
+ {
+ Bitu port=Fetchb();
+ if (CPU_IO_Exception(port,2)) RUNEXCEPTION();
+ reg_ax=IO_ReadW(port);
+ break;
+ }
+ CASE_B(0xe6) /* OUT Ib,AL */
+ {
+ Bitu port=Fetchb();
+ if (CPU_IO_Exception(port,1)) RUNEXCEPTION();
+ IO_WriteB(port,reg_al);
+ break;
+ }
+ CASE_W(0xe7) /* OUT Ib,AX */
+ {
+ Bitu port=Fetchb();
+ if (CPU_IO_Exception(port,2)) RUNEXCEPTION();
+ IO_WriteW(port,reg_ax);
+ break;
+ }
+ CASE_W(0xe8) /* CALL Jw */
+ {
+ Bit16u addip=Fetchws();
+ SAVEIP;
+ Push_16(reg_eip);
+ reg_eip=(Bit16u)(reg_eip+addip);
+ continue;
+ }
+ CASE_W(0xe9) /* JMP Jw */
+ {
+ Bit16u addip=Fetchws();
+ SAVEIP;
+ reg_eip=(Bit16u)(reg_eip+addip);
+ continue;
+ }
+ CASE_W(0xea) /* JMP Ap */
+ {
+ Bit16u newip=Fetchw();
+ Bit16u newcs=Fetchw();
+ FillFlags();
+ CPU_JMP(false,newcs,newip,GETIP);
+#if CPU_TRAP_CHECK
+ if (GETFLAG(TF)) {
+ cpudecoder=CPU_Core_Normal_Trap_Run;
+ return CBRET_NONE;
+ }
+#endif
+ continue;
+ }
+ CASE_W(0xeb) /* JMP Jb */
+ {
+ Bit16s addip=Fetchbs();
+ SAVEIP;
+ reg_eip=(Bit16u)(reg_eip+addip);
+ continue;
+ }
+ CASE_B(0xec) /* IN AL,DX */
+ if (CPU_IO_Exception(reg_dx,1)) RUNEXCEPTION();
+ reg_al=IO_ReadB(reg_dx);
+ break;
+ CASE_W(0xed) /* IN AX,DX */
+ if (CPU_IO_Exception(reg_dx,2)) RUNEXCEPTION();
+ reg_ax=IO_ReadW(reg_dx);
+ break;
+ CASE_B(0xee) /* OUT DX,AL */
+ if (CPU_IO_Exception(reg_dx,1)) RUNEXCEPTION();
+ IO_WriteB(reg_dx,reg_al);
+ break;
+ CASE_W(0xef) /* OUT DX,AX */
+ if (CPU_IO_Exception(reg_dx,2)) RUNEXCEPTION();
+ IO_WriteW(reg_dx,reg_ax);
+ break;
+ CASE_B(0xf0) /* LOCK */
+ LOG(LOG_CPU,LOG_NORMAL)("CPU:LOCK"); /* FIXME: see case D_LOCK in core_full/load.h */
+ break;
+ CASE_B(0xf1) /* ICEBP */
+ CPU_SW_Interrupt_NoIOPLCheck(1,GETIP);
+#if CPU_TRAP_CHECK
+ cpu.trap_skip=true;
+#endif
+ continue;
+ CASE_B(0xf2) /* REPNZ */
+ DO_PREFIX_REP(false);
+ break;
+ CASE_B(0xf3) /* REPZ */
+ DO_PREFIX_REP(true);
+ break;
+ CASE_B(0xf4) /* HLT */
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ FillFlags();
+ CPU_HLT(GETIP);
+ return CBRET_NONE; //Needs to return for hlt cpu core
+ CASE_B(0xf5) /* CMC */
+ FillFlags();
+ SETFLAGBIT(CF,!(reg_flags & FLAG_CF));
+ break;
+ CASE_B(0xf6) /* GRP3 Eb(,Ib) */
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ switch (which) {
+ case 0x00: /* TEST Eb,Ib */
+ case 0x01: /* TEST Eb,Ib Undocumented*/
+ {
+ if (rm >= 0xc0 ) {GetEArb;TESTB(*earb,Fetchb(),LoadRb,0)}
+ else {GetEAa;TESTB(eaa,Fetchb(),LoadMb,0);}
+ break;
+ }
+ case 0x02: /* NOT Eb */
+ {
+ if (rm >= 0xc0 ) {GetEArb;*earb=~*earb;}
+ else {GetEAa;SaveMb(eaa,~LoadMb(eaa));}
+ break;
+ }
+ case 0x03: /* NEG Eb */
+ {
+ lflags.type=t_NEGb;
+ if (rm >= 0xc0 ) {
+ GetEArb;lf_var1b=*earb;lf_resb=0-lf_var1b;
+ *earb=lf_resb;
+ } else {
+ GetEAa;lf_var1b=LoadMb(eaa);lf_resb=0-lf_var1b;
+ SaveMb(eaa,lf_resb);
+ }
+ break;
+ }
+ case 0x04: /* MUL AL,Eb */
+ RMEb(MULB);
+ break;
+ case 0x05: /* IMUL AL,Eb */
+ RMEb(IMULB);
+ break;
+ case 0x06: /* DIV Eb */
+ RMEb(DIVB);
+ break;
+ case 0x07: /* IDIV Eb */
+ RMEb(IDIVB);
+ break;
+ }
+ break;
+ }
+ CASE_W(0xf7) /* GRP3 Ew(,Iw) */
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ switch (which) {
+ case 0x00: /* TEST Ew,Iw */
+ case 0x01: /* TEST Ew,Iw Undocumented*/
+ {
+ if (rm >= 0xc0 ) {GetEArw;TESTW(*earw,Fetchw(),LoadRw,SaveRw);}
+ else {GetEAa;TESTW(eaa,Fetchw(),LoadMw,SaveMw);}
+ break;
+ }
+ case 0x02: /* NOT Ew */
+ {
+ if (rm >= 0xc0 ) {GetEArw;*earw=~*earw;}
+ else {GetEAa;SaveMw(eaa,~LoadMw(eaa));}
+ break;
+ }
+ case 0x03: /* NEG Ew */
+ {
+ lflags.type=t_NEGw;
+ if (rm >= 0xc0 ) {
+ GetEArw;lf_var1w=*earw;lf_resw=0-lf_var1w;
+ *earw=lf_resw;
+ } else {
+ GetEAa;lf_var1w=LoadMw(eaa);lf_resw=0-lf_var1w;
+ SaveMw(eaa,lf_resw);
+ }
+ break;
+ }
+ case 0x04: /* MUL AX,Ew */
+ RMEw(MULW);
+ break;
+ case 0x05: /* IMUL AX,Ew */
+ RMEw(IMULW)
+ break;
+ case 0x06: /* DIV Ew */
+ RMEw(DIVW)
+ break;
+ case 0x07: /* IDIV Ew */
+ RMEw(IDIVW)
+ break;
+ }
+ break;
+ }
+ CASE_B(0xf8) /* CLC */
+ FillFlags();
+ SETFLAGBIT(CF,false);
+ break;
+ CASE_B(0xf9) /* STC */
+ FillFlags();
+ SETFLAGBIT(CF,true);
+ break;
+ CASE_B(0xfa) /* CLI */
+ if (CPU_CLI()) RUNEXCEPTION();
+ break;
+ CASE_B(0xfb) /* STI */
+ if (CPU_STI()) RUNEXCEPTION();
+#if CPU_PIC_CHECK
+ if (GETFLAG(IF) && PIC_IRQCheck) goto decode_end;
+#endif
+ break;
+ CASE_B(0xfc) /* CLD */
+ SETFLAGBIT(DF,false);
+ cpu.direction=1;
+ break;
+ CASE_B(0xfd) /* STD */
+ SETFLAGBIT(DF,true);
+ cpu.direction=-1;
+ break;
+ CASE_B(0xfe) /* GRP4 Eb */
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ switch (which) {
+ case 0x00: /* INC Eb */
+ RMEb(INCB);
+ break;
+ case 0x01: /* DEC Eb */
+ RMEb(DECB);
+ break;
+ case 0x07: /* CallBack */
+ {
+ Bitu cb=Fetchw();
+ FillFlags();SAVEIP;
+ return cb;
+ }
+ default:
+ E_Exit("Illegal GRP4 Call %d",(rm>>3) & 7);
+ break;
+ }
+ break;
+ }
+ CASE_W(0xff) /* GRP5 Ew */
+ {
+ GetRM;Bitu which=(rm>>3)&7;
+ switch (which) {
+ case 0x00: /* INC Ew */
+ RMEw(INCW);
+ break;
+ case 0x01: /* DEC Ew */
+ RMEw(DECW);
+ break;
+ case 0x02: /* CALL Ev */
+ if (rm >= 0xc0 ) {GetEArw;reg_eip=*earw;}
+ else {GetEAa;reg_eip=LoadMw(eaa);}
+ Push_16(GETIP);
+ continue;
+ case 0x03: /* CALL Ep */
+ {
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ Bit16u newip=LoadMw(eaa);
+ Bit16u newcs=LoadMw(eaa+2);
+ FillFlags();
+ CPU_CALL(false,newcs,newip,GETIP);
+#if CPU_TRAP_CHECK
+ if (GETFLAG(TF)) {
+ cpudecoder=CPU_Core_Normal_Trap_Run;
+ return CBRET_NONE;
+ }
+#endif
+ continue;
+ }
+ break;
+ case 0x04: /* JMP Ev */
+ if (rm >= 0xc0 ) {GetEArw;reg_eip=*earw;}
+ else {GetEAa;reg_eip=LoadMw(eaa);}
+ continue;
+ case 0x05: /* JMP Ep */
+ {
+ if (rm >= 0xc0) goto illegal_opcode;
+ GetEAa;
+ Bit16u newip=LoadMw(eaa);
+ Bit16u newcs=LoadMw(eaa+2);
+ FillFlags();
+ CPU_JMP(false,newcs,newip,GETIP);
+#if CPU_TRAP_CHECK
+ if (GETFLAG(TF)) {
+ cpudecoder=CPU_Core_Normal_Trap_Run;
+ return CBRET_NONE;
+ }
+#endif
+ continue;
+ }
+ break;
+ case 0x06: /* PUSH Ev */
+ if (rm >= 0xc0 ) {GetEArw;Push_16(*earw);}
+ else {GetEAa;Push_16(LoadMw(eaa));}
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("CPU:GRP5:Illegal Call %2X",which);
+ goto illegal_opcode;
+ }
+ break;
+ }
+
+
+
+
--- /dev/null
+/*
+ * 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.
+ */
+
+enum STRING_OP {
+ R_OUTSB,R_OUTSW,R_OUTSD,
+ R_INSB,R_INSW,R_INSD,
+ R_MOVSB,R_MOVSW,R_MOVSD,
+ R_LODSB,R_LODSW,R_LODSD,
+ R_STOSB,R_STOSW,R_STOSD,
+ R_SCASB,R_SCASW,R_SCASD,
+ R_CMPSB,R_CMPSW,R_CMPSD
+};
+
+#define LoadD(_BLAH) _BLAH
+
+static void DoString(STRING_OP type) {
+ PhysPt si_base,di_base;
+ Bitu si_index,di_index;
+ Bitu add_mask;
+ Bitu count,count_left;
+ Bits add_index;
+
+ si_base=BaseDS;
+ di_base=SegBase(es);
+ add_mask=AddrMaskTable[core.prefixes & PREFIX_ADDR];
+ si_index=reg_esi & add_mask;
+ di_index=reg_edi & add_mask;
+ count=reg_ecx & add_mask;
+ if (!TEST_PREFIX_REP) {
+ count=1;
+ } else {
+ CPU_Cycles++;
+ /* Calculate amount of ops to do before cycles run out */
+ if ((count>(Bitu)CPU_Cycles) && (type<R_SCASB)) {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ LOADIP; //RESET IP to the start
+ } else {
+ /* Won't interrupt scas and cmps instruction since they can interrupt themselves */
+ if ((count<=1) && (CPU_Cycles<=1)) CPU_Cycles--;
+ else if (type<R_SCASB) CPU_Cycles-=count;
+ count_left=0;
+ }
+ }
+ add_index=cpu.direction;
+ if (count) switch (type) {
+ case R_OUTSB:
+ for (;count>0;count--) {
+ IO_WriteB(reg_dx,LoadMb(si_base+si_index));
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_OUTSW:
+ add_index<<=1;
+ for (;count>0;count--) {
+ IO_WriteW(reg_dx,LoadMw(si_base+si_index));
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_OUTSD:
+ add_index<<=2;
+ for (;count>0;count--) {
+ IO_WriteD(reg_dx,LoadMd(si_base+si_index));
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_INSB:
+ for (;count>0;count--) {
+ SaveMb(di_base+di_index,IO_ReadB(reg_dx));
+ di_index=(di_index+add_index) & add_mask;
+ }
+ break;
+ case R_INSW:
+ add_index<<=1;
+ for (;count>0;count--) {
+ SaveMw(di_base+di_index,IO_ReadW(reg_dx));
+ di_index=(di_index+add_index) & add_mask;
+ }
+ break;
+ case R_INSD:
+ add_index<<=2;
+ for (;count>0;count--) {
+ SaveMd(di_base+di_index,IO_ReadD(reg_dx));
+ di_index=(di_index+add_index) & add_mask;
+ }
+ break;
+ case R_STOSB:
+ for (;count>0;count--) {
+ SaveMb(di_base+di_index,reg_al);
+ di_index=(di_index+add_index) & add_mask;
+ }
+ break;
+ case R_STOSW:
+ add_index<<=1;
+ for (;count>0;count--) {
+ SaveMw(di_base+di_index,reg_ax);
+ di_index=(di_index+add_index) & add_mask;
+ }
+ break;
+ case R_STOSD:
+ add_index<<=2;
+ for (;count>0;count--) {
+ SaveMd(di_base+di_index,reg_eax);
+ di_index=(di_index+add_index) & add_mask;
+ }
+ break;
+ case R_MOVSB:
+ for (;count>0;count--) {
+ SaveMb(di_base+di_index,LoadMb(si_base+si_index));
+ di_index=(di_index+add_index) & add_mask;
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_MOVSW:
+ add_index<<=1;
+ for (;count>0;count--) {
+ SaveMw(di_base+di_index,LoadMw(si_base+si_index));
+ di_index=(di_index+add_index) & add_mask;
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_MOVSD:
+ add_index<<=2;
+ for (;count>0;count--) {
+ SaveMd(di_base+di_index,LoadMd(si_base+si_index));
+ di_index=(di_index+add_index) & add_mask;
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_LODSB:
+ for (;count>0;count--) {
+ reg_al=LoadMb(si_base+si_index);
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_LODSW:
+ add_index<<=1;
+ for (;count>0;count--) {
+ reg_ax=LoadMw(si_base+si_index);
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_LODSD:
+ add_index<<=2;
+ for (;count>0;count--) {
+ reg_eax=LoadMd(si_base+si_index);
+ si_index=(si_index+add_index) & add_mask;
+ }
+ break;
+ case R_SCASB:
+ {
+ Bit8u val2;
+ for (;count>0;) {
+ count--;CPU_Cycles--;
+ val2=LoadMb(di_base+di_index);
+ di_index=(di_index+add_index) & add_mask;
+ if ((reg_al==val2)!=core.rep_zero) break;
+ }
+ CMPB(reg_al,val2,LoadD,0);
+ }
+ break;
+ case R_SCASW:
+ {
+ add_index<<=1;Bit16u val2;
+ for (;count>0;) {
+ count--;CPU_Cycles--;
+ val2=LoadMw(di_base+di_index);
+ di_index=(di_index+add_index) & add_mask;
+ if ((reg_ax==val2)!=core.rep_zero) break;
+ }
+ CMPW(reg_ax,val2,LoadD,0);
+ }
+ break;
+ case R_SCASD:
+ {
+ add_index<<=2;Bit32u val2;
+ for (;count>0;) {
+ count--;CPU_Cycles--;
+ val2=LoadMd(di_base+di_index);
+ di_index=(di_index+add_index) & add_mask;
+ if ((reg_eax==val2)!=core.rep_zero) break;
+ }
+ CMPD(reg_eax,val2,LoadD,0);
+ }
+ break;
+ case R_CMPSB:
+ {
+ Bit8u val1,val2;
+ for (;count>0;) {
+ count--;CPU_Cycles--;
+ val1=LoadMb(si_base+si_index);
+ val2=LoadMb(di_base+di_index);
+ si_index=(si_index+add_index) & add_mask;
+ di_index=(di_index+add_index) & add_mask;
+ if ((val1==val2)!=core.rep_zero) break;
+ }
+ CMPB(val1,val2,LoadD,0);
+ }
+ break;
+ case R_CMPSW:
+ {
+ add_index<<=1;Bit16u val1,val2;
+ for (;count>0;) {
+ count--;CPU_Cycles--;
+ val1=LoadMw(si_base+si_index);
+ val2=LoadMw(di_base+di_index);
+ si_index=(si_index+add_index) & add_mask;
+ di_index=(di_index+add_index) & add_mask;
+ if ((val1==val2)!=core.rep_zero) break;
+ }
+ CMPW(val1,val2,LoadD,0);
+ }
+ break;
+ case R_CMPSD:
+ {
+ add_index<<=2;Bit32u val1,val2;
+ for (;count>0;) {
+ count--;CPU_Cycles--;
+ val1=LoadMd(si_base+si_index);
+ val2=LoadMd(di_base+di_index);
+ si_index=(si_index+add_index) & add_mask;
+ di_index=(di_index+add_index) & add_mask;
+ if ((val1==val2)!=core.rep_zero) break;
+ }
+ CMPD(val1,val2,LoadD,0);
+ }
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled string op %d",type);
+ }
+ /* Clean up after certain amount of instructions */
+ reg_esi&=(~add_mask);
+ reg_esi|=(si_index & add_mask);
+ reg_edi&=(~add_mask);
+ reg_edi|=(di_index & add_mask);
+ if (TEST_PREFIX_REP) {
+ count+=count_left;
+ reg_ecx&=(~add_mask);
+ reg_ecx|=(count & add_mask);
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#define LoadMbs(off) (Bit8s)(LoadMb(off))
+#define LoadMws(off) (Bit16s)(LoadMw(off))
+#define LoadMds(off) (Bit32s)(LoadMd(off))
+
+#define LoadRb(reg) reg
+#define LoadRw(reg) reg
+#define LoadRd(reg) reg
+
+#define SaveRb(reg,val) reg=val
+#define SaveRw(reg,val) reg=val
+#define SaveRd(reg,val) reg=val
+
+static INLINE Bit8s Fetchbs() {
+ return Fetchb();
+}
+static INLINE Bit16s Fetchws() {
+ return Fetchw();
+}
+
+static INLINE Bit32s Fetchds() {
+ return Fetchd();
+}
+
+
+#define RUNEXCEPTION() { \
+ CPU_Exception(cpu.exception.which,cpu.exception.error); \
+ continue; \
+}
+
+#define EXCEPTION(blah) \
+ { \
+ CPU_Exception(blah); \
+ continue; \
+ }
+
+//TODO Could probably make all byte operands fast?
+#define JumpCond16_b(COND) { \
+ SAVEIP; \
+ if (COND) reg_ip+=Fetchbs(); \
+ reg_ip+=1; \
+ continue; \
+}
+
+#define JumpCond16_w(COND) { \
+ SAVEIP; \
+ if (COND) reg_ip+=Fetchws(); \
+ reg_ip+=2; \
+ continue; \
+}
+
+#define JumpCond32_b(COND) { \
+ SAVEIP; \
+ if (COND) reg_eip+=Fetchbs(); \
+ reg_eip+=1; \
+ continue; \
+}
+
+#define JumpCond32_d(COND) { \
+ SAVEIP; \
+ if (COND) reg_eip+=Fetchds(); \
+ reg_eip+=4; \
+ continue; \
+}
+
+
+#define SETcc(cc) \
+ { \
+ GetRM; \
+ if (rm >= 0xc0 ) {GetEArb;*earb=(cc) ? 1 : 0;} \
+ else {GetEAa;SaveMb(eaa,(cc) ? 1 : 0);} \
+ }
+
+#include "helpers.h"
+#include "table_ea.h"
+#include "../modrm.h"
+
+
--- /dev/null
+/*
+ * 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.
+ */
+
+typedef PhysPt (*EA_LookupHandler)(void);
+
+/* The MOD/RM Decoder for EA for this decoder's addressing modes */
+static PhysPt EA_16_00_n(void) { return BaseDS+(Bit16u)(reg_bx+(Bit16s)reg_si); }
+static PhysPt EA_16_01_n(void) { return BaseDS+(Bit16u)(reg_bx+(Bit16s)reg_di); }
+static PhysPt EA_16_02_n(void) { return BaseSS+(Bit16u)(reg_bp+(Bit16s)reg_si); }
+static PhysPt EA_16_03_n(void) { return BaseSS+(Bit16u)(reg_bp+(Bit16s)reg_di); }
+static PhysPt EA_16_04_n(void) { return BaseDS+(Bit16u)(reg_si); }
+static PhysPt EA_16_05_n(void) { return BaseDS+(Bit16u)(reg_di); }
+static PhysPt EA_16_06_n(void) { return BaseDS+(Bit16u)(Fetchw());}
+static PhysPt EA_16_07_n(void) { return BaseDS+(Bit16u)(reg_bx); }
+
+static PhysPt EA_16_40_n(void) { return BaseDS+(Bit16u)(reg_bx+(Bit16s)reg_si+Fetchbs()); }
+static PhysPt EA_16_41_n(void) { return BaseDS+(Bit16u)(reg_bx+(Bit16s)reg_di+Fetchbs()); }
+static PhysPt EA_16_42_n(void) { return BaseSS+(Bit16u)(reg_bp+(Bit16s)reg_si+Fetchbs()); }
+static PhysPt EA_16_43_n(void) { return BaseSS+(Bit16u)(reg_bp+(Bit16s)reg_di+Fetchbs()); }
+static PhysPt EA_16_44_n(void) { return BaseDS+(Bit16u)(reg_si+Fetchbs()); }
+static PhysPt EA_16_45_n(void) { return BaseDS+(Bit16u)(reg_di+Fetchbs()); }
+static PhysPt EA_16_46_n(void) { return BaseSS+(Bit16u)(reg_bp+Fetchbs()); }
+static PhysPt EA_16_47_n(void) { return BaseDS+(Bit16u)(reg_bx+Fetchbs()); }
+
+static PhysPt EA_16_80_n(void) { return BaseDS+(Bit16u)(reg_bx+(Bit16s)reg_si+Fetchws()); }
+static PhysPt EA_16_81_n(void) { return BaseDS+(Bit16u)(reg_bx+(Bit16s)reg_di+Fetchws()); }
+static PhysPt EA_16_82_n(void) { return BaseSS+(Bit16u)(reg_bp+(Bit16s)reg_si+Fetchws()); }
+static PhysPt EA_16_83_n(void) { return BaseSS+(Bit16u)(reg_bp+(Bit16s)reg_di+Fetchws()); }
+static PhysPt EA_16_84_n(void) { return BaseDS+(Bit16u)(reg_si+Fetchws()); }
+static PhysPt EA_16_85_n(void) { return BaseDS+(Bit16u)(reg_di+Fetchws()); }
+static PhysPt EA_16_86_n(void) { return BaseSS+(Bit16u)(reg_bp+Fetchws()); }
+static PhysPt EA_16_87_n(void) { return BaseDS+(Bit16u)(reg_bx+Fetchws()); }
+
+static Bit32u SIBZero=0;
+static Bit32u * SIBIndex[8]= { ®_eax,®_ecx,®_edx,®_ebx,&SIBZero,®_ebp,®_esi,®_edi };
+
+static INLINE PhysPt Sib(Bitu mode) {
+ Bit8u sib=Fetchb();
+ PhysPt base;
+ switch (sib&7) {
+ case 0: /* EAX Base */
+ base=BaseDS+reg_eax;break;
+ case 1: /* ECX Base */
+ base=BaseDS+reg_ecx;break;
+ case 2: /* EDX Base */
+ base=BaseDS+reg_edx;break;
+ case 3: /* EBX Base */
+ base=BaseDS+reg_ebx;break;
+ case 4: /* ESP Base */
+ base=BaseSS+reg_esp;break;
+ case 5: /* #1 Base */
+ if (!mode) {
+ base=BaseDS+Fetchd();break;
+ } else {
+ base=BaseSS+reg_ebp;break;
+ }
+ case 6: /* ESI Base */
+ base=BaseDS+reg_esi;break;
+ case 7: /* EDI Base */
+ base=BaseDS+reg_edi;break;
+ }
+ base+=*SIBIndex[(sib >> 3) &7] << (sib >> 6);
+ return base;
+}
+
+static PhysPt EA_32_00_n(void) { return BaseDS+reg_eax; }
+static PhysPt EA_32_01_n(void) { return BaseDS+reg_ecx; }
+static PhysPt EA_32_02_n(void) { return BaseDS+reg_edx; }
+static PhysPt EA_32_03_n(void) { return BaseDS+reg_ebx; }
+static PhysPt EA_32_04_n(void) { return Sib(0);}
+static PhysPt EA_32_05_n(void) { return BaseDS+Fetchd(); }
+static PhysPt EA_32_06_n(void) { return BaseDS+reg_esi; }
+static PhysPt EA_32_07_n(void) { return BaseDS+reg_edi; }
+
+static PhysPt EA_32_40_n(void) { return BaseDS+reg_eax+Fetchbs(); }
+static PhysPt EA_32_41_n(void) { return BaseDS+reg_ecx+Fetchbs(); }
+static PhysPt EA_32_42_n(void) { return BaseDS+reg_edx+Fetchbs(); }
+static PhysPt EA_32_43_n(void) { return BaseDS+reg_ebx+Fetchbs(); }
+static PhysPt EA_32_44_n(void) { PhysPt temp=Sib(1);return temp+Fetchbs();}
+//static PhysPt EA_32_44_n(void) { return Sib(1)+Fetchbs();}
+static PhysPt EA_32_45_n(void) { return BaseSS+reg_ebp+Fetchbs(); }
+static PhysPt EA_32_46_n(void) { return BaseDS+reg_esi+Fetchbs(); }
+static PhysPt EA_32_47_n(void) { return BaseDS+reg_edi+Fetchbs(); }
+
+static PhysPt EA_32_80_n(void) { return BaseDS+reg_eax+Fetchds(); }
+static PhysPt EA_32_81_n(void) { return BaseDS+reg_ecx+Fetchds(); }
+static PhysPt EA_32_82_n(void) { return BaseDS+reg_edx+Fetchds(); }
+static PhysPt EA_32_83_n(void) { return BaseDS+reg_ebx+Fetchds(); }
+static PhysPt EA_32_84_n(void) { PhysPt temp=Sib(2);return temp+Fetchds();}
+//static PhysPt EA_32_84_n(void) { return Sib(2)+Fetchds();}
+static PhysPt EA_32_85_n(void) { return BaseSS+reg_ebp+Fetchds(); }
+static PhysPt EA_32_86_n(void) { return BaseDS+reg_esi+Fetchds(); }
+static PhysPt EA_32_87_n(void) { return BaseDS+reg_edi+Fetchds(); }
+
+static GetEAHandler EATable[512]={
+/* 00 */
+ EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
+ EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
+ EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
+ EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
+ EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
+ EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
+ EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
+ EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n,
+/* 01 */
+ EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
+ EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
+ EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
+ EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
+ EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
+ EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
+ EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
+ EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n,
+/* 10 */
+ EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
+ EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
+ EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
+ EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
+ EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
+ EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
+ EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
+ EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n,
+/* 11 These are illegal so make em 0 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+/* 00 */
+ EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
+ EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
+ EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
+ EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
+ EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
+ EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
+ EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
+ EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n,
+/* 01 */
+ EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
+ EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
+ EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
+ EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
+ EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
+ EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
+ EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
+ EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n,
+/* 10 */
+ EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
+ EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
+ EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
+ EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
+ EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
+ EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
+ EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
+ EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n,
+/* 11 These are illegal so make em 0 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+#define GetEADirect \
+ PhysPt eaa; \
+ if (TEST_PREFIX_ADDR) { \
+ eaa=BaseDS+Fetchd(); \
+ } else { \
+ eaa=BaseDS+Fetchw(); \
+ } \
+
+
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#include <stdio.h>
+
+#include "dosbox.h"
+#include "mem.h"
+#include "cpu.h"
+#include "lazyflags.h"
+#include "inout.h"
+#include "callback.h"
+#include "pic.h"
+#include "fpu.h"
+#include "paging.h"
+
+#if C_DEBUG
+#include "debug.h"
+#endif
+
+#if (!C_CORE_INLINE)
+#define LoadMb(off) mem_readb(off)
+#define LoadMw(off) mem_readw(off)
+#define LoadMd(off) mem_readd(off)
+#define SaveMb(off,val) mem_writeb(off,val)
+#define SaveMw(off,val) mem_writew(off,val)
+#define SaveMd(off,val) mem_writed(off,val)
+#else
+#include "paging.h"
+#define LoadMb(off) mem_readb_inline(off)
+#define LoadMw(off) mem_readw_inline(off)
+#define LoadMd(off) mem_readd_inline(off)
+#define SaveMb(off,val) mem_writeb_inline(off,val)
+#define SaveMw(off,val) mem_writew_inline(off,val)
+#define SaveMd(off,val) mem_writed_inline(off,val)
+#endif
+
+extern Bitu cycle_count;
+
+#if C_FPU
+#define CPU_FPU 1 //Enable FPU escape instructions
+#endif
+
+#define CPU_PIC_CHECK 1
+#define CPU_TRAP_CHECK 1
+
+#define OPCODE_NONE 0x000
+#define OPCODE_0F 0x100
+#define OPCODE_SIZE 0x200
+
+#define PREFIX_ADDR 0x1
+#define PREFIX_REP 0x2
+
+#define TEST_PREFIX_ADDR (core.prefixes & PREFIX_ADDR)
+#define TEST_PREFIX_REP (core.prefixes & PREFIX_REP)
+
+#define DO_PREFIX_SEG(_SEG) \
+ BaseDS=SegBase(_SEG); \
+ BaseSS=SegBase(_SEG); \
+ core.base_val_ds=_SEG; \
+ goto restart_opcode;
+
+#define DO_PREFIX_ADDR() \
+ core.prefixes=(core.prefixes & ~PREFIX_ADDR) | \
+ (cpu.code.big ^ PREFIX_ADDR); \
+ core.ea_table=&EATable[(core.prefixes&1) * 256]; \
+ goto restart_opcode;
+
+#define DO_PREFIX_REP(_ZERO) \
+ core.prefixes|=PREFIX_REP; \
+ core.rep_zero=_ZERO; \
+ goto restart_opcode;
+
+typedef PhysPt (*GetEAHandler)(void);
+
+static const Bit32u AddrMaskTable[2]={0x0000ffff,0xffffffff};
+
+static struct {
+ Bitu opcode_index;
+ PhysPt cseip;
+ PhysPt base_ds,base_ss;
+ SegNames base_val_ds;
+ bool rep_zero;
+ Bitu prefixes;
+ GetEAHandler * ea_table;
+} core;
+
+#define GETIP (core.cseip-SegBase(cs))
+#define SAVEIP reg_eip=GETIP;
+#define LOADIP core.cseip=(SegBase(cs)+reg_eip);
+
+#define SegBase(c) SegPhys(c)
+#define BaseDS core.base_ds
+#define BaseSS core.base_ss
+
+
+#define MAX_PQ_SIZE 32
+static Bit8u prefetch_buffer[MAX_PQ_SIZE];
+static bool pq_valid=false;
+static Bitu pq_start;
+
+static Bit8u Fetchb() {
+ Bit8u temp;
+ if (pq_valid && (core.cseip>=pq_start) && (core.cseip<pq_start+CPU_PrefetchQueueSize)) {
+ temp=prefetch_buffer[core.cseip-pq_start];
+ if ((core.cseip+1>=pq_start+CPU_PrefetchQueueSize-4) &&
+ (core.cseip+1<pq_start+CPU_PrefetchQueueSize)) {
+ Bitu remaining_bytes=pq_start+CPU_PrefetchQueueSize-(core.cseip+1);
+ for (Bitu i=0; i<remaining_bytes; i++) prefetch_buffer[i]=prefetch_buffer[core.cseip+1-pq_start+i];
+ for (Bitu i=remaining_bytes; i<CPU_PrefetchQueueSize; i++) prefetch_buffer[i]=LoadMb(core.cseip+1+i);
+ pq_start=core.cseip+1;
+ pq_valid=true;
+ }
+ } else {
+ for (Bitu i=0; i<CPU_PrefetchQueueSize; i++) prefetch_buffer[i]=LoadMb(core.cseip+i);
+ pq_start=core.cseip;
+ pq_valid=true;
+ temp=prefetch_buffer[0];
+ }
+/* if (temp!=LoadMb(core.cseip)) {
+ LOG_MSG("prefetch queue content!=memory at %x:%x",SegValue(cs),reg_eip);
+ } */
+ core.cseip+=1;
+ return temp;
+}
+
+static Bit16u Fetchw() {
+ Bit16u temp;
+ if (pq_valid && (core.cseip>=pq_start) && (core.cseip+2<pq_start+CPU_PrefetchQueueSize)) {
+ temp=prefetch_buffer[core.cseip-pq_start]|
+ (prefetch_buffer[core.cseip-pq_start+1]<<8);
+ if ((core.cseip+2>=pq_start+CPU_PrefetchQueueSize-4) &&
+ (core.cseip+2<pq_start+CPU_PrefetchQueueSize)) {
+ Bitu remaining_bytes=pq_start+CPU_PrefetchQueueSize-(core.cseip+2);
+ for (Bitu i=0; i<remaining_bytes; i++) prefetch_buffer[i]=prefetch_buffer[core.cseip+2-pq_start+i];
+ for (Bitu i=remaining_bytes; i<CPU_PrefetchQueueSize; i++) prefetch_buffer[i]=LoadMb(core.cseip+2+i);
+ pq_start=core.cseip+2;
+ pq_valid=true;
+ }
+ } else {
+ for (Bitu i=0; i<CPU_PrefetchQueueSize; i++) prefetch_buffer[i]=LoadMb(core.cseip+i);
+ pq_start=core.cseip;
+ pq_valid=true;
+ temp=prefetch_buffer[0] | (prefetch_buffer[1]<<8);
+ }
+/* if (temp!=LoadMw(core.cseip)) {
+ LOG_MSG("prefetch queue content!=memory at %x:%x",SegValue(cs),reg_eip);
+ } */
+ core.cseip+=2;
+ return temp;
+}
+
+static Bit32u Fetchd() {
+ Bit32u temp;
+ if (pq_valid && (core.cseip>=pq_start) && (core.cseip+4<pq_start+CPU_PrefetchQueueSize)) {
+ temp=prefetch_buffer[core.cseip-pq_start]|
+ (prefetch_buffer[core.cseip-pq_start+1]<<8)|
+ (prefetch_buffer[core.cseip-pq_start+2]<<16)|
+ (prefetch_buffer[core.cseip-pq_start+3]<<24);
+ if ((core.cseip+4>=pq_start+CPU_PrefetchQueueSize-4) &&
+ (core.cseip+4<pq_start+CPU_PrefetchQueueSize)) {
+ Bitu remaining_bytes=pq_start+CPU_PrefetchQueueSize-(core.cseip+4);
+ for (Bitu i=0; i<remaining_bytes; i++) prefetch_buffer[i]=prefetch_buffer[core.cseip+4-pq_start+i];
+ for (Bitu i=remaining_bytes; i<CPU_PrefetchQueueSize; i++) prefetch_buffer[i]=LoadMb(core.cseip+4+i);
+ pq_start=core.cseip+4;
+ pq_valid=true;
+ }
+ } else {
+ for (Bitu i=0; i<CPU_PrefetchQueueSize; i++) prefetch_buffer[i]=LoadMb(core.cseip+i);
+ pq_start=core.cseip;
+ pq_valid=true;
+ temp=prefetch_buffer[0] | (prefetch_buffer[1]<<8) |
+ (prefetch_buffer[2]<<16) | (prefetch_buffer[3]<<24);
+ }
+/* if (temp!=LoadMd(core.cseip)) {
+ LOG_MSG("prefetch queue content!=memory at %x:%x",SegValue(cs),reg_eip);
+ } */
+ core.cseip+=4;
+ return temp;
+}
+
+#define Push_16 CPU_Push16
+#define Push_32 CPU_Push32
+#define Pop_16 CPU_Pop16
+#define Pop_32 CPU_Pop32
+
+#include "instructions.h"
+#include "core_normal/support.h"
+#include "core_normal/string.h"
+
+
+#define EALookupTable (core.ea_table)
+
+Bits CPU_Core_Prefetch_Run(void) {
+ bool invalidate_pq=false;
+ while (CPU_Cycles-->0) {
+ if (invalidate_pq) {
+ pq_valid=false;
+ invalidate_pq=false;
+ }
+ LOADIP;
+ core.opcode_index=cpu.code.big*0x200;
+ core.prefixes=cpu.code.big;
+ core.ea_table=&EATable[cpu.code.big*256];
+ BaseDS=SegBase(ds);
+ BaseSS=SegBase(ss);
+ core.base_val_ds=ds;
+#if C_DEBUG
+#if C_HEAVY_DEBUG
+ if (DEBUG_HeavyIsBreakpoint()) {
+ FillFlags();
+ return debugCallback;
+ };
+#endif
+ cycle_count++;
+#endif
+restart_opcode:
+ Bit8u next_opcode=Fetchb();
+ invalidate_pq=false;
+ if (core.opcode_index&OPCODE_0F) invalidate_pq=true;
+ else switch (next_opcode) {
+ case 0x70: case 0x71: case 0x72: case 0x73:
+ case 0x74: case 0x75: case 0x76: case 0x77:
+ case 0x78: case 0x79: case 0x7a: case 0x7b:
+ case 0x7c: case 0x7d: case 0x7e: case 0x7f: // jcc
+ case 0x9a: // call
+ case 0xc2: case 0xc3: // retn
+ case 0xc8: // enter
+ case 0xc9: // leave
+ case 0xca: case 0xcb: // retf
+ case 0xcc: // int3
+ case 0xcd: // int
+ case 0xce: // into
+ case 0xcf: // iret
+ case 0xe0: // loopnz
+ case 0xe1: // loopz
+ case 0xe2: // loop
+ case 0xe3: // jcxz
+ case 0xe8: // call
+ case 0xe9: case 0xea: case 0xeb: // jmp
+ case 0xff:
+ invalidate_pq=true;
+ break;
+ default:
+ break;
+ }
+ switch (core.opcode_index+next_opcode) {
+ #include "core_normal/prefix_none.h"
+ #include "core_normal/prefix_0f.h"
+ #include "core_normal/prefix_66.h"
+ #include "core_normal/prefix_66_0f.h"
+ default:
+ illegal_opcode:
+#if C_DEBUG
+ {
+ Bitu len=(GETIP-reg_eip);
+ LOADIP;
+ if (len>16) len=16;
+ char tempcode[16*2+1];char * writecode=tempcode;
+ for (;len>0;len--) {
+ sprintf(writecode,"%02X",mem_readb(core.cseip++));
+ writecode+=2;
+ }
+ LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode);
+ }
+#endif
+ CPU_Exception(6,0);
+ invalidate_pq=true;
+ continue;
+ }
+ SAVEIP;
+ }
+ FillFlags();
+ return CBRET_NONE;
+decode_end:
+ SAVEIP;
+ FillFlags();
+ return CBRET_NONE;
+}
+
+Bits CPU_Core_Prefetch_Trap_Run(void) {
+ Bits oldCycles = CPU_Cycles;
+ CPU_Cycles = 1;
+ cpu.trap_skip = false;
+
+ Bits ret=CPU_Core_Prefetch_Run();
+ if (!cpu.trap_skip) CPU_HW_Interrupt(1);
+ CPU_Cycles = oldCycles-1;
+ cpudecoder = &CPU_Core_Prefetch_Run;
+
+ return ret;
+}
+
+
+
+void CPU_Core_Prefetch_Init(void) {
+
+}
+
--- /dev/null
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+
+#include "dosbox.h"
+#include "mem.h"
+#include "cpu.h"
+#include "lazyflags.h"
+#include "inout.h"
+#include "callback.h"
+#include "pic.h"
+#include "fpu.h"
+
+#if C_DEBUG
+#include "debug.h"
+#endif
+
+#include "paging.h"
+#define SegBase(c) SegPhys(c)
+#define LoadMb(off) mem_readb(off)
+#define LoadMw(off) mem_readw(off)
+#define LoadMd(off) mem_readd(off)
+
+#define SaveMb(off,val) mem_writeb(off,val)
+#define SaveMw(off,val) mem_writew(off,val)
+#define SaveMd(off,val) mem_writed(off,val)
+
+extern Bitu cycle_count;
+
+#if C_FPU
+#define CPU_FPU 1 //Enable FPU escape instructions
+#endif
+
+#define CPU_PIC_CHECK 1
+#define CPU_TRAP_CHECK 1
+
+#define OPCODE_NONE 0x000
+#define OPCODE_0F 0x100
+#define OPCODE_SIZE 0x200
+
+#define PREFIX_ADDR 0x1
+#define PREFIX_REP 0x2
+
+#define TEST_PREFIX_ADDR (core.prefixes & PREFIX_ADDR)
+#define TEST_PREFIX_REP (core.prefixes & PREFIX_REP)
+
+#define DO_PREFIX_SEG(_SEG) \
+ BaseDS=SegBase(_SEG); \
+ BaseSS=SegBase(_SEG); \
+ core.base_val_ds=_SEG; \
+ goto restart_opcode;
+
+#define DO_PREFIX_ADDR() \
+ core.prefixes=(core.prefixes & ~PREFIX_ADDR) | \
+ (cpu.code.big ^ PREFIX_ADDR); \
+ core.ea_table=&EATable[(core.prefixes&1) * 256]; \
+ goto restart_opcode;
+
+#define DO_PREFIX_REP(_ZERO) \
+ core.prefixes|=PREFIX_REP; \
+ core.rep_zero=_ZERO; \
+ goto restart_opcode;
+
+typedef PhysPt (*GetEAHandler)(void);
+
+static const Bit32u AddrMaskTable[2]={0x0000ffff,0xffffffff};
+
+static struct {
+ Bitu opcode_index;
+#if defined (_MSC_VER)
+ volatile HostPt cseip;
+#else
+ HostPt cseip;
+#endif
+ PhysPt base_ds,base_ss;
+ SegNames base_val_ds;
+ bool rep_zero;
+ Bitu prefixes;
+ GetEAHandler * ea_table;
+} core;
+
+#define GETIP (core.cseip-SegBase(cs)-MemBase)
+#define SAVEIP reg_eip=GETIP;
+#define LOADIP core.cseip=(MemBase+SegBase(cs)+reg_eip);
+
+#define SegBase(c) SegPhys(c)
+#define BaseDS core.base_ds
+#define BaseSS core.base_ss
+
+static INLINE Bit8u Fetchb() {
+ Bit8u temp=host_readb(core.cseip);
+ core.cseip+=1;
+ return temp;
+}
+
+static INLINE Bit16u Fetchw() {
+ Bit16u temp=host_readw(core.cseip);
+ core.cseip+=2;
+ return temp;
+}
+static INLINE Bit32u Fetchd() {
+ Bit32u temp=host_readd(core.cseip);
+ core.cseip+=4;
+ return temp;
+}
+
+#define Push_16 CPU_Push16
+#define Push_32 CPU_Push32
+#define Pop_16 CPU_Pop16
+#define Pop_32 CPU_Pop32
+
+#include "instructions.h"
+#include "core_normal/support.h"
+#include "core_normal/string.h"
+
+
+#define EALookupTable (core.ea_table)
+
+Bits CPU_Core_Simple_Run(void) {
+ while (CPU_Cycles-->0) {
+ LOADIP;
+ core.opcode_index=cpu.code.big*0x200;
+ core.prefixes=cpu.code.big;
+ core.ea_table=&EATable[cpu.code.big*256];
+ BaseDS=SegBase(ds);
+ BaseSS=SegBase(ss);
+ core.base_val_ds=ds;
+#if C_DEBUG
+#if C_HEAVY_DEBUG
+ if (DEBUG_HeavyIsBreakpoint()) {
+ FillFlags();
+ return debugCallback;
+ };
+#endif
+ cycle_count++;
+#endif
+restart_opcode:
+ switch (core.opcode_index+Fetchb()) {
+
+ #include "core_normal/prefix_none.h"
+ #include "core_normal/prefix_0f.h"
+ #include "core_normal/prefix_66.h"
+ #include "core_normal/prefix_66_0f.h"
+ default:
+ illegal_opcode:
+#if C_DEBUG
+ {
+ Bitu len=(GETIP-reg_eip);
+ LOADIP;
+ if (len>16) len=16;
+ char tempcode[16*2+1];char * writecode=tempcode;
+ for (;len>0;len--) {
+// sprintf(writecode,"%X",mem_readb(core.cseip++));
+ writecode+=2;
+ }
+ LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode);
+ }
+#endif
+ CPU_Exception(6,0);
+ continue;
+ }
+ SAVEIP;
+ }
+ FillFlags();
+ return CBRET_NONE;
+decode_end:
+ SAVEIP;
+ FillFlags();
+ return CBRET_NONE;
+}
+
+// not really used
+Bits CPU_Core_Simple_Trap_Run(void) {
+ Bits oldCycles = CPU_Cycles;
+ CPU_Cycles = 1;
+ cpu.trap_skip = false;
+
+ Bits ret=CPU_Core_Normal_Run();
+ if (!cpu.trap_skip) CPU_HW_Interrupt(1);
+ CPU_Cycles = oldCycles-1;
+ cpudecoder = &CPU_Core_Simple_Run;
+
+ return ret;
+}
+
+
+
+void CPU_Core_Simple_Init(void) {
+
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#include <assert.h>
+#include <sstream>
+#include <stddef.h>
+#include "dosbox.h"
+#include "cpu.h"
+#include "memory.h"
+#include "debug.h"
+#include "mapper.h"
+#include "setup.h"
+#include "programs.h"
+#include "paging.h"
+#include "lazyflags.h"
+#include "support.h"
+
+Bitu DEBUG_EnableDebugger(void);
+extern void GFX_SetTitle(Bit32s cycles ,Bits frameskip,bool paused);
+
+#if 1
+#undef LOG
+#if defined (_MSC_VER)
+#define LOG(X,Y)
+#else
+#define LOG(X,Y) CPU_LOG
+#define CPU_LOG(...)
+#endif
+#endif
+
+CPU_Regs cpu_regs;
+CPUBlock cpu;
+Segments Segs;
+
+Bit32s CPU_Cycles = 0;
+Bit32s CPU_CycleLeft = 3000;
+Bit32s CPU_CycleMax = 3000;
+Bit32s CPU_OldCycleMax = 3000;
+Bit32s CPU_CyclePercUsed = 100;
+Bit32s CPU_CycleLimit = -1;
+Bit32s CPU_CycleUp = 0;
+Bit32s CPU_CycleDown = 0;
+Bit64s CPU_IODelayRemoved = 0;
+CPU_Decoder * cpudecoder;
+bool CPU_CycleAutoAdjust = false;
+bool CPU_SkipCycleAutoAdjust = false;
+Bitu CPU_AutoDetermineMode = 0;
+
+Bitu CPU_ArchitectureType = CPU_ARCHTYPE_MIXED;
+
+Bitu CPU_extflags_toggle=0; // ID and AC flags may be toggled depending on emulated CPU architecture
+
+Bitu CPU_PrefetchQueueSize=0;
+
+void CPU_Core_Full_Init(void);
+void CPU_Core_Normal_Init(void);
+void CPU_Core_Simple_Init(void);
+#if (C_DYNAMIC_X86)
+void CPU_Core_Dyn_X86_Init(void);
+void CPU_Core_Dyn_X86_Cache_Init(bool enable_cache);
+void CPU_Core_Dyn_X86_Cache_Close(void);
+void CPU_Core_Dyn_X86_SetFPUMode(bool dh_fpu);
+#elif (C_DYNREC)
+void CPU_Core_Dynrec_Init(void);
+void CPU_Core_Dynrec_Cache_Init(bool enable_cache);
+void CPU_Core_Dynrec_Cache_Close(void);
+#endif
+
+/* In debug mode exceptions are tested and dosbox exits when
+ * a unhandled exception state is detected.
+ * USE CHECK_EXCEPT to raise an exception in that case to see if that exception
+ * solves the problem.
+ *
+ * In non-debug mode dosbox doesn't do detection (and hence doesn't crash at
+ * that point). (game might crash later due to the unhandled exception) */
+
+#if C_DEBUG
+// #define CPU_CHECK_EXCEPT 1
+// #define CPU_CHECK_IGNORE 1
+ /* Use CHECK_EXCEPT when something doesn't work to see if a exception is
+ * needed that isn't enabled by default.*/
+#else
+/* NORMAL NO CHECKING => More Speed */
+#define CPU_CHECK_IGNORE 1
+#endif /* C_DEBUG */
+
+#if defined(CPU_CHECK_IGNORE)
+#define CPU_CHECK_COND(cond,msg,exc,sel) { \
+ if (cond) do {} while (0); \
+}
+#elif defined(CPU_CHECK_EXCEPT)
+#define CPU_CHECK_COND(cond,msg,exc,sel) { \
+ if (cond) { \
+ CPU_Exception(exc,sel); \
+ return; \
+ } \
+}
+#else
+#define CPU_CHECK_COND(cond,msg,exc,sel) { \
+ if (cond) E_Exit(msg); \
+}
+#endif
+
+
+void Descriptor::Load(PhysPt address) {
+ cpu.mpl=0;
+ Bit32u* data = (Bit32u*)&saved;
+ *data = mem_readd(address);
+ *(data+1) = mem_readd(address+4);
+ cpu.mpl=3;
+}
+void Descriptor:: Save(PhysPt address) {
+ cpu.mpl=0;
+ Bit32u* data = (Bit32u*)&saved;
+ mem_writed(address,*data);
+ mem_writed(address+4,*(data+1));
+ cpu.mpl=03;
+}
+
+
+void CPU_Push16(Bitu value) {
+ Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-2)&cpu.stack.mask);
+ mem_writew(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value);
+ reg_esp=new_esp;
+}
+
+void CPU_Push32(Bitu value) {
+ Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-4)&cpu.stack.mask);
+ mem_writed(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value);
+ reg_esp=new_esp;
+}
+
+Bitu CPU_Pop16(void) {
+ Bitu val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask));
+ reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask);
+ return val;
+}
+
+Bitu CPU_Pop32(void) {
+ Bitu val=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask));
+ reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask);
+ return val;
+}
+
+PhysPt SelBase(Bitu sel) {
+ if (cpu.cr0 & CR0_PROTECTION) {
+ Descriptor desc;
+ cpu.gdt.GetDescriptor(sel,desc);
+ return desc.GetBase();
+ } else {
+ return sel<<4;
+ }
+}
+
+
+void CPU_SetFlags(Bitu word,Bitu mask) {
+ mask|=CPU_extflags_toggle; // ID-flag and AC-flag can be toggled on CPUID-supporting CPUs
+ reg_flags=(reg_flags & ~mask)|(word & mask)|2;
+ cpu.direction=1-((reg_flags & FLAG_DF) >> 9);
+}
+
+bool CPU_PrepareException(Bitu which,Bitu error) {
+ cpu.exception.which=which;
+ cpu.exception.error=error;
+ return true;
+}
+
+bool CPU_CLI(void) {
+ if (cpu.pmode && ((!GETFLAG(VM) && (GETFLAG_IOPL<cpu.cpl)) || (GETFLAG(VM) && (GETFLAG_IOPL<3)))) {
+ return CPU_PrepareException(EXCEPTION_GP,0);
+ } else {
+ SETFLAGBIT(IF,false);
+ return false;
+ }
+}
+
+bool CPU_STI(void) {
+ if (cpu.pmode && ((!GETFLAG(VM) && (GETFLAG_IOPL<cpu.cpl)) || (GETFLAG(VM) && (GETFLAG_IOPL<3)))) {
+ return CPU_PrepareException(EXCEPTION_GP,0);
+ } else {
+ SETFLAGBIT(IF,true);
+ return false;
+ }
+}
+
+bool CPU_POPF(Bitu use32) {
+ if (cpu.pmode && GETFLAG(VM) && (GETFLAG(IOPL)!=FLAG_IOPL)) {
+ /* Not enough privileges to execute POPF */
+ return CPU_PrepareException(EXCEPTION_GP,0);
+ }
+ Bitu mask=FMASK_ALL;
+ /* IOPL field can only be modified when CPL=0 or in real mode: */
+ if (cpu.pmode && (cpu.cpl>0)) mask &= (~FLAG_IOPL);
+ if (cpu.pmode && !GETFLAG(VM) && (GETFLAG_IOPL<cpu.cpl)) mask &= (~FLAG_IF);
+ if (use32)
+ CPU_SetFlags(CPU_Pop32(),mask);
+ else CPU_SetFlags(CPU_Pop16(),mask & 0xffff);
+ DestroyConditionFlags();
+ return false;
+}
+
+bool CPU_PUSHF(Bitu use32) {
+ if (cpu.pmode && GETFLAG(VM) && (GETFLAG(IOPL)!=FLAG_IOPL)) {
+ /* Not enough privileges to execute PUSHF */
+ return CPU_PrepareException(EXCEPTION_GP,0);
+ }
+ FillFlags();
+ if (use32)
+ CPU_Push32(reg_flags & 0xfcffff);
+ else CPU_Push16(reg_flags);
+ return false;
+}
+
+void CPU_CheckSegments(void) {
+ bool needs_invalidation=false;
+ Descriptor desc;
+ if (!cpu.gdt.GetDescriptor(SegValue(es),desc)) needs_invalidation=true;
+ else switch (desc.Type()) {
+ case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA:
+ if (cpu.cpl>desc.DPL()) needs_invalidation=true; break;
+ default: break; }
+ if (needs_invalidation) CPU_SetSegGeneral(es,0);
+
+ needs_invalidation=false;
+ if (!cpu.gdt.GetDescriptor(SegValue(ds),desc)) needs_invalidation=true;
+ else switch (desc.Type()) {
+ case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA:
+ if (cpu.cpl>desc.DPL()) needs_invalidation=true; break;
+ default: break; }
+ if (needs_invalidation) CPU_SetSegGeneral(ds,0);
+
+ needs_invalidation=false;
+ if (!cpu.gdt.GetDescriptor(SegValue(fs),desc)) needs_invalidation=true;
+ else switch (desc.Type()) {
+ case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA:
+ if (cpu.cpl>desc.DPL()) needs_invalidation=true; break;
+ default: break; }
+ if (needs_invalidation) CPU_SetSegGeneral(fs,0);
+
+ needs_invalidation=false;
+ if (!cpu.gdt.GetDescriptor(SegValue(gs),desc)) needs_invalidation=true;
+ else switch (desc.Type()) {
+ case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA:
+ if (cpu.cpl>desc.DPL()) needs_invalidation=true; break;
+ default: break; }
+ if (needs_invalidation) CPU_SetSegGeneral(gs,0);
+}
+
+
+class TaskStateSegment {
+public:
+ TaskStateSegment() {
+ valid=false;
+ }
+ bool IsValid(void) {
+ return valid;
+ }
+ Bitu Get_back(void) {
+ cpu.mpl=0;
+ Bit16u backlink=mem_readw(base);
+ cpu.mpl=3;
+ return backlink;
+ }
+ void SaveSelector(void) {
+ cpu.gdt.SetDescriptor(selector,desc);
+ }
+ void Get_SSx_ESPx(Bitu level,Bitu & _ss,Bitu & _esp) {
+ cpu.mpl=0;
+ if (is386) {
+ PhysPt where=base+offsetof(TSS_32,esp0)+level*8;
+ _esp=mem_readd(where);
+ _ss=mem_readw(where+4);
+ } else {
+ PhysPt where=base+offsetof(TSS_16,sp0)+level*4;
+ _esp=mem_readw(where);
+ _ss=mem_readw(where+2);
+ }
+ cpu.mpl=3;
+ }
+ bool SetSelector(Bitu new_sel) {
+ valid=false;
+ if ((new_sel & 0xfffc)==0) {
+ selector=0;
+ base=0;
+ limit=0;
+ is386=1;
+ return true;
+ }
+ if (new_sel&4) return false;
+ if (!cpu.gdt.GetDescriptor(new_sel,desc)) return false;
+ switch (desc.Type()) {
+ case DESC_286_TSS_A: case DESC_286_TSS_B:
+ case DESC_386_TSS_A: case DESC_386_TSS_B:
+ break;
+ default:
+ return false;
+ }
+ if (!desc.saved.seg.p) return false;
+ selector=new_sel;
+ valid=true;
+ base=desc.GetBase();
+ limit=desc.GetLimit();
+ is386=desc.Is386();
+ return true;
+ }
+ TSS_Descriptor desc;
+ Bitu selector;
+ PhysPt base;
+ Bitu limit;
+ Bitu is386;
+ bool valid;
+};
+
+TaskStateSegment cpu_tss;
+
+enum TSwitchType {
+ TSwitch_JMP,TSwitch_CALL_INT,TSwitch_IRET
+};
+
+bool CPU_SwitchTask(Bitu new_tss_selector,TSwitchType tstype,Bitu old_eip) {
+ FillFlags();
+ TaskStateSegment new_tss;
+ if (!new_tss.SetSelector(new_tss_selector))
+ E_Exit("Illegal TSS for switch, selector=%x, switchtype=%x",new_tss_selector,tstype);
+ if (tstype==TSwitch_IRET) {
+ if (!new_tss.desc.IsBusy())
+ E_Exit("TSS not busy for IRET");
+ } else {
+ if (new_tss.desc.IsBusy())
+ E_Exit("TSS busy for JMP/CALL/INT");
+ }
+ Bitu new_cr3=0;
+ Bitu new_eax,new_ebx,new_ecx,new_edx,new_esp,new_ebp,new_esi,new_edi;
+ Bitu new_es,new_cs,new_ss,new_ds,new_fs,new_gs;
+ Bitu new_ldt,new_eip,new_eflags;
+ /* Read new context from new TSS */
+ if (new_tss.is386) {
+ new_cr3=mem_readd(new_tss.base+offsetof(TSS_32,cr3));
+ new_eip=mem_readd(new_tss.base+offsetof(TSS_32,eip));
+ new_eflags=mem_readd(new_tss.base+offsetof(TSS_32,eflags));
+ new_eax=mem_readd(new_tss.base+offsetof(TSS_32,eax));
+ new_ecx=mem_readd(new_tss.base+offsetof(TSS_32,ecx));
+ new_edx=mem_readd(new_tss.base+offsetof(TSS_32,edx));
+ new_ebx=mem_readd(new_tss.base+offsetof(TSS_32,ebx));
+ new_esp=mem_readd(new_tss.base+offsetof(TSS_32,esp));
+ new_ebp=mem_readd(new_tss.base+offsetof(TSS_32,ebp));
+ new_edi=mem_readd(new_tss.base+offsetof(TSS_32,edi));
+ new_esi=mem_readd(new_tss.base+offsetof(TSS_32,esi));
+
+ new_es=mem_readw(new_tss.base+offsetof(TSS_32,es));
+ new_cs=mem_readw(new_tss.base+offsetof(TSS_32,cs));
+ new_ss=mem_readw(new_tss.base+offsetof(TSS_32,ss));
+ new_ds=mem_readw(new_tss.base+offsetof(TSS_32,ds));
+ new_fs=mem_readw(new_tss.base+offsetof(TSS_32,fs));
+ new_gs=mem_readw(new_tss.base+offsetof(TSS_32,gs));
+ new_ldt=mem_readw(new_tss.base+offsetof(TSS_32,ldt));
+ } else {
+ E_Exit("286 task switch");
+ new_cr3=0;
+ new_eip=0;
+ new_eflags=0;
+ new_eax=0; new_ecx=0; new_edx=0; new_ebx=0;
+ new_esp=0; new_ebp=0; new_edi=0; new_esi=0;
+
+ new_es=0; new_cs=0; new_ss=0; new_ds=0; new_fs=0; new_gs=0;
+ new_ldt=0;
+ }
+
+ /* Check if we need to clear busy bit of old TASK */
+ if (tstype==TSwitch_JMP || tstype==TSwitch_IRET) {
+ cpu_tss.desc.SetBusy(false);
+ cpu_tss.SaveSelector();
+ }
+ Bit32u old_flags = reg_flags;
+ if (tstype==TSwitch_IRET) old_flags &= (~FLAG_NT);
+
+ /* Save current context in current TSS */
+ if (cpu_tss.is386) {
+ mem_writed(cpu_tss.base+offsetof(TSS_32,eflags),old_flags);
+ mem_writed(cpu_tss.base+offsetof(TSS_32,eip),old_eip);
+
+ mem_writed(cpu_tss.base+offsetof(TSS_32,eax),reg_eax);
+ mem_writed(cpu_tss.base+offsetof(TSS_32,ecx),reg_ecx);
+ mem_writed(cpu_tss.base+offsetof(TSS_32,edx),reg_edx);
+ mem_writed(cpu_tss.base+offsetof(TSS_32,ebx),reg_ebx);
+ mem_writed(cpu_tss.base+offsetof(TSS_32,esp),reg_esp);
+ mem_writed(cpu_tss.base+offsetof(TSS_32,ebp),reg_ebp);
+ mem_writed(cpu_tss.base+offsetof(TSS_32,esi),reg_esi);
+ mem_writed(cpu_tss.base+offsetof(TSS_32,edi),reg_edi);
+
+ mem_writed(cpu_tss.base+offsetof(TSS_32,es),SegValue(es));
+ mem_writed(cpu_tss.base+offsetof(TSS_32,cs),SegValue(cs));
+ mem_writed(cpu_tss.base+offsetof(TSS_32,ss),SegValue(ss));
+ mem_writed(cpu_tss.base+offsetof(TSS_32,ds),SegValue(ds));
+ mem_writed(cpu_tss.base+offsetof(TSS_32,fs),SegValue(fs));
+ mem_writed(cpu_tss.base+offsetof(TSS_32,gs),SegValue(gs));
+ } else {
+ E_Exit("286 task switch");
+ }
+
+ /* Setup a back link to the old TSS in new TSS */
+ if (tstype==TSwitch_CALL_INT) {
+ if (new_tss.is386) {
+ mem_writed(new_tss.base+offsetof(TSS_32,back),cpu_tss.selector);
+ } else {
+ mem_writew(new_tss.base+offsetof(TSS_16,back),cpu_tss.selector);
+ }
+ /* And make the new task's eflag have the nested task bit */
+ new_eflags|=FLAG_NT;
+ }
+ /* Set the busy bit in the new task */
+ if (tstype==TSwitch_JMP || tstype==TSwitch_CALL_INT) {
+ new_tss.desc.SetBusy(true);
+ new_tss.SaveSelector();
+ }
+
+// cpu.cr0|=CR0_TASKSWITCHED;
+ if (new_tss_selector == cpu_tss.selector) {
+ reg_eip = old_eip;
+ new_cs = SegValue(cs);
+ new_ss = SegValue(ss);
+ new_ds = SegValue(ds);
+ new_es = SegValue(es);
+ new_fs = SegValue(fs);
+ new_gs = SegValue(gs);
+ } else {
+
+ /* Setup the new cr3 */
+ PAGING_SetDirBase(new_cr3);
+
+ /* Load new context */
+ if (new_tss.is386) {
+ reg_eip=new_eip;
+ CPU_SetFlags(new_eflags,FMASK_ALL | FLAG_VM);
+ reg_eax=new_eax;
+ reg_ecx=new_ecx;
+ reg_edx=new_edx;
+ reg_ebx=new_ebx;
+ reg_esp=new_esp;
+ reg_ebp=new_ebp;
+ reg_edi=new_edi;
+ reg_esi=new_esi;
+
+// new_cs=mem_readw(new_tss.base+offsetof(TSS_32,cs));
+ } else {
+ E_Exit("286 task switch");
+ }
+ }
+ /* Load the new selectors */
+ if (reg_flags & FLAG_VM) {
+ SegSet16(cs,new_cs);
+ cpu.code.big=false;
+ cpu.cpl=3; //We don't have segment caches so this will do
+ } else {
+ /* Protected mode task */
+ if (new_ldt!=0) CPU_LLDT(new_ldt);
+ /* Load the new CS*/
+ Descriptor cs_desc;
+ cpu.cpl=new_cs & 3;
+ if (!cpu.gdt.GetDescriptor(new_cs,cs_desc))
+ E_Exit("Task switch with CS beyond limits");
+ if (!cs_desc.saved.seg.p)
+ E_Exit("Task switch with non present code-segment");
+ switch (cs_desc.Type()) {
+ case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA:
+ case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA:
+ if (cpu.cpl != cs_desc.DPL()) E_Exit("Task CS RPL != DPL");
+ goto doconforming;
+ case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA:
+ case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA:
+ if (cpu.cpl < cs_desc.DPL()) E_Exit("Task CS RPL < DPL");
+doconforming:
+ Segs.phys[cs]=cs_desc.GetBase();
+ cpu.code.big=cs_desc.Big()>0;
+ Segs.val[cs]=new_cs;
+ break;
+ default:
+ E_Exit("Task switch CS Type %d",cs_desc.Type());
+ }
+ }
+ CPU_SetSegGeneral(es,new_es);
+ CPU_SetSegGeneral(ss,new_ss);
+ CPU_SetSegGeneral(ds,new_ds);
+ CPU_SetSegGeneral(fs,new_fs);
+ CPU_SetSegGeneral(gs,new_gs);
+ if (!cpu_tss.SetSelector(new_tss_selector)) {
+ LOG(LOG_CPU,LOG_NORMAL)("TaskSwitch: set tss selector %X failed",new_tss_selector);
+ }
+// cpu_tss.desc.SetBusy(true);
+// cpu_tss.SaveSelector();
+// LOG_MSG("Task CPL %X CS:%X IP:%X SS:%X SP:%X eflags %x",cpu.cpl,SegValue(cs),reg_eip,SegValue(ss),reg_esp,reg_flags);
+ return true;
+}
+
+bool CPU_IO_Exception(Bitu port,Bitu size) {
+ if (cpu.pmode && ((GETFLAG_IOPL<cpu.cpl) || GETFLAG(VM))) {
+ cpu.mpl=0;
+ if (!cpu_tss.is386) goto doexception;
+ PhysPt bwhere=cpu_tss.base+0x66;
+ Bitu ofs=mem_readw(bwhere);
+ if (ofs>cpu_tss.limit) goto doexception;
+ bwhere=cpu_tss.base+ofs+(port/8);
+ Bitu map=mem_readw(bwhere);
+ Bitu mask=(0xffff>>(16-size)) << (port&7);
+ if (map & mask) goto doexception;
+ cpu.mpl=3;
+ }
+ return false;
+doexception:
+ cpu.mpl=3;
+ LOG(LOG_CPU,LOG_NORMAL)("IO Exception port %X",port);
+ return CPU_PrepareException(EXCEPTION_GP,0);
+}
+
+void CPU_Exception(Bitu which,Bitu error ) {
+// LOG_MSG("Exception %d error %x",which,error);
+ cpu.exception.error=error;
+ CPU_Interrupt(which,CPU_INT_EXCEPTION | ((which>=8) ? CPU_INT_HAS_ERROR : 0),reg_eip);
+}
+
+Bit8u lastint;
+void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip) {
+ lastint=num;
+ FillFlags();
+#if C_DEBUG
+ switch (num) {
+ case 0xcd:
+#if C_HEAVY_DEBUG
+ LOG(LOG_CPU,LOG_ERROR)("Call to interrupt 0xCD this is BAD");
+ DEBUG_HeavyWriteLogInstruction();
+ E_Exit("Call to interrupt 0xCD this is BAD");
+#endif
+ break;
+ case 0x03:
+ if (DEBUG_Breakpoint()) {
+ CPU_Cycles=0;
+ return;
+ }
+ };
+#endif
+ if (!cpu.pmode) {
+ /* Save everything on a 16-bit stack */
+ CPU_Push16(reg_flags & 0xffff);
+ CPU_Push16(SegValue(cs));
+ CPU_Push16(oldeip);
+ SETFLAGBIT(IF,false);
+ SETFLAGBIT(TF,false);
+ /* Get the new CS:IP from vector table */
+ PhysPt base=cpu.idt.GetBase();
+ reg_eip=mem_readw(base+(num << 2));
+ Segs.val[cs]=mem_readw(base+(num << 2)+2);
+ Segs.phys[cs]=Segs.val[cs]<<4;
+ cpu.code.big=false;
+ return;
+ } else {
+ /* Protected Mode Interrupt */
+ if ((reg_flags & FLAG_VM) && (type&CPU_INT_SOFTWARE) && !(type&CPU_INT_NOIOPLCHECK)) {
+// LOG_MSG("Software int in v86, AH %X IOPL %x",reg_ah,(reg_flags & FLAG_IOPL) >>12);
+ if ((reg_flags & FLAG_IOPL)!=FLAG_IOPL) {
+ CPU_Exception(EXCEPTION_GP,0);
+ return;
+ }
+ }
+
+ Descriptor gate;
+ if (!cpu.idt.GetDescriptor(num<<3,gate)) {
+ // zone66
+ CPU_Exception(EXCEPTION_GP,num*8+2+(type&CPU_INT_SOFTWARE)?0:1);
+ return;
+ }
+
+ if ((type&CPU_INT_SOFTWARE) && (gate.DPL()<cpu.cpl)) {
+ // zone66, win3.x e
+ CPU_Exception(EXCEPTION_GP,num*8+2);
+ return;
+ }
+
+
+ switch (gate.Type()) {
+ case DESC_286_INT_GATE: case DESC_386_INT_GATE:
+ case DESC_286_TRAP_GATE: case DESC_386_TRAP_GATE:
+ {
+ CPU_CHECK_COND(!gate.saved.seg.p,
+ "INT:Gate segment not present",
+ EXCEPTION_NP,num*8+2+(type&CPU_INT_SOFTWARE)?0:1)
+
+ Descriptor cs_desc;
+ Bitu gate_sel=gate.GetSelector();
+ Bitu gate_off=gate.GetOffset();
+ CPU_CHECK_COND((gate_sel & 0xfffc)==0,
+ "INT:Gate with CS zero selector",
+ EXCEPTION_GP,(type&CPU_INT_SOFTWARE)?0:1)
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(gate_sel,cs_desc),
+ "INT:Gate with CS beyond limit",
+ EXCEPTION_GP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
+
+ Bitu cs_dpl=cs_desc.DPL();
+ CPU_CHECK_COND(cs_dpl>cpu.cpl,
+ "Interrupt to higher privilege",
+ EXCEPTION_GP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
+ switch (cs_desc.Type()) {
+ case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA:
+ case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA:
+ if (cs_dpl<cpu.cpl) {
+ /* Prepare for gate to inner level */
+ CPU_CHECK_COND(!cs_desc.saved.seg.p,
+ "INT:Inner level:CS segment not present",
+ EXCEPTION_NP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
+ CPU_CHECK_COND((reg_flags & FLAG_VM) && (cs_dpl!=0),
+ "V86 interrupt calling codesegment with DPL>0",
+ EXCEPTION_GP,gate_sel & 0xfffc)
+
+ Bitu n_ss,n_esp;
+ Bitu o_ss,o_esp;
+ o_ss=SegValue(ss);
+ o_esp=reg_esp;
+ cpu_tss.Get_SSx_ESPx(cs_dpl,n_ss,n_esp);
+ CPU_CHECK_COND((n_ss & 0xfffc)==0,
+ "INT:Gate with SS zero selector",
+ EXCEPTION_TS,(type&CPU_INT_SOFTWARE)?0:1)
+ Descriptor n_ss_desc;
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss,n_ss_desc),
+ "INT:Gate with SS beyond limit",
+ EXCEPTION_TS,(n_ss & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
+ CPU_CHECK_COND(((n_ss & 3)!=cs_dpl) || (n_ss_desc.DPL()!=cs_dpl),
+ "INT:Inner level with CS_DPL!=SS_DPL and SS_RPL",
+ EXCEPTION_TS,(n_ss & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
+
+ // check if stack segment is a writable data segment
+ switch (n_ss_desc.Type()) {
+ case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ break;
+ default:
+ E_Exit("INT:Inner level:Stack segment not writable."); // or #TS(ss_sel+EXT)
+ }
+ CPU_CHECK_COND(!n_ss_desc.saved.seg.p,
+ "INT:Inner level with nonpresent SS",
+ EXCEPTION_SS,(n_ss & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
+
+ // commit point
+ Segs.phys[ss]=n_ss_desc.GetBase();
+ Segs.val[ss]=n_ss;
+ if (n_ss_desc.Big()) {
+ cpu.stack.big=true;
+ cpu.stack.mask=0xffffffff;
+ cpu.stack.notmask=0;
+ reg_esp=n_esp;
+ } else {
+ cpu.stack.big=false;
+ cpu.stack.mask=0xffff;
+ cpu.stack.notmask=0xffff0000;
+ reg_sp=n_esp & 0xffff;
+ }
+
+ cpu.cpl=cs_dpl;
+ if (gate.Type() & 0x8) { /* 32-bit Gate */
+ if (reg_flags & FLAG_VM) {
+ CPU_Push32(SegValue(gs));SegSet16(gs,0x0);
+ CPU_Push32(SegValue(fs));SegSet16(fs,0x0);
+ CPU_Push32(SegValue(ds));SegSet16(ds,0x0);
+ CPU_Push32(SegValue(es));SegSet16(es,0x0);
+ }
+ CPU_Push32(o_ss);
+ CPU_Push32(o_esp);
+ } else { /* 16-bit Gate */
+ if (reg_flags & FLAG_VM) E_Exit("V86 to 16-bit gate");
+ CPU_Push16(o_ss);
+ CPU_Push16(o_esp);
+ }
+// LOG_MSG("INT:Gate to inner level SS:%X SP:%X",n_ss,n_esp);
+ goto do_interrupt;
+ }
+ if (cs_dpl!=cpu.cpl)
+ E_Exit("Non-conforming intra privilege INT with DPL!=CPL");
+ case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA:
+ case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA:
+ /* Prepare stack for gate to same priviledge */
+ CPU_CHECK_COND(!cs_desc.saved.seg.p,
+ "INT:Same level:CS segment not present",
+ EXCEPTION_NP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
+ if ((reg_flags & FLAG_VM) && (cs_dpl<cpu.cpl))
+ E_Exit("V86 interrupt doesn't change to pl0"); // or #GP(cs_sel)
+
+ // commit point
+do_interrupt:
+ if (gate.Type() & 0x8) { /* 32-bit Gate */
+ CPU_Push32(reg_flags);
+ CPU_Push32(SegValue(cs));
+ CPU_Push32(oldeip);
+ if (type & CPU_INT_HAS_ERROR) CPU_Push32(cpu.exception.error);
+ } else { /* 16-bit gate */
+ CPU_Push16(reg_flags & 0xffff);
+ CPU_Push16(SegValue(cs));
+ CPU_Push16(oldeip);
+ if (type & CPU_INT_HAS_ERROR) CPU_Push16(cpu.exception.error);
+ }
+ break;
+ default:
+ E_Exit("INT:Gate Selector points to illegal descriptor with type %x",cs_desc.Type());
+ }
+
+ Segs.val[cs]=(gate_sel&0xfffc) | cpu.cpl;
+ Segs.phys[cs]=cs_desc.GetBase();
+ cpu.code.big=cs_desc.Big()>0;
+ reg_eip=gate_off;
+
+ if (!(gate.Type()&1)) {
+ SETFLAGBIT(IF,false);
+ }
+ SETFLAGBIT(TF,false);
+ SETFLAGBIT(NT,false);
+ SETFLAGBIT(VM,false);
+ LOG(LOG_CPU,LOG_NORMAL)("INT:Gate to %X:%X big %d %s",gate_sel,gate_off,cs_desc.Big(),gate.Type() & 0x8 ? "386" : "286");
+ return;
+ }
+ case DESC_TASK_GATE:
+ CPU_CHECK_COND(!gate.saved.seg.p,
+ "INT:Gate segment not present",
+ EXCEPTION_NP,num*8+2+(type&CPU_INT_SOFTWARE)?0:1)
+
+ CPU_SwitchTask(gate.GetSelector(),TSwitch_CALL_INT,oldeip);
+ if (type & CPU_INT_HAS_ERROR) {
+ //TODO Be sure about this, seems somewhat unclear
+ if (cpu_tss.is386) CPU_Push32(cpu.exception.error);
+ else CPU_Push16(cpu.exception.error);
+ }
+ return;
+ default:
+ E_Exit("Illegal descriptor type %X for int %X",gate.Type(),num);
+ }
+ }
+ assert(1);
+ return ; // make compiler happy
+}
+
+
+void CPU_IRET(bool use32,Bitu oldeip) {
+ if (!cpu.pmode) { /* RealMode IRET */
+ if (use32) {
+ reg_eip=CPU_Pop32();
+ SegSet16(cs,CPU_Pop32());
+ CPU_SetFlags(CPU_Pop32(),FMASK_ALL);
+ } else {
+ reg_eip=CPU_Pop16();
+ SegSet16(cs,CPU_Pop16());
+ CPU_SetFlags(CPU_Pop16(),FMASK_ALL & 0xffff);
+ }
+ cpu.code.big=false;
+ DestroyConditionFlags();
+ return;
+ } else { /* Protected mode IRET */
+ if (reg_flags & FLAG_VM) {
+ if ((reg_flags & FLAG_IOPL)!=FLAG_IOPL) {
+ // win3.x e
+ CPU_Exception(EXCEPTION_GP,0);
+ return;
+ } else {
+ if (use32) {
+ Bit32u new_eip=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask));
+ Bit32u tempesp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask);
+ Bit32u new_cs=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ tempesp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask);
+ Bit32u new_flags=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ reg_esp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask);
+
+ reg_eip=new_eip;
+ SegSet16(cs,(Bit16u)(new_cs&0xffff));
+ /* IOPL can not be modified in v86 mode by IRET */
+ CPU_SetFlags(new_flags,FMASK_NORMAL|FLAG_NT);
+ } else {
+ Bit16u new_eip=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask));
+ Bit32u tempesp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask);
+ Bit16u new_cs=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ tempesp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask);
+ Bit16u new_flags=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ reg_esp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask);
+
+ reg_eip=(Bit32u)new_eip;
+ SegSet16(cs,new_cs);
+ /* IOPL can not be modified in v86 mode by IRET */
+ CPU_SetFlags(new_flags,FMASK_NORMAL|FLAG_NT);
+ }
+ cpu.code.big=false;
+ DestroyConditionFlags();
+ return;
+ }
+ }
+ /* Check if this is task IRET */
+ if (GETFLAG(NT)) {
+ if (GETFLAG(VM)) E_Exit("Pmode IRET with VM bit set");
+ CPU_CHECK_COND(!cpu_tss.IsValid(),
+ "TASK Iret without valid TSS",
+ EXCEPTION_TS,cpu_tss.selector & 0xfffc)
+ if (!cpu_tss.desc.IsBusy()) {
+ LOG(LOG_CPU,LOG_ERROR)("TASK Iret:TSS not busy");
+ }
+ Bitu back_link=cpu_tss.Get_back();
+ CPU_SwitchTask(back_link,TSwitch_IRET,oldeip);
+ return;
+ }
+ Bitu n_cs_sel,n_eip,n_flags;
+ Bit32u tempesp;
+ if (use32) {
+ n_eip=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask));
+ tempesp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask);
+ n_cs_sel=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask)) & 0xffff;
+ tempesp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask);
+ n_flags=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ tempesp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask);
+
+ if ((n_flags & FLAG_VM) && (cpu.cpl==0)) {
+ // commit point
+ reg_esp=tempesp;
+ reg_eip=n_eip & 0xffff;
+ Bitu n_ss,n_esp,n_es,n_ds,n_fs,n_gs;
+ n_esp=CPU_Pop32();
+ n_ss=CPU_Pop32() & 0xffff;
+ n_es=CPU_Pop32() & 0xffff;
+ n_ds=CPU_Pop32() & 0xffff;
+ n_fs=CPU_Pop32() & 0xffff;
+ n_gs=CPU_Pop32() & 0xffff;
+
+ CPU_SetFlags(n_flags,FMASK_ALL | FLAG_VM);
+ DestroyConditionFlags();
+ cpu.cpl=3;
+
+ CPU_SetSegGeneral(ss,n_ss);
+ CPU_SetSegGeneral(es,n_es);
+ CPU_SetSegGeneral(ds,n_ds);
+ CPU_SetSegGeneral(fs,n_fs);
+ CPU_SetSegGeneral(gs,n_gs);
+ reg_esp=n_esp;
+ cpu.code.big=false;
+ SegSet16(cs,n_cs_sel);
+ LOG(LOG_CPU,LOG_NORMAL)("IRET:Back to V86: CS:%X IP %X SS:%X SP %X FLAGS:%X",SegValue(cs),reg_eip,SegValue(ss),reg_esp,reg_flags);
+ return;
+ }
+ if (n_flags & FLAG_VM) E_Exit("IRET from pmode to v86 with CPL!=0");
+ } else {
+ n_eip=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask));
+ tempesp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask);
+ n_cs_sel=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ tempesp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask);
+ n_flags=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ n_flags|=(reg_flags & 0xffff0000);
+ tempesp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask);
+
+ if (n_flags & FLAG_VM) E_Exit("VM Flag in 16-bit iret");
+ }
+ CPU_CHECK_COND((n_cs_sel & 0xfffc)==0,
+ "IRET:CS selector zero",
+ EXCEPTION_GP,0)
+ Bitu n_cs_rpl=n_cs_sel & 3;
+ Descriptor n_cs_desc;
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_cs_sel,n_cs_desc),
+ "IRET:CS selector beyond limits",
+ EXCEPTION_GP,n_cs_sel & 0xfffc)
+ CPU_CHECK_COND(n_cs_rpl<cpu.cpl,
+ "IRET to lower privilege",
+ EXCEPTION_GP,n_cs_sel & 0xfffc)
+
+ switch (n_cs_desc.Type()) {
+ case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA:
+ case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA:
+ case 18:
+ CPU_CHECK_COND(n_cs_rpl!=n_cs_desc.DPL(),
+ "IRET:NC:DPL!=RPL",
+ EXCEPTION_GP,n_cs_sel & 0xfffc)
+ break;
+ case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA:
+ case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA:
+ CPU_CHECK_COND(n_cs_desc.DPL()>n_cs_rpl,
+ "IRET:C:DPL>RPL",
+ EXCEPTION_GP,n_cs_sel & 0xfffc)
+ break;
+ default:
+ E_Exit("IRET:Illegal descriptor type %X",n_cs_desc.Type());
+ }
+ CPU_CHECK_COND(!n_cs_desc.saved.seg.p,
+ "IRET with nonpresent code segment",
+ EXCEPTION_NP,n_cs_sel & 0xfffc)
+
+ if (n_cs_rpl==cpu.cpl) {
+ /* Return to same level */
+
+ // commit point
+ reg_esp=tempesp;
+ Segs.phys[cs]=n_cs_desc.GetBase();
+ cpu.code.big=n_cs_desc.Big()>0;
+ Segs.val[cs]=n_cs_sel;
+ reg_eip=n_eip;
+
+ Bitu mask=cpu.cpl ? (FMASK_NORMAL | FLAG_NT) : FMASK_ALL;
+ if (GETFLAG_IOPL<cpu.cpl) mask &= (~FLAG_IF);
+ CPU_SetFlags(n_flags,mask);
+ DestroyConditionFlags();
+ LOG(LOG_CPU,LOG_NORMAL)("IRET:Same level:%X:%X big %d",n_cs_sel,n_eip,cpu.code.big);
+ } else {
+ /* Return to outer level */
+ Bitu n_ss,n_esp;
+ if (use32) {
+ n_esp=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ tempesp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask);
+ n_ss=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask)) & 0xffff;
+ } else {
+ n_esp=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ tempesp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask);
+ n_ss=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ }
+ CPU_CHECK_COND((n_ss & 0xfffc)==0,
+ "IRET:Outer level:SS selector zero",
+ EXCEPTION_GP,0)
+ CPU_CHECK_COND((n_ss & 3)!=n_cs_rpl,
+ "IRET:Outer level:SS rpl!=CS rpl",
+ EXCEPTION_GP,n_ss & 0xfffc)
+ Descriptor n_ss_desc;
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss,n_ss_desc),
+ "IRET:Outer level:SS beyond limit",
+ EXCEPTION_GP,n_ss & 0xfffc)
+ CPU_CHECK_COND(n_ss_desc.DPL()!=n_cs_rpl,
+ "IRET:Outer level:SS dpl!=CS rpl",
+ EXCEPTION_GP,n_ss & 0xfffc)
+
+ // check if stack segment is a writable data segment
+ switch (n_ss_desc.Type()) {
+ case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ break;
+ default:
+ E_Exit("IRET:Outer level:Stack segment not writable"); // or #GP(ss_sel)
+ }
+ CPU_CHECK_COND(!n_ss_desc.saved.seg.p,
+ "IRET:Outer level:Stack segment not present",
+ EXCEPTION_NP,n_ss & 0xfffc)
+
+ // commit point
+
+ Segs.phys[cs]=n_cs_desc.GetBase();
+ cpu.code.big=n_cs_desc.Big()>0;
+ Segs.val[cs]=n_cs_sel;
+
+ Bitu mask=cpu.cpl ? (FMASK_NORMAL | FLAG_NT) : FMASK_ALL;
+ if (GETFLAG_IOPL<cpu.cpl) mask &= (~FLAG_IF);
+ CPU_SetFlags(n_flags,mask);
+ DestroyConditionFlags();
+
+ cpu.cpl=n_cs_rpl;
+ reg_eip=n_eip;
+
+ Segs.val[ss]=n_ss;
+ Segs.phys[ss]=n_ss_desc.GetBase();
+ if (n_ss_desc.Big()) {
+ cpu.stack.big=true;
+ cpu.stack.mask=0xffffffff;
+ cpu.stack.notmask=0;
+ reg_esp=n_esp;
+ } else {
+ cpu.stack.big=false;
+ cpu.stack.mask=0xffff;
+ cpu.stack.notmask=0xffff0000;
+ reg_sp=n_esp & 0xffff;
+ }
+
+ // borland extender, zrdx
+ CPU_CheckSegments();
+
+ LOG(LOG_CPU,LOG_NORMAL)("IRET:Outer level:%X:%X big %d",n_cs_sel,n_eip,cpu.code.big);
+ }
+ return;
+ }
+}
+
+
+void CPU_JMP(bool use32,Bitu selector,Bitu offset,Bitu oldeip) {
+ if (!cpu.pmode || (reg_flags & FLAG_VM)) {
+ if (!use32) {
+ reg_eip=offset&0xffff;
+ } else {
+ reg_eip=offset;
+ }
+ SegSet16(cs,selector);
+ cpu.code.big=false;
+ return;
+ } else {
+ CPU_CHECK_COND((selector & 0xfffc)==0,
+ "JMP:CS selector zero",
+ EXCEPTION_GP,0)
+ Bitu rpl=selector & 3;
+ Descriptor desc;
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(selector,desc),
+ "JMP:CS beyond limits",
+ EXCEPTION_GP,selector & 0xfffc)
+ switch (desc.Type()) {
+ case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA:
+ case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA:
+ case 18:
+ CPU_CHECK_COND(rpl>cpu.cpl,
+ "JMP:NC:RPL>CPL",
+ EXCEPTION_GP,selector & 0xfffc)
+ CPU_CHECK_COND(cpu.cpl!=desc.DPL(),
+ "JMP:NC:RPL != DPL",
+ EXCEPTION_GP,selector & 0xfffc)
+ LOG(LOG_CPU,LOG_NORMAL)("JMP:Code:NC to %X:%X big %d",selector,offset,desc.Big());
+ goto CODE_jmp;
+ case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA:
+ case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA:
+ LOG(LOG_CPU,LOG_NORMAL)("JMP:Code:C to %X:%X big %d",selector,offset,desc.Big());
+ CPU_CHECK_COND(cpu.cpl<desc.DPL(),
+ "JMP:C:CPL < DPL",
+ EXCEPTION_GP,selector & 0xfffc)
+CODE_jmp:
+ if (!desc.saved.seg.p) {
+ // win
+ CPU_Exception(EXCEPTION_NP,selector & 0xfffc);
+ return;
+ }
+
+ /* Normal jump to another selector:offset */
+ Segs.phys[cs]=desc.GetBase();
+ cpu.code.big=desc.Big()>0;
+ Segs.val[cs]=(selector & 0xfffc) | cpu.cpl;
+ reg_eip=offset;
+ return;
+ case DESC_386_TSS_A:
+ CPU_CHECK_COND(desc.DPL()<cpu.cpl,
+ "JMP:TSS:dpl<cpl",
+ EXCEPTION_GP,selector & 0xfffc)
+ CPU_CHECK_COND(desc.DPL()<rpl,
+ "JMP:TSS:dpl<rpl",
+ EXCEPTION_GP,selector & 0xfffc)
+ LOG(LOG_CPU,LOG_NORMAL)("JMP:TSS to %X",selector);
+ CPU_SwitchTask(selector,TSwitch_JMP,oldeip);
+ break;
+ default:
+ E_Exit("JMP Illegal descriptor type %X",desc.Type());
+ }
+ }
+ assert(1);
+}
+
+
+void CPU_CALL(bool use32,Bitu selector,Bitu offset,Bitu oldeip) {
+ if (!cpu.pmode || (reg_flags & FLAG_VM)) {
+ if (!use32) {
+ CPU_Push16(SegValue(cs));
+ CPU_Push16(oldeip);
+ reg_eip=offset&0xffff;
+ } else {
+ CPU_Push32(SegValue(cs));
+ CPU_Push32(oldeip);
+ reg_eip=offset;
+ }
+ cpu.code.big=false;
+ SegSet16(cs,selector);
+ return;
+ } else {
+ CPU_CHECK_COND((selector & 0xfffc)==0,
+ "CALL:CS selector zero",
+ EXCEPTION_GP,0)
+ Bitu rpl=selector & 3;
+ Descriptor call;
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(selector,call),
+ "CALL:CS beyond limits",
+ EXCEPTION_GP,selector & 0xfffc)
+ /* Check for type of far call */
+ switch (call.Type()) {
+ case DESC_CODE_N_NC_A:case DESC_CODE_N_NC_NA:
+ case DESC_CODE_R_NC_A:case DESC_CODE_R_NC_NA:
+ CPU_CHECK_COND(rpl>cpu.cpl,
+ "CALL:CODE:NC:RPL>CPL",
+ EXCEPTION_GP,selector & 0xfffc)
+ CPU_CHECK_COND(call.DPL()!=cpu.cpl,
+ "CALL:CODE:NC:DPL!=CPL",
+ EXCEPTION_GP,selector & 0xfffc)
+ LOG(LOG_CPU,LOG_NORMAL)("CALL:CODE:NC to %X:%X",selector,offset);
+ goto call_code;
+ case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA:
+ case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA:
+ CPU_CHECK_COND(call.DPL()>cpu.cpl,
+ "CALL:CODE:C:DPL>CPL",
+ EXCEPTION_GP,selector & 0xfffc)
+ LOG(LOG_CPU,LOG_NORMAL)("CALL:CODE:C to %X:%X",selector,offset);
+call_code:
+ if (!call.saved.seg.p) {
+ // borland extender (RTM)
+ CPU_Exception(EXCEPTION_NP,selector & 0xfffc);
+ return;
+ }
+ // commit point
+ if (!use32) {
+ CPU_Push16(SegValue(cs));
+ CPU_Push16(oldeip);
+ reg_eip=offset & 0xffff;
+ } else {
+ CPU_Push32(SegValue(cs));
+ CPU_Push32(oldeip);
+ reg_eip=offset;
+ }
+ Segs.phys[cs]=call.GetBase();
+ cpu.code.big=call.Big()>0;
+ Segs.val[cs]=(selector & 0xfffc) | cpu.cpl;
+ return;
+ case DESC_386_CALL_GATE:
+ case DESC_286_CALL_GATE:
+ {
+ CPU_CHECK_COND(call.DPL()<cpu.cpl,
+ "CALL:Gate:Gate DPL<CPL",
+ EXCEPTION_GP,selector & 0xfffc)
+ CPU_CHECK_COND(call.DPL()<rpl,
+ "CALL:Gate:Gate DPL<RPL",
+ EXCEPTION_GP,selector & 0xfffc)
+ CPU_CHECK_COND(!call.saved.seg.p,
+ "CALL:Gate:Segment not present",
+ EXCEPTION_NP,selector & 0xfffc)
+ Descriptor n_cs_desc;
+ Bitu n_cs_sel=call.GetSelector();
+
+ CPU_CHECK_COND((n_cs_sel & 0xfffc)==0,
+ "CALL:Gate:CS selector zero",
+ EXCEPTION_GP,0)
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_cs_sel,n_cs_desc),
+ "CALL:Gate:CS beyond limits",
+ EXCEPTION_GP,n_cs_sel & 0xfffc)
+ Bitu n_cs_dpl = n_cs_desc.DPL();
+ CPU_CHECK_COND(n_cs_dpl>cpu.cpl,
+ "CALL:Gate:CS DPL>CPL",
+ EXCEPTION_GP,n_cs_sel & 0xfffc)
+
+ CPU_CHECK_COND(!n_cs_desc.saved.seg.p,
+ "CALL:Gate:CS not present",
+ EXCEPTION_NP,n_cs_sel & 0xfffc)
+
+ Bitu n_eip = call.GetOffset();
+ switch (n_cs_desc.Type()) {
+ case DESC_CODE_N_NC_A:case DESC_CODE_N_NC_NA:
+ case DESC_CODE_R_NC_A:case DESC_CODE_R_NC_NA:
+ /* Check if we goto inner priviledge */
+ if (n_cs_dpl < cpu.cpl) {
+ /* Get new SS:ESP out of TSS */
+ Bitu n_ss_sel,n_esp;
+ Descriptor n_ss_desc;
+ cpu_tss.Get_SSx_ESPx(n_cs_dpl,n_ss_sel,n_esp);
+ CPU_CHECK_COND((n_ss_sel & 0xfffc)==0,
+ "CALL:Gate:NC:SS selector zero",
+ EXCEPTION_TS,0)
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss_sel,n_ss_desc),
+ "CALL:Gate:Invalid SS selector",
+ EXCEPTION_TS,n_ss_sel & 0xfffc)
+ CPU_CHECK_COND(((n_ss_sel & 3)!=n_cs_desc.DPL()) || (n_ss_desc.DPL()!=n_cs_desc.DPL()),
+ "CALL:Gate:Invalid SS selector privileges",
+ EXCEPTION_TS,n_ss_sel & 0xfffc)
+
+ switch (n_ss_desc.Type()) {
+ case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ // writable data segment
+ break;
+ default:
+ E_Exit("Call:Gate:SS no writable data segment"); // or #TS(ss_sel)
+ }
+ CPU_CHECK_COND(!n_ss_desc.saved.seg.p,
+ "CALL:Gate:Stack segment not present",
+ EXCEPTION_SS,n_ss_sel & 0xfffc)
+
+ /* Load the new SS:ESP and save data on it */
+ Bitu o_esp = reg_esp;
+ Bitu o_ss = SegValue(ss);
+ PhysPt o_stack = SegPhys(ss)+(reg_esp & cpu.stack.mask);
+
+
+ // catch pagefaults
+ if (call.saved.gate.paramcount&31) {
+ if (call.Type()==DESC_386_CALL_GATE) {
+ for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--)
+ mem_readd(o_stack+i*4);
+ } else {
+ for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--)
+ mem_readw(o_stack+i*2);
+ }
+ }
+
+ // commit point
+ Segs.val[ss]=n_ss_sel;
+ Segs.phys[ss]=n_ss_desc.GetBase();
+ if (n_ss_desc.Big()) {
+ cpu.stack.big=true;
+ cpu.stack.mask=0xffffffff;
+ cpu.stack.notmask=0;
+ reg_esp=n_esp;
+ } else {
+ cpu.stack.big=false;
+ cpu.stack.mask=0xffff;
+ cpu.stack.notmask=0xffff0000;
+ reg_sp=n_esp & 0xffff;
+ }
+
+ cpu.cpl = n_cs_desc.DPL();
+ Bit16u oldcs = SegValue(cs);
+ /* Switch to new CS:EIP */
+ Segs.phys[cs] = n_cs_desc.GetBase();
+ Segs.val[cs] = (n_cs_sel & 0xfffc) | cpu.cpl;
+ cpu.code.big = n_cs_desc.Big()>0;
+ reg_eip = n_eip;
+ if (!use32) reg_eip&=0xffff;
+
+ if (call.Type()==DESC_386_CALL_GATE) {
+ CPU_Push32(o_ss); //save old stack
+ CPU_Push32(o_esp);
+ if (call.saved.gate.paramcount&31)
+ for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--)
+ CPU_Push32(mem_readd(o_stack+i*4));
+ CPU_Push32(oldcs);
+ CPU_Push32(oldeip);
+ } else {
+ CPU_Push16(o_ss); //save old stack
+ CPU_Push16(o_esp);
+ if (call.saved.gate.paramcount&31)
+ for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--)
+ CPU_Push16(mem_readw(o_stack+i*2));
+ CPU_Push16(oldcs);
+ CPU_Push16(oldeip);
+ }
+
+ break;
+ } else if (n_cs_dpl > cpu.cpl)
+ E_Exit("CALL:GATE:CS DPL>CPL"); // or #GP(sel)
+ case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA:
+ case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA:
+ // zrdx extender
+
+ if (call.Type()==DESC_386_CALL_GATE) {
+ CPU_Push32(SegValue(cs));
+ CPU_Push32(oldeip);
+ } else {
+ CPU_Push16(SegValue(cs));
+ CPU_Push16(oldeip);
+ }
+
+ /* Switch to new CS:EIP */
+ Segs.phys[cs] = n_cs_desc.GetBase();
+ Segs.val[cs] = (n_cs_sel & 0xfffc) | cpu.cpl;
+ cpu.code.big = n_cs_desc.Big()>0;
+ reg_eip = n_eip;
+ if (!use32) reg_eip&=0xffff;
+ break;
+ default:
+ E_Exit("CALL:GATE:CS no executable segment");
+ }
+ } /* Call Gates */
+ break;
+ case DESC_386_TSS_A:
+ CPU_CHECK_COND(call.DPL()<cpu.cpl,
+ "CALL:TSS:dpl<cpl",
+ EXCEPTION_GP,selector & 0xfffc)
+ CPU_CHECK_COND(call.DPL()<rpl,
+ "CALL:TSS:dpl<rpl",
+ EXCEPTION_GP,selector & 0xfffc)
+
+ CPU_CHECK_COND(!call.saved.seg.p,
+ "CALL:TSS:Segment not present",
+ EXCEPTION_NP,selector & 0xfffc)
+
+ LOG(LOG_CPU,LOG_NORMAL)("CALL:TSS to %X",selector);
+ CPU_SwitchTask(selector,TSwitch_CALL_INT,oldeip);
+ break;
+ case DESC_DATA_EU_RW_NA: // vbdos
+ case DESC_INVALID: // used by some installers
+ CPU_Exception(EXCEPTION_GP,selector & 0xfffc);
+ return;
+ default:
+ E_Exit("CALL:Descriptor type %x unsupported",call.Type());
+ }
+ }
+ assert(1);
+}
+
+
+void CPU_RET(bool use32,Bitu bytes,Bitu oldeip) {
+ if (!cpu.pmode || (reg_flags & FLAG_VM)) {
+ Bitu new_ip,new_cs;
+ if (!use32) {
+ new_ip=CPU_Pop16();
+ new_cs=CPU_Pop16();
+ } else {
+ new_ip=CPU_Pop32();
+ new_cs=CPU_Pop32() & 0xffff;
+ }
+ reg_esp+=bytes;
+ SegSet16(cs,new_cs);
+ reg_eip=new_ip;
+ cpu.code.big=false;
+ return;
+ } else {
+ Bitu offset,selector;
+ if (!use32) selector = mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask) + 2);
+ else selector = mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask) + 4) & 0xffff;
+
+ Descriptor desc;
+ Bitu rpl=selector & 3;
+ if(rpl < cpu.cpl) {
+ // win setup
+ CPU_Exception(EXCEPTION_GP,selector & 0xfffc);
+ return;
+ }
+
+ CPU_CHECK_COND((selector & 0xfffc)==0,
+ "RET:CS selector zero",
+ EXCEPTION_GP,0)
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(selector,desc),
+ "RET:CS beyond limits",
+ EXCEPTION_GP,selector & 0xfffc)
+
+ if (cpu.cpl==rpl) {
+ /* Return to same level */
+ switch (desc.Type()) {
+ case DESC_CODE_N_NC_A:case DESC_CODE_N_NC_NA:
+ case DESC_CODE_R_NC_A:case DESC_CODE_R_NC_NA:
+ case 18:
+ CPU_CHECK_COND(cpu.cpl!=desc.DPL(),
+ "RET to NC segment of other privilege",
+ EXCEPTION_GP,selector & 0xfffc)
+ goto RET_same_level;
+ case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA:
+ case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA:
+ CPU_CHECK_COND(desc.DPL()>cpu.cpl,
+ "RET to C segment of higher privilege",
+ EXCEPTION_GP,selector & 0xfffc)
+ break;
+ default:
+ E_Exit("RET from illegal descriptor type %X",desc.Type());
+ }
+RET_same_level:
+ if (!desc.saved.seg.p) {
+ // borland extender (RTM)
+ CPU_Exception(EXCEPTION_NP,selector & 0xfffc);
+ return;
+ }
+
+ // commit point
+ if (!use32) {
+ offset=CPU_Pop16();
+ selector=CPU_Pop16();
+ } else {
+ offset=CPU_Pop32();
+ selector=CPU_Pop32() & 0xffff;
+ }
+
+ Segs.phys[cs]=desc.GetBase();
+ cpu.code.big=desc.Big()>0;
+ Segs.val[cs]=selector;
+ reg_eip=offset;
+ if (cpu.stack.big) {
+ reg_esp+=bytes;
+ } else {
+ reg_sp+=bytes;
+ }
+ LOG(LOG_CPU,LOG_NORMAL)("RET - Same level to %X:%X RPL %X DPL %X",selector,offset,rpl,desc.DPL());
+ return;
+ } else {
+ /* Return to outer level */
+ switch (desc.Type()) {
+ case DESC_CODE_N_NC_A:case DESC_CODE_N_NC_NA:
+ case DESC_CODE_R_NC_A:case DESC_CODE_R_NC_NA:
+ CPU_CHECK_COND(desc.DPL()!=rpl,
+ "RET to outer NC segment with DPL!=RPL",
+ EXCEPTION_GP,selector & 0xfffc)
+ break;
+ case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA:
+ case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA:
+ CPU_CHECK_COND(desc.DPL()>rpl,
+ "RET to outer C segment with DPL>RPL",
+ EXCEPTION_GP,selector & 0xfffc)
+ break;
+ default:
+ E_Exit("RET from illegal descriptor type %X",desc.Type()); // or #GP(selector)
+ }
+
+ CPU_CHECK_COND(!desc.saved.seg.p,
+ "RET:Outer level:CS not present",
+ EXCEPTION_NP,selector & 0xfffc)
+
+ // commit point
+ Bitu n_esp,n_ss;
+ if (use32) {
+ offset=CPU_Pop32();
+ selector=CPU_Pop32() & 0xffff;
+ reg_esp+=bytes;
+ n_esp = CPU_Pop32();
+ n_ss = CPU_Pop32() & 0xffff;
+ } else {
+ offset=CPU_Pop16();
+ selector=CPU_Pop16();
+ reg_esp+=bytes;
+ n_esp = CPU_Pop16();
+ n_ss = CPU_Pop16();
+ }
+
+ CPU_CHECK_COND((n_ss & 0xfffc)==0,
+ "RET to outer level with SS selector zero",
+ EXCEPTION_GP,0)
+
+ Descriptor n_ss_desc;
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss,n_ss_desc),
+ "RET:SS beyond limits",
+ EXCEPTION_GP,n_ss & 0xfffc)
+
+ CPU_CHECK_COND(((n_ss & 3)!=rpl) || (n_ss_desc.DPL()!=rpl),
+ "RET to outer segment with invalid SS privileges",
+ EXCEPTION_GP,n_ss & 0xfffc)
+ switch (n_ss_desc.Type()) {
+ case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ break;
+ default:
+ E_Exit("RET:SS selector type no writable data segment"); // or #GP(selector)
+ }
+ CPU_CHECK_COND(!n_ss_desc.saved.seg.p,
+ "RET:Stack segment not present",
+ EXCEPTION_SS,n_ss & 0xfffc)
+
+ cpu.cpl = rpl;
+ Segs.phys[cs]=desc.GetBase();
+ cpu.code.big=desc.Big()>0;
+ Segs.val[cs]=(selector&0xfffc) | cpu.cpl;
+ reg_eip=offset;
+
+ Segs.val[ss]=n_ss;
+ Segs.phys[ss]=n_ss_desc.GetBase();
+ if (n_ss_desc.Big()) {
+ cpu.stack.big=true;
+ cpu.stack.mask=0xffffffff;
+ cpu.stack.notmask=0;
+ reg_esp=n_esp+bytes;
+ } else {
+ cpu.stack.big=false;
+ cpu.stack.mask=0xffff;
+ cpu.stack.notmask=0xffff0000;
+ reg_sp=(n_esp & 0xffff)+bytes;
+ }
+
+ CPU_CheckSegments();
+
+// LOG(LOG_MISC,LOG_ERROR)("RET - Higher level to %X:%X RPL %X DPL %X",selector,offset,rpl,desc.DPL());
+ return;
+ }
+ LOG(LOG_CPU,LOG_NORMAL)("Prot ret %X:%X",selector,offset);
+ return;
+ }
+ assert(1);
+}
+
+
+Bitu CPU_SLDT(void) {
+ return cpu.gdt.SLDT();
+}
+
+bool CPU_LLDT(Bitu selector) {
+ if (!cpu.gdt.LLDT(selector)) {
+ LOG(LOG_CPU,LOG_ERROR)("LLDT failed, selector=%X",selector);
+ return true;
+ }
+ LOG(LOG_CPU,LOG_NORMAL)("LDT Set to %X",selector);
+ return false;
+}
+
+Bitu CPU_STR(void) {
+ return cpu_tss.selector;
+}
+
+bool CPU_LTR(Bitu selector) {
+ if ((selector & 0xfffc)==0) {
+ cpu_tss.SetSelector(selector);
+ return false;
+ }
+ TSS_Descriptor desc;
+ if ((selector & 4) || (!cpu.gdt.GetDescriptor(selector,desc))) {
+ LOG(LOG_CPU,LOG_ERROR)("LTR failed, selector=%X",selector);
+ return CPU_PrepareException(EXCEPTION_GP,selector);
+ }
+
+ if ((desc.Type()==DESC_286_TSS_A) || (desc.Type()==DESC_386_TSS_A)) {
+ if (!desc.saved.seg.p) {
+ LOG(LOG_CPU,LOG_ERROR)("LTR failed, selector=%X (not present)",selector);
+ return CPU_PrepareException(EXCEPTION_NP,selector);
+ }
+ if (!cpu_tss.SetSelector(selector)) E_Exit("LTR failed, selector=%X",selector);
+ cpu_tss.desc.SetBusy(true);
+ cpu_tss.SaveSelector();
+ } else {
+ /* Descriptor was no available TSS descriptor */
+ LOG(LOG_CPU,LOG_NORMAL)("LTR failed, selector=%X (type=%X)",selector,desc.Type());
+ return CPU_PrepareException(EXCEPTION_GP,selector);
+ }
+ return false;
+}
+
+void CPU_LGDT(Bitu limit,Bitu base) {
+ LOG(LOG_CPU,LOG_NORMAL)("GDT Set to base:%X limit:%X",base,limit);
+ cpu.gdt.SetLimit(limit);
+ cpu.gdt.SetBase(base);
+}
+
+void CPU_LIDT(Bitu limit,Bitu base) {
+ LOG(LOG_CPU,LOG_NORMAL)("IDT Set to base:%X limit:%X",base,limit);
+ cpu.idt.SetLimit(limit);
+ cpu.idt.SetBase(base);
+}
+
+Bitu CPU_SGDT_base(void) {
+ return cpu.gdt.GetBase();
+}
+Bitu CPU_SGDT_limit(void) {
+ return cpu.gdt.GetLimit();
+}
+
+Bitu CPU_SIDT_base(void) {
+ return cpu.idt.GetBase();
+}
+Bitu CPU_SIDT_limit(void) {
+ return cpu.idt.GetLimit();
+}
+
+static bool printed_cycles_auto_info = false;
+void CPU_SET_CRX(Bitu cr,Bitu value) {
+ switch (cr) {
+ case 0:
+ {
+ value|=CR0_FPUPRESENT;
+ Bitu changed=cpu.cr0 ^ value;
+ if (!changed) return;
+ cpu.cr0=value;
+ if (value & CR0_PROTECTION) {
+ cpu.pmode=true;
+ LOG(LOG_CPU,LOG_NORMAL)("Protected mode");
+ PAGING_Enable((value & CR0_PAGING)>0);
+
+ if (!(CPU_AutoDetermineMode&CPU_AUTODETERMINE_MASK)) break;
+
+ if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CYCLES) {
+ CPU_CycleAutoAdjust=true;
+ CPU_CycleLeft=0;
+ CPU_Cycles=0;
+ CPU_OldCycleMax=CPU_CycleMax;
+ GFX_SetTitle(CPU_CyclePercUsed,-1,false);
+ if(!printed_cycles_auto_info) {
+ printed_cycles_auto_info = true;
+ LOG_MSG("DOSBox has switched to max cycles, because of the setting: cycles=auto.\nIf the game runs too fast, try a fixed cycles amount in DOSBox's options.");
+ }
+ } else {
+ GFX_SetTitle(-1,-1,false);
+ }
+#if (C_DYNAMIC_X86)
+ if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CORE) {
+ CPU_Core_Dyn_X86_Cache_Init(true);
+ cpudecoder=&CPU_Core_Dyn_X86_Run;
+ }
+#elif (C_DYNREC)
+ if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CORE) {
+ CPU_Core_Dynrec_Cache_Init(true);
+ cpudecoder=&CPU_Core_Dynrec_Run;
+ }
+#endif
+ CPU_AutoDetermineMode<<=CPU_AUTODETERMINE_SHIFT;
+ } else {
+ cpu.pmode=false;
+ if (value & CR0_PAGING) LOG_MSG("Paging requested without PE=1");
+ PAGING_Enable(false);
+ LOG(LOG_CPU,LOG_NORMAL)("Real mode");
+ }
+ break;
+ }
+ case 2:
+ paging.cr2=value;
+ break;
+ case 3:
+ PAGING_SetDirBase(value);
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV CR%d,%X",cr,value);
+ break;
+ }
+}
+
+bool CPU_WRITE_CRX(Bitu cr,Bitu value) {
+ /* Check if privileged to access control registers */
+ if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
+ if ((cr==1) || (cr>4)) return CPU_PrepareException(EXCEPTION_UD,0);
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) {
+ if (cr==4) return CPU_PrepareException(EXCEPTION_UD,0);
+ }
+ CPU_SET_CRX(cr,value);
+ return false;
+}
+
+Bitu CPU_GET_CRX(Bitu cr) {
+ switch (cr) {
+ case 0:
+ if (CPU_ArchitectureType>=CPU_ARCHTYPE_PENTIUMSLOW) return cpu.cr0;
+ else if (CPU_ArchitectureType>=CPU_ARCHTYPE_486OLDSLOW) return (cpu.cr0 & 0xe005003f);
+ else return (cpu.cr0 | 0x7ffffff0);
+ case 2:
+ return paging.cr2;
+ case 3:
+ return PAGING_GetDirBase() & 0xfffff000;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV XXX, CR%d",cr);
+ break;
+ }
+ return 0;
+}
+
+bool CPU_READ_CRX(Bitu cr,Bit32u & retvalue) {
+ /* Check if privileged to access control registers */
+ if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
+ if ((cr==1) || (cr>4)) return CPU_PrepareException(EXCEPTION_UD,0);
+ retvalue=CPU_GET_CRX(cr);
+ return false;
+}
+
+
+bool CPU_WRITE_DRX(Bitu dr,Bitu value) {
+ /* Check if privileged to access control registers */
+ if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
+ switch (dr) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ cpu.drx[dr]=value;
+ break;
+ case 4:
+ case 6:
+ cpu.drx[6]=(value|0xffff0ff0) & 0xffffefff;
+ break;
+ case 5:
+ case 7:
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_PENTIUMSLOW) {
+ cpu.drx[7]=(value|0x400) & 0xffff2fff;
+ } else {
+ cpu.drx[7]=(value|0x400);
+ }
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV DR%d,%X",dr,value);
+ break;
+ }
+ return false;
+}
+
+bool CPU_READ_DRX(Bitu dr,Bit32u & retvalue) {
+ /* Check if privileged to access control registers */
+ if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
+ switch (dr) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 6:
+ case 7:
+ retvalue=cpu.drx[dr];
+ break;
+ case 4:
+ retvalue=cpu.drx[6];
+ break;
+ case 5:
+ retvalue=cpu.drx[7];
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV XXX, DR%d",dr);
+ retvalue=0;
+ break;
+ }
+ return false;
+}
+
+bool CPU_WRITE_TRX(Bitu tr,Bitu value) {
+ /* Check if privileged to access control registers */
+ if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
+ switch (tr) {
+// case 3:
+ case 6:
+ case 7:
+ cpu.trx[tr]=value;
+ return false;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV TR%d,%X",tr,value);
+ break;
+ }
+ return CPU_PrepareException(EXCEPTION_UD,0);
+}
+
+bool CPU_READ_TRX(Bitu tr,Bit32u & retvalue) {
+ /* Check if privileged to access control registers */
+ if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
+ switch (tr) {
+// case 3:
+ case 6:
+ case 7:
+ retvalue=cpu.trx[tr];
+ return false;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV XXX, TR%d",tr);
+ break;
+ }
+ return CPU_PrepareException(EXCEPTION_UD,0);
+}
+
+
+Bitu CPU_SMSW(void) {
+ return cpu.cr0;
+}
+
+bool CPU_LMSW(Bitu word) {
+ if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0);
+ word&=0xf;
+ if (cpu.cr0 & 1) word|=1;
+ word|=(cpu.cr0&0xfffffff0);
+ CPU_SET_CRX(0,word);
+ return false;
+}
+
+void CPU_ARPL(Bitu & dest_sel,Bitu src_sel) {
+ FillFlags();
+ if ((dest_sel & 3) < (src_sel & 3)) {
+ dest_sel=(dest_sel & 0xfffc) + (src_sel & 3);
+// dest_sel|=0xff3f0000;
+ SETFLAGBIT(ZF,true);
+ } else {
+ SETFLAGBIT(ZF,false);
+ }
+}
+
+void CPU_LAR(Bitu selector,Bitu & ar) {
+ FillFlags();
+ if (selector == 0) {
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ Descriptor desc;Bitu rpl=selector & 3;
+ if (!cpu.gdt.GetDescriptor(selector,desc)){
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ switch (desc.Type()){
+ case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA:
+ case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA:
+ break;
+
+ case DESC_286_INT_GATE: case DESC_286_TRAP_GATE: {
+ case DESC_386_INT_GATE: case DESC_386_TRAP_GATE:
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+
+ case DESC_LDT:
+ case DESC_TASK_GATE:
+
+ case DESC_286_TSS_A: case DESC_286_TSS_B:
+ case DESC_286_CALL_GATE:
+
+ case DESC_386_TSS_A: case DESC_386_TSS_B:
+ case DESC_386_CALL_GATE:
+
+
+ case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A:
+ case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A:
+ case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA:
+ case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA:
+ if (desc.DPL()<cpu.cpl || desc.DPL() < rpl) {
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ break;
+ default:
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ /* Valid descriptor */
+ ar=desc.saved.fill[1] & 0x00ffff00;
+ SETFLAGBIT(ZF,true);
+}
+
+void CPU_LSL(Bitu selector,Bitu & limit) {
+ FillFlags();
+ if (selector == 0) {
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ Descriptor desc;Bitu rpl=selector & 3;
+ if (!cpu.gdt.GetDescriptor(selector,desc)){
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ switch (desc.Type()){
+ case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA:
+ case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA:
+ break;
+
+ case DESC_LDT:
+ case DESC_286_TSS_A:
+ case DESC_286_TSS_B:
+
+ case DESC_386_TSS_A:
+ case DESC_386_TSS_B:
+
+ case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A:
+ case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A:
+ case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+
+ case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA:
+ case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA:
+ if (desc.DPL()<cpu.cpl || desc.DPL() < rpl) {
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ break;
+ default:
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ limit=desc.GetLimit();
+ SETFLAGBIT(ZF,true);
+}
+
+void CPU_VERR(Bitu selector) {
+ FillFlags();
+ if (selector == 0) {
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ Descriptor desc;Bitu rpl=selector & 3;
+ if (!cpu.gdt.GetDescriptor(selector,desc)){
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ switch (desc.Type()){
+ case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA:
+ //Conforming readable code segments can be always read
+ break;
+ case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A:
+ case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A:
+ case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+
+ case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA:
+ if (desc.DPL()<cpu.cpl || desc.DPL() < rpl) {
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ break;
+ default:
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ SETFLAGBIT(ZF,true);
+}
+
+void CPU_VERW(Bitu selector) {
+ FillFlags();
+ if (selector == 0) {
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ Descriptor desc;Bitu rpl=selector & 3;
+ if (!cpu.gdt.GetDescriptor(selector,desc)){
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ switch (desc.Type()){
+ case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ if (desc.DPL()<cpu.cpl || desc.DPL() < rpl) {
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ break;
+ default:
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ SETFLAGBIT(ZF,true);
+}
+
+bool CPU_SetSegGeneral(SegNames seg,Bitu value) {
+ value &= 0xffff;
+ if (!cpu.pmode || (reg_flags & FLAG_VM)) {
+ Segs.val[seg]=value;
+ Segs.phys[seg]=value << 4;
+ if (seg==ss) {
+ cpu.stack.big=false;
+ cpu.stack.mask=0xffff;
+ cpu.stack.notmask=0xffff0000;
+ }
+ return false;
+ } else {
+ if (seg==ss) {
+ // Stack needs to be non-zero
+ if ((value & 0xfffc)==0) {
+ E_Exit("CPU_SetSegGeneral: Stack segment zero");
+// return CPU_PrepareException(EXCEPTION_GP,0);
+ }
+ Descriptor desc;
+ if (!cpu.gdt.GetDescriptor(value,desc)) {
+ E_Exit("CPU_SetSegGeneral: Stack segment beyond limits");
+// return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
+ }
+ if (((value & 3)!=cpu.cpl) || (desc.DPL()!=cpu.cpl)) {
+ E_Exit("CPU_SetSegGeneral: Stack segment with invalid privileges");
+// return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
+ }
+
+ switch (desc.Type()) {
+ case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ break;
+ default:
+ //Earth Siege 1
+ return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
+ }
+
+ if (!desc.saved.seg.p) {
+// E_Exit("CPU_SetSegGeneral: Stack segment not present"); // or #SS(sel)
+ return CPU_PrepareException(EXCEPTION_SS,value & 0xfffc);
+ }
+
+ Segs.val[seg]=value;
+ Segs.phys[seg]=desc.GetBase();
+ if (desc.Big()) {
+ cpu.stack.big=true;
+ cpu.stack.mask=0xffffffff;
+ cpu.stack.notmask=0;
+ } else {
+ cpu.stack.big=false;
+ cpu.stack.mask=0xffff;
+ cpu.stack.notmask=0xffff0000;
+ }
+ } else {
+ if ((value & 0xfffc)==0) {
+ Segs.val[seg]=value;
+ Segs.phys[seg]=0; // ??
+ return false;
+ }
+ Descriptor desc;
+ if (!cpu.gdt.GetDescriptor(value,desc)) {
+ return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
+ }
+ switch (desc.Type()) {
+ case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A:
+ case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A:
+ case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA:
+ if (((value & 3)>desc.DPL()) || (cpu.cpl>desc.DPL())) {
+ // extreme pinball
+ return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
+ }
+ break;
+ case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA:
+ break;
+ default:
+ // gabriel knight
+ return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
+
+ }
+ if (!desc.saved.seg.p) {
+ // win
+ return CPU_PrepareException(EXCEPTION_NP,value & 0xfffc);
+ }
+
+ Segs.val[seg]=value;
+ Segs.phys[seg]=desc.GetBase();
+ }
+
+ return false;
+ }
+}
+
+bool CPU_PopSeg(SegNames seg,bool use32) {
+ Bitu val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask));
+ if (CPU_SetSegGeneral(seg,val)) return true;
+ Bitu addsp=use32?0x04:0x02;
+ reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+addsp)&cpu.stack.mask);
+ return false;
+}
+
+bool CPU_CPUID(void) {
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486NEWSLOW) return false;
+ switch (reg_eax) {
+ case 0: /* Vendor ID String and maximum level? */
+ reg_eax=1; /* Maximum level */
+ reg_ebx='G' | ('e' << 8) | ('n' << 16) | ('u'<< 24);
+ reg_edx='i' | ('n' << 8) | ('e' << 16) | ('I'<< 24);
+ reg_ecx='n' | ('t' << 8) | ('e' << 16) | ('l'<< 24);
+ break;
+ case 1: /* get processor type/family/model/stepping and feature flags */
+ if ((CPU_ArchitectureType==CPU_ARCHTYPE_486NEWSLOW) ||
+ (CPU_ArchitectureType==CPU_ARCHTYPE_MIXED)) {
+ reg_eax=0x402; /* intel 486dx */
+ reg_ebx=0; /* Not Supported */
+ reg_ecx=0; /* No features */
+ reg_edx=0x00000001; /* FPU */
+ } else if (CPU_ArchitectureType==CPU_ARCHTYPE_PENTIUMSLOW) {
+ reg_eax=0x513; /* intel pentium */
+ reg_ebx=0; /* Not Supported */
+ reg_ecx=0; /* No features */
+ reg_edx=0x00000011; /* FPU+TimeStamp/RDTSC */
+ } else {
+ return false;
+ }
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled CPUID Function %x",reg_eax);
+ reg_eax=0;
+ reg_ebx=0;
+ reg_ecx=0;
+ reg_edx=0;
+ break;
+ }
+ return true;
+}
+
+static Bits HLT_Decode(void) {
+ /* Once an interrupt occurs, it should change cpu core */
+ if (reg_eip!=cpu.hlt.eip || SegValue(cs) != cpu.hlt.cs) {
+ cpudecoder=cpu.hlt.old_decoder;
+ } else {
+ CPU_IODelayRemoved += CPU_Cycles;
+ CPU_Cycles=0;
+ }
+ return 0;
+}
+
+void CPU_HLT(Bitu oldeip) {
+ reg_eip=oldeip;
+ CPU_IODelayRemoved += CPU_Cycles;
+ CPU_Cycles=0;
+ cpu.hlt.cs=SegValue(cs);
+ cpu.hlt.eip=reg_eip;
+ cpu.hlt.old_decoder=cpudecoder;
+ cpudecoder=&HLT_Decode;
+}
+
+void CPU_ENTER(bool use32,Bitu bytes,Bitu level) {
+ level&=0x1f;
+ Bitu sp_index=reg_esp&cpu.stack.mask;
+ Bitu bp_index=reg_ebp&cpu.stack.mask;
+ if (!use32) {
+ sp_index-=2;
+ mem_writew(SegPhys(ss)+sp_index,reg_bp);
+ reg_bp=(Bit16u)(reg_esp-2);
+ if (level) {
+ for (Bitu i=1;i<level;i++) {
+ sp_index-=2;bp_index-=2;
+ mem_writew(SegPhys(ss)+sp_index,mem_readw(SegPhys(ss)+bp_index));
+ }
+ sp_index-=2;
+ mem_writew(SegPhys(ss)+sp_index,reg_bp);
+ }
+ } else {
+ sp_index-=4;
+ mem_writed(SegPhys(ss)+sp_index,reg_ebp);
+ reg_ebp=(reg_esp-4);
+ if (level) {
+ for (Bitu i=1;i<level;i++) {
+ sp_index-=4;bp_index-=4;
+ mem_writed(SegPhys(ss)+sp_index,mem_readd(SegPhys(ss)+bp_index));
+ }
+ sp_index-=4;
+ mem_writed(SegPhys(ss)+sp_index,reg_ebp);
+ }
+ }
+ sp_index-=bytes;
+ reg_esp=(reg_esp&cpu.stack.notmask)|((sp_index)&cpu.stack.mask);
+}
+
+static void CPU_CycleIncrease(bool pressed) {
+ if (!pressed) return;
+ if (CPU_CycleAutoAdjust) {
+ CPU_CyclePercUsed+=5;
+ if (CPU_CyclePercUsed>105) CPU_CyclePercUsed=105;
+ LOG_MSG("CPU speed: max %d percent.",CPU_CyclePercUsed);
+ GFX_SetTitle(CPU_CyclePercUsed,-1,false);
+ } else {
+ Bit32s old_cycles=CPU_CycleMax;
+ if (CPU_CycleUp < 100) {
+ CPU_CycleMax = (Bit32s)(CPU_CycleMax * (1 + (float)CPU_CycleUp / 100.0));
+ } else {
+ CPU_CycleMax = (Bit32s)(CPU_CycleMax + CPU_CycleUp);
+ }
+
+ CPU_CycleLeft=0;CPU_Cycles=0;
+ if (CPU_CycleMax==old_cycles) CPU_CycleMax++;
+ if(CPU_CycleMax > 15000 )
+ LOG_MSG("CPU speed: fixed %d cycles. If you need more than 20000, try core=dynamic in DOSBox's options.",CPU_CycleMax);
+ else
+ LOG_MSG("CPU speed: fixed %d cycles.",CPU_CycleMax);
+ GFX_SetTitle(CPU_CycleMax,-1,false);
+ }
+}
+
+static void CPU_CycleDecrease(bool pressed) {
+ if (!pressed) return;
+ if (CPU_CycleAutoAdjust) {
+ CPU_CyclePercUsed-=5;
+ if (CPU_CyclePercUsed<=0) CPU_CyclePercUsed=1;
+ if(CPU_CyclePercUsed <=70)
+ LOG_MSG("CPU speed: max %d percent. If the game runs too fast, try a fixed cycles amount in DOSBox's options.",CPU_CyclePercUsed);
+ else
+ LOG_MSG("CPU speed: max %d percent.",CPU_CyclePercUsed);
+ GFX_SetTitle(CPU_CyclePercUsed,-1,false);
+ } else {
+ if (CPU_CycleDown < 100) {
+ CPU_CycleMax = (Bit32s)(CPU_CycleMax / (1 + (float)CPU_CycleDown / 100.0));
+ } else {
+ CPU_CycleMax = (Bit32s)(CPU_CycleMax - CPU_CycleDown);
+ }
+ CPU_CycleLeft=0;CPU_Cycles=0;
+ if (CPU_CycleMax <= 0) CPU_CycleMax=1;
+ LOG_MSG("CPU speed: fixed %d cycles.",CPU_CycleMax);
+ GFX_SetTitle(CPU_CycleMax,-1,false);
+ }
+}
+
+void CPU_Enable_SkipAutoAdjust(void) {
+ if (CPU_CycleAutoAdjust) {
+ CPU_CycleMax /= 2;
+ if (CPU_CycleMax < CPU_CYCLES_LOWER_LIMIT)
+ CPU_CycleMax = CPU_CYCLES_LOWER_LIMIT;
+ }
+ CPU_SkipCycleAutoAdjust=true;
+}
+
+void CPU_Disable_SkipAutoAdjust(void) {
+ CPU_SkipCycleAutoAdjust=false;
+}
+
+
+extern Bit32s ticksDone;
+extern Bit32u ticksScheduled;
+
+void CPU_Reset_AutoAdjust(void) {
+ CPU_IODelayRemoved = 0;
+ ticksDone = 0;
+ ticksScheduled = 0;
+}
+
+class CPU: public Module_base {
+private:
+ static bool inited;
+public:
+ CPU(Section* configuration):Module_base(configuration) {
+ if(inited) {
+ Change_Config(configuration);
+ return;
+ }
+// Section_prop * section=static_cast<Section_prop *>(configuration);
+ inited=true;
+ reg_eax=0;
+ reg_ebx=0;
+ reg_ecx=0;
+ reg_edx=0;
+ reg_edi=0;
+ reg_esi=0;
+ reg_ebp=0;
+ reg_esp=0;
+
+ SegSet16(cs,0);
+ SegSet16(ds,0);
+ SegSet16(es,0);
+ SegSet16(fs,0);
+ SegSet16(gs,0);
+ SegSet16(ss,0);
+
+ CPU_SetFlags(FLAG_IF,FMASK_ALL); //Enable interrupts
+ cpu.cr0=0xffffffff;
+ CPU_SET_CRX(0,0); //Initialize
+ cpu.code.big=false;
+ cpu.stack.mask=0xffff;
+ cpu.stack.notmask=0xffff0000;
+ cpu.stack.big=false;
+ cpu.trap_skip=false;
+ cpu.idt.SetBase(0);
+ cpu.idt.SetLimit(1023);
+
+ for (Bitu i=0; i<7; i++) {
+ cpu.drx[i]=0;
+ cpu.trx[i]=0;
+ }
+ if (CPU_ArchitectureType==CPU_ARCHTYPE_PENTIUMSLOW) {
+ cpu.drx[6]=0xffff0ff0;
+ } else {
+ cpu.drx[6]=0xffff1ff0;
+ }
+ cpu.drx[7]=0x00000400;
+
+ /* Init the cpu cores */
+ CPU_Core_Normal_Init();
+ CPU_Core_Simple_Init();
+ CPU_Core_Full_Init();
+#if (C_DYNAMIC_X86)
+ CPU_Core_Dyn_X86_Init();
+#elif (C_DYNREC)
+ CPU_Core_Dynrec_Init();
+#endif
+ MAPPER_AddHandler(CPU_CycleDecrease,MK_f11,MMOD1,"cycledown","Dec Cycles");
+ MAPPER_AddHandler(CPU_CycleIncrease,MK_f12,MMOD1,"cycleup" ,"Inc Cycles");
+ Change_Config(configuration);
+ CPU_JMP(false,0,0,0); //Setup the first cpu core
+ }
+ bool Change_Config(Section* newconfig){
+ Section_prop * section=static_cast<Section_prop *>(newconfig);
+ CPU_AutoDetermineMode=CPU_AUTODETERMINE_NONE;
+ //CPU_CycleLeft=0;//needed ?
+ CPU_Cycles=0;
+ CPU_SkipCycleAutoAdjust=false;
+
+ Prop_multival* p = section->Get_multival("cycles");
+ std::string type = p->GetSection()->Get_string("type");
+ std::string str ;
+ CommandLine cmd(0,p->GetSection()->Get_string("parameters"));
+ if (type=="max") {
+ CPU_CycleMax=0;
+ CPU_CyclePercUsed=100;
+ CPU_CycleAutoAdjust=true;
+ CPU_CycleLimit=-1;
+ for (Bitu cmdnum=1; cmdnum<=cmd.GetCount(); cmdnum++) {
+ if (cmd.FindCommand(cmdnum,str)) {
+ if (str.find('%')==str.length()-1) {
+ str.erase(str.find('%'));
+ int percval=0;
+ std::istringstream stream(str);
+ stream >> percval;
+ if ((percval>0) && (percval<=105)) CPU_CyclePercUsed=(Bit32s)percval;
+ } else if (str=="limit") {
+ cmdnum++;
+ if (cmd.FindCommand(cmdnum,str)) {
+ int cyclimit=0;
+ std::istringstream stream(str);
+ stream >> cyclimit;
+ if (cyclimit>0) CPU_CycleLimit=cyclimit;
+ }
+ }
+ }
+ }
+ } else {
+ if (type=="auto") {
+ CPU_AutoDetermineMode|=CPU_AUTODETERMINE_CYCLES;
+ CPU_CycleMax=3000;
+ CPU_OldCycleMax=3000;
+ CPU_CyclePercUsed=100;
+ for (Bitu cmdnum=0; cmdnum<=cmd.GetCount(); cmdnum++) {
+ if (cmd.FindCommand(cmdnum,str)) {
+ if (str.find('%')==str.length()-1) {
+ str.erase(str.find('%'));
+ int percval=0;
+ std::istringstream stream(str);
+ stream >> percval;
+ if ((percval>0) && (percval<=105)) CPU_CyclePercUsed=(Bit32s)percval;
+ } else if (str=="limit") {
+ cmdnum++;
+ if (cmd.FindCommand(cmdnum,str)) {
+ int cyclimit=0;
+ std::istringstream stream(str);
+ stream >> cyclimit;
+ if (cyclimit>0) CPU_CycleLimit=cyclimit;
+ }
+ } else {
+ int rmdval=0;
+ std::istringstream stream(str);
+ stream >> rmdval;
+ if (rmdval>0) {
+ CPU_CycleMax=(Bit32s)rmdval;
+ CPU_OldCycleMax=(Bit32s)rmdval;
+ }
+ }
+ }
+ }
+ } else if(type =="fixed") {
+ cmd.FindCommand(1,str);
+ int rmdval=0;
+ std::istringstream stream(str);
+ stream >> rmdval;
+ CPU_CycleMax=(Bit32s)rmdval;
+ } else {
+ std::istringstream stream(type);
+ int rmdval=0;
+ stream >> rmdval;
+ if(rmdval) CPU_CycleMax=(Bit32s)rmdval;
+ }
+ CPU_CycleAutoAdjust=false;
+ }
+
+ CPU_CycleUp=section->Get_int("cycleup");
+ CPU_CycleDown=section->Get_int("cycledown");
+ std::string core(section->Get_string("core"));
+ cpudecoder=&CPU_Core_Normal_Run;
+ if (core == "normal") {
+ cpudecoder=&CPU_Core_Normal_Run;
+ } else if (core =="simple") {
+ cpudecoder=&CPU_Core_Simple_Run;
+ } else if (core == "full") {
+ cpudecoder=&CPU_Core_Full_Run;
+ } else if (core == "auto") {
+ cpudecoder=&CPU_Core_Normal_Run;
+#if (C_DYNAMIC_X86)
+ CPU_AutoDetermineMode|=CPU_AUTODETERMINE_CORE;
+ }
+ else if (core == "dynamic") {
+ cpudecoder=&CPU_Core_Dyn_X86_Run;
+ CPU_Core_Dyn_X86_SetFPUMode(true);
+ } else if (core == "dynamic_nodhfpu") {
+ cpudecoder=&CPU_Core_Dyn_X86_Run;
+ CPU_Core_Dyn_X86_SetFPUMode(false);
+#elif (C_DYNREC)
+ CPU_AutoDetermineMode|=CPU_AUTODETERMINE_CORE;
+ }
+ else if (core == "dynamic") {
+ cpudecoder=&CPU_Core_Dynrec_Run;
+#else
+
+#endif
+ }
+
+#if (C_DYNAMIC_X86)
+ CPU_Core_Dyn_X86_Cache_Init((core == "dynamic") || (core == "dynamic_nodhfpu"));
+#elif (C_DYNREC)
+ CPU_Core_Dynrec_Cache_Init( core == "dynamic" );
+#endif
+
+ CPU_ArchitectureType = CPU_ARCHTYPE_MIXED;
+ std::string cputype(section->Get_string("cputype"));
+ if (cputype == "auto") {
+ CPU_ArchitectureType = CPU_ARCHTYPE_MIXED;
+ } else if (cputype == "386") {
+ CPU_ArchitectureType = CPU_ARCHTYPE_386FAST;
+ } else if (cputype == "386_prefetch") {
+ CPU_ArchitectureType = CPU_ARCHTYPE_386FAST;
+ if (core == "normal") {
+ cpudecoder=&CPU_Core_Prefetch_Run;
+ CPU_PrefetchQueueSize = 16;
+ } else if (core == "auto") {
+ cpudecoder=&CPU_Core_Prefetch_Run;
+ CPU_PrefetchQueueSize = 16;
+ CPU_AutoDetermineMode&=(~CPU_AUTODETERMINE_CORE);
+ } else {
+ E_Exit("prefetch queue emulation requires the normal core setting.");
+ }
+ } else if (cputype == "386_slow") {
+ CPU_ArchitectureType = CPU_ARCHTYPE_386SLOW;
+ } else if (cputype == "486_slow") {
+ CPU_ArchitectureType = CPU_ARCHTYPE_486NEWSLOW;
+ } else if (cputype == "486_prefetch") {
+ CPU_ArchitectureType = CPU_ARCHTYPE_486NEWSLOW;
+ if (core == "normal") {
+ cpudecoder=&CPU_Core_Prefetch_Run;
+ CPU_PrefetchQueueSize = 32;
+ } else if (core == "auto") {
+ cpudecoder=&CPU_Core_Prefetch_Run;
+ CPU_PrefetchQueueSize = 32;
+ CPU_AutoDetermineMode&=(~CPU_AUTODETERMINE_CORE);
+ } else {
+ E_Exit("prefetch queue emulation requires the normal core setting.");
+ }
+ } else if (cputype == "pentium_slow") {
+ CPU_ArchitectureType = CPU_ARCHTYPE_PENTIUMSLOW;
+ }
+
+ if (CPU_ArchitectureType>=CPU_ARCHTYPE_486NEWSLOW) CPU_extflags_toggle=(FLAG_ID|FLAG_AC);
+ else if (CPU_ArchitectureType>=CPU_ARCHTYPE_486OLDSLOW) CPU_extflags_toggle=(FLAG_AC);
+ else CPU_extflags_toggle=0;
+
+
+ if(CPU_CycleMax <= 0) CPU_CycleMax = 3000;
+ if(CPU_CycleUp <= 0) CPU_CycleUp = 500;
+ if(CPU_CycleDown <= 0) CPU_CycleDown = 20;
+ if (CPU_CycleAutoAdjust) GFX_SetTitle(CPU_CyclePercUsed,-1,false);
+ else GFX_SetTitle(CPU_CycleMax,-1,false);
+ return true;
+ }
+ ~CPU(){ /* empty */};
+};
+
+static CPU * test;
+
+void CPU_ShutDown(Section* sec) {
+#if (C_DYNAMIC_X86)
+ CPU_Core_Dyn_X86_Cache_Close();
+#elif (C_DYNREC)
+ CPU_Core_Dynrec_Cache_Close();
+#endif
+ delete test;
+}
+
+void CPU_Init(Section* sec) {
+ test = new CPU(sec);
+ sec->AddDestroyFunction(&CPU_ShutDown,true);
+}
+//initialize static members
+bool CPU::inited=false;
--- /dev/null
+/*
+ * 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.
+ */
+
+/*
+ Lazy flag system was designed after the same kind of system used in Bochs.
+ Probably still some bugs left in here.
+*/
+
+#include "dosbox.h"
+#include "cpu.h"
+#include "lazyflags.h"
+#include "pic.h"
+
+LazyFlags lflags;
+
+/* CF Carry Flag -- Set on high-order bit carry or borrow; cleared
+ otherwise.
+*/
+Bit32u get_CF(void) {
+
+ switch (lflags.type) {
+ case t_UNKNOWN:
+ case t_INCb:
+ case t_INCw:
+ case t_INCd:
+ case t_DECb:
+ case t_DECw:
+ case t_DECd:
+ case t_MUL:
+ return GETFLAG(CF);
+ case t_ADDb:
+ return (lf_resb<lf_var1b);
+ case t_ADDw:
+ return (lf_resw<lf_var1w);
+ case t_ADDd:
+ return (lf_resd<lf_var1d);
+ case t_ADCb:
+ return (lf_resb < lf_var1b) || (lflags.oldcf && (lf_resb == lf_var1b));
+ case t_ADCw:
+ return (lf_resw < lf_var1w) || (lflags.oldcf && (lf_resw == lf_var1w));
+ case t_ADCd:
+ return (lf_resd < lf_var1d) || (lflags.oldcf && (lf_resd == lf_var1d));
+ case t_SBBb:
+ return (lf_var1b < lf_resb) || (lflags.oldcf && (lf_var2b==0xff));
+ case t_SBBw:
+ return (lf_var1w < lf_resw) || (lflags.oldcf && (lf_var2w==0xffff));
+ case t_SBBd:
+ return (lf_var1d < lf_resd) || (lflags.oldcf && (lf_var2d==0xffffffff));
+ case t_SUBb:
+ case t_CMPb:
+ return (lf_var1b<lf_var2b);
+ case t_SUBw:
+ case t_CMPw:
+ return (lf_var1w<lf_var2w);
+ case t_SUBd:
+ case t_CMPd:
+ return (lf_var1d<lf_var2d);
+ case t_SHLb:
+ if (lf_var2b>8) return false;
+ else return (lf_var1b >> (8-lf_var2b)) & 1;
+ case t_SHLw:
+ if (lf_var2b>16) return false;
+ else return (lf_var1w >> (16-lf_var2b)) & 1;
+ case t_SHLd:
+ case t_DSHLw: /* Hmm this is not correct for shift higher than 16 */
+ case t_DSHLd:
+ return (lf_var1d >> (32 - lf_var2b)) & 1;
+ case t_RCRb:
+ case t_SHRb:
+ return (lf_var1b >> (lf_var2b - 1)) & 1;
+ case t_RCRw:
+ case t_SHRw:
+ return (lf_var1w >> (lf_var2b - 1)) & 1;
+ case t_RCRd:
+ case t_SHRd:
+ case t_DSHRw: /* Hmm this is not correct for shift higher than 16 */
+ case t_DSHRd:
+ return (lf_var1d >> (lf_var2b - 1)) & 1;
+ case t_SARb:
+ return (((Bit8s) lf_var1b) >> (lf_var2b - 1)) & 1;
+ case t_SARw:
+ return (((Bit16s) lf_var1w) >> (lf_var2b - 1)) & 1;
+ case t_SARd:
+ return (((Bit32s) lf_var1d) >> (lf_var2b - 1)) & 1;
+ case t_NEGb:
+ return lf_var1b;
+ case t_NEGw:
+ return lf_var1w;
+ case t_NEGd:
+ return lf_var1d;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ return false; /* Set to false */
+ case t_DIV:
+ return false; /* Unkown */
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("get_CF Unknown %d",lflags.type);
+ }
+ return 0;
+}
+
+/* AF Adjust flag -- Set on carry from or borrow to the low order
+ four bits of AL; cleared otherwise. Used for decimal
+ arithmetic.
+*/
+Bit32u get_AF(void) {
+ Bitu type=lflags.type;
+ switch (type) {
+ case t_UNKNOWN:
+ return GETFLAG(AF);
+ case t_ADDb:
+ case t_ADCb:
+ case t_SBBb:
+ case t_SUBb:
+ case t_CMPb:
+ return ((lf_var1b ^ lf_var2b) ^ lf_resb) & 0x10;
+ case t_ADDw:
+ case t_ADCw:
+ case t_SBBw:
+ case t_SUBw:
+ case t_CMPw:
+ return ((lf_var1w ^ lf_var2w) ^ lf_resw) & 0x10;
+ case t_ADCd:
+ case t_ADDd:
+ case t_SBBd:
+ case t_SUBd:
+ case t_CMPd:
+ return ((lf_var1d ^ lf_var2d) ^ lf_resd) & 0x10;
+ case t_INCb:
+ return (lf_resb & 0x0f) == 0;
+ case t_INCw:
+ return (lf_resw & 0x0f) == 0;
+ case t_INCd:
+ return (lf_resd & 0x0f) == 0;
+ case t_DECb:
+ return (lf_resb & 0x0f) == 0x0f;
+ case t_DECw:
+ return (lf_resw & 0x0f) == 0x0f;
+ case t_DECd:
+ return (lf_resd & 0x0f) == 0x0f;
+ case t_NEGb:
+ return lf_var1b & 0x0f;
+ case t_NEGw:
+ return lf_var1w & 0x0f;
+ case t_NEGd:
+ return lf_var1d & 0x0f;
+ case t_SHLb:
+ case t_SHRb:
+ case t_SARb:
+ return lf_var2b & 0x1f;
+ case t_SHLw:
+ case t_SHRw:
+ case t_SARw:
+ return lf_var2w & 0x1f;
+ case t_SHLd:
+ case t_SHRd:
+ case t_SARd:
+ return lf_var2d & 0x1f;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ case t_DSHLw:
+ case t_DSHLd:
+ case t_DSHRw:
+ case t_DSHRd:
+ case t_DIV:
+ case t_MUL:
+ return false; /* Unkown */
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("get_AF Unknown %d",lflags.type);
+ }
+ return 0;
+}
+
+/* ZF Zero Flag -- Set if result is zero; cleared otherwise.
+*/
+
+Bit32u get_ZF(void) {
+ Bitu type=lflags.type;
+ switch (type) {
+ case t_UNKNOWN:
+ return GETFLAG(ZF);
+ case t_ADDb:
+ case t_ORb:
+ case t_ADCb:
+ case t_SBBb:
+ case t_ANDb:
+ case t_XORb:
+ case t_SUBb:
+ case t_CMPb:
+ case t_INCb:
+ case t_DECb:
+ case t_TESTb:
+ case t_SHLb:
+ case t_SHRb:
+ case t_SARb:
+ case t_NEGb:
+ return (lf_resb==0);
+ case t_ADDw:
+ case t_ORw:
+ case t_ADCw:
+ case t_SBBw:
+ case t_ANDw:
+ case t_XORw:
+ case t_SUBw:
+ case t_CMPw:
+ case t_INCw:
+ case t_DECw:
+ case t_TESTw:
+ case t_SHLw:
+ case t_SHRw:
+ case t_SARw:
+ case t_DSHLw:
+ case t_DSHRw:
+ case t_NEGw:
+ return (lf_resw==0);
+ case t_ADDd:
+ case t_ORd:
+ case t_ADCd:
+ case t_SBBd:
+ case t_ANDd:
+ case t_XORd:
+ case t_SUBd:
+ case t_CMPd:
+ case t_INCd:
+ case t_DECd:
+ case t_TESTd:
+ case t_SHLd:
+ case t_SHRd:
+ case t_SARd:
+ case t_DSHLd:
+ case t_DSHRd:
+ case t_NEGd:
+ return (lf_resd==0);
+ case t_DIV:
+ case t_MUL:
+ return false; /* Unkown */
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("get_ZF Unknown %d",lflags.type);
+ }
+ return false;
+}
+/* SF Sign Flag -- Set equal to high-order bit of result (0 is
+ positive, 1 if negative).
+*/
+Bit32u get_SF(void) {
+ Bitu type=lflags.type;
+ switch (type) {
+ case t_UNKNOWN:
+ return GETFLAG(SF);
+ case t_ADDb:
+ case t_ORb:
+ case t_ADCb:
+ case t_SBBb:
+ case t_ANDb:
+ case t_XORb:
+ case t_SUBb:
+ case t_CMPb:
+ case t_INCb:
+ case t_DECb:
+ case t_TESTb:
+ case t_SHLb:
+ case t_SHRb:
+ case t_SARb:
+ case t_NEGb:
+ return (lf_resb&0x80);
+ case t_ADDw:
+ case t_ORw:
+ case t_ADCw:
+ case t_SBBw:
+ case t_ANDw:
+ case t_XORw:
+ case t_SUBw:
+ case t_CMPw:
+ case t_INCw:
+ case t_DECw:
+ case t_TESTw:
+ case t_SHLw:
+ case t_SHRw:
+ case t_SARw:
+ case t_DSHLw:
+ case t_DSHRw:
+ case t_NEGw:
+ return (lf_resw&0x8000);
+ case t_ADDd:
+ case t_ORd:
+ case t_ADCd:
+ case t_SBBd:
+ case t_ANDd:
+ case t_XORd:
+ case t_SUBd:
+ case t_CMPd:
+ case t_INCd:
+ case t_DECd:
+ case t_TESTd:
+ case t_SHLd:
+ case t_SHRd:
+ case t_SARd:
+ case t_DSHLd:
+ case t_DSHRd:
+ case t_NEGd:
+ return (lf_resd&0x80000000);
+ case t_DIV:
+ case t_MUL:
+ return false; /* Unkown */
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("get_SF Unkown %d",lflags.type);
+ }
+ return false;
+
+}
+Bit32u get_OF(void) {
+ Bitu type=lflags.type;
+ switch (type) {
+ case t_UNKNOWN:
+ case t_MUL:
+ return GETFLAG(OF);
+ case t_ADDb:
+ case t_ADCb:
+ return ((lf_var1b ^ lf_var2b ^ 0x80) & (lf_resb ^ lf_var2b)) & 0x80;
+ case t_ADDw:
+ case t_ADCw:
+ return ((lf_var1w ^ lf_var2w ^ 0x8000) & (lf_resw ^ lf_var2w)) & 0x8000;
+ case t_ADDd:
+ case t_ADCd:
+ return ((lf_var1d ^ lf_var2d ^ 0x80000000) & (lf_resd ^ lf_var2d)) & 0x80000000;
+ case t_SBBb:
+ case t_SUBb:
+ case t_CMPb:
+ return ((lf_var1b ^ lf_var2b) & (lf_var1b ^ lf_resb)) & 0x80;
+ case t_SBBw:
+ case t_SUBw:
+ case t_CMPw:
+ return ((lf_var1w ^ lf_var2w) & (lf_var1w ^ lf_resw)) & 0x8000;
+ case t_SBBd:
+ case t_SUBd:
+ case t_CMPd:
+ return ((lf_var1d ^ lf_var2d) & (lf_var1d ^ lf_resd)) & 0x80000000;
+ case t_INCb:
+ return (lf_resb == 0x80);
+ case t_INCw:
+ return (lf_resw == 0x8000);
+ case t_INCd:
+ return (lf_resd == 0x80000000);
+ case t_DECb:
+ return (lf_resb == 0x7f);
+ case t_DECw:
+ return (lf_resw == 0x7fff);
+ case t_DECd:
+ return (lf_resd == 0x7fffffff);
+ case t_NEGb:
+ return (lf_var1b == 0x80);
+ case t_NEGw:
+ return (lf_var1w == 0x8000);
+ case t_NEGd:
+ return (lf_var1d == 0x80000000);
+ case t_SHLb:
+ return (lf_resb ^ lf_var1b) & 0x80;
+ case t_SHLw:
+ case t_DSHRw:
+ case t_DSHLw:
+ return (lf_resw ^ lf_var1w) & 0x8000;
+ case t_SHLd:
+ case t_DSHRd:
+ case t_DSHLd:
+ return (lf_resd ^ lf_var1d) & 0x80000000;
+ case t_SHRb:
+ if ((lf_var2b&0x1f)==1) return (lf_var1b > 0x80);
+ else return false;
+ case t_SHRw:
+ if ((lf_var2b&0x1f)==1) return (lf_var1w > 0x8000);
+ else return false;
+ case t_SHRd:
+ if ((lf_var2b&0x1f)==1) return (lf_var1d > 0x80000000);
+ else return false;
+ case t_ORb:
+ case t_ORw:
+ case t_ORd:
+ case t_ANDb:
+ case t_ANDw:
+ case t_ANDd:
+ case t_XORb:
+ case t_XORw:
+ case t_XORd:
+ case t_TESTb:
+ case t_TESTw:
+ case t_TESTd:
+ case t_SARb:
+ case t_SARw:
+ case t_SARd:
+ return false; /* Return false */
+ case t_DIV:
+ return false; /* Unkown */
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("get_OF Unkown %d",lflags.type);
+ }
+ return false;
+}
+
+Bit16u parity_lookup[256] = {
+ FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF,
+ 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0,
+ 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0,
+ FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF,
+ 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0,
+ FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF,
+ FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF,
+ 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0,
+ 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0,
+ FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF,
+ FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF,
+ 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0,
+ FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF,
+ 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0,
+ 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0,
+ FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF
+ };
+
+Bit32u get_PF(void) {
+ switch (lflags.type) {
+ case t_UNKNOWN:
+ return GETFLAG(PF);
+ default:
+ return (parity_lookup[lf_resb]);
+ };
+ return 0;
+}
+
+
+#if 0
+
+Bitu FillFlags(void) {
+// if (lflags.type==t_UNKNOWN) return reg_flags;
+ Bitu new_word=(reg_flags & ~FLAG_MASK);
+ if (get_CF()) new_word|=FLAG_CF;
+ if (get_PF()) new_word|=FLAG_PF;
+ if (get_AF()) new_word|=FLAG_AF;
+ if (get_ZF()) new_word|=FLAG_ZF;
+ if (get_SF()) new_word|=FLAG_SF;
+ if (get_OF()) new_word|=FLAG_OF;
+ reg_flags=new_word;
+ lflags.type=t_UNKNOWN;
+ return reg_flags;
+}
+
+#else
+
+#define DOFLAG_PF reg_flags=(reg_flags & ~FLAG_PF) | parity_lookup[lf_resb];
+
+#define DOFLAG_AF reg_flags=(reg_flags & ~FLAG_AF) | (((lf_var1b ^ lf_var2b) ^ lf_resb) & 0x10);
+
+#define DOFLAG_ZFb SETFLAGBIT(ZF,lf_resb==0);
+#define DOFLAG_ZFw SETFLAGBIT(ZF,lf_resw==0);
+#define DOFLAG_ZFd SETFLAGBIT(ZF,lf_resd==0);
+
+#define DOFLAG_SFb reg_flags=(reg_flags & ~FLAG_SF) | ((lf_resb & 0x80) >> 0);
+#define DOFLAG_SFw reg_flags=(reg_flags & ~FLAG_SF) | ((lf_resw & 0x8000) >> 8);
+#define DOFLAG_SFd reg_flags=(reg_flags & ~FLAG_SF) | ((lf_resd & 0x80000000) >> 24);
+
+#define SETCF(NEWBIT) reg_flags=(reg_flags & ~FLAG_CF)|(NEWBIT);
+
+#define SET_FLAG SETFLAGBIT
+
+Bitu FillFlags(void) {
+ switch (lflags.type) {
+ case t_UNKNOWN:
+ break;
+ case t_ADDb:
+ SET_FLAG(CF,(lf_resb<lf_var1b));
+ DOFLAG_AF;
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,((lf_var1b ^ lf_var2b ^ 0x80) & (lf_resb ^ lf_var1b)) & 0x80);
+ DOFLAG_PF;
+ break;
+ case t_ADDw:
+ SET_FLAG(CF,(lf_resw<lf_var1w));
+ DOFLAG_AF;
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,((lf_var1w ^ lf_var2w ^ 0x8000) & (lf_resw ^ lf_var1w)) & 0x8000);
+ DOFLAG_PF;
+ break;
+ case t_ADDd:
+ SET_FLAG(CF,(lf_resd<lf_var1d));
+ DOFLAG_AF;
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,((lf_var1d ^ lf_var2d ^ 0x80000000) & (lf_resd ^ lf_var1d)) & 0x80000000);
+ DOFLAG_PF;
+ break;
+ case t_ADCb:
+ SET_FLAG(CF,(lf_resb < lf_var1b) || (lflags.oldcf && (lf_resb == lf_var1b)));
+ DOFLAG_AF;
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,((lf_var1b ^ lf_var2b ^ 0x80) & (lf_resb ^ lf_var1b)) & 0x80);
+ DOFLAG_PF;
+ break;
+ case t_ADCw:
+ SET_FLAG(CF,(lf_resw < lf_var1w) || (lflags.oldcf && (lf_resw == lf_var1w)));
+ DOFLAG_AF;
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,((lf_var1w ^ lf_var2w ^ 0x8000) & (lf_resw ^ lf_var1w)) & 0x8000);
+ DOFLAG_PF;
+ break;
+ case t_ADCd:
+ SET_FLAG(CF,(lf_resd < lf_var1d) || (lflags.oldcf && (lf_resd == lf_var1d)));
+ DOFLAG_AF;
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,((lf_var1d ^ lf_var2d ^ 0x80000000) & (lf_resd ^ lf_var1d)) & 0x80000000);
+ DOFLAG_PF;
+ break;
+
+
+ case t_SBBb:
+ SET_FLAG(CF,(lf_var1b < lf_resb) || (lflags.oldcf && (lf_var2b==0xff)));
+ DOFLAG_AF;
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,(lf_var1b ^ lf_var2b) & (lf_var1b ^ lf_resb) & 0x80);
+ DOFLAG_PF;
+ break;
+ case t_SBBw:
+ SET_FLAG(CF,(lf_var1w < lf_resw) || (lflags.oldcf && (lf_var2w==0xffff)));
+ DOFLAG_AF;
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,(lf_var1w ^ lf_var2w) & (lf_var1w ^ lf_resw) & 0x8000);
+ DOFLAG_PF;
+ break;
+ case t_SBBd:
+ SET_FLAG(CF,(lf_var1d < lf_resd) || (lflags.oldcf && (lf_var2d==0xffffffff)));
+ DOFLAG_AF;
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,(lf_var1d ^ lf_var2d) & (lf_var1d ^ lf_resd) & 0x80000000);
+ DOFLAG_PF;
+ break;
+
+
+ case t_SUBb:
+ case t_CMPb:
+ SET_FLAG(CF,(lf_var1b<lf_var2b));
+ DOFLAG_AF;
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,(lf_var1b ^ lf_var2b) & (lf_var1b ^ lf_resb) & 0x80);
+ DOFLAG_PF;
+ break;
+ case t_SUBw:
+ case t_CMPw:
+ SET_FLAG(CF,(lf_var1w<lf_var2w));
+ DOFLAG_AF;
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,(lf_var1w ^ lf_var2w) & (lf_var1w ^ lf_resw) & 0x8000);
+ DOFLAG_PF;
+ break;
+ case t_SUBd:
+ case t_CMPd:
+ SET_FLAG(CF,(lf_var1d<lf_var2d));
+ DOFLAG_AF;
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,(lf_var1d ^ lf_var2d) & (lf_var1d ^ lf_resd) & 0x80000000);
+ DOFLAG_PF;
+ break;
+
+
+ case t_ORb:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+ case t_ORw:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+ case t_ORd:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+
+
+ case t_TESTb:
+ case t_ANDb:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+ case t_TESTw:
+ case t_ANDw:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+ case t_TESTd:
+ case t_ANDd:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+
+
+ case t_XORb:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+ case t_XORw:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+ case t_XORd:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+
+
+ case t_SHLb:
+ if (lf_var2b>8) SET_FLAG(CF,false);
+ else SET_FLAG(CF,(lf_var1b >> (8-lf_var2b)) & 1);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,(lf_resb ^ lf_var1b) & 0x80);
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2b&0x1f));
+ break;
+ case t_SHLw:
+ if (lf_var2b>16) SET_FLAG(CF,false);
+ else SET_FLAG(CF,(lf_var1w >> (16-lf_var2b)) & 1);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,(lf_resw ^ lf_var1w) & 0x8000);
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2w&0x1f));
+ break;
+ case t_SHLd:
+ SET_FLAG(CF,(lf_var1d >> (32 - lf_var2b)) & 1);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,(lf_resd ^ lf_var1d) & 0x80000000);
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2d&0x1f));
+ break;
+
+
+ case t_DSHLw:
+ SET_FLAG(CF,(lf_var1d >> (32 - lf_var2b)) & 1);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,(lf_resw ^ lf_var1w) & 0x8000);
+ DOFLAG_PF;
+ break;
+ case t_DSHLd:
+ SET_FLAG(CF,(lf_var1d >> (32 - lf_var2b)) & 1);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,(lf_resd ^ lf_var1d) & 0x80000000);
+ DOFLAG_PF;
+ break;
+
+
+ case t_SHRb:
+ SET_FLAG(CF,(lf_var1b >> (lf_var2b - 1)) & 1);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ if ((lf_var2b&0x1f)==1) SET_FLAG(OF,(lf_var1b >= 0x80));
+ else SET_FLAG(OF,false);
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2b&0x1f));
+ break;
+ case t_SHRw:
+ SET_FLAG(CF,(lf_var1w >> (lf_var2b - 1)) & 1);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ if ((lf_var2w&0x1f)==1) SET_FLAG(OF,(lf_var1w >= 0x8000));
+ else SET_FLAG(OF,false);
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2w&0x1f));
+ break;
+ case t_SHRd:
+ SET_FLAG(CF,(lf_var1d >> (lf_var2b - 1)) & 1);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ if ((lf_var2d&0x1f)==1) SET_FLAG(OF,(lf_var1d >= 0x80000000));
+ else SET_FLAG(OF,false);
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2d&0x1f));
+ break;
+
+
+ case t_DSHRw: /* Hmm this is not correct for shift higher than 16 */
+ SET_FLAG(CF,(lf_var1d >> (lf_var2b - 1)) & 1);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,(lf_resw ^ lf_var1w) & 0x8000);
+ DOFLAG_PF;
+ break;
+ case t_DSHRd:
+ SET_FLAG(CF,(lf_var1d >> (lf_var2b - 1)) & 1);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,(lf_resd ^ lf_var1d) & 0x80000000);
+ DOFLAG_PF;
+ break;
+
+
+ case t_SARb:
+ SET_FLAG(CF,(((Bit8s) lf_var1b) >> (lf_var2b - 1)) & 1);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2b&0x1f));
+ break;
+ case t_SARw:
+ SET_FLAG(CF,(((Bit16s) lf_var1w) >> (lf_var2b - 1)) & 1);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2w&0x1f));
+ break;
+ case t_SARd:
+ SET_FLAG(CF,(((Bit32s) lf_var1d) >> (lf_var2b - 1)) & 1);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2d&0x1f));
+ break;
+
+ case t_INCb:
+ SET_FLAG(AF,(lf_resb & 0x0f) == 0);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,(lf_resb == 0x80));
+ DOFLAG_PF;
+ break;
+ case t_INCw:
+ SET_FLAG(AF,(lf_resw & 0x0f) == 0);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,(lf_resw == 0x8000));
+ DOFLAG_PF;
+ break;
+ case t_INCd:
+ SET_FLAG(AF,(lf_resd & 0x0f) == 0);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,(lf_resd == 0x80000000));
+ DOFLAG_PF;
+ break;
+
+ case t_DECb:
+ SET_FLAG(AF,(lf_resb & 0x0f) == 0x0f);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,(lf_resb == 0x7f));
+ DOFLAG_PF;
+ break;
+ case t_DECw:
+ SET_FLAG(AF,(lf_resw & 0x0f) == 0x0f);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,(lf_resw == 0x7fff));
+ DOFLAG_PF;
+ break;
+ case t_DECd:
+ SET_FLAG(AF,(lf_resd & 0x0f) == 0x0f);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,(lf_resd == 0x7fffffff));
+ DOFLAG_PF;
+ break;
+
+ case t_NEGb:
+ SET_FLAG(CF,(lf_var1b!=0));
+ SET_FLAG(AF,(lf_resb & 0x0f) != 0);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,(lf_var1b == 0x80));
+ DOFLAG_PF;
+ break;
+ case t_NEGw:
+ SET_FLAG(CF,(lf_var1w!=0));
+ SET_FLAG(AF,(lf_resw & 0x0f) != 0);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,(lf_var1w == 0x8000));
+ DOFLAG_PF;
+ break;
+ case t_NEGd:
+ SET_FLAG(CF,(lf_var1d!=0));
+ SET_FLAG(AF,(lf_resd & 0x0f) != 0);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,(lf_var1d == 0x80000000));
+ DOFLAG_PF;
+ break;
+
+
+ case t_DIV:
+ case t_MUL:
+ break;
+
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled flag type %d",lflags.type);
+ return 0;
+ }
+ lflags.type=t_UNKNOWN;
+ return reg_flags;
+}
+
+void FillFlagsNoCFOF(void) {
+ switch (lflags.type) {
+ case t_UNKNOWN:
+ return;
+ case t_ADDb:
+ DOFLAG_AF;
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ break;
+ case t_ADDw:
+ DOFLAG_AF;
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ break;
+ case t_ADDd:
+ DOFLAG_AF;
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ break;
+ case t_ADCb:
+ DOFLAG_AF;
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ break;
+ case t_ADCw:
+ DOFLAG_AF;
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ break;
+ case t_ADCd:
+ DOFLAG_AF;
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ break;
+
+
+ case t_SBBb:
+ DOFLAG_AF;
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ break;
+ case t_SBBw:
+ DOFLAG_AF;
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ break;
+ case t_SBBd:
+ DOFLAG_AF;
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ break;
+
+
+ case t_SUBb:
+ case t_CMPb:
+ DOFLAG_AF;
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ break;
+ case t_SUBw:
+ case t_CMPw:
+ DOFLAG_AF;
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ break;
+ case t_SUBd:
+ case t_CMPd:
+ DOFLAG_AF;
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ break;
+
+
+ case t_ORb:
+ SET_FLAG(AF,false);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ break;
+ case t_ORw:
+ SET_FLAG(AF,false);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ break;
+ case t_ORd:
+ SET_FLAG(AF,false);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ break;
+
+
+ case t_TESTb:
+ case t_ANDb:
+ SET_FLAG(AF,false);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ break;
+ case t_TESTw:
+ case t_ANDw:
+ SET_FLAG(AF,false);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ break;
+ case t_TESTd:
+ case t_ANDd:
+ SET_FLAG(AF,false);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ break;
+
+
+ case t_XORb:
+ SET_FLAG(AF,false);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ break;
+ case t_XORw:
+ SET_FLAG(AF,false);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ break;
+ case t_XORd:
+ SET_FLAG(AF,false);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ break;
+
+
+ case t_SHLb:
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2b&0x1f));
+ break;
+ case t_SHLw:
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2w&0x1f));
+ break;
+ case t_SHLd:
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2d&0x1f));
+ break;
+
+
+ case t_DSHLw:
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ break;
+ case t_DSHLd:
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ break;
+
+
+ case t_SHRb:
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2b&0x1f));
+ break;
+ case t_SHRw:
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2w&0x1f));
+ break;
+ case t_SHRd:
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2d&0x1f));
+ break;
+
+
+ case t_DSHRw: /* Hmm this is not correct for shift higher than 16 */
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ break;
+ case t_DSHRd:
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ break;
+
+
+ case t_SARb:
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2b&0x1f));
+ break;
+ case t_SARw:
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2w&0x1f));
+ break;
+ case t_SARd:
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ SET_FLAG(AF,(lf_var2d&0x1f));
+ break;
+
+ case t_INCb:
+ SET_FLAG(AF,(lf_resb & 0x0f) == 0);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ break;
+ case t_INCw:
+ SET_FLAG(AF,(lf_resw & 0x0f) == 0);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ break;
+ case t_INCd:
+ SET_FLAG(AF,(lf_resd & 0x0f) == 0);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ break;
+
+ case t_DECb:
+ SET_FLAG(AF,(lf_resb & 0x0f) == 0x0f);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ break;
+ case t_DECw:
+ SET_FLAG(AF,(lf_resw & 0x0f) == 0x0f);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ break;
+ case t_DECd:
+ SET_FLAG(AF,(lf_resd & 0x0f) == 0x0f);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ break;
+
+ case t_NEGb:
+ SET_FLAG(AF,(lf_resb & 0x0f) != 0);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ DOFLAG_PF;
+ break;
+ case t_NEGw:
+ SET_FLAG(AF,(lf_resw & 0x0f) != 0);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ DOFLAG_PF;
+ break;
+ case t_NEGd:
+ SET_FLAG(AF,(lf_resd & 0x0f) != 0);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ DOFLAG_PF;
+ break;
+
+
+ case t_DIV:
+ case t_MUL:
+ break;
+
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled flag type %d",lflags.type);
+ break;
+ }
+ lflags.type=t_UNKNOWN;
+}
+
+void DestroyConditionFlags(void) {
+ lflags.type=t_UNKNOWN;
+}
+
+#endif
--- /dev/null
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# include/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/dosbox
+pkgincludedir = $(includedir)/dosbox
+pkglibdir = $(libdir)/dosbox
+pkglibexecdir = $(libexecdir)/dosbox
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = x86_64-pc-linux-gnu
+host_triplet = x86_64-pc-linux-gnu
+subdir = include
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_$(V))
+am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY))
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = aclocal-1.16
+ALSA_CFLAGS =
+ALSA_LIBS = -lasound -lm -ldl -lpthread
+AMTAR = $${TAR-tar}
+AM_DEFAULT_VERBOSITY = 1
+AUTOCONF = autoconf
+AUTOHEADER = autoheader
+AUTOMAKE = automake-1.16
+AWK = gawk
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS = -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
+CXX = g++
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+ECHO_C =
+ECHO_N = -n
+ECHO_T =
+EGREP = /bin/grep -E
+EXEEXT =
+GREP = /bin/grep
+INSTALL = /usr/bin/install -c
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = $(install_sh) -c -s
+LDFLAGS =
+LIBOBJS =
+LIBS = -lasound -lm -ldl -lpthread -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL -lXfont2 -lXi -lpng -lz -lX11 -lGL
+LTLIBOBJS =
+MAKEINFO = makeinfo
+MKDIR_P = /bin/mkdir -p
+OBJEXT = o
+PACKAGE = dosbox
+PACKAGE_BUGREPORT =
+PACKAGE_NAME = dosbox
+PACKAGE_STRING = dosbox 0.74
+PACKAGE_TARNAME = dosbox
+PACKAGE_URL =
+PACKAGE_VERSION = 0.74
+PATH_SEPARATOR = :
+RANLIB = ranlib
+SDL_CFLAGS = -I/usr/local/include/SDL -D_GNU_SOURCE=1 -D_REENTRANT
+SDL_CONFIG = /usr/local/bin/sdl-config
+SDL_LIBS = -L/usr/local/lib -Wl,-rpath,/usr/local/lib -lSDL -lXfont2 -lXi -lpthread
+SET_MAKE =
+SHELL = /bin/bash
+STRIP =
+VERSION = 0.74
+WINDRES = :
+abs_builddir = /home/whatisthis/src/DOSVAXJ3/include
+abs_srcdir = /home/whatisthis/src/DOSVAXJ3/include
+abs_top_builddir = /home/whatisthis/src/DOSVAXJ3
+abs_top_srcdir = /home/whatisthis/src/DOSVAXJ3
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = $${TAR-tar} chof - "$$tardir"
+am__untar = $${TAR-tar} xf -
+bindir = ${exec_prefix}/bin
+build = x86_64-pc-linux-gnu
+build_alias =
+build_cpu = x86_64
+build_os = linux-gnu
+build_vendor = pc
+builddir = .
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = x86_64-pc-linux-gnu
+host_alias =
+host_cpu = x86_64
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = ${SHELL} /home/whatisthis/src/DOSVAXJ3/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${datarootdir}/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = $(MKDIR_P)
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+runstatedir = ${localstatedir}/run
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+srcdir = .
+sysconfdir = ${prefix}/etc
+target_alias =
+top_build_prefix = ../
+top_builddir = ..
+top_srcdir = ..
+noinst_HEADERS = \
+bios.h \
+bios_disk.h \
+callback.h \
+cpu.h \
+cross.h \
+control.h \
+debug.h \
+dma.h \
+dos_inc.h \
+dos_system.h \
+dosbox.h \
+dosv.h \
+fpu.h \
+hardware.h \
+inout.h \
+ipx.h \
+ipxserver.h \
+j3.h \
+jega.h \
+jfont.h \
+joystick.h \
+keyboard.h \
+logging.h \
+mapper.h \
+mem.h \
+midi.h \
+mixer.h \
+modules.h \
+mouse.h \
+paging.h \
+pci_bus.h \
+pic.h \
+programs.h \
+render.h \
+regs.h \
+render.h \
+serialport.h \
+setup.h \
+shell.h \
+support.h \
+timer.h \
+vga.h \
+video.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu include/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+noinst_HEADERS = \
+bios.h \
+bios_disk.h \
+callback.h \
+cpu.h \
+cross.h \
+control.h \
+debug.h \
+dma.h \
+dos_inc.h \
+dos_system.h \
+dosbox.h \
+dosv.h \
+fpu.h \
+hardware.h \
+inout.h \
+ipx.h \
+ipxserver.h \
+j3.h \
+jega.h \
+jfont.h \
+joystick.h \
+keyboard.h \
+logging.h \
+mapper.h \
+mem.h \
+midi.h \
+mixer.h \
+modules.h \
+mouse.h \
+paging.h \
+pci_bus.h \
+pic.h \
+programs.h \
+render.h \
+regs.h \
+render.h \
+serialport.h \
+setup.h \
+shell.h \
+support.h \
+timer.h \
+vga.h \
+video.h
+
--- /dev/null
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_CONFIG = @SDL_CONFIG@
+SDL_LIBS = @SDL_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WINDRES = @WINDRES@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_HEADERS = \
+bios.h \
+bios_disk.h \
+callback.h \
+cpu.h \
+cross.h \
+control.h \
+debug.h \
+dma.h \
+dos_inc.h \
+dos_system.h \
+dosbox.h \
+dosv.h \
+fpu.h \
+hardware.h \
+inout.h \
+ipx.h \
+ipxserver.h \
+j3.h \
+jega.h \
+jfont.h \
+joystick.h \
+keyboard.h \
+logging.h \
+mapper.h \
+mem.h \
+midi.h \
+mixer.h \
+modules.h \
+mouse.h \
+paging.h \
+pci_bus.h \
+pic.h \
+programs.h \
+render.h \
+regs.h \
+render.h \
+serialport.h \
+setup.h \
+shell.h \
+support.h \
+timer.h \
+vga.h \
+video.h
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu include/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ cscopelist-am ctags ctags-am distclean distclean-generic \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_BIOS_H
+#define DOSBOX_BIOS_H
+
+#define BIOS_BASE_ADDRESS_COM1 0x400
+#define BIOS_BASE_ADDRESS_COM2 0x402
+#define BIOS_BASE_ADDRESS_COM3 0x404
+#define BIOS_BASE_ADDRESS_COM4 0x406
+#define BIOS_ADDRESS_LPT1 0x408
+#define BIOS_ADDRESS_LPT2 0x40a
+#define BIOS_ADDRESS_LPT3 0x40c
+/* 0x40e is reserved */
+#define BIOS_CONFIGURATION 0x410
+/* 0x412 is reserved */
+#define BIOS_MEMORY_SIZE 0x413
+#define BIOS_TRUE_MEMORY_SIZE 0x415
+/* #define bios_expansion_memory_size (*(unsigned int *) 0x415) */
+#define BIOS_KEYBOARD_STATE 0x417
+#define BIOS_KEYBOARD_FLAGS1 BIOS_KEYBOARD_STATE
+#define BIOS_KEYBOARD_FLAGS2 0x418
+#define BIOS_KEYBOARD_TOKEN 0x419
+/* used for keyboard input with Alt-Number */
+#define BIOS_KEYBOARD_BUFFER_HEAD 0x41a
+#define BIOS_KEYBOARD_BUFFER_TAIL 0x41c
+#define BIOS_KEYBOARD_BUFFER 0x41e
+/* #define bios_keyboard_buffer (*(unsigned int *) 0x41e) */
+#define BIOS_DRIVE_ACTIVE 0x43e
+#define BIOS_DRIVE_RUNNING 0x43f
+#define BIOS_DISK_MOTOR_TIMEOUT 0x440
+#define BIOS_DISK_STATUS 0x441
+/* #define bios_fdc_result_buffer (*(unsigned short *) 0x442) */
+#define BIOS_VIDEO_MODE 0x449
+#define BIOS_SCREEN_COLUMNS 0x44a
+#define BIOS_VIDEO_MEMORY_USED 0x44c
+#define BIOS_VIDEO_MEMORY_ADDRESS 0x44e
+#define BIOS_VIDEO_CURSOR_POS 0x450
+
+
+#define BIOS_CURSOR_SHAPE 0x460
+#define BIOS_CURSOR_LAST_LINE 0x460
+#define BIOS_CURSOR_FIRST_LINE 0x461
+#define BIOS_CURRENT_SCREEN_PAGE 0x462
+#define BIOS_VIDEO_PORT 0x463
+#define BIOS_VDU_CONTROL 0x465
+#define BIOS_VDU_COLOR_REGISTER 0x466
+/* 0x467-0x468 is reserved */
+#define BIOS_LAST_UNEXPECTED_IRQ 0x46b
+#define BIOS_TIMER 0x46c
+#define BIOS_24_HOURS_FLAG 0x470
+#define BIOS_KEYBOARD_FLAGS 0x471
+#define BIOS_CTRL_ALT_DEL_FLAG 0x472
+#define BIOS_HARDDISK_COUNT 0x475
+/* 0x474, 0x476, 0x477 is reserved */
+#define BIOS_LPT1_TIMEOUT 0x478
+#define BIOS_LPT2_TIMEOUT 0x479
+#define BIOS_LPT3_TIMEOUT 0x47a
+/* 0x47b is reserved */
+#define BIOS_COM1_TIMEOUT 0x47c
+#define BIOS_COM2_TIMEOUT 0x47d
+#define BIOS_COM3_TIMEOUT 0x47e
+#define BIOS_COM4_TIMEOUT 0x47f
+/* 0x47e is reserved */ //<- why that?
+/* 0x47f-0x4ff is unknow for me */
+#define BIOS_KEYBOARD_BUFFER_START 0x480
+#define BIOS_KEYBOARD_BUFFER_END 0x482
+
+#define BIOS_ROWS_ON_SCREEN_MINUS_1 0x484
+#define BIOS_FONT_HEIGHT 0x485
+
+#define BIOS_VIDEO_INFO_0 0x487
+#define BIOS_VIDEO_INFO_1 0x488
+#define BIOS_VIDEO_INFO_2 0x489
+#define BIOS_VIDEO_COMBO 0x48a
+
+#define BIOS_KEYBOARD_FLAGS3 0x496
+#define BIOS_KEYBOARD_LEDS 0x497
+
+#define BIOS_WAIT_FLAG_POINTER 0x498
+#define BIOS_WAIT_FLAG_COUNT 0x49c
+#define BIOS_WAIT_FLAG_ACTIVE 0x4a0
+#define BIOS_WAIT_FLAG_TEMP 0x4a1
+
+
+#define BIOS_PRINT_SCREEN_FLAG 0x500
+
+#define BIOS_VIDEO_SAVEPTR 0x4a8
+
+
+#define BIOS_DEFAULT_HANDLER_LOCATION (RealMake(0xf000,0xff53))
+#define BIOS_DEFAULT_INT5_LOCATION (RealMake(0xf000,0xff54))
+#define BIOS_DEFAULT_IRQ0_LOCATION (RealMake(0xf000,0xfea5))
+#define BIOS_DEFAULT_IRQ1_LOCATION (RealMake(0xf000,0xe987))
+#define BIOS_DEFAULT_IRQ2_LOCATION (RealMake(0xf000,0xff55))
+#define BIOS_DEFAULT_RESET_LOCATION (RealMake(0xf000,0xe05b))
+
+/* maximum of scancodes handled by keyboard bios routines */
+//#define MAX_SCAN_CODE 0x7f
+#define MAX_SCAN_CODE 0x93
+
+/* The Section handling Bios Disk Access */
+//#define BIOS_MAX_DISK 10
+
+//#define MAX_SWAPPABLE_DISKS 20
+
+void BIOS_ZeroExtendedSize(bool in);
+void char_out(Bit8u chr,Bit32u att,Bit8u page);
+void INT10_StartUp(void);
+void INT16_StartUp(void);
+void INT2A_StartUp(void);
+void INT2F_StartUp(void);
+void INT33_StartUp(void);
+void INT13_StartUp(void);
+
+bool BIOS_AddKeyToBuffer(Bit16u code);
+
+void INT10_ReloadRomFonts();
+
+void BIOS_SetComPorts (Bit16u baseaddr[]);
+void BIOS_SetLPTPort (Bitu port, Bit16u baseaddr);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_BIOS_DISK_H
+#define DOSBOX_BIOS_DISK_H
+
+#include <stdio.h>
+#ifndef DOSBOX_MEM_H
+#include "mem.h"
+#endif
+#ifndef DOSBOX_DOS_INC_H
+#include "dos_inc.h"
+#endif
+#ifndef DOSBOX_BIOS_H
+#include "bios.h"
+#endif
+
+/* The Section handling Bios Disk Access */
+#define BIOS_MAX_DISK 10
+
+#define MAX_SWAPPABLE_DISKS 20
+struct diskGeo {
+ Bit32u ksize; /* Size in kilobytes */
+ Bit16u secttrack; /* Sectors per track */
+ Bit16u headscyl; /* Heads per cylinder */
+ Bit16u cylcount; /* Cylinders per side */
+ Bit16u biosval; /* Type to return from BIOS */
+};
+extern diskGeo DiskGeometryList[];
+
+class imageDisk {
+public:
+ Bit8u Read_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,void * data);
+ Bit8u Write_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,void * data);
+ Bit8u Read_AbsoluteSector(Bit32u sectnum, void * data);
+ Bit8u Write_AbsoluteSector(Bit32u sectnum, void * data);
+
+ void Set_Geometry(Bit32u setHeads, Bit32u setCyl, Bit32u setSect, Bit32u setSectSize);
+ void Get_Geometry(Bit32u * getHeads, Bit32u *getCyl, Bit32u *getSect, Bit32u *getSectSize);
+ Bit8u GetBiosType(void);
+ Bit32u getSectSize(void);
+ imageDisk(FILE *imgFile, Bit8u *imgName, Bit32u imgSizeK, bool isHardDisk);
+ ~imageDisk() { if(diskimg != NULL) { fclose(diskimg); } };
+
+ bool hardDrive;
+ bool active;
+ FILE *diskimg;
+ Bit8u diskname[512];
+ Bit8u floppytype;
+
+ Bit32u sector_size;
+ Bit32u heads,cylinders,sectors;
+private:
+ Bit32u current_fpos;
+ enum { NONE,READ,WRITE } last_action;
+};
+
+void updateDPT(void);
+void incrementFDD(void);
+
+#define MAX_HDD_IMAGES 2
+
+extern imageDisk *imageDiskList[2 + MAX_HDD_IMAGES];
+extern imageDisk *diskSwap[20];
+extern Bit32s swapPosition;
+extern Bit16u imgDTASeg; /* Real memory location of temporary DTA pointer for fat image disk access */
+extern RealPt imgDTAPtr; /* Real memory location of temporary DTA pointer for fat image disk access */
+extern DOS_DTA *imgDTA;
+
+void swapInDisks(void);
+void swapInNextDisk(void);
+bool getSwapRequest(void);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_CALLBACK_H
+#define DOSBOX_CALLBACK_H
+
+#ifndef DOSBOX_MEM_H
+#include "mem.h"
+#endif
+
+typedef Bitu (*CallBack_Handler)(void);
+extern CallBack_Handler CallBack_Handlers[];
+
+enum { CB_RETN,CB_RETF,CB_RETF8,CB_IRET,CB_IRETD,CB_IRET_STI,CB_IRET_EOI_PIC1,
+ CB_IRQ0,CB_IRQ1,CB_IRQ9,CB_IRQ12,CB_IRQ12_RET,CB_IRQ6_PCJR,CB_MOUSE,
+ CB_INT29,CB_INT16,CB_HOOKABLE,CB_TDE_IRET,CB_IPXESR,CB_IPXESR_RET,
+ CB_INT21,CB_INT13,
+ CB_INT6F_ATOK };
+
+#define CB_MAX 128
+#define CB_SIZE 32
+#define CB_SEG 0xF000
+#define CB_SOFFSET 0x1000
+
+enum {
+ CBRET_NONE=0,CBRET_STOP=1
+};
+
+extern Bit8u lastint;
+
+static INLINE RealPt CALLBACK_RealPointer(Bitu callback) {
+ return RealMake(CB_SEG,(Bit16u)(CB_SOFFSET+callback*CB_SIZE));
+}
+
+static INLINE PhysPt CALLBACK_PhysPointer(Bitu callback) {
+ return PhysMake(CB_SEG,(Bit16u)(CB_SOFFSET+callback*CB_SIZE));
+}
+
+static INLINE PhysPt CALLBACK_GetBase(void) {
+ return (CB_SEG << 4) + CB_SOFFSET;
+}
+
+Bitu CALLBACK_Allocate();
+
+void CALLBACK_Idle(void);
+
+
+void CALLBACK_RunRealInt(Bit8u intnum);
+void CALLBACK_RunRealFar(Bit16u seg,Bit16u off);
+
+bool CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type,const char* descr);
+Bitu CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type,PhysPt addr,const char* descr);
+
+const char* CALLBACK_GetDescription(Bitu callback);
+bool CALLBACK_Free(Bitu callback);
+
+void CALLBACK_SCF(bool val);
+void CALLBACK_SZF(bool val);
+void CALLBACK_SIF(bool val);
+
+extern Bitu call_priv_io;
+
+
+class CALLBACK_HandlerObject{
+private:
+ bool installed;
+ Bitu m_callback;
+ enum {NONE,SETUP,SETUPAT} m_type;
+ struct {
+ RealPt old_vector;
+ Bit8u interrupt;
+ bool installed;
+ } vectorhandler;
+public:
+ CALLBACK_HandlerObject():installed(false),m_type(NONE) {
+ vectorhandler.installed=false;
+ }
+ ~CALLBACK_HandlerObject();
+
+ //Install and allocate a callback.
+ void Install(CallBack_Handler handler,Bitu type,const char* description);
+ void Install(CallBack_Handler handler,Bitu type,PhysPt addr,const char* description);
+
+ void Uninstall();
+
+ //Only allocate a callback number
+ void Allocate(CallBack_Handler handler,const char* description=0);
+ Bit16u Get_callback() {
+ return (Bit16u)m_callback;
+ }
+ RealPt Get_RealPointer() {
+ return CALLBACK_RealPointer(m_callback);
+ }
+ void Set_RealVec(Bit8u vec);
+};
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_CONTROL_H
+#define DOSBOX_CONTROL_H
+
+#ifdef _MSC_VER
+#pragma warning ( disable : 4786 )
+#pragma warning ( disable : 4290 )
+#endif
+
+#ifndef DOSBOX_PROGRAMS_H
+#include "programs.h"
+#endif
+#ifndef DOSBOX_SETUP_H
+#include "setup.h"
+#endif
+
+#ifndef CH_LIST
+#define CH_LIST
+#include <list>
+#endif
+
+#ifndef CH_VECTOR
+#define CH_VECTOR
+#include <vector>
+#endif
+
+#ifndef CH_STRING
+#define CH_STRING
+#include <string>
+#endif
+
+
+
+
+class Config{
+public:
+ CommandLine * cmdline;
+private:
+ std::list<Section*> sectionlist;
+ typedef std::list<Section*>::iterator it;
+ typedef std::list<Section*>::reverse_iterator reverse_it;
+ typedef std::list<Section*>::const_iterator const_it;
+ typedef std::list<Section*>::const_reverse_iterator const_reverse_it;
+ void (* _start_function)(void);
+ bool secure_mode; //Sandbox mode
+public:
+ bool initialised;
+ std::vector<std::string> startup_params;
+ std::vector<std::string> configfiles;
+ Config(CommandLine * cmd):cmdline(cmd),secure_mode(false) {
+ startup_params.push_back(cmdline->GetFileName());
+ cmdline->FillVector(startup_params);
+ initialised=false;
+ }
+ ~Config();
+
+ Section_line * AddSection_line(char const * const _name,void (*_initfunction)(Section*));
+ Section_prop * AddSection_prop(char const * const _name,void (*_initfunction)(Section*),bool canchange=false);
+
+ Section* GetSection(int index);
+ Section* GetSection(std::string const&_sectionname) const;
+ Section* GetSectionFromProperty(char const * const prop) const;
+
+ void SetStartUp(void (*_function)(void));
+ void Init();
+ void ShutDown();
+ void StartUp();
+ bool PrintConfig(char const * const configfilename) const;
+ bool ParseConfigFile(char const * const configfilename);
+ void ParseEnv(char ** envp);
+ bool SecureMode() const { return secure_mode; }
+ void SwitchToSecureMode() { secure_mode = true; }//can't be undone
+};
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_CPU_H
+#define DOSBOX_CPU_H
+
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+#ifndef DOSBOX_REGS_H
+#include "regs.h"
+#endif
+#ifndef DOSBOX_MEM_H
+#include "mem.h"
+#endif
+
+#define CPU_AUTODETERMINE_NONE 0x00
+#define CPU_AUTODETERMINE_CORE 0x01
+#define CPU_AUTODETERMINE_CYCLES 0x02
+
+#define CPU_AUTODETERMINE_SHIFT 0x02
+#define CPU_AUTODETERMINE_MASK 0x03
+
+#define CPU_CYCLES_LOWER_LIMIT 200
+
+
+#define CPU_ARCHTYPE_MIXED 0xff
+#define CPU_ARCHTYPE_386SLOW 0x30
+#define CPU_ARCHTYPE_386FAST 0x35
+#define CPU_ARCHTYPE_486OLDSLOW 0x40
+#define CPU_ARCHTYPE_486NEWSLOW 0x45
+#define CPU_ARCHTYPE_PENTIUMSLOW 0x50
+
+/* CPU Cycle Timing */
+extern Bit32s CPU_Cycles;
+extern Bit32s CPU_CycleLeft;
+extern Bit32s CPU_CycleMax;
+extern Bit32s CPU_OldCycleMax;
+extern Bit32s CPU_CyclePercUsed;
+extern Bit32s CPU_CycleLimit;
+extern Bit64s CPU_IODelayRemoved;
+extern bool CPU_CycleAutoAdjust;
+extern bool CPU_SkipCycleAutoAdjust;
+extern Bitu CPU_AutoDetermineMode;
+
+extern Bitu CPU_ArchitectureType;
+
+extern Bitu CPU_PrefetchQueueSize;
+
+/* Some common Defines */
+/* A CPU Handler */
+typedef Bits (CPU_Decoder)(void);
+extern CPU_Decoder * cpudecoder;
+
+Bits CPU_Core_Normal_Run(void);
+Bits CPU_Core_Normal_Trap_Run(void);
+Bits CPU_Core_Simple_Run(void);
+Bits CPU_Core_Full_Run(void);
+Bits CPU_Core_Dyn_X86_Run(void);
+Bits CPU_Core_Dyn_X86_Trap_Run(void);
+Bits CPU_Core_Dynrec_Run(void);
+Bits CPU_Core_Dynrec_Trap_Run(void);
+Bits CPU_Core_Prefetch_Run(void);
+Bits CPU_Core_Prefetch_Trap_Run(void);
+
+void CPU_Enable_SkipAutoAdjust(void);
+void CPU_Disable_SkipAutoAdjust(void);
+void CPU_Reset_AutoAdjust(void);
+
+
+//CPU Stuff
+
+extern Bit16u parity_lookup[256];
+
+bool CPU_LLDT(Bitu selector);
+bool CPU_LTR(Bitu selector);
+void CPU_LIDT(Bitu limit,Bitu base);
+void CPU_LGDT(Bitu limit,Bitu base);
+
+Bitu CPU_STR(void);
+Bitu CPU_SLDT(void);
+Bitu CPU_SIDT_base(void);
+Bitu CPU_SIDT_limit(void);
+Bitu CPU_SGDT_base(void);
+Bitu CPU_SGDT_limit(void);
+
+void CPU_ARPL(Bitu & dest_sel,Bitu src_sel);
+void CPU_LAR(Bitu selector,Bitu & ar);
+void CPU_LSL(Bitu selector,Bitu & limit);
+
+void CPU_SET_CRX(Bitu cr,Bitu value);
+bool CPU_WRITE_CRX(Bitu cr,Bitu value);
+Bitu CPU_GET_CRX(Bitu cr);
+bool CPU_READ_CRX(Bitu cr,Bit32u & retvalue);
+
+bool CPU_WRITE_DRX(Bitu dr,Bitu value);
+bool CPU_READ_DRX(Bitu dr,Bit32u & retvalue);
+
+bool CPU_WRITE_TRX(Bitu dr,Bitu value);
+bool CPU_READ_TRX(Bitu dr,Bit32u & retvalue);
+
+Bitu CPU_SMSW(void);
+bool CPU_LMSW(Bitu word);
+
+void CPU_VERR(Bitu selector);
+void CPU_VERW(Bitu selector);
+
+void CPU_JMP(bool use32,Bitu selector,Bitu offset,Bitu oldeip);
+void CPU_CALL(bool use32,Bitu selector,Bitu offset,Bitu oldeip);
+void CPU_RET(bool use32,Bitu bytes,Bitu oldeip);
+void CPU_IRET(bool use32,Bitu oldeip);
+void CPU_HLT(Bitu oldeip);
+
+bool CPU_POPF(Bitu use32);
+bool CPU_PUSHF(Bitu use32);
+bool CPU_CLI(void);
+bool CPU_STI(void);
+
+bool CPU_IO_Exception(Bitu port,Bitu size);
+void CPU_RunException(void);
+
+void CPU_ENTER(bool use32,Bitu bytes,Bitu level);
+
+#define CPU_INT_SOFTWARE 0x1
+#define CPU_INT_EXCEPTION 0x2
+#define CPU_INT_HAS_ERROR 0x4
+#define CPU_INT_NOIOPLCHECK 0x8
+
+void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip);
+static INLINE void CPU_HW_Interrupt(Bitu num) {
+ CPU_Interrupt(num,0,reg_eip);
+}
+static INLINE void CPU_SW_Interrupt(Bitu num,Bitu oldeip) {
+ CPU_Interrupt(num,CPU_INT_SOFTWARE,oldeip);
+}
+static INLINE void CPU_SW_Interrupt_NoIOPLCheck(Bitu num,Bitu oldeip) {
+ CPU_Interrupt(num,CPU_INT_SOFTWARE|CPU_INT_NOIOPLCHECK,oldeip);
+}
+
+bool CPU_PrepareException(Bitu which,Bitu error);
+void CPU_Exception(Bitu which,Bitu error=0);
+
+bool CPU_SetSegGeneral(SegNames seg,Bitu value);
+bool CPU_PopSeg(SegNames seg,bool use32);
+
+bool CPU_CPUID(void);
+Bitu CPU_Pop16(void);
+Bitu CPU_Pop32(void);
+void CPU_Push16(Bitu value);
+void CPU_Push32(Bitu value);
+
+void CPU_SetFlags(Bitu word,Bitu mask);
+
+
+#define EXCEPTION_UD 6
+#define EXCEPTION_TS 10
+#define EXCEPTION_NP 11
+#define EXCEPTION_SS 12
+#define EXCEPTION_GP 13
+#define EXCEPTION_PF 14
+
+#define CR0_PROTECTION 0x00000001
+#define CR0_MONITORPROCESSOR 0x00000002
+#define CR0_FPUEMULATION 0x00000004
+#define CR0_TASKSWITCH 0x00000008
+#define CR0_FPUPRESENT 0x00000010
+#define CR0_PAGING 0x80000000
+
+
+// *********************************************************************
+// Descriptor
+// *********************************************************************
+
+#define DESC_INVALID 0x00
+#define DESC_286_TSS_A 0x01
+#define DESC_LDT 0x02
+#define DESC_286_TSS_B 0x03
+#define DESC_286_CALL_GATE 0x04
+#define DESC_TASK_GATE 0x05
+#define DESC_286_INT_GATE 0x06
+#define DESC_286_TRAP_GATE 0x07
+
+#define DESC_386_TSS_A 0x09
+#define DESC_386_TSS_B 0x0b
+#define DESC_386_CALL_GATE 0x0c
+#define DESC_386_INT_GATE 0x0e
+#define DESC_386_TRAP_GATE 0x0f
+
+/* EU/ED Expand UP/DOWN RO/RW Read Only/Read Write NA/A Accessed */
+#define DESC_DATA_EU_RO_NA 0x10
+#define DESC_DATA_EU_RO_A 0x11
+#define DESC_DATA_EU_RW_NA 0x12
+#define DESC_DATA_EU_RW_A 0x13
+#define DESC_DATA_ED_RO_NA 0x14
+#define DESC_DATA_ED_RO_A 0x15
+#define DESC_DATA_ED_RW_NA 0x16
+#define DESC_DATA_ED_RW_A 0x17
+
+/* N/R Readable NC/C Confirming A/NA Accessed */
+#define DESC_CODE_N_NC_A 0x18
+#define DESC_CODE_N_NC_NA 0x19
+#define DESC_CODE_R_NC_A 0x1a
+#define DESC_CODE_R_NC_NA 0x1b
+#define DESC_CODE_N_C_A 0x1c
+#define DESC_CODE_N_C_NA 0x1d
+#define DESC_CODE_R_C_A 0x1e
+#define DESC_CODE_R_C_NA 0x1f
+
+#ifdef _MSC_VER
+#pragma pack (1)
+#endif
+
+struct S_Descriptor {
+#ifdef WORDS_BIGENDIAN
+ Bit32u base_0_15 :16;
+ Bit32u limit_0_15 :16;
+ Bit32u base_24_31 :8;
+ Bit32u g :1;
+ Bit32u big :1;
+ Bit32u r :1;
+ Bit32u avl :1;
+ Bit32u limit_16_19 :4;
+ Bit32u p :1;
+ Bit32u dpl :2;
+ Bit32u type :5;
+ Bit32u base_16_23 :8;
+#else
+ Bit32u limit_0_15 :16;
+ Bit32u base_0_15 :16;
+ Bit32u base_16_23 :8;
+ Bit32u type :5;
+ Bit32u dpl :2;
+ Bit32u p :1;
+ Bit32u limit_16_19 :4;
+ Bit32u avl :1;
+ Bit32u r :1;
+ Bit32u big :1;
+ Bit32u g :1;
+ Bit32u base_24_31 :8;
+#endif
+}GCC_ATTRIBUTE(packed);
+
+struct G_Descriptor {
+#ifdef WORDS_BIGENDIAN
+ Bit32u selector: 16;
+ Bit32u offset_0_15 :16;
+ Bit32u offset_16_31 :16;
+ Bit32u p :1;
+ Bit32u dpl :2;
+ Bit32u type :5;
+ Bit32u reserved :3;
+ Bit32u paramcount :5;
+#else
+ Bit32u offset_0_15 :16;
+ Bit32u selector :16;
+ Bit32u paramcount :5;
+ Bit32u reserved :3;
+ Bit32u type :5;
+ Bit32u dpl :2;
+ Bit32u p :1;
+ Bit32u offset_16_31 :16;
+#endif
+} GCC_ATTRIBUTE(packed);
+
+struct TSS_16 {
+ Bit16u back; /* Back link to other task */
+ Bit16u sp0; /* The CK stack pointer */
+ Bit16u ss0; /* The CK stack selector */
+ Bit16u sp1; /* The parent KL stack pointer */
+ Bit16u ss1; /* The parent KL stack selector */
+ Bit16u sp2; /* Unused */
+ Bit16u ss2; /* Unused */
+ Bit16u ip; /* The instruction pointer */
+ Bit16u flags; /* The flags */
+ Bit16u ax, cx, dx, bx; /* The general purpose registers */
+ Bit16u sp, bp, si, di; /* The special purpose registers */
+ Bit16u es; /* The extra selector */
+ Bit16u cs; /* The code selector */
+ Bit16u ss; /* The application stack selector */
+ Bit16u ds; /* The data selector */
+ Bit16u ldt; /* The local descriptor table */
+} GCC_ATTRIBUTE(packed);
+
+struct TSS_32 {
+ Bit32u back; /* Back link to other task */
+ Bit32u esp0; /* The CK stack pointer */
+ Bit32u ss0; /* The CK stack selector */
+ Bit32u esp1; /* The parent KL stack pointer */
+ Bit32u ss1; /* The parent KL stack selector */
+ Bit32u esp2; /* Unused */
+ Bit32u ss2; /* Unused */
+ Bit32u cr3; /* The page directory pointer */
+ Bit32u eip; /* The instruction pointer */
+ Bit32u eflags; /* The flags */
+ Bit32u eax, ecx, edx, ebx; /* The general purpose registers */
+ Bit32u esp, ebp, esi, edi; /* The special purpose registers */
+ Bit32u es; /* The extra selector */
+ Bit32u cs; /* The code selector */
+ Bit32u ss; /* The application stack selector */
+ Bit32u ds; /* The data selector */
+ Bit32u fs; /* And another extra selector */
+ Bit32u gs; /* ... and another one */
+ Bit32u ldt; /* The local descriptor table */
+} GCC_ATTRIBUTE(packed);
+
+#ifdef _MSC_VER
+#pragma pack()
+#endif
+class Descriptor
+{
+public:
+ Descriptor() { saved.fill[0]=saved.fill[1]=0; }
+
+ void Load(PhysPt address);
+ void Save(PhysPt address);
+
+ PhysPt GetBase (void) {
+ return (saved.seg.base_24_31<<24) | (saved.seg.base_16_23<<16) | saved.seg.base_0_15;
+ }
+ Bitu GetLimit (void) {
+ Bitu limit = (saved.seg.limit_16_19<<16) | saved.seg.limit_0_15;
+ if (saved.seg.g) return (limit<<12) | 0xFFF;
+ return limit;
+ }
+ Bitu GetOffset(void) {
+ return (saved.gate.offset_16_31 << 16) | saved.gate.offset_0_15;
+ }
+ Bitu GetSelector(void) {
+ return saved.gate.selector;
+ }
+ Bitu Type(void) {
+ return saved.seg.type;
+ }
+ Bitu Conforming(void) {
+ return saved.seg.type & 8;
+ }
+ Bitu DPL(void) {
+ return saved.seg.dpl;
+ }
+ Bitu Big(void) {
+ return saved.seg.big;
+ }
+public:
+ union {
+ S_Descriptor seg;
+ G_Descriptor gate;
+ Bit32u fill[2];
+ } saved;
+};
+
+class DescriptorTable {
+public:
+ PhysPt GetBase (void) { return table_base; }
+ Bitu GetLimit (void) { return table_limit; }
+ void SetBase (PhysPt _base) { table_base = _base; }
+ void SetLimit (Bitu _limit) { table_limit= _limit; }
+
+ bool GetDescriptor (Bitu selector, Descriptor& desc) {
+ selector&=~7;
+ if (selector>=table_limit) return false;
+ desc.Load(table_base+(selector));
+ return true;
+ }
+protected:
+ PhysPt table_base;
+ Bitu table_limit;
+};
+
+class GDTDescriptorTable : public DescriptorTable {
+public:
+ bool GetDescriptor(Bitu selector, Descriptor& desc) {
+ Bitu address=selector & ~7;
+ if (selector & 4) {
+ if (address>=ldt_limit) return false;
+ desc.Load(ldt_base+address);
+ return true;
+ } else {
+ if (address>=table_limit) return false;
+ desc.Load(table_base+address);
+ return true;
+ }
+ }
+ bool SetDescriptor(Bitu selector, Descriptor& desc) {
+ Bitu address=selector & ~7;
+ if (selector & 4) {
+ if (address>=ldt_limit) return false;
+ desc.Save(ldt_base+address);
+ return true;
+ } else {
+ if (address>=table_limit) return false;
+ desc.Save(table_base+address);
+ return true;
+ }
+ }
+ Bitu SLDT(void) {
+ return ldt_value;
+ }
+ bool LLDT(Bitu value) {
+ if ((value&0xfffc)==0) {
+ ldt_value=0;
+ ldt_base=0;
+ ldt_limit=0;
+ return true;
+ }
+ Descriptor desc;
+ if (!GetDescriptor(value,desc)) return !CPU_PrepareException(EXCEPTION_GP,value);
+ if (desc.Type()!=DESC_LDT) return !CPU_PrepareException(EXCEPTION_GP,value);
+ if (!desc.saved.seg.p) return !CPU_PrepareException(EXCEPTION_NP,value);
+ ldt_base=desc.GetBase();
+ ldt_limit=desc.GetLimit();
+ ldt_value=value;
+ return true;
+ }
+private:
+ PhysPt ldt_base;
+ Bitu ldt_limit;
+ Bitu ldt_value;
+};
+
+class TSS_Descriptor : public Descriptor {
+public:
+ Bitu IsBusy(void) {
+ return saved.seg.type & 2;
+ }
+ Bitu Is386(void) {
+ return saved.seg.type & 8;
+ }
+ void SetBusy(bool busy) {
+ if (busy) saved.seg.type|=2;
+ else saved.seg.type&=~2;
+ }
+};
+
+
+struct CPUBlock {
+ Bitu cpl; /* Current Privilege */
+ Bitu mpl;
+ Bitu cr0;
+ bool pmode; /* Is Protected mode enabled */
+ GDTDescriptorTable gdt;
+ DescriptorTable idt;
+ struct {
+ Bitu mask,notmask;
+ bool big;
+ } stack;
+ struct {
+ bool big;
+ } code;
+ struct {
+ Bitu cs,eip;
+ CPU_Decoder * old_decoder;
+ } hlt;
+ struct {
+ Bitu which,error;
+ } exception;
+ Bits direction;
+ bool trap_skip;
+ Bit32u drx[8];
+ Bit32u trx[8];
+};
+
+extern CPUBlock cpu;
+
+static INLINE void CPU_SetFlagsd(Bitu word) {
+ Bitu mask=cpu.cpl ? FMASK_NORMAL : FMASK_ALL;
+ CPU_SetFlags(word,mask);
+}
+
+static INLINE void CPU_SetFlagsw(Bitu word) {
+ Bitu mask=(cpu.cpl ? FMASK_NORMAL : FMASK_ALL) & 0xffff;
+ CPU_SetFlags(word,mask);
+}
+
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2002-2017 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.
+ *
+ * Wengier: LFN support
+ */
+
+
+#ifndef DOSBOX_CROSS_H
+#define DOSBOX_CROSS_H
+
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string>
+
+#if defined (_MSC_VER) /* MS Visual C++ */
+#include <direct.h>
+#include <io.h>
+#define LONGTYPE(a) a##i64
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+#else /* LINUX / GCC */
+#include <dirent.h>
+#include <unistd.h>
+#define LONGTYPE(a) a##LL
+#endif
+
+#define CROSS_LEN 512 /* Maximum filename size */
+
+
+#if defined (WIN32) || defined (OS2) /* Win 32 & OS/2*/
+#define CROSS_FILENAME(blah)
+#define CROSS_FILESPLIT '\\'
+#define F_OK 0
+#else
+#define CROSS_FILENAME(blah) strreplace(blah,'\\','/')
+#define CROSS_FILESPLIT '/'
+#endif
+
+#define CROSS_NONE 0
+#define CROSS_FILE 1
+#define CROSS_DIR 2
+#if defined (WIN32)
+#define ftruncate(blah,blah2) chsize(blah,blah2)
+#endif
+
+//Solaris maybe others
+#if defined (DB_HAVE_NO_POWF)
+#include <math.h>
+static inline float powf (float x, float y) { return (float) pow (x,y); }
+#endif
+
+class Cross {
+public:
+ static void GetPlatformConfigDir(std::string& in);
+ static void GetPlatformConfigName(std::string& in);
+ static void CreatePlatformConfigDir(std::string& in);
+ static void ResolveHomedir(std::string & temp_line);
+ static void CreateDir(std::string const& temp);
+ static bool IsPathAbsolute(std::string const& in);
+};
+
+
+#if defined (WIN32)
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from
+#include <windows.h>
+
+typedef struct dir_struct {
+ HANDLE handle;
+ char base_path[MAX_PATH+4];
+ WIN32_FIND_DATA search_data;
+} dir_information;
+
+#else
+
+//#include <sys/types.h> //Included above
+#include <dirent.h>
+
+typedef struct dir_struct {
+ DIR* dir;
+ char base_path[CROSS_LEN];
+} dir_information;
+
+#endif
+
+dir_information* open_directory(const char* dirname);
+bool read_directory_first(dir_information* dirp, char* entry_name, char* entry_sname, bool& is_directory);
+bool read_directory_next(dir_information* dirp, char* entry_name, char* entry_sname, bool& is_directory);
+void close_directory(dir_information* dirp);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+void DEBUG_SetupConsole(void);
+void DEBUG_DrawScreen(void);
+bool DEBUG_Breakpoint(void);
+bool DEBUG_IntBreakpoint(Bit8u intNum);
+void DEBUG_Enable(bool pressed);
+void DEBUG_CheckExecuteBreakpoint(Bit16u seg, Bit32u off);
+bool DEBUG_ExitLoop(void);
+void DEBUG_RefreshPage(char scroll);
+Bitu DEBUG_EnableDebugger(void);
+
+extern Bitu cycle_count;
+extern Bitu debugCallback;
+
+#ifdef C_HEAVY_DEBUG
+bool DEBUG_HeavyIsBreakpoint(void);
+void DEBUG_HeavyWriteLogInstruction(void);
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_DMA_H
+#define DOSBOX_DMA_H
+
+enum DMAEvent {
+ DMA_REACHED_TC,
+ DMA_MASKED,
+ DMA_UNMASKED,
+ DMA_TRANSFEREND
+};
+
+class DmaChannel;
+typedef void (* DMA_CallBack)(DmaChannel * chan,DMAEvent event);
+
+class DmaChannel {
+public:
+ Bit32u pagebase;
+ Bit16u baseaddr;
+ Bit32u curraddr;
+ Bit16u basecnt;
+ Bit16u currcnt;
+ Bit8u channum;
+ Bit8u pagenum;
+ Bit8u DMA16;
+ bool increment;
+ bool autoinit;
+ Bit8u trantype;
+ bool masked;
+ bool tcount;
+ bool request;
+ DMA_CallBack callback;
+
+ DmaChannel(Bit8u num, bool dma16);
+ void DoCallBack(DMAEvent event) {
+ if (callback) (*callback)(this,event);
+ }
+ void SetMask(bool _mask) {
+ masked=_mask;
+ DoCallBack(masked ? DMA_MASKED : DMA_UNMASKED);
+ }
+ void Register_Callback(DMA_CallBack _cb) {
+ callback = _cb;
+ SetMask(masked);
+ if (callback) Raise_Request();
+ else Clear_Request();
+ }
+ void ReachedTC(void) {
+ tcount=true;
+ DoCallBack(DMA_REACHED_TC);
+ }
+ void SetPage(Bit8u val) {
+ pagenum=val;
+ pagebase=(pagenum >> DMA16) << (16+DMA16);
+ }
+ void Raise_Request(void) {
+ request=true;
+ }
+ void Clear_Request(void) {
+ request=false;
+ }
+ Bitu Read(Bitu size, Bit8u * buffer);
+ Bitu Write(Bitu size, Bit8u * buffer);
+};
+
+class DmaController {
+private:
+ Bit8u ctrlnum;
+ bool flipflop;
+ DmaChannel *DmaChannels[4];
+public:
+ IO_ReadHandleObject DMA_ReadHandler[0x11];
+ IO_WriteHandleObject DMA_WriteHandler[0x11];
+ DmaController(Bit8u num) {
+ flipflop = false;
+ ctrlnum = num; /* first or second DMA controller */
+ for(Bit8u i=0;i<4;i++) {
+ DmaChannels[i] = new DmaChannel(i+ctrlnum*4,ctrlnum==1);
+ }
+ }
+ ~DmaController(void) {
+ for(Bit8u i=0;i<4;i++) {
+ delete DmaChannels[i];
+ }
+ }
+ DmaChannel * GetChannel(Bit8u chan) {
+ if (chan<4) return DmaChannels[chan];
+ else return NULL;
+ }
+ void WriteControllerReg(Bitu reg,Bitu val,Bitu len);
+ Bitu ReadControllerReg(Bitu reg,Bitu len);
+};
+
+DmaChannel * GetDMAChannel(Bit8u chan);
+
+void CloseSecondDMAController(void);
+bool SecondDMAControllerAvailable(void);
+
+void DMA_SetWrapping(Bitu wrap);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2002-2017 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.
+ *
+ * Wengier: LFN support
+ */
+
+
+#ifndef DOSBOX_DOS_INC_H
+#define DOSBOX_DOS_INC_H
+
+#ifndef DOSBOX_DOS_SYSTEM_H
+#include "dos_system.h"
+#endif
+#ifndef DOSBOX_MEM_H
+#include "mem.h"
+#endif
+
+#include <stddef.h> //for offsetof
+#define CTBUF 127
+
+#ifdef _MSC_VER
+#pragma pack (1)
+#endif
+struct CommandTail{
+ Bit8u count; /* number of bytes returned */
+ char buffer[CTBUF]; /* the buffer itself */
+} GCC_ATTRIBUTE(packed);
+#ifdef _MSC_VER
+#pragma pack ()
+#endif
+
+struct DOS_Date {
+ Bit16u year;
+ Bit8u month;
+ Bit8u day;
+};
+
+struct DOS_Version {
+ Bit8u major,minor,revision;
+};
+
+
+#ifdef _MSC_VER
+#pragma pack (1)
+#endif
+union bootSector {
+ struct entries {
+ Bit8u jump[3];
+ Bit8u oem_name[8];
+ Bit16u bytesect;
+ Bit8u sectclust;
+ Bit16u reserve_sect;
+ Bit8u misc[496];
+ } bootdata;
+ Bit8u rawdata[512];
+} GCC_ATTRIBUTE(packed);
+#ifdef _MSC_VER
+#pragma pack ()
+#endif
+
+
+enum { MCB_FREE=0x0000,MCB_DOS=0x0008 };
+enum { RETURN_EXIT=0,RETURN_CTRLC=1,RETURN_ABORT=2,RETURN_TSR=3};
+
+#define DOS_FILES 127
+#define DOS_DRIVES 26
+#define DOS_DEVICES 20
+
+
+// dos swappable area is 0x320 bytes beyond the sysvars table
+// device driver chain is inside sysvars
+#define DOS_INFOBLOCK_SEG 0x80 // sysvars (list of lists)
+#define DOS_CONDRV_SEG 0xa0
+#define DOS_CONSTRING_SEG 0xa8
+#define DOS_SDA_SEG 0xb2 // dos swappable area
+#define DOS_SDA_OFS 0
+#define DOS_CDS_SEG 0x108
+#define DOS_FIRST_SHELL 0x118
+#define DOS_MEM_START 0x16f //First Segment that DOS can use
+
+#define DOS_PRIVATE_SEGMENT 0xc800
+#define DOS_PRIVATE_SEGMENT_END 0xd000
+
+/* internal Dos Tables */
+
+extern DOS_File * Files[DOS_FILES];
+extern DOS_Drive * Drives[DOS_DRIVES];
+extern DOS_Device * Devices[DOS_DEVICES];
+
+extern Bit8u dos_copybuf[0x10000];
+
+
+void DOS_SetError(Bit16u code);
+
+/* File Handling Routines */
+
+enum { STDIN=0,STDOUT=1,STDERR=2,STDAUX=3,STDPRN=4};
+enum { HAND_NONE=0,HAND_FILE,HAND_DEVICE};
+
+/* Routines for File Class */
+void DOS_SetupFiles (void);
+bool DOS_ReadFile(Bit16u handle,Bit8u * data,Bit16u * amount, bool fcb = false);
+bool DOS_WriteFile(Bit16u handle,Bit8u * data,Bit16u * amount,bool fcb = false);
+bool DOS_SeekFile(Bit16u handle,Bit32u * pos,Bit32u type,bool fcb = false);
+bool DOS_CloseFile(Bit16u handle,bool fcb = false);
+bool DOS_FlushFile(Bit16u handle);
+bool DOS_DuplicateEntry(Bit16u entry,Bit16u * newentry);
+bool DOS_ForceDuplicateEntry(Bit16u entry,Bit16u newentry);
+bool DOS_GetFileDate(Bit16u entry, Bit16u* otime, Bit16u* odate);
+
+/* Routines for Drive Class */
+bool DOS_OpenFile(char const * name,Bit8u flags,Bit16u * entry,bool fcb = false);
+bool DOS_OpenFileExtended(char const * name, Bit16u flags, Bit16u createAttr, Bit16u action, Bit16u *entry, Bit16u* status);
+bool DOS_CreateFile(char const * name,Bit16u attribute,Bit16u * entry, bool fcb = false);
+bool DOS_UnlinkFile(char const * const name);
+bool DOS_GetSFNPath(char const * const path, char *SFNpath, bool LFN);
+bool DOS_FindFirst(char *search,Bit16u attr,bool fcb_findfirst=false);
+bool DOS_FindNext(void);
+bool DOS_Canonicalize(char const * const name,char * const big);
+bool DOS_CreateTempFile(char * const name,Bit16u * entry);
+bool DOS_FileExists(char const * const name);
+
+/* Helper Functions */
+bool DOS_MakeName(char const * const name,char * const fullname,Bit8u * drive);
+/* Drive Handing Routines */
+Bit8u DOS_GetDefaultDrive(void);
+void DOS_SetDefaultDrive(Bit8u drive);
+bool DOS_SetDrive(Bit8u drive);
+bool DOS_GetCurrentDir(Bit8u drive,char * const buffer, bool LFN);
+bool DOS_ChangeDir(char const * const dir);
+bool DOS_MakeDir(char const * const dir);
+bool DOS_RemoveDir(char const * const dir);
+bool DOS_Rename(char const * const oldname,char const * const newname);
+bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit8u * sectors,Bit16u * clusters,Bit16u * free);
+bool DOS_GetFileAttr(char const * const name,Bit16u * attr);
+bool DOS_SetFileAttr(char const * const name,Bit16u attr);
+bool DOS_GetFileAttrEx(char const* const name, struct stat *status, Bit8u hdrive=-1);
+DWORD DOS_GetCompressedFileSize(char const* const name);
+HANDLE DOS_CreateOpenFile(char const* const name);
+
+/* IOCTL Stuff */
+bool DOS_IOCTL(void);
+bool DOS_GetSTDINStatus();
+Bit8u DOS_FindDevice(char const * name);
+void DOS_SetupDevices(void);
+void DOS_ClearKeyMap(void);
+
+/* Execute and new process creation */
+bool DOS_NewPSP(Bit16u pspseg,Bit16u size);
+bool DOS_ChildPSP(Bit16u pspseg,Bit16u size);
+bool DOS_Execute(char * name,PhysPt block,Bit8u flags);
+void DOS_Terminate(Bit16u pspseg,bool tsr,Bit8u exitcode);
+
+/* Memory Handling Routines */
+void DOS_SetupMemory(void);
+bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks);
+bool DOS_ResizeMemory(Bit16u segment,Bit16u * blocks);
+bool DOS_FreeMemory(Bit16u segment);
+void DOS_FreeProcessMemory(Bit16u pspseg);
+Bit16u DOS_GetMemory(Bit16u pages);
+bool DOS_SetMemAllocStrategy(Bit16u strat);
+Bit16u DOS_GetMemAllocStrategy(void);
+void DOS_BuildUMBChain(bool umb_active,bool ems_active);
+bool DOS_LinkUMBsToMemChain(Bit16u linkstate);
+
+/* FCB stuff */
+bool DOS_FCBOpen(Bit16u seg,Bit16u offset);
+bool DOS_FCBCreate(Bit16u seg,Bit16u offset);
+bool DOS_FCBClose(Bit16u seg,Bit16u offset);
+bool DOS_FCBFindFirst(Bit16u seg,Bit16u offset);
+bool DOS_FCBFindNext(Bit16u seg,Bit16u offset);
+Bit8u DOS_FCBRead(Bit16u seg,Bit16u offset, Bit16u numBlocks);
+Bit8u DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u numBlocks);
+Bit8u DOS_FCBRandomRead(Bit16u seg,Bit16u offset,Bit16u * numRec,bool restore);
+Bit8u DOS_FCBRandomWrite(Bit16u seg,Bit16u offset,Bit16u * numRec,bool restore);
+bool DOS_FCBGetFileSize(Bit16u seg,Bit16u offset);
+bool DOS_FCBDeleteFile(Bit16u seg,Bit16u offset);
+bool DOS_FCBRenameFile(Bit16u seg, Bit16u offset);
+void DOS_FCBSetRandomRecord(Bit16u seg, Bit16u offset);
+Bit8u FCB_Parsename(Bit16u seg,Bit16u offset,Bit8u parser ,char *string, Bit8u *change);
+bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters);
+
+/* Extra DOS Interrupts */
+void DOS_SetupMisc(void);
+
+/* The DOS Tables */
+void DOS_SetupTables(void);
+
+/* Internal DOS Setup Programs */
+void DOS_SetupPrograms(void);
+
+/* Initialize Keyboard Layout */
+void DOS_KeyboardLayout_Init(Section* sec);
+
+bool DOS_LayoutKey(Bitu key, Bit8u flags1, Bit8u flags2, Bit8u flags3);
+
+enum {
+ KEYB_NOERROR=0,
+ KEYB_FILENOTFOUND,
+ KEYB_INVALIDFILE,
+ KEYB_LAYOUTNOTFOUND,
+ KEYB_INVALIDCPFILE
+};
+
+
+static INLINE Bit16u long2para(Bit32u size) {
+ if (size>0xFFFF0) return 0xffff;
+ if (size&0xf) return (Bit16u)((size>>4)+1);
+ else return (Bit16u)(size>>4);
+}
+
+
+static INLINE Bit16u DOS_PackTime(Bit16u hour,Bit16u min,Bit16u sec) {
+ return (hour&0x1f)<<11 | (min&0x3f) << 5 | ((sec/2)&0x1f);
+}
+
+static INLINE Bit16u DOS_PackDate(Bit16u year,Bit16u mon,Bit16u day) {
+ return ((year-1980)&0x7f)<<9 | (mon&0x3f) << 5 | (day&0x1f);
+}
+
+/* Dos Error Codes */
+#define DOSERR_NONE 0
+#define DOSERR_FUNCTION_NUMBER_INVALID 1
+#define DOSERR_FILE_NOT_FOUND 2
+#define DOSERR_PATH_NOT_FOUND 3
+#define DOSERR_TOO_MANY_OPEN_FILES 4
+#define DOSERR_ACCESS_DENIED 5
+#define DOSERR_INVALID_HANDLE 6
+#define DOSERR_MCB_DESTROYED 7
+#define DOSERR_INSUFFICIENT_MEMORY 8
+#define DOSERR_MB_ADDRESS_INVALID 9
+#define DOSERR_ENVIRONMENT_INVALID 10
+#define DOSERR_FORMAT_INVALID 11
+#define DOSERR_ACCESS_CODE_INVALID 12
+#define DOSERR_DATA_INVALID 13
+#define DOSERR_RESERVED 14
+#define DOSERR_FIXUP_OVERFLOW 14
+#define DOSERR_INVALID_DRIVE 15
+#define DOSERR_REMOVE_CURRENT_DIRECTORY 16
+#define DOSERR_NOT_SAME_DEVICE 17
+#define DOSERR_NO_MORE_FILES 18
+#define DOSERR_WRITE_PROTECTED_DISK 19
+#define DOSERR_FILE_ALREADY_EXISTS 80
+
+
+/* Remains some classes used to access certain things */
+#define sOffset(s,m) ((char*)&(((s*)NULL)->m)-(char*)NULL)
+#define sGet(s,m) GetIt(sizeof(((s *)&pt)->m),(PhysPt)sOffset(s,m))
+#define sSave(s,m,val) SaveIt(sizeof(((s *)&pt)->m),(PhysPt)sOffset(s,m),val)
+
+class MemStruct {
+public:
+ Bitu GetIt(Bitu size,PhysPt addr) {
+ switch (size) {
+ case 1:return mem_readb(pt+addr);
+ case 2:return mem_readw(pt+addr);
+ case 4:return mem_readd(pt+addr);
+ }
+ return 0;
+ }
+ void SaveIt(Bitu size,PhysPt addr,Bitu val) {
+ switch (size) {
+ case 1:mem_writeb(pt+addr,(Bit8u)val);break;
+ case 2:mem_writew(pt+addr,(Bit16u)val);break;
+ case 4:mem_writed(pt+addr,(Bit32u)val);break;
+ }
+ }
+ void SetPt(Bit16u seg) { pt=PhysMake(seg,0);}
+ void SetPt(Bit16u seg,Bit16u off) { pt=PhysMake(seg,off);}
+ void SetPt(RealPt addr) { pt=Real2Phys(addr);}
+protected:
+ PhysPt pt;
+};
+
+class DOS_PSP :public MemStruct {
+public:
+ DOS_PSP (Bit16u segment) { SetPt(segment);seg=segment;};
+ void MakeNew (Bit16u memSize);
+ void CopyFileTable (DOS_PSP* srcpsp,bool createchildpsp);
+ Bit16u FindFreeFileEntry (void);
+ void CloseFiles (void);
+
+ void SaveVectors (void);
+ void RestoreVectors (void);
+ void SetSize (Bit16u size) { sSave(sPSP,next_seg,size); };
+ Bit16u GetSize (void) { return (Bit16u)sGet(sPSP,next_seg); };
+ void SetEnvironment (Bit16u envseg) { sSave(sPSP,environment,envseg); };
+ Bit16u GetEnvironment (void) { return (Bit16u)sGet(sPSP,environment); };
+ Bit16u GetSegment (void) { return seg; };
+ void SetFileHandle (Bit16u index, Bit8u handle);
+ Bit8u GetFileHandle (Bit16u index);
+ void SetParent (Bit16u parent) { sSave(sPSP,psp_parent,parent); };
+ Bit16u GetParent (void) { return (Bit16u)sGet(sPSP,psp_parent); };
+ void SetStack (RealPt stackpt) { sSave(sPSP,stack,stackpt); };
+ RealPt GetStack (void) { return sGet(sPSP,stack); };
+ void SetInt22 (RealPt int22pt) { sSave(sPSP,int_22,int22pt); };
+ RealPt GetInt22 (void) { return sGet(sPSP,int_22); };
+ void SetFCB1 (RealPt src);
+ void SetFCB2 (RealPt src);
+ void SetCommandTail (RealPt src);
+ void StoreCommandTail (void);
+ void RestoreCommandTail (void);
+ bool SetNumFiles (Bit16u fileNum);
+ Bit16u FindEntryByHandle (Bit8u handle);
+
+private:
+ #ifdef _MSC_VER
+ #pragma pack(1)
+ #endif
+ struct sPSP {
+ Bit8u exit[2]; /* CP/M-like exit poimt */
+ Bit16u next_seg; /* Segment of first byte beyond memory allocated or program */
+ Bit8u fill_1; /* single char fill */
+ Bit8u far_call; /* far call opcode */
+ RealPt cpm_entry; /* CPM Service Request address*/
+ RealPt int_22; /* Terminate Address */
+ RealPt int_23; /* Break Address */
+ RealPt int_24; /* Critical Error Address */
+ Bit16u psp_parent; /* Parent PSP Segment */
+ Bit8u files[20]; /* File Table - 0xff is unused */
+ Bit16u environment; /* Segment of evironment table */
+ RealPt stack; /* SS:SP Save point for int 0x21 calls */
+ Bit16u max_files; /* Maximum open files */
+ RealPt file_table; /* Pointer to File Table PSP:0x18 */
+ RealPt prev_psp; /* Pointer to previous PSP */
+ Bit8u interim_flag;
+ Bit8u truename_flag;
+ Bit16u nn_flags;
+ Bit16u dos_version;
+ Bit8u fill_2[14]; /* Lot's of unused stuff i can't care aboue */
+ Bit8u service[3]; /* INT 0x21 Service call int 0x21;retf; */
+ Bit8u fill_3[9]; /* This has some blocks with FCB info */
+ Bit8u fcb1[16]; /* first FCB */
+ Bit8u fcb2[16]; /* second FCB */
+ Bit8u fill_4[4]; /* unused */
+ CommandTail cmdtail;
+ } GCC_ATTRIBUTE(packed);
+ #ifdef _MSC_VER
+ #pragma pack()
+ #endif
+ Bit16u seg;
+public:
+ static Bit16u rootpsp;
+};
+
+class DOS_ParamBlock:public MemStruct {
+public:
+ DOS_ParamBlock(PhysPt addr) {pt=addr;}
+ void Clear(void);
+ void LoadData(void);
+ void SaveData(void); /* Save it as an exec block */
+ #ifdef _MSC_VER
+ #pragma pack (1)
+ #endif
+ struct sOverlay {
+ Bit16u loadseg;
+ Bit16u relocation;
+ } GCC_ATTRIBUTE(packed);
+ struct sExec {
+ Bit16u envseg;
+ RealPt cmdtail;
+ RealPt fcb1;
+ RealPt fcb2;
+ RealPt initsssp;
+ RealPt initcsip;
+ }GCC_ATTRIBUTE(packed);
+ #ifdef _MSC_VER
+ #pragma pack()
+ #endif
+ sExec exec;
+ sOverlay overlay;
+};
+
+class DOS_InfoBlock:public MemStruct {
+public:
+ DOS_InfoBlock () {};
+ void SetLocation(Bit16u seg);
+ void SetFirstMCB(Bit16u _first_mcb);
+ void SetBuffers(Bit16u x,Bit16u y);
+ void SetCurDirStruct(Bit32u _curdirstruct);
+ void SetFCBTable(Bit32u _fcbtable);
+ void SetDeviceChainStart(Bit32u _devchain);
+ void SetDiskBufferHeadPt(Bit32u _dbheadpt);
+ void SetStartOfUMBChain(Bit16u _umbstartseg);
+ void SetUMBChainState(Bit8u _umbchaining);
+ Bit16u GetStartOfUMBChain(void);
+ Bit8u GetUMBChainState(void);
+ RealPt GetPointer(void);
+ Bit32u GetDeviceChain(void);
+
+ #ifdef _MSC_VER
+ #pragma pack(1)
+ #endif
+ struct sDIB {
+ Bit8u unknown1[4];
+ Bit16u magicWord; // -0x22 needs to be 1
+ Bit8u unknown2[8];
+ Bit16u regCXfrom5e; // -0x18 CX from last int21/ah=5e
+ Bit16u countLRUcache; // -0x16 LRU counter for FCB caching
+ Bit16u countLRUopens; // -0x14 LRU counter for FCB openings
+ Bit8u stuff[6]; // -0x12 some stuff, hopefully never used....
+ Bit16u sharingCount; // -0x0c sharing retry count
+ Bit16u sharingDelay; // -0x0a sharing retry delay
+ RealPt diskBufPtr; // -0x08 pointer to disk buffer
+ Bit16u ptrCONinput; // -0x04 pointer to con input
+ Bit16u firstMCB; // -0x02 first memory control block
+ RealPt firstDPB; // 0x00 first drive parameter block
+ RealPt firstFileTable; // 0x04 first system file table
+ RealPt activeClock; // 0x08 active clock device header
+ RealPt activeCon; // 0x0c active console device header
+ Bit16u maxSectorLength; // 0x10 maximum bytes per sector of any block device;
+ RealPt diskInfoBuffer; // 0x12 pointer to disk info buffer
+ RealPt curDirStructure; // 0x16 pointer to current array of directory structure
+ RealPt fcbTable; // 0x1a pointer to system FCB table
+ Bit16u protFCBs; // 0x1e protected fcbs
+ Bit8u blockDevices; // 0x20 installed block devices
+ Bit8u lastdrive; // 0x21 lastdrive
+ Bit32u nulNextDriver; // 0x22 NUL driver next pointer
+ Bit16u nulAttributes; // 0x26 NUL driver aattributes
+ Bit32u nulStrategy; // 0x28 NUL driver strategy routine
+ Bit8u nulString[8]; // 0x2c NUL driver name string
+ Bit8u joindedDrives; // 0x34 joined drives
+ Bit16u specialCodeSeg; // 0x35 special code segment
+ RealPt setverPtr; // 0x37 pointer to setver
+ Bit16u a20FixOfs; // 0x3b a20 fix routine offset
+ Bit16u pspLastIfHMA; // 0x3d psp of last program (if dos in hma)
+ Bit16u buffers_x; // 0x3f x in BUFFERS x,y
+ Bit16u buffers_y; // 0x41 y in BUFFERS x,y
+ Bit8u bootDrive; // 0x43 boot drive
+ Bit8u useDwordMov; // 0x44 use dword moves
+ Bit16u extendedSize; // 0x45 size of extended memory
+ Bit32u diskBufferHeadPt; // 0x47 pointer to least-recently used buffer header
+ Bit16u dirtyDiskBuffers; // 0x4b number of dirty disk buffers
+ Bit32u lookaheadBufPt; // 0x4d pointer to lookahead buffer
+ Bit16u lookaheadBufNumber; // 0x51 number of lookahead buffers
+ Bit8u bufferLocation; // 0x53 workspace buffer location
+ Bit32u workspaceBuffer; // 0x54 pointer to workspace buffer
+ Bit8u unknown3[11]; // 0x58
+ Bit8u chainingUMB; // 0x63 bit0: UMB chain linked to MCB chain
+ Bit16u minMemForExec; // 0x64 minimum paragraphs needed for current program
+ Bit16u startOfUMBChain; // 0x66 segment of first UMB-MCB
+ Bit16u memAllocScanStart; // 0x68 start paragraph for memory allocation
+ } GCC_ATTRIBUTE(packed);
+ #ifdef _MSC_VER
+ #pragma pack ()
+ #endif
+ Bit16u seg;
+};
+
+class DOS_DTA:public MemStruct{
+public:
+ DOS_DTA(RealPt addr) { SetPt(addr); }
+
+ void SetupSearch(Bit8u _sdrive,Bit8u _sattr,char * _pattern);
+ void SetResult(const char * _name,const char * _lname,Bit32u _size,Bit16u _date,Bit16u _time,Bit8u _attr);
+
+ int GetFindData(int fmt,char * finddata);
+ Bit8u GetSearchDrive(void);
+ void GetSearchParams(Bit8u & _sattr,char * _spattern,bool lfn);
+ void GetResult(char * _name,char * _lname,Bit32u & _size,Bit16u & _date,Bit16u & _time,Bit8u & _attr);
+
+ void SetDirID(Bit16u entry) { sSave(sDTA,dirID,entry); };
+ void SetDirIDCluster(Bit16u entry) { sSave(sDTA,dirCluster,entry); };
+ Bit16u GetDirID(void) { return (Bit16u)sGet(sDTA,dirID); };
+ Bit16u GetDirIDCluster(void) { return (Bit16u)sGet(sDTA,dirCluster); };
+private:
+ #ifdef _MSC_VER
+ #pragma pack(1)
+ #endif
+ struct sDTA {
+ Bit8u sdrive; /* The Drive the search is taking place */
+ Bit8u spname[8]; /* The Search pattern for the filename */
+ Bit8u spext[3]; /* The Search pattern for the extenstion */
+ Bit8u sattr; /* The Attributes that need to be found */
+ Bit16u dirID; /* custom: dir-search ID for multiple searches at the same time */
+ Bit16u dirCluster; /* custom (drive_fat only): cluster number for multiple searches at the same time */
+ Bit8u fill[4];
+ Bit8u attr;
+ Bit16u time;
+ Bit16u date;
+ Bit32u size;
+ char name[DOS_NAMELENGTH_ASCII];
+ } GCC_ATTRIBUTE(packed);
+ #ifdef _MSC_VER
+ #pragma pack()
+ #endif
+};
+
+class DOS_FCB: public MemStruct {
+public:
+ DOS_FCB(Bit16u seg,Bit16u off,bool allow_extended=true);
+ void Create(bool _extended);
+ void SetName(Bit8u _drive,char * _fname,char * _ext);
+ void SetSizeDateTime(Bit32u _size, Bit16u _date, Bit16u _time, bool byFindFCB = false);
+ void GetSizeDateTime(Bit32u & _size,Bit16u & _date,Bit16u & _time);
+ void GetName(char * fillname);
+ void FileOpen(Bit8u _fhandle);
+ void FileClose(Bit8u & _fhandle);
+ void GetRecord(Bit16u & _cur_block,Bit8u & _cur_rec);
+ void SetRecord(Bit16u _cur_block,Bit8u _cur_rec);
+ void GetSeqData(Bit8u & _fhandle,Bit16u & _rec_size);
+ void SetSeqData(Bit8u _fhandle,Bit16u _rec_size);
+ void GetRandom(Bit32u & _random);
+ void SetRandom(Bit32u _random);
+ Bit8u GetDrive(void);
+ bool Extended(void);
+ void GetAttr(Bit8u & attr);
+ void SetAttr(Bit8u attr, bool byFindFCB = false);
+ void SetResult(Bit32u size,Bit16u date,Bit16u time,Bit8u attr);
+ bool Valid(void);
+ void ClearBlockRecsize(void);
+private:
+ bool extended;
+ PhysPt real_pt;
+ #ifdef _MSC_VER
+ #pragma pack (1)
+ #endif
+ struct sFCB {
+ Bit8u drive; /* Drive number 0=default, 1=A, etc */
+ Bit8u filename[8]; /* Space padded name */
+ Bit8u ext[3]; /* Space padded extension */
+ Bit16u cur_block; /* Current Block */
+ Bit16u rec_size; /* Logical record size */
+ Bit32u filesize; /* File Size */
+ Bit16u date;
+ Bit16u time;
+ /* Reserved Block should be 8 bytes */
+ Bit8u sft_entries;
+ Bit8u share_attributes;
+ Bit8u extra_info;
+ /* Maybe swap file_handle and sft_entries now that fcbs
+ * aren't stored in the psp filetable anymore */
+ Bit8u file_handle;
+ Bit8u reserved[4];
+ /* end */
+ Bit8u cur_rec; /* Current record in current block */
+ Bit32u rndm; /* Current relative record number */
+ } GCC_ATTRIBUTE(packed);
+ #ifdef _MSC_VER
+ #pragma pack ()
+ #endif
+};
+
+class DOS_MCB : public MemStruct{
+public:
+ DOS_MCB(Bit16u seg) { SetPt(seg); }
+ void SetFileName(char const * const _name) { MEM_BlockWrite(pt+offsetof(sMCB,filename),_name,8); }
+ void GetFileName(char * const _name) { MEM_BlockRead(pt+offsetof(sMCB,filename),_name,8);_name[8]=0;}
+ void SetType(Bit8u _type) { sSave(sMCB,type,_type);}
+ void SetSize(Bit16u _size) { sSave(sMCB,size,_size);}
+ void SetPSPSeg(Bit16u _pspseg) { sSave(sMCB,psp_segment,_pspseg);}
+ Bit8u GetType(void) { return (Bit8u)sGet(sMCB,type);}
+ Bit16u GetSize(void) { return (Bit16u)sGet(sMCB,size);}
+ Bit16u GetPSPSeg(void) { return (Bit16u)sGet(sMCB,psp_segment);}
+private:
+ #ifdef _MSC_VER
+ #pragma pack (1)
+ #endif
+ struct sMCB {
+ Bit8u type;
+ Bit16u psp_segment;
+ Bit16u size;
+ Bit8u unused[3];
+ Bit8u filename[8];
+ } GCC_ATTRIBUTE(packed);
+ #ifdef _MSC_VER
+ #pragma pack ()
+ #endif
+};
+
+class DOS_SDA : public MemStruct {
+public:
+ DOS_SDA(Bit16u _seg,Bit16u _offs) { SetPt(_seg,_offs); }
+ void Init();
+ void SetDrive(Bit8u _drive) { sSave(sSDA,current_drive, _drive); }
+ void SetDTA(Bit32u _dta) { sSave(sSDA,current_dta, _dta); }
+ void SetPSP(Bit16u _psp) { sSave(sSDA,current_psp, _psp); }
+ Bit8u GetDrive(void) { return (Bit8u)sGet(sSDA,current_drive); }
+ Bit16u GetPSP(void) { return (Bit16u)sGet(sSDA,current_psp); }
+ Bit32u GetDTA(void) { return (Bit32u)sGet(sSDA,current_dta); }
+
+
+private:
+ #ifdef _MSC_VER
+ #pragma pack (1)
+ #endif
+ struct sSDA {
+ Bit8u crit_error_flag; /* 0x00 Critical Error Flag */
+ Bit8u inDOS_flag; /* 0x01 InDOS flag (count of active INT 21 calls) */
+ Bit8u drive_crit_error; /* 0x02 Drive on which current critical error occurred or FFh */
+ Bit8u locus_of_last_error; /* 0x03 locus of last error */
+ Bit16u extended_error_code; /* 0x04 extended error code of last error */
+ Bit8u suggested_action; /* 0x06 suggested action for last error */
+ Bit8u error_class; /* 0x07 class of last error*/
+ Bit32u last_error_pointer; /* 0x08 ES:DI pointer for last error */
+ Bit32u current_dta; /* 0x0C current DTA (Disk Transfer Address) */
+ Bit16u current_psp; /* 0x10 current PSP */
+ Bit16u sp_int_23; /* 0x12 stores SP across an INT 23 */
+ Bit16u return_code; /* 0x14 return code from last process termination (zerod after reading with AH=4Dh) */
+ Bit8u current_drive; /* 0x16 current drive */
+ Bit8u extended_break_flag; /* 0x17 extended break flag */
+ Bit8u fill[2]; /* 0x18 flag: code page switching || flag: copy of previous byte in case of INT 24 Abort*/
+ } GCC_ATTRIBUTE(packed);
+ #ifdef _MSC_VER
+ #pragma pack()
+ #endif
+};
+extern DOS_InfoBlock dos_infoblock;
+
+struct DOS_Block {
+ DOS_Date date;
+ DOS_Version version;
+ Bit16u firstMCB;
+ Bit16u errorcode;
+ Bit16u psp(){return DOS_SDA(DOS_SDA_SEG,DOS_SDA_OFS).GetPSP();};
+ void psp(Bit16u _seg){ DOS_SDA(DOS_SDA_SEG,DOS_SDA_OFS).SetPSP(_seg);};
+ Bit16u env;
+ RealPt cpmentry;
+ RealPt dta(){return DOS_SDA(DOS_SDA_SEG,DOS_SDA_OFS).GetDTA();};
+ void dta(RealPt _dta){DOS_SDA(DOS_SDA_SEG,DOS_SDA_OFS).SetDTA(_dta);};
+ Bit8u return_code,return_mode;
+
+ Bit8u current_drive;
+ bool verify;
+ bool breakcheck;
+ bool echo; // if set to true dev_con::read will echo input
+ bool direct_output;
+ struct {
+ RealPt mediaid;
+ RealPt tempdta;
+ RealPt tempdta_fcbdelete;
+ RealPt dbcs;
+ RealPt filenamechar;
+ RealPt collatingseq;
+ RealPt upcase;
+ //Bit8u* country;//Will be copied to dos memory. resides in real mem
+ Bit16u dpb; //Fake Disk parameter system using only the first entry so the drive letter matches
+ Bit16u country_seg;
+ } tables;
+ Bit16u loaded_codepage;
+
+ //for AX
+ bool set_ax_enabled;
+
+ bool set_dosv_enabled;
+};
+
+extern DOS_Block dos;
+
+static INLINE Bit8u RealHandle(Bit16u handle) {
+ DOS_PSP psp(dos.psp());
+ return psp.GetFileHandle(handle);
+}
+
+#define IS_DOS_JAPANESE (real_readw(dos.tables.country_seg,5) == 932 && mem_readb(Real2Phys(dos.tables.dbcs) + 0x02) == 0x81)
+#define IS_DOSV (dos.set_dosv_enabled)
+
+#define AUTORELOAD_CMD 0x01
+#define AUTORELOAD_DOS 0x02
+#define AUTORELOAD_ALL 0x03
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2002-2017 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.
+ *
+ * Wengier: LFN support
+ */
+
+
+#ifndef DOSBOX_DOS_SYSTEM_H
+#define DOSBOX_DOS_SYSTEM_H
+
+#include <vector>
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+#ifndef DOSBOX_CROSS_H
+#include "cross.h"
+#endif
+#ifndef DOSBOX_SUPPORT_H
+#include "support.h"
+#endif
+#ifndef DOSBOX_MEM_H
+#include "mem.h"
+#endif
+
+#define DOS_NAMELENGTH 12
+#define DOS_NAMELENGTH_ASCII (DOS_NAMELENGTH+1)
+#define LFN_NAMELENGTH 255
+#define DOS_FCBNAME 15
+#define DOS_DIRDEPTH 8
+#define DOS_PATHLENGTH 255
+#define DOS_TEMPSIZE 1024
+
+enum {
+ DOS_ATTR_READ_ONLY= 0x01,
+ DOS_ATTR_HIDDEN= 0x02,
+ DOS_ATTR_SYSTEM= 0x04,
+ DOS_ATTR_VOLUME= 0x08,
+ DOS_ATTR_DIRECTORY= 0x10,
+ DOS_ATTR_ARCHIVE= 0x20,
+ DOS_ATTR_DEVICE= 0x40
+};
+
+struct FileStat_Block {
+ Bit32u size;
+ Bit16u time;
+ Bit16u date;
+ Bit16u attr;
+};
+
+class DOS_DTA;
+
+class DOS_File {
+public:
+ DOS_File():flags(0) { name=0; refCtr = 0; hdrive=0xff; };
+ DOS_File(const DOS_File& orig);
+ DOS_File & operator= (const DOS_File & orig);
+ virtual ~DOS_File(){if(name) delete [] name;};
+ virtual bool Read(Bit8u * data,Bit16u * size)=0;
+ virtual bool Write(Bit8u * data,Bit16u * size)=0;
+ virtual bool Seek(Bit32u * pos,Bit32u type)=0;
+ virtual bool Close()=0;
+ virtual Bit16u GetInformation(void)=0;
+ virtual void SetName(const char* _name) { if (name) delete[] name; name = new char[strlen(_name)+1]; strcpy(name,_name); }
+ virtual char* GetName(void) { return name; };
+ virtual bool IsOpen() { return open; };
+ virtual bool IsName(const char* _name) { if (!name) return false; return strcasecmp(name,_name)==0; };
+ virtual void AddRef() { refCtr++; };
+ virtual Bits RemoveRef() { return --refCtr; };
+ virtual bool UpdateDateTimeFromHost() { return true; }
+ void SetDrive(Bit8u drv) { hdrive=drv;}
+ Bit8u GetDrive(void) { return hdrive;}
+ Bit32u flags;
+ Bit16u time;
+ Bit16u date;
+ Bit16u attr;
+ Bits refCtr;
+ bool open;
+ char* name;
+/* Some Device Specific Stuff */
+private:
+ Bit8u hdrive;
+};
+
+class DOS_Device : public DOS_File {
+public:
+ DOS_Device(const DOS_Device& orig):DOS_File(orig) {
+ devnum=orig.devnum;
+ open=true;
+ }
+ DOS_Device & operator= (const DOS_Device & orig) {
+ DOS_File::operator=(orig);
+ devnum=orig.devnum;
+ open=true;
+ return *this;
+ }
+ DOS_Device():DOS_File(),devnum(0){};
+ virtual bool Read(Bit8u * data,Bit16u * size);
+ virtual bool Write(Bit8u * data,Bit16u * size);
+ virtual bool Seek(Bit32u * pos,Bit32u type);
+ virtual bool Close();
+ virtual Bit16u GetInformation(void);
+ virtual bool ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode);
+ virtual bool WriteToControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode);
+ void SetDeviceNumber(Bitu num) { devnum=num;}
+private:
+ Bitu devnum;
+};
+
+/* The following variable can be lowered to free up some memory.
+ * The negative side effect: The stored searches will be turned over faster.
+ * Should not have impact on systems with few directory entries. */
+#define MAX_OPENDIRS 2048
+//Can be high as it's only storage (16 bit variable)
+
+class DOS_Drive_Cache {
+public:
+ DOS_Drive_Cache (void);
+ DOS_Drive_Cache (const char* path);
+ ~DOS_Drive_Cache (void);
+
+ enum TDirSort { NOSORT, ALPHABETICAL, DIRALPHABETICAL, ALPHABETICALREV, DIRALPHABETICALREV };
+
+ void SetBaseDir (const char* path);
+ void SetDirSort (TDirSort sort) { sortDirType = sort; };
+ bool OpenDir (const char* path, Bit16u& id);
+ bool ReadDir (Bit16u id, char* &result, char * &lresult);
+
+ void ExpandName (char* path);
+ char* GetExpandName (const char* path);
+ bool GetShortName (const char* fullname, char* shortname);
+
+ bool FindFirst (char* path, Bit16u& id);
+ bool FindNext (Bit16u id, char* &result, char* &lresult);
+
+ void CacheOut (const char* path, bool ignoreLastDir = false);
+ void AddEntry (const char* path, bool checkExist = false);
+ void DeleteEntry (const char* path, bool ignoreLastDir = false);
+
+ void EmptyCache (void);
+ void SetLabel (const char* name,bool cdrom,bool allowupdate);
+ char* GetLabel (void) { return label; };
+
+ class CFileInfo {
+ public:
+ CFileInfo(void) {
+ orgname[0] = shortname[0] = 0;
+ isDir = false;
+ id = MAX_OPENDIRS;
+ nextEntry = shortNr = 0;
+ }
+ ~CFileInfo(void) {
+ for (Bit32u i=0; i<fileList.size(); i++) delete fileList[i];
+ fileList.clear();
+ longNameList.clear();
+ };
+ char orgname [CROSS_LEN];
+ char shortname [DOS_NAMELENGTH_ASCII+16];
+ bool isDir;
+ Bit16u id;
+ Bitu nextEntry;
+ Bitu shortNr;
+ // contents
+ std::vector<CFileInfo*> fileList;
+ std::vector<CFileInfo*> longNameList;
+ };
+
+private:
+ void ClearFileInfo(CFileInfo *dir);
+ void DeleteFileInfo(CFileInfo *dir);
+
+ bool RemoveTrailingDot (char* shortname);
+ Bits GetLongName (CFileInfo* info, char* shortname);
+ void CreateShortName (CFileInfo* dir, CFileInfo* info);
+ Bitu CreateShortNameID (CFileInfo* dir, const char* name);
+ int CompareShortname (const char* compareName, const char* shortName);
+ bool SetResult (CFileInfo* dir, char * &result, char * &lresult, Bitu entryNr);
+ bool IsCachedIn (CFileInfo* dir);
+ CFileInfo* FindDirInfo (const char* path, char* expandedPath);
+ bool RemoveSpaces (char* str);
+ bool OpenDir (CFileInfo* dir, const char* path, Bit16u& id);
+ void CreateEntry (CFileInfo* dir, const char* name, const char* sname, bool query_directory);
+ void CopyEntry (CFileInfo* dir, CFileInfo* from);
+ Bit16u GetFreeID (CFileInfo* dir);
+ void Clear (void);
+
+ CFileInfo* dirBase;
+ char dirPath [CROSS_LEN];
+ char basePath [CROSS_LEN];
+ bool dirFirstTime;
+ TDirSort sortDirType;
+ CFileInfo* save_dir;
+ char save_path [CROSS_LEN];
+ char save_expanded [CROSS_LEN];
+
+ Bit16u srchNr;
+ CFileInfo* dirSearch [MAX_OPENDIRS];
+ char dirSearchName [MAX_OPENDIRS];
+ CFileInfo* dirFindFirst [MAX_OPENDIRS];
+ Bit16u nextFreeFindFirst;
+
+ char label [CROSS_LEN];
+ bool updatelabel;
+};
+
+class DOS_Drive {
+public:
+ DOS_Drive();
+ virtual ~DOS_Drive(){};
+ virtual bool FileOpen(DOS_File * * file,char * name,Bit32u flags)=0;
+ virtual bool FileCreate(DOS_File * * file,char * name,Bit16u attributes)=0;
+ virtual bool FileUnlink(char * _name)=0;
+ virtual bool RemoveDir(char * _dir)=0;
+ virtual bool MakeDir(char * _dir)=0;
+ virtual bool TestDir(char * _dir)=0;
+ virtual bool FindFirst(char * _dir,DOS_DTA & dta,bool fcb_findfirst=false)=0;
+ virtual bool FindNext(DOS_DTA & dta)=0;
+ virtual bool GetFileAttr(char * name,Bit16u * attr)=0;
+ virtual bool GetFileAttrEx(char* name, struct stat *status)=0;
+ virtual DWORD GetCompressedSize(char* name)=0;
+ virtual HANDLE CreateOpenFile(char const* const name)=0;
+ virtual bool Rename(char * oldname,char * newname)=0;
+ virtual bool AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters)=0;
+ virtual bool FileExists(const char* name)=0;
+ virtual bool FileStat(const char* name, FileStat_Block * const stat_block)=0;
+ virtual Bit8u GetMediaByte(void)=0;
+ virtual void SetDir(const char* path) { strcpy(curdir,path); };
+ virtual void EmptyCache(void) { dirCache.EmptyCache(); };
+ virtual bool isRemote(void)=0;
+ virtual bool isRemovable(void)=0;
+ virtual bool isWriteProtected(void) = 0;
+ virtual Bits UnMount(void)=0;
+
+ char * GetInfo(void);
+ char curdir[DOS_PATHLENGTH];
+ char info[256];
+ /* Can be overridden for example in iso images */
+ virtual char const * GetLabel(){return dirCache.GetLabel();};
+
+ DOS_Drive_Cache dirCache;
+
+ // disk cycling functionality (request resources)
+ virtual void Activate(void) {};
+};
+
+enum { OPEN_READ=0, OPEN_WRITE=1, OPEN_READWRITE=2, OPEN_READ_NO_MOD=4, DOS_NOT_INHERIT=128};
+enum { DOS_SEEK_SET=0,DOS_SEEK_CUR=1,DOS_SEEK_END=2};
+
+
+/*
+ A multiplex handler should read the registers to check what function is being called
+ If the handler returns false dos will stop checking other handlers
+*/
+
+typedef bool (MultiplexHandler)(void);
+void DOS_AddMultiplexHandler(MultiplexHandler * handler);
+void DOS_DelMultiplexHandler(MultiplexHandler * handler);
+
+/* AddDevice stores the pointer to a created device */
+void DOS_AddDevice(DOS_Device * adddev);
+/* DelDevice destroys the device that is pointed to. */
+void DOS_DelDevice(DOS_Device * dev);
+
+void VFILE_Register(const char * name,Bit8u * data,Bit32u size);
+#endif
--- /dev/null
+/*\r
+ * Copyright (C) 2002-2017 The DOSBox Team\r
+ * Copyright (C) 2016 akm\r
+ * Copyright (C) 2019 takapyu\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+ */\r
+\r
+\r
+#ifndef DOSBOX_DOSBOX_H\r
+#define DOSBOX_DOSBOX_H\r
+\r
+#include "config.h"\r
+\r
+#define BUILD_VERSION "JP190520"\r
+#ifndef VERSION\r
+#define VERSION BUILD_VERSION\r
+#endif\r
+\r
+GCC_ATTRIBUTE(noreturn) void E_Exit(const char * message,...) GCC_ATTRIBUTE( __format__(__printf__, 1, 2));\r
+\r
+void MSG_Add(const char*,const char*); //add messages to the internal languagefile\r
+const char* MSG_Get(char const *); //get messages from the internal languagefile\r
+\r
+class Section;\r
+\r
+typedef Bitu (LoopHandler)(void);\r
+\r
+void DOSBOX_RunMachine();\r
+void DOSBOX_SetLoop(LoopHandler * handler);\r
+void DOSBOX_SetNormalLoop();\r
+\r
+void DOSBOX_Init(void);\r
+\r
+class Config;\r
+extern Config * control;\r
+\r
+enum MachineType {\r
+ MCH_HERC,\r
+ MCH_CGA,\r
+ MCH_TANDY,\r
+ MCH_PCJR,\r
+ MCH_EGA,\r
+ MCH_DCGA,\r
+ MCH_VGA\r
+};\r
+\r
+enum SVGACards {\r
+ SVGA_None,\r
+ SVGA_S3Trio,\r
+ SVGA_TsengET4K,\r
+ SVGA_TsengET3K,\r
+ SVGA_ParadisePVGA1A\r
+}; \r
+\r
+extern SVGACards svgaCard;\r
+extern MachineType machine;\r
+extern bool SDLNetInited, uselfn, autolfn;;\r
+\r
+#define IS_TANDY_ARCH ((machine==MCH_TANDY) || (machine==MCH_PCJR))\r
+#define IS_EGAVGA_ARCH ((machine==MCH_EGA) || (machine==MCH_VGA))\r
+#define IS_VGA_ARCH ((machine==MCH_VGA))\r
+#define TANDY_ARCH_CASE MCH_TANDY: case MCH_PCJR\r
+#define EGAVGA_ARCH_CASE MCH_EGA: case MCH_VGA\r
+#define VGA_ARCH_CASE MCH_VGA\r
+#define IS_AX_ARCH (machine==MCH_EGA)// upper compatible with EGA\r
+//#define IS_AX_ARCH (machine==MCH_AX)\r
+#define IS_J3_ARCH (machine==MCH_DCGA)\r
+\r
+#ifndef DOSBOX_LOGGING_H\r
+#include "logging.h"\r
+#endif // the logging system.\r
+\r
+#if !defined (WIN32)\r
+ typedef unsigned int DWORD;\r
+ typedef signed int HANDLE;\r
+#define INVALID_HANDLE_VALUE -1\r
+#endif\r
+\r
+#endif /* DOSBOX_DOSBOX_H */\r
--- /dev/null
+\r
+#ifndef DOSBOX_DOSV\r
+#define DOSBOX_DOSV\r
+\r
+#include "setup.h"\r
+\r
+enum DOSV_VTEXT_MODE {\r
+ DOSV_VGA, // 80x25\r
+ DOSV_VTEXT_VGA, // 80x30\r
+ DOSV_VTEXT_SVGA, // 100x37\r
+ DOSV_VTEXT_XGA, // 128x48\r
+ DOSV_VTEXT_XGA_24, // 85x32\r
+ DOSV_VTEXT_SXGA, // 160x64\r
+ DOSV_VTEXT_SXGA_24, // 106x42\r
+};\r
+\r
+enum DOSV_FONT {\r
+ DOSV_FONT_8X16,\r
+ DOSV_FONT_8X19,\r
+ DOSV_FONT_16X16,\r
+ DOSV_FONT_12X24,\r
+ DOSV_FONT_24X24,\r
+\r
+ DOSV_FONT_16X16_WRITE,\r
+ DOSV_FONT_24X24_WRITE,\r
+\r
+ DOSV_FONT_MAX\r
+};\r
+\r
+bool INT10_DOSV_SetCRTBIOSMode(Bitu mode);\r
+void DOSV_SetConfig(Section_prop *section);\r
+void DOSV_Setup();\r
+void DOSV_OffCursor();\r
+void INT8_DOSV();\r
+Bit16u DOSV_GetFontHandlerOffset(enum DOSV_FONT font);\r
+enum DOSV_VTEXT_MODE DOSV_GetVtextMode(Bitu no = 0);\r
+\r
+#endif\r
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_FPU_H
+#define DOSBOX_FPU_H
+
+#ifndef DOSBOX_MEM_H
+#include "mem.h"
+#endif
+
+void FPU_ESC0_Normal(Bitu rm);
+void FPU_ESC0_EA(Bitu func,PhysPt ea);
+void FPU_ESC1_Normal(Bitu rm);
+void FPU_ESC1_EA(Bitu func,PhysPt ea);
+void FPU_ESC2_Normal(Bitu rm);
+void FPU_ESC2_EA(Bitu func,PhysPt ea);
+void FPU_ESC3_Normal(Bitu rm);
+void FPU_ESC3_EA(Bitu func,PhysPt ea);
+void FPU_ESC4_Normal(Bitu rm);
+void FPU_ESC4_EA(Bitu func,PhysPt ea);
+void FPU_ESC5_Normal(Bitu rm);
+void FPU_ESC5_EA(Bitu func,PhysPt ea);
+void FPU_ESC6_Normal(Bitu rm);
+void FPU_ESC6_EA(Bitu func,PhysPt ea);
+void FPU_ESC7_Normal(Bitu rm);
+void FPU_ESC7_EA(Bitu func,PhysPt ea);
+
+
+typedef union {
+ double d;
+#ifndef WORDS_BIGENDIAN
+ struct {
+ Bit32u lower;
+ Bit32s upper;
+ } l;
+#else
+ struct {
+ Bit32s upper;
+ Bit32u lower;
+ } l;
+#endif
+ Bit64s ll;
+} FPU_Reg;
+
+typedef struct {
+ Bit32u m1;
+ Bit32u m2;
+ Bit16u m3;
+
+ Bit16u d1;
+ Bit32u d2;
+} FPU_P_Reg;
+
+enum FPU_Tag {
+ TAG_Valid = 0,
+ TAG_Zero = 1,
+ TAG_Weird = 2,
+ TAG_Empty = 3
+};
+
+enum FPU_Round {
+ ROUND_Nearest = 0,
+ ROUND_Down = 1,
+ ROUND_Up = 2,
+ ROUND_Chop = 3
+};
+
+typedef struct {
+ FPU_Reg regs[9];
+ FPU_P_Reg p_regs[9];
+ FPU_Tag tags[9];
+ Bit16u cw,cw_mask_all;
+ Bit16u sw;
+ Bit32u top;
+ FPU_Round round;
+} FPU_rec;
+
+
+//get pi from a real library
+#define PI 3.14159265358979323846
+#define L2E 1.4426950408889634
+#define L2T 3.3219280948873623
+#define LN2 0.69314718055994531
+#define LG2 0.3010299956639812
+
+
+extern FPU_rec fpu;
+
+#define TOP fpu.top
+#define STV(i) ( (fpu.top+ (i) ) & 7 )
+
+
+Bit16u FPU_GetTag(void);
+void FPU_FLDCW(PhysPt addr);
+
+static INLINE void FPU_SetTag(Bit16u tag){
+ for(Bitu i=0;i<8;i++)
+ fpu.tags[i] = static_cast<FPU_Tag>((tag >>(2*i))&3);
+}
+
+static INLINE void FPU_SetCW(Bitu word){
+ fpu.cw = (Bit16u)word;
+ fpu.cw_mask_all = (Bit16u)(word | 0x3f);
+ fpu.round = (FPU_Round)((word >> 10) & 3);
+}
+
+
+static INLINE Bitu FPU_GET_TOP(void) {
+ return (fpu.sw & 0x3800)>>11;
+}
+
+static INLINE void FPU_SET_TOP(Bitu val){
+ fpu.sw &= ~0x3800;
+ fpu.sw |= (val&7)<<11;
+}
+
+
+static INLINE void FPU_SET_C0(Bitu C){
+ fpu.sw &= ~0x0100;
+ if(C) fpu.sw |= 0x0100;
+}
+
+static INLINE void FPU_SET_C1(Bitu C){
+ fpu.sw &= ~0x0200;
+ if(C) fpu.sw |= 0x0200;
+}
+
+static INLINE void FPU_SET_C2(Bitu C){
+ fpu.sw &= ~0x0400;
+ if(C) fpu.sw |= 0x0400;
+}
+
+static INLINE void FPU_SET_C3(Bitu C){
+ fpu.sw &= ~0x4000;
+ if(C) fpu.sw |= 0x4000;
+}
+
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_HARDWARE_H
+#define DOSBOX_HARDWARE_H
+
+#include <stdio.h>
+
+class Section;
+enum OPL_Mode {
+ OPL_none,OPL_cms,OPL_opl2,OPL_dualopl2,OPL_opl3,OPL_opl3gold
+};
+#define CAPTURE_WAVE 0x01
+#define CAPTURE_OPL 0x02
+#define CAPTURE_MIDI 0x04
+#define CAPTURE_IMAGE 0x08
+#define CAPTURE_VIDEO 0x10
+
+extern Bitu CaptureState;
+
+void OPL_Init(Section* sec,OPL_Mode mode);
+void CMS_Init(Section* sec);
+void OPL_ShutDown(Section* sec);
+void CMS_ShutDown(Section* sec);
+
+bool SB_Get_Address(Bitu& sbaddr, Bitu& sbirq, Bitu& sbdma);
+bool TS_Get_Address(Bitu& tsaddr, Bitu& tsirq, Bitu& tsdma);
+
+extern Bit8u adlib_commandreg;
+FILE * OpenCaptureFile(const char * type,const char * ext);
+
+void CAPTURE_AddWave(Bit32u freq, Bit32u len, Bit16s * data);
+#define CAPTURE_FLAG_DBLW 0x1
+#define CAPTURE_FLAG_DBLH 0x2
+void CAPTURE_AddImage(Bitu width, Bitu height, Bitu bpp, Bitu pitch, Bitu flags, float fps, Bit8u * data, Bit8u * pal);
+void CAPTURE_AddMidi(bool sysex, Bitu len, Bit8u * data);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_INOUT_H
+#define DOSBOX_INOUT_H
+
+#define IO_MAX (64*1024+3)
+
+#define IO_MB 0x1
+#define IO_MW 0x2
+#define IO_MD 0x4
+#define IO_MA (IO_MB | IO_MW | IO_MD )
+
+typedef Bitu IO_ReadHandler(Bitu port,Bitu iolen);
+typedef void IO_WriteHandler(Bitu port,Bitu val,Bitu iolen);
+
+extern IO_WriteHandler * io_writehandlers[3][IO_MAX];
+extern IO_ReadHandler * io_readhandlers[3][IO_MAX];
+
+void IO_RegisterReadHandler(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range=1);
+void IO_RegisterWriteHandler(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range=1);
+
+void IO_FreeReadHandler(Bitu port,Bitu mask,Bitu range=1);
+void IO_FreeWriteHandler(Bitu port,Bitu mask,Bitu range=1);
+
+void IO_WriteB(Bitu port,Bitu val);
+void IO_WriteW(Bitu port,Bitu val);
+void IO_WriteD(Bitu port,Bitu val);
+
+Bitu IO_ReadB(Bitu port);
+Bitu IO_ReadW(Bitu port);
+Bitu IO_ReadD(Bitu port);
+
+/* Classes to manage the IO objects created by the various devices.
+ * The io objects will remove itself on destruction.*/
+class IO_Base{
+protected:
+ bool installed;
+ Bitu m_port, m_mask,m_range;
+public:
+ IO_Base():installed(false){};
+};
+class IO_ReadHandleObject: private IO_Base{
+public:
+ void Install(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range=1);
+ void Uninstall();
+ ~IO_ReadHandleObject();
+};
+class IO_WriteHandleObject: private IO_Base{
+public:
+ void Install(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range=1);
+ void Uninstall();
+ ~IO_WriteHandleObject();
+};
+
+static INLINE void IO_Write(Bitu port,Bit8u val) {
+ IO_WriteB(port,val);
+}
+static INLINE Bit8u IO_Read(Bitu port){
+ return (Bit8u)IO_ReadB(port);
+}
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_IPX_H
+#define DOSBOX_IPX_H
+
+// Uncomment this for a lot of debug messages:
+//#define IPX_DEBUGMSG
+
+#ifdef IPX_DEBUGMSG
+#define LOG_IPX LOG_MSG
+#else
+#if defined (_MSC_VER)
+#define LOG_IPX
+#else
+#define LOG_IPX(...)
+#endif
+#endif
+
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+#ifndef DOSBOX_MEM_H
+#include "mem.h"
+#endif
+
+// In Use Flag codes
+#define USEFLAG_AVAILABLE 0x00
+#define USEFLAG_AESTEMP 0xe0
+#define USEFLAG_IPXCRIT 0xf8
+#define USEFLAG_SPXLISTEN 0xf9
+#define USEFLAG_PROCESSING 0xfa
+#define USEFLAG_HOLDING 0xfb
+#define USEFLAG_AESWAITING 0xfc
+#define USEFLAG_AESCOUNT 0xfd
+#define USEFLAG_LISTENING 0xfe
+#define USEFLAG_SENDING 0xff
+
+// Completion codes
+#define COMP_SUCCESS 0x00
+#define COMP_REMOTETERM 0xec
+#define COMP_DISCONNECT 0xed
+#define COMP_INVALIDID 0xee
+#define COMP_SPXTABLEFULL 0xef
+#define COMP_EVENTNOTCANCELED 0xf9
+#define COMP_NOCONNECTION 0xfa
+#define COMP_CANCELLED 0xfc
+#define COMP_MALFORMED 0xfd
+#define COMP_UNDELIVERABLE 0xfe
+#define COMP_HARDWAREERROR 0xff
+
+#ifdef _MSC_VER
+#pragma pack(1)
+#endif
+
+// For Uint8 type
+#include "SDL_net.h"
+
+struct PackedIP {
+ Uint32 host;
+ Uint16 port;
+} GCC_ATTRIBUTE(packed);
+
+struct nodeType {
+ Uint8 node[6];
+} GCC_ATTRIBUTE(packed) ;
+
+struct IPXHeader {
+ Uint8 checkSum[2];
+ Uint8 length[2];
+ Uint8 transControl; // Transport control
+ Uint8 pType; // Packet type
+
+ struct transport {
+ Uint8 network[4];
+ union addrtype {
+ nodeType byNode;
+ PackedIP byIP ;
+ } GCC_ATTRIBUTE(packed) addr;
+ Uint8 socket[2];
+ } dest, src;
+} GCC_ATTRIBUTE(packed);
+
+struct fragmentDescriptor {
+ Bit16u offset;
+ Bit16u segment;
+ Bit16u size;
+};
+
+#define IPXBUFFERSIZE 1424
+
+class ECBClass {
+public:
+ RealPt ECBAddr;
+ bool isInESRList;
+ ECBClass *prevECB; // Linked List
+ ECBClass *nextECB;
+
+ Bit8u iuflag; // Need to save data since we are not always in
+ Bit16u mysocket; // real mode
+
+ Bit8u* databuffer; // received data is stored here until we get called
+ Bitu buflen; // by Interrupt
+
+#ifdef IPX_DEBUGMSG
+ Bitu SerialNumber;
+#endif
+
+ ECBClass(Bit16u segment, Bit16u offset);
+ Bit16u getSocket(void);
+
+ Bit8u getInUseFlag(void);
+
+ void setInUseFlag(Bit8u flagval);
+
+ void setCompletionFlag(Bit8u flagval);
+
+ Bit16u getFragCount(void);
+
+ bool writeData();
+ void writeDataBuffer(Bit8u* buffer, Bit16u length);
+
+ void getFragDesc(Bit16u descNum, fragmentDescriptor *fragDesc);
+ RealPt getESRAddr(void);
+
+ void NotifyESR(void);
+
+ void setImmAddress(Bit8u *immAddr);
+ void getImmAddress(Bit8u* immAddr);
+
+ ~ECBClass();
+};
+
+// The following routines may not be needed on all systems. On my build of SDL the IPaddress structure is 8 octects
+// and therefore screws up my IPXheader structure since it needs to be packed.
+
+void UnpackIP(PackedIP ipPack, IPaddress * ipAddr);
+void PackIP(IPaddress ipAddr, PackedIP *ipPack);
+
+#ifdef _MSC_VER
+#pragma pack()
+#endif
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_IPXSERVER_H_
+#define DOSBOX_IPXSERVER_H_
+
+#if C_IPX
+
+#include "SDL_net.h"
+
+struct packetBuffer {
+ Bit8u buffer[1024];
+ Bit16s packetSize; // Packet size remaining in read
+ Bit16s packetRead; // Bytes read of total packet
+ bool inPacket; // In packet reception flag
+ bool connected; // Connected flag
+ bool waitsize;
+};
+
+#define SOCKETTABLESIZE 16
+#define CONVIP(hostvar) hostvar & 0xff, (hostvar >> 8) & 0xff, (hostvar >> 16) & 0xff, (hostvar >> 24) & 0xff
+#define CONVIPX(hostvar) hostvar[0], hostvar[1], hostvar[2], hostvar[3], hostvar[4], hostvar[5]
+
+
+void IPX_StopServer();
+bool IPX_StartServer(Bit16u portnum);
+bool IPX_isConnectedToServer(Bits tableNum, IPaddress ** ptrAddr);
+
+Bit8u packetCRC(Bit8u *buffer, Bit16u bufSize);
+
+#endif
+
+#endif
--- /dev/null
+\r
+#ifndef DOSBOX_J3_H\r
+#define DOSBOX_J3_H\r
+\r
+#ifndef DOSBOX_DOSBOX_H\r
+#include "dosbox.h"\r
+#endif\r
+\r
+#include "control.h"\r
+\r
+/* AX Global Area */\r
+#define BIOSMEM_J3_SEG 0x40\r
+\r
+#define BIOSMEM_J3_MODE 0xD0\r
+#define BIOSMEM_J3_LINE_COUNT 0xD4\r
+#define BIOSMEM_J3_GRAPH_ADDR 0xD6\r
+#define BIOSMEM_J3_CODE_SEG 0xDA\r
+#define BIOSMEM_J3_CODE_OFFSET 0xD8\r
+#define BIOSMEM_J3_SCROLL 0xE2\r
+#define BIOSMEM_J3_BLINK 0xE9\r
+\r
+#define GRAPH_J3_SEG 0xb800\r
+\r
+//int10_j3.cpp\r
+bool INT10_J3_SetCRTBIOSMode(Bitu mode);\r
+Bitu INT60_Handler(void);\r
+Bitu INT6F_Handler(void);\r
+void INT60_J3_Setup();\r
+void INT8_J3();\r
+void J3_OffCursor();\r
+void J3_SetConfig(Section_prop *section);\r
+void J3_GetPalette(Bit8u no, Bit8u &r, Bit8u &g, Bit8u &b);\r
+Bit16u J3_GetMachineCode();\r
+bool J3_IsJapanese();\r
+\r
+#endif\r
--- /dev/null
+\r
+#ifndef DOSBOX_JEGA\r
+#define DOSBOX_JEGA\r
+\r
+#ifndef DOSBOX_DOSBOX_H\r
+#include "dosbox.h"\r
+#endif\r
+\r
+/* AX Global Area */\r
+#define BIOSMEM_AX_SEG 0x40\r
+\r
+#define BIOSMEM_AX_VTRAM_SEGADDR 0xE0\r
+#define BIOSMEM_AX_GRAPH_CHAR 0xE2\r
+#define BIOSMEM_AX_GRAPH_ATTR 0xE3\r
+#define BIOSMEM_AX_JPNSTATUS 0xE4\r
+#define BIOSMEM_AX_JEGA_RMOD1 0xE9\r
+#define BIOSMEM_AX_JEGA_RMOD2 0xEA\r
+#define BIOSMEM_AX_KBDSTATUS 0xEB\r
+\r
+#define BIOS_KEYBOARD_AX_KBDSTATUS 0x4EB\r
+/* 40h:EBh Keyboard Additional Status bits\r
+ bit 2 : Kana holding\r
+ bit 1 : Kana Lock key\r
+ bit 0 : Kana LED indicating\r
+*/\r
+\r
+/* JEGA internal registers */\r
+typedef struct {\r
+ Bitu RMOD1//b9: Mode register 1\r
+ , RMOD2//ba: Mode register 2\r
+ , RDAGS//bb: ANK Group sel (not implemented)\r
+ , RDFFB//bc: Font access first byte\r
+ , RDFSB//bd: Font access second byte\r
+ , RDFAP//be: Font Access Pattern\r
+ , RPESL//09: end scan line (superceded by EGA)\r
+ , RPULP//14: under scan line (superceded by EGA)\r
+ , RPSSC//db: DBCS start scan line\r
+ , RPSSU//d9: 2x DBCS upper start scan\r
+ , RPSSL//da: 2x DBCS lower start scan\r
+ , RPPAJ//dc: super imposed (only AX-2 system, not implemented)\r
+ , RCMOD//dd: Cursor Mode (not implemented)\r
+ , RCCLH//0e: Cursor location Upper bits (superceded by EGA)\r
+ , RCCLL//0f: Cursor location Lower bits (superceded by EGA)\r
+ , RCCSL//0a: Cursor Start Line (superceded by EGA)\r
+ , RCCEL//0b: Cursor End Line (superceded by EGA)\r
+ , RCSKW//de: Cursor Skew control (not implemented)\r
+ , ROMSL//df: Unused?\r
+ , RSTAT//bf: Font register accessible status\r
+ ;\r
+ Bitu fontIndex = 0;\r
+} JEGA_DATA;\r
+\r
+extern JEGA_DATA jega;\r
+\r
+//jfontload.cpp\r
+extern Bit8u jfont_sbcs_19[];\r
+extern Bit8u jfont_dbcs_16[];\r
+extern Bit8u jfont_cache_dbcs_16[];\r
+// for J-3100\r
+extern Bit8u jfont_sbcs_16[];\r
+extern Bit8u jfont_dbcs_24[];\r
+extern Bit8u jfont_sbcs_24[];\r
+\r
+//vga_jega.cpp\r
+void SVGA_Setup_JEGA(void);//Init JEGA and AX system area\r
+\r
+//int10_ax.cpp\r
+bool INT10_AX_SetCRTBIOSMode(Bitu mode);\r
+Bitu INT10_AX_GetCRTBIOSMode(void);\r
+bool INT16_AX_SetKBDBIOSMode(Bitu mode);\r
+Bitu INT16_AX_GetKBDBIOSMode(void);\r
+\r
+//int10_char.cpp\r
+extern Bit8u prevchr;\r
+void ReadVTRAMChar(Bit16u col, Bit16u row, Bit16u * result);\r
+void SetVTRAMChar(Bit16u col, Bit16u row, Bit8u chr, Bit8u attr);\r
+void WriteCharJ(Bit16u col, Bit16u row, Bit8u page, Bit8u chr, Bit8u attr, bool useattr);\r
+\r
+//inline functions\r
+inline bool isKanji1(Bit8u chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); }\r
+inline bool isKanji2(Bit8u chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); }\r
+inline bool isJEGAEnabled() {\r
+ if (!IS_AX_ARCH) return false;\r
+ return !(jega.RMOD1 & 0x40);\r
+}\r
+\r
+#endif\r
--- /dev/null
+\r
+#ifndef DOSBOX_JFONT_H\r
+#define DOSBOX_JFONT_H\r
+\r
+#include "setup.h"\r
+\r
+#define VIRTUAL_TEXT_SIZE 0x500\r
+\r
+void InitFontHandle();\r
+void QuitFont();\r
+bool GetWindowsFont(Bitu code, Bit8u *buff, int width, int height);\r
+Bit16u GetTextSeg();\r
+void SetTextSeg();\r
+bool MakeSbcs19Font();\r
+bool MakeSbcs16Font();\r
+bool MakeSbcs24Font();\r
+Bit8u GetKanjiAttr(Bitu x, Bitu y);\r
+Bit8u GetKanjiAttr();\r
+Bit8u *GetSbcsFont(Bitu code);\r
+Bit8u *GetSbcs19Font(Bitu code);\r
+Bit8u *GetSbcs24Font(Bitu code);\r
+void SetFontName(const char *name);\r
+void GetDbcsFrameFont(Bitu code, Bit8u *buff);\r
+Bit8u *GetDbcsFont(Bitu code);\r
+Bit8u *GetDbcs24Font(Bitu code);\r
+bool CheckStayVz();\r
+bool CheckAnotherDisplayDriver();\r
+Bit16u GetGaijiSeg();\r
+void SetGaijiConfig(Section_prop *section);\r
+bool SetGaijiData(Bit16u code, PhysPt data);\r
+bool SetGaijiData24(Bit16u code, PhysPt data);\r
+\r
+#ifdef NDEBUG\r
+#define JTrace\r
+#else\r
+void JTrace(const char *form , ...);\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_JOYSTICK_H
+#define DOSBOX_JOYSTICK_H
+void JOYSTICK_Enable(Bitu which,bool enabled);
+
+void JOYSTICK_Button(Bitu which,Bitu num,bool pressed);
+
+void JOYSTICK_Move_X(Bitu which,float x);
+
+void JOYSTICK_Move_Y(Bitu which,float y);
+
+bool JOYSTICK_IsEnabled(Bitu which);
+
+bool JOYSTICK_GetButton(Bitu which, Bitu num);
+
+float JOYSTICK_GetMove_X(Bitu which);
+
+float JOYSTICK_GetMove_Y(Bitu which);
+
+enum JoystickType {
+ JOY_NONE,
+ JOY_AUTO,
+ JOY_2AXIS,
+ JOY_4AXIS,
+ JOY_4AXIS_2,
+ JOY_FCS,
+ JOY_CH
+};
+
+extern JoystickType joytype;
+extern bool button_wrapping_enabled;
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2002-2015 The DOSBox Team\r
+ * Copyright (C) 2016 akm
+ *
+ * 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 DOSBOX_KEYBOARD_H
+#define DOSBOX_KEYBOARD_H
+
+enum KBD_KEYS {
+ KBD_NONE,
+ KBD_1, KBD_2, KBD_3, KBD_4, KBD_5, KBD_6, KBD_7, KBD_8, KBD_9, KBD_0,
+ KBD_q, KBD_w, KBD_e, KBD_r, KBD_t, KBD_y, KBD_u, KBD_i, KBD_o, KBD_p,
+ KBD_a, KBD_s, KBD_d, KBD_f, KBD_g, KBD_h, KBD_j, KBD_k, KBD_l, KBD_z,
+ KBD_x, KBD_c, KBD_v, KBD_b, KBD_n, KBD_m,
+ KBD_f1, KBD_f2, KBD_f3, KBD_f4, KBD_f5, KBD_f6, KBD_f7, KBD_f8, KBD_f9, KBD_f10,KBD_f11,KBD_f12,
+
+ /*Now the weirder keys */
+
+ KBD_esc,KBD_tab,KBD_backspace,KBD_enter,KBD_space,
+ KBD_leftalt,KBD_rightalt,KBD_leftctrl,KBD_rightctrl,KBD_leftshift,KBD_rightshift,
+ KBD_capslock,KBD_scrolllock,KBD_numlock,
+
+ KBD_grave,KBD_minus,KBD_equals,KBD_backslash,KBD_leftbracket,KBD_rightbracket,
+ KBD_semicolon,KBD_quote,KBD_period,KBD_comma,KBD_slash,KBD_extra_lt_gt,
+
+ KBD_printscreen,KBD_pause,
+ KBD_insert,KBD_home,KBD_pageup,KBD_delete,KBD_end,KBD_pagedown,
+ KBD_left,KBD_up,KBD_down,KBD_right,
+
+ KBD_kp1,KBD_kp2,KBD_kp3,KBD_kp4,KBD_kp5,KBD_kp6,KBD_kp7,KBD_kp8,KBD_kp9,KBD_kp0,
+ KBD_kpdivide,KBD_kpmultiply,KBD_kpminus,KBD_kpplus,KBD_kpenter,KBD_kpperiod,\r
+ KBD_yen, KBD_underscore,//JP layout
+ KBD_ax,KBD_conv,KBD_nconv, // for AX
+\r
+ KBD_f13,KBD_f14,KBD_f15,
+\r
+ KBD_LAST
+};
+
+void KEYBOARD_ClrBuffer(void);
+void KEYBOARD_AddKey(KBD_KEYS keytype,bool pressed);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_LOGGING_H
+#define DOSBOX_LOGGING_H
+enum LOG_TYPES {
+ LOG_ALL,
+ LOG_VGA, LOG_VGAGFX,LOG_VGAMISC,LOG_INT10,
+ LOG_SB,LOG_DMACONTROL,
+ LOG_FPU,LOG_CPU,LOG_PAGING,
+ LOG_FCB,LOG_FILES,LOG_IOCTL,LOG_EXEC,LOG_DOSMISC,
+ LOG_PIT,LOG_KEYBOARD,LOG_PIC,
+ LOG_MOUSE,LOG_BIOS,LOG_GUI,LOG_MISC,
+ LOG_IO,
+ LOG_PCI,
+ LOG_MAX
+};
+
+enum LOG_SEVERITIES {
+ LOG_NORMAL,
+ LOG_WARN,
+ LOG_ERROR
+};
+
+#if C_DEBUG
+class LOG
+{
+ LOG_TYPES d_type;
+ LOG_SEVERITIES d_severity;
+public:
+
+ LOG (LOG_TYPES type , LOG_SEVERITIES severity):
+ d_type(type),
+ d_severity(severity)
+ {}
+ void operator() (char const* buf, ...) GCC_ATTRIBUTE(__format__(__printf__, 2, 3)); //../src/debug/debug_gui.cpp
+
+};
+
+void DEBUG_ShowMsg(char const* format,...) GCC_ATTRIBUTE(__format__(__printf__, 1, 2));
+#define LOG_MSG DEBUG_ShowMsg
+
+#else //C_DEBUG
+
+struct LOG
+{
+ LOG(LOG_TYPES , LOG_SEVERITIES ) { }
+ void operator()(char const* ) { }
+ void operator()(char const* , double ) { }
+ void operator()(char const* , double , double ) { }
+ void operator()(char const* , double , double , double ) { }
+ void operator()(char const* , double , double , double , double ) { }
+ void operator()(char const* , double , double , double , double , double ) { }
+ void operator()(char const* , double , double , double , double , double , double ) { }
+ void operator()(char const* , double , double , double , double , double , double , double) { }
+
+
+
+ void operator()(char const* , char const* ) { }
+ void operator()(char const* , char const* , double ) { }
+ void operator()(char const* , char const* , double ,double ) { }
+ void operator()(char const* , double , char const* ) { }
+ void operator()(char const* , double , double, char const* ) { }
+ void operator()(char const* , char const*, char const*) { }
+
+ void operator()(char const* , double , double , double , char const* ) { }
+}; //add missing operators to here
+ //try to avoid anything smaller than bit32...
+void GFX_ShowMsg(char const* format,...) GCC_ATTRIBUTE(__format__(__printf__, 1, 2));
+#define LOG_MSG GFX_ShowMsg
+
+#endif //C_DEBUG
+
+
+#endif //DOSBOX_LOGGING_H
--- /dev/null
+ /*
+ * 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.
+ */
+
+#ifndef DOSBOX_MAPPER_H
+#define DOSBOX_MAPPER_H
+
+enum MapKeys {
+ MK_f1,MK_f2,MK_f3,MK_f4,MK_f5,MK_f6,MK_f7,MK_f8,MK_f9,MK_f10,MK_f11,MK_f12,
+ MK_return,MK_kpminus,MK_scrolllock,MK_printscreen,MK_pause,MK_home
+
+};
+
+typedef void (MAPPER_Handler)(bool pressed);
+void MAPPER_AddHandler(MAPPER_Handler * handler,MapKeys key,Bitu mods,char const * const eventname,char const * const buttonname);
+void MAPPER_Init(void);
+void MAPPER_StartUp(Section * sec);
+void MAPPER_Run(bool pressed);
+void MAPPER_RunInternal();
+void MAPPER_LosingFocus(void);
+
+
+#define MMOD1 0x1
+#define MMOD2 0x2
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_MEM_H
+#define DOSBOX_MEM_H
+
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+
+typedef Bit32u PhysPt;
+typedef Bit8u * HostPt;
+typedef Bit32u RealPt;
+
+typedef Bit32s MemHandle;
+
+#define MEM_PAGESIZE 4096
+
+extern HostPt MemBase;
+HostPt GetMemBase(void);
+
+bool MEM_A20_Enabled(void);
+void MEM_A20_Enable(bool enable);
+
+/* Memory management / EMS mapping */
+HostPt MEM_GetBlockPage(void);
+Bitu MEM_FreeTotal(void); //Free 4 kb pages
+Bitu MEM_FreeLargest(void); //Largest free 4 kb pages block
+Bitu MEM_TotalPages(void); //Total amount of 4 kb pages
+Bitu MEM_AllocatedPages(MemHandle handle); // amount of allocated pages of handle
+MemHandle MEM_AllocatePages(Bitu pages,bool sequence);
+MemHandle MEM_GetNextFreePage(void);
+PhysPt MEM_AllocatePage(void);
+void MEM_ReleasePages(MemHandle handle);
+bool MEM_ReAllocatePages(MemHandle & handle,Bitu pages,bool sequence);
+
+MemHandle MEM_NextHandle(MemHandle handle);
+MemHandle MEM_NextHandleAt(MemHandle handle,Bitu where);
+
+/*
+ The folowing six functions are used everywhere in the end so these should be changed for
+ Working on big or little endian machines
+*/
+
+#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY)
+
+static INLINE Bit8u host_readb(HostPt off) {
+ return off[0];
+}
+static INLINE Bit16u host_readw(HostPt off) {
+ return off[0] | (off[1] << 8);
+}
+static INLINE Bit32u host_readd(HostPt off) {
+ return off[0] | (off[1] << 8) | (off[2] << 16) | (off[3] << 24);
+}
+static INLINE void host_writeb(HostPt off,Bit8u val) {
+ off[0]=val;
+}
+static INLINE void host_writew(HostPt off,Bit16u val) {
+ off[0]=(Bit8u)(val);
+ off[1]=(Bit8u)(val >> 8);
+}
+static INLINE void host_writed(HostPt off,Bit32u val) {
+ off[0]=(Bit8u)(val);
+ off[1]=(Bit8u)(val >> 8);
+ off[2]=(Bit8u)(val >> 16);
+ off[3]=(Bit8u)(val >> 24);
+}
+
+#else
+
+static INLINE Bit8u host_readb(HostPt off) {
+ return *(Bit8u *)off;
+}
+static INLINE Bit16u host_readw(HostPt off) {
+ return *(Bit16u *)off;
+}
+static INLINE Bit32u host_readd(HostPt off) {
+ return *(Bit32u *)off;
+}
+static INLINE void host_writeb(HostPt off,Bit8u val) {
+ *(Bit8u *)(off)=val;
+}
+static INLINE void host_writew(HostPt off,Bit16u val) {
+ *(Bit16u *)(off)=val;
+}
+static INLINE void host_writed(HostPt off,Bit32u val) {
+ *(Bit32u *)(off)=val;
+}
+
+#endif
+
+
+static INLINE void var_write(Bit8u * var, Bit8u val) {
+ host_writeb((HostPt)var, val);
+}
+
+static INLINE void var_write(Bit16u * var, Bit16u val) {
+ host_writew((HostPt)var, val);
+}
+
+static INLINE void var_write(Bit32u * var, Bit32u val) {
+ host_writed((HostPt)var, val);
+}
+
+/* The Folowing six functions are slower but they recognize the paged memory system */
+
+Bit8u mem_readb(PhysPt pt);
+Bit16u mem_readw(PhysPt pt);
+Bit32u mem_readd(PhysPt pt);
+
+void mem_writeb(PhysPt pt,Bit8u val);
+void mem_writew(PhysPt pt,Bit16u val);
+void mem_writed(PhysPt pt,Bit32u val);
+
+static INLINE void phys_writeb(PhysPt addr,Bit8u val) {
+ host_writeb(MemBase+addr,val);
+}
+static INLINE void phys_writew(PhysPt addr,Bit16u val){
+ host_writew(MemBase+addr,val);
+}
+static INLINE void phys_writed(PhysPt addr,Bit32u val){
+ host_writed(MemBase+addr,val);
+}
+
+static INLINE Bit8u phys_readb(PhysPt addr) {
+ return host_readb(MemBase+addr);
+}
+static INLINE Bit16u phys_readw(PhysPt addr){
+ return host_readw(MemBase+addr);
+}
+static INLINE Bit32u phys_readd(PhysPt addr){
+ return host_readd(MemBase+addr);
+}
+
+/* These don't check for alignment, better be sure it's correct */
+
+void MEM_BlockWrite(PhysPt pt,void const * const data,Bitu size);
+void MEM_BlockRead(PhysPt pt,void * data,Bitu size);
+void MEM_BlockCopy(PhysPt dest,PhysPt src,Bitu size);
+void MEM_StrCopy(PhysPt pt,char * data,Bitu size);
+
+void mem_memcpy(PhysPt dest,PhysPt src,Bitu size);
+Bitu mem_strlen(PhysPt pt);
+void mem_strcpy(PhysPt dest,PhysPt src);
+
+/* The folowing functions are all shortcuts to the above functions using physical addressing */
+
+static INLINE Bit8u real_readb(Bit16u seg,Bit16u off) {
+ return mem_readb((seg<<4)+off);
+}
+static INLINE Bit16u real_readw(Bit16u seg,Bit16u off) {
+ return mem_readw((seg<<4)+off);
+}
+static INLINE Bit32u real_readd(Bit16u seg,Bit16u off) {
+ return mem_readd((seg<<4)+off);
+}
+
+static INLINE void real_writeb(Bit16u seg,Bit16u off,Bit8u val) {
+ mem_writeb(((seg<<4)+off),val);
+}
+static INLINE void real_writew(Bit16u seg,Bit16u off,Bit16u val) {
+ mem_writew(((seg<<4)+off),val);
+}
+static INLINE void real_writed(Bit16u seg,Bit16u off,Bit32u val) {
+ mem_writed(((seg<<4)+off),val);
+}
+
+
+static INLINE Bit16u RealSeg(RealPt pt) {
+ return (Bit16u)(pt>>16);
+}
+
+static INLINE Bit16u RealOff(RealPt pt) {
+ return (Bit16u)(pt&0xffff);
+}
+
+static INLINE PhysPt Real2Phys(RealPt pt) {
+ return (RealSeg(pt)<<4) +RealOff(pt);
+}
+
+static INLINE PhysPt PhysMake(Bit16u seg,Bit16u off) {
+ return (seg<<4)+off;
+}
+
+static INLINE RealPt RealMake(Bit16u seg,Bit16u off) {
+ return (seg<<16)+off;
+}
+
+static INLINE void RealSetVec(Bit8u vec,RealPt pt) {
+ mem_writed(vec<<2,pt);
+}
+
+static INLINE void RealSetVec(Bit8u vec,RealPt pt,RealPt &old) {
+ old = mem_readd(vec<<2);
+ mem_writed(vec<<2,pt);
+}
+
+static INLINE RealPt RealGetVec(Bit8u vec) {
+ return mem_readd(vec<<2);
+}
+
+#endif
+
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_MIDI_H
+#define DOSBOX_MIDI_H
+
+#ifndef DOSBOX_PROGRAMS_H
+#include "programs.h"
+#endif
+
+class MidiHandler {
+public:
+ MidiHandler();
+ virtual bool Open(const char * /*conf*/) { return true; };
+ virtual void Close(void) {};
+ virtual void PlayMsg(Bit8u * /*msg*/) {};
+ virtual void PlaySysex(Bit8u * /*sysex*/,Bitu /*len*/) {};
+ virtual const char * GetName(void) { return "none"; };
+ virtual void ListAll(Program * base) {};
+ virtual ~MidiHandler() { };
+ MidiHandler * next;
+};
+
+
+#define SYSEX_SIZE 8192
+struct DB_Midi {
+ Bitu status;
+ Bitu cmd_len;
+ Bitu cmd_pos;
+ Bit8u cmd_buf[8];
+ Bit8u rt_buf[8];
+ struct {
+ Bit8u buf[SYSEX_SIZE];
+ Bitu used;
+ Bitu delay;
+ Bit32u start;
+ } sysex;
+ bool available;
+ MidiHandler * handler;
+};
+
+extern DB_Midi midi;
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_MIXER_H
+#define DOSBOX_MIXER_H
+
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+
+typedef void (*MIXER_MixHandler)(Bit8u * sampdate,Bit32u len);
+typedef void (*MIXER_Handler)(Bitu len);
+
+enum BlahModes {
+ MIXER_8MONO,MIXER_8STEREO,
+ MIXER_16MONO,MIXER_16STEREO
+};
+
+enum MixerModes {
+ M_8M,M_8S,
+ M_16M,M_16S
+};
+
+#define MIXER_BUFSIZE (16*1024)
+#define MIXER_BUFMASK (MIXER_BUFSIZE-1)
+extern Bit8u MixTemp[MIXER_BUFSIZE];
+
+#define MAX_AUDIO ((1<<(16-1))-1)
+#define MIN_AUDIO -(1<<(16-1))
+
+class MixerChannel {
+public:
+ void SetVolume(float _left,float _right);
+ void SetScale( float f );
+ void UpdateVolume(void);
+ void SetFreq(Bitu _freq);
+ void Mix(Bitu _needed);
+ void AddSilence(void); //Fill up until needed
+
+ template<class Type,bool stereo,bool signeddata,bool nativeorder>
+ void AddSamples(Bitu len, const Type* data);
+
+ void AddSamples_m8(Bitu len, const Bit8u * data);
+ void AddSamples_s8(Bitu len, const Bit8u * data);
+ void AddSamples_m8s(Bitu len, const Bit8s * data);
+ void AddSamples_s8s(Bitu len, const Bit8s * data);
+ void AddSamples_m16(Bitu len, const Bit16s * data);
+ void AddSamples_s16(Bitu len, const Bit16s * data);
+ void AddSamples_m16u(Bitu len, const Bit16u * data);
+ void AddSamples_s16u(Bitu len, const Bit16u * data);
+ void AddSamples_m32(Bitu len, const Bit32s * data);
+ void AddSamples_s32(Bitu len, const Bit32s * data);
+ void AddSamples_m16_nonnative(Bitu len, const Bit16s * data);
+ void AddSamples_s16_nonnative(Bitu len, const Bit16s * data);
+ void AddSamples_m16u_nonnative(Bitu len, const Bit16u * data);
+ void AddSamples_s16u_nonnative(Bitu len, const Bit16u * data);
+ void AddSamples_m32_nonnative(Bitu len, const Bit32s * data);
+ void AddSamples_s32_nonnative(Bitu len, const Bit32s * data);
+
+ void AddStretched(Bitu len,Bit16s * data); //Strech block up into needed data
+ void FillUp(void);
+ void Enable(bool _yesno);
+ MIXER_Handler handler;
+ float volmain[2];
+ float scale;
+ Bit32s volmul[2];
+ Bitu freq_add,freq_index;
+ Bitu done,needed;
+ Bits last[2];
+ const char * name;
+ bool enabled;
+ MixerChannel * next;
+};
+
+MixerChannel * MIXER_AddChannel(MIXER_Handler handler,Bitu freq,const char * name);
+MixerChannel * MIXER_FindChannel(const char * name);
+/* Find the device you want to delete with findchannel "delchan gets deleted" */
+void MIXER_DelChannel(MixerChannel* delchan);
+
+/* Object to maintain a mixerchannel; As all objects it registers itself with create
+ * and removes itself when destroyed. */
+class MixerObject{
+private:
+ bool installed;
+ char m_name[32];
+public:
+ MixerObject():installed(false){};
+ MixerChannel* Install(MIXER_Handler handler,Bitu freq,const char * name);
+ ~MixerObject();
+};
+
+
+/* PC Speakers functions, tightly related to the timer functions */
+void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode);
+void PCSPEAKER_SetType(Bitu mode);
+
+#endif
--- /dev/null
+/* Standard data types used */
+
+typedef unsigned char Bit8u;
+typedef signed char Bit8s;
+typedef unsigned short Bit16u;
+typedef signed short Bit16s;
+typedef unsigned long Bit32u;
+typedef signed long Bit32s;
+#if defined(_MSC_VER)
+typedef unsigned __int64 Bit64u;
+typedef signed __int64 Bit64s;
+#else
+typedef unsigned long long int Bit64u;
+typedef signed long long int Bit64s;
+#endif
+
+
+
+/* Setting up pointers to all subfunctions */
+#ifdef MODULE_WANT_IO_READ
+typedef Bit8u (* IO_ReadHandler)(Bit32u port);
+static void (* IO_RegisterReadHandler)(Bit32u port,IO_ReadHandler handler,char * name);
+static void (* IO_FreeReadHandler)(Bit32u port);
+#endif
+
+#ifdef MODULE_WANT_IO_WRITE
+typedef void (* IO_WriteHandler)(Bit32u port,Bit8u value);
+static void (* IO_RegisterWriteHandler)(Bit32u port,IO_WriteHandler handler,char * name);
+static void (* IO_FreeWriteHandler)(Bit32u port);
+#endif
+
+#ifdef MODULE_WANT_IRQ_EOI
+typedef void (* IRQ_EOIHandler)(void);
+static void (* IRQ_RegisterEOIHandler)(Bit32u irq,IRQ_EOIHandler handler,char * name);
+static void (* IRQ_FreeEOIHandler)(Bit32u irq);
+#endif
+
+#ifdef MODULE_WANT_IRQ
+static void (* IRQ_Activate)(Bit32u irq);
+static void (* IRQ_Deactivate)(Bit32u irq);
+#endif
+
+#ifdef MODULE_WANT_TIMER
+typedef void (* TIMER_MicroHandler)(void);
+static void (* TIMER_RegisterMicroHandler)(TIMER_MicroHandler handler,Bit32u micro);
+#endif
+
+#ifdef MODULE_WANT_TIMER_TICK
+typedef void (* TIMER_TickHandler)(Bit32u ticks);
+static void (* TIMER_RegisterTickHandler)(TIMER_TickHandler handler);
+#endif
+
+/*
+ 4 8-bit and 4 16-bit channels you can read data from
+ 16-bit reads are word sized
+*/
+
+#ifdef MODULE_WANT_DMA_READ
+static void (* DMA_8_Read)(Bit32u chan,Bit8u * data,Bit16u size);
+static void (* DMA_16_Read)(Bit32u chan,Bit8u * data,Bit16u size);
+#endif
+
+/*
+ 4 8-bit and 4 16-bit channels you can write data from
+ 16-bit writes are word sized
+*/
+
+#ifdef MODULE_WANT_DMA_READ
+static void (* DMA_8_Write)(Bit32u chan,Bit8u * data,Bit16u size);
+static void (* DMA_16_Write)(Bit32u chan,Bit8u * data,Bit16u size);
+#endif
+
+
+#ifdef MODULE_WANT_MIXER
+/* The len here means the amount of samples needed not the buffersize it needed to fill */
+typedef void (* MIXER_MixHandler)(Bit8u * sampdate,Bit32u len);
+
+/* Different types if modes a mixer channel can work in */
+#define MIXER_8MONO 0
+#define MIXER_8STEREO 1
+#define MIXER_16MONO 2
+#define MIXER_16STEREO 3
+struct MIXER_Channel;
+
+#define MAX_AUDIO ((1<<(16-1))-1)
+#define MIN_AUDIO -(1<<(16-1))
+
+MIXER_Channel *(* MIXER_AddChannel)(MIXER_MixHandler handler,Bit32u freq,char * name);
+void (* MIXER_SetVolume)(MIXER_Channel * chan,Bit8u vol);
+void (* MIXER_SetFreq)(MIXER_Channel * chan,Bit32u freq);
+void (* MIXER_SetMode)(MIXER_Channel * chan,Bit8u mode);
+void (* MIXER_Enable)(MIXER_Channel * chan,bool enable);
+#endif
+
+typedef bool (* MODULE_FindHandler)(char * name,void * * function);
+typedef char *(* MODULE_StartHandler)(MODULE_FindHandler find_handler);
+
+#define MODULE_START_PROC "ModuleStart"
+
+#ifdef MODULE_START_FUNCTION
+#include <stdio.h>
+
+#define GET_FUNCTION(a) \
+ if (!find_handler(#a ,(void * *) &a)) { \
+ return "Can't find requested function"; \
+ };
+
+
+#if defined (WIN32)
+#include <windows.h>
+BOOL APIENTRY DllMain( HANDLE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ return TRUE;
+}
+
+extern "C" {
+__declspec(dllexport)
+#endif
+char * ModuleStart (MODULE_FindHandler find_handler) {
+
+#ifdef MODULE_WANT_IRQ_EOI
+GET_FUNCTION(IRQ_RegisterEOIHandler);
+GET_FUNCTION(IRQ_FreeEOIHandler);
+#endif
+
+#ifdef MODULE_WANT_IRQ
+GET_FUNCTION(IRQ_Activate);
+GET_FUNCTION(IRQ_Deactivate);
+#endif
+
+#ifdef MODULE_WANT_IO_READ
+GET_FUNCTION(IO_RegisterReadHandler);
+GET_FUNCTION(IO_FreeReadHandler);
+#endif
+
+#ifdef MODULE_WANT_IO_WRITE
+GET_FUNCTION(IO_RegisterWriteHandler);
+GET_FUNCTION(IO_FreeWriteHandler);
+#endif
+
+#ifdef MODULE_WANT_TIMER
+GET_FUNCTION(TIMER_RegisterMicroHandler);
+#endif
+
+#ifdef MODULE_WANT_TIMER_TICKS
+GET_FUNCTION(TIMER_RegisterTickHandler);
+#endif
+
+#ifdef MODULE_WANT_DMA_READ
+GET_FUNCTION(DMA_8_Read);
+GET_FUNCTION(DMA_16_Read);
+#endif
+
+#ifdef MODULE_WANT_DMA_WRITE
+GET_FUNCTION(DMA_8_Write);
+GET_FUNCTION(DMA_16_Write);
+#endif
+
+#ifdef MODULE_WANT_MIXER
+GET_FUNCTION(MIXER_AddChannel);
+GET_FUNCTION(MIXER_SetVolume);
+GET_FUNCTION(MIXER_SetFreq);
+GET_FUNCTION(MIXER_SetMode);
+GET_FUNCTION(MIXER_Enable);
+#endif
+
+return MODULE_START_FUNCTION;
+
+}
+#if defined (WIN32)
+}
+#endif
+
+
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (C) 2002-2017 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.
+ *
+ * Wengier: MOUSE CLIPBOARD support
+ */
+
+#ifndef DOSBOX_MOUSE_H
+#define DOSBOX_MOUSE_H
+
+
+void Mouse_ShowCursor(void);
+void Mouse_HideCursor(void);
+
+bool Mouse_SetPS2State(bool use);
+
+void Mouse_ChangePS2Callback(Bit16u pseg, Bit16u pofs);
+
+
+void Mouse_CursorMoved(float xrel,float yrel,float x,float y,bool emulate);
+#if C_CLIPBOARD
+const char* Mouse_GetSelected(int x1, int y1, int x2, int y2, int w, int h);
+void Mouse_Select(int x1, int y1, int x2, int y2, int w, int h);
+void Restore_Text(int x1, int y1, int x2, int y2, int w, int h);
+#endif
+void Mouse_CursorSet(float x,float y);
+void Mouse_ButtonPressed(Bit8u button);
+void Mouse_ButtonReleased(Bit8u button);
+
+void Mouse_AutoLock(bool enable);
+void Mouse_BeforeNewVideoMode(bool setmode);
+void Mouse_AfterNewVideoMode(bool setmode);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_PAGING_H
+#define DOSBOX_PAGING_H
+
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+#ifndef DOSBOX_MEM_H
+#include "mem.h"
+#endif
+
+// disable this to reduce the size of the TLB
+// NOTE: does not work with the dynamic core (dynrec is fine)
+#define USE_FULL_TLB
+
+class PageDirectory;
+
+#define MEM_PAGE_SIZE (4096)
+#define XMS_START (0x110)
+
+#if defined(USE_FULL_TLB)
+#define TLB_SIZE (1024*1024)
+#else
+#define TLB_SIZE 65536 // This must a power of 2 and greater then LINK_START
+#define BANK_SHIFT 28
+#define BANK_MASK 0xffff // always the same as TLB_SIZE-1?
+#define TLB_BANKS ((1024*1024/TLB_SIZE)-1)
+#endif
+
+#define PFLAG_READABLE 0x1
+#define PFLAG_WRITEABLE 0x2
+#define PFLAG_HASROM 0x4
+#define PFLAG_HASCODE 0x8 //Page contains dynamic code
+#define PFLAG_NOCODE 0x10 //No dynamic code can be generated here
+#define PFLAG_INIT 0x20 //No dynamic code can be generated here
+
+#define LINK_START ((1024+64)/4) //Start right after the HMA
+
+//Allow 128 mb of memory to be linked
+#define PAGING_LINKS (128*1024/4)
+
+class PageHandler {
+public:
+ virtual ~PageHandler(void) { }
+ virtual Bitu readb(PhysPt addr);
+ virtual Bitu readw(PhysPt addr);
+ virtual Bitu readd(PhysPt addr);
+ virtual void writeb(PhysPt addr,Bitu val);
+ virtual void writew(PhysPt addr,Bitu val);
+ virtual void writed(PhysPt addr,Bitu val);
+ virtual HostPt GetHostReadPt(Bitu phys_page);
+ virtual HostPt GetHostWritePt(Bitu phys_page);
+ virtual bool readb_checked(PhysPt addr,Bit8u * val);
+ virtual bool readw_checked(PhysPt addr,Bit16u * val);
+ virtual bool readd_checked(PhysPt addr,Bit32u * val);
+ virtual bool writeb_checked(PhysPt addr,Bitu val);
+ virtual bool writew_checked(PhysPt addr,Bitu val);
+ virtual bool writed_checked(PhysPt addr,Bitu val);
+ Bitu flags;
+};
+
+/* Some other functions */
+void PAGING_Enable(bool enabled);
+bool PAGING_Enabled(void);
+
+Bitu PAGING_GetDirBase(void);
+void PAGING_SetDirBase(Bitu cr3);
+void PAGING_InitTLB(void);
+void PAGING_ClearTLB(void);
+
+void PAGING_LinkPage(Bitu lin_page,Bitu phys_page);
+void PAGING_LinkPage_ReadOnly(Bitu lin_page,Bitu phys_page);
+void PAGING_UnlinkPages(Bitu lin_page,Bitu pages);
+/* This maps the page directly, only use when paging is disabled */
+void PAGING_MapPage(Bitu lin_page,Bitu phys_page);
+bool PAGING_MakePhysPage(Bitu & page);
+bool PAGING_ForcePageInit(Bitu lin_addr);
+
+void MEM_SetLFB(Bitu page, Bitu pages, PageHandler *handler, PageHandler *mmiohandler);
+void MEM_SetPageHandler(Bitu phys_page, Bitu pages, PageHandler * handler);
+void MEM_ResetPageHandler(Bitu phys_page, Bitu pages);
+
+
+#ifdef _MSC_VER
+#pragma pack (1)
+#endif
+struct X86_PageEntryBlock{
+#ifdef WORDS_BIGENDIAN
+ Bit32u base:20;
+ Bit32u avl:3;
+ Bit32u g:1;
+ Bit32u pat:1;
+ Bit32u d:1;
+ Bit32u a:1;
+ Bit32u pcd:1;
+ Bit32u pwt:1;
+ Bit32u us:1;
+ Bit32u wr:1;
+ Bit32u p:1;
+#else
+ Bit32u p:1;
+ Bit32u wr:1;
+ Bit32u us:1;
+ Bit32u pwt:1;
+ Bit32u pcd:1;
+ Bit32u a:1;
+ Bit32u d:1;
+ Bit32u pat:1;
+ Bit32u g:1;
+ Bit32u avl:3;
+ Bit32u base:20;
+#endif
+} GCC_ATTRIBUTE(packed);
+#ifdef _MSC_VER
+#pragma pack ()
+#endif
+
+
+union X86PageEntry {
+ Bit32u load;
+ X86_PageEntryBlock block;
+};
+
+#if !defined(USE_FULL_TLB)
+typedef struct {
+ HostPt read;
+ HostPt write;
+ PageHandler * readhandler;
+ PageHandler * writehandler;
+ Bit32u phys_page;
+} tlb_entry;
+#endif
+
+struct PagingBlock {
+ Bitu cr3;
+ Bitu cr2;
+ struct {
+ Bitu page;
+ PhysPt addr;
+ } base;
+#if defined(USE_FULL_TLB)
+ struct {
+ HostPt read[TLB_SIZE];
+ HostPt write[TLB_SIZE];
+ PageHandler * readhandler[TLB_SIZE];
+ PageHandler * writehandler[TLB_SIZE];
+ Bit32u phys_page[TLB_SIZE];
+ } tlb;
+#else
+ tlb_entry tlbh[TLB_SIZE];
+ tlb_entry *tlbh_banks[TLB_BANKS];
+#endif
+ struct {
+ Bitu used;
+ Bit32u entries[PAGING_LINKS];
+ } links;
+ Bit32u firstmb[LINK_START];
+ bool enabled;
+};
+
+extern PagingBlock paging;
+
+/* Some support functions */
+
+PageHandler * MEM_GetPageHandler(Bitu phys_page);
+
+
+/* Unaligned address handlers */
+Bit16u mem_unalignedreadw(PhysPt address);
+Bit32u mem_unalignedreadd(PhysPt address);
+void mem_unalignedwritew(PhysPt address,Bit16u val);
+void mem_unalignedwrited(PhysPt address,Bit32u val);
+
+bool mem_unalignedreadw_checked(PhysPt address,Bit16u * val);
+bool mem_unalignedreadd_checked(PhysPt address,Bit32u * val);
+bool mem_unalignedwritew_checked(PhysPt address,Bit16u val);
+bool mem_unalignedwrited_checked(PhysPt address,Bit32u val);
+
+#if defined(USE_FULL_TLB)
+
+static INLINE HostPt get_tlb_read(PhysPt address) {
+ return paging.tlb.read[address>>12];
+}
+static INLINE HostPt get_tlb_write(PhysPt address) {
+ return paging.tlb.write[address>>12];
+}
+static INLINE PageHandler* get_tlb_readhandler(PhysPt address) {
+ return paging.tlb.readhandler[address>>12];
+}
+static INLINE PageHandler* get_tlb_writehandler(PhysPt address) {
+ return paging.tlb.writehandler[address>>12];
+}
+
+/* Use these helper functions to access linear addresses in readX/writeX functions */
+static INLINE PhysPt PAGING_GetPhysicalPage(PhysPt linePage) {
+ return (paging.tlb.phys_page[linePage>>12]<<12);
+}
+
+static INLINE PhysPt PAGING_GetPhysicalAddress(PhysPt linAddr) {
+ return (paging.tlb.phys_page[linAddr>>12]<<12)|(linAddr&0xfff);
+}
+
+#else
+
+void PAGING_InitTLBBank(tlb_entry **bank);
+
+static INLINE tlb_entry *get_tlb_entry(PhysPt address) {
+ Bitu index=(address>>12);
+ if (TLB_BANKS && (index > TLB_SIZE)) {
+ Bitu bank=(address>>BANK_SHIFT) - 1;
+ if (!paging.tlbh_banks[bank])
+ PAGING_InitTLBBank(&paging.tlbh_banks[bank]);
+ return &paging.tlbh_banks[bank][index & BANK_MASK];
+ }
+ return &paging.tlbh[index];
+}
+
+static INLINE HostPt get_tlb_read(PhysPt address) {
+ return get_tlb_entry(address)->read;
+}
+static INLINE HostPt get_tlb_write(PhysPt address) {
+ return get_tlb_entry(address)->write;
+}
+static INLINE PageHandler* get_tlb_readhandler(PhysPt address) {
+ return get_tlb_entry(address)->readhandler;
+}
+static INLINE PageHandler* get_tlb_writehandler(PhysPt address) {
+ return get_tlb_entry(address)->writehandler;
+}
+
+/* Use these helper functions to access linear addresses in readX/writeX functions */
+static INLINE PhysPt PAGING_GetPhysicalPage(PhysPt linePage) {
+ tlb_entry *entry = get_tlb_entry(linePage);
+ return (entry->phys_page<<12);
+}
+
+static INLINE PhysPt PAGING_GetPhysicalAddress(PhysPt linAddr) {
+ tlb_entry *entry = get_tlb_entry(linAddr);
+ return (entry->phys_page<<12)|(linAddr&0xfff);
+}
+#endif
+
+/* Special inlined memory reading/writing */
+static INLINE Bit8u mem_readb_inline(PhysPt address) {
+ HostPt tlb_addr=get_tlb_read(address);
+ if (tlb_addr) return host_readb(tlb_addr+address);
+ else return (Bit8u)(get_tlb_readhandler(address))->readb(address);
+}
+
+static INLINE Bit16u mem_readw_inline(PhysPt address) {
+ if ((address & 0xfff)<0xfff) {
+ HostPt tlb_addr=get_tlb_read(address);
+ if (tlb_addr) return host_readw(tlb_addr+address);
+ else return (Bit16u)(get_tlb_readhandler(address))->readw(address);
+ } else return mem_unalignedreadw(address);
+}
+
+static INLINE Bit32u mem_readd_inline(PhysPt address) {
+ if ((address & 0xfff)<0xffd) {
+ HostPt tlb_addr=get_tlb_read(address);
+ if (tlb_addr) return host_readd(tlb_addr+address);
+ else return (get_tlb_readhandler(address))->readd(address);
+ } else return mem_unalignedreadd(address);
+}
+
+static INLINE void mem_writeb_inline(PhysPt address,Bit8u val) {
+ HostPt tlb_addr=get_tlb_write(address);
+ if (tlb_addr) host_writeb(tlb_addr + address, val);
+ else (get_tlb_writehandler(address))->writeb(address,val);
+}
+
+static INLINE void mem_writew_inline(PhysPt address,Bit16u val) {
+ if ((address & 0xfff)<0xfff) {
+ HostPt tlb_addr=get_tlb_write(address);
+ if (tlb_addr) host_writew(tlb_addr+address,val);
+ else (get_tlb_writehandler(address))->writew(address,val);
+ } else mem_unalignedwritew(address,val);
+}
+
+static INLINE void mem_writed_inline(PhysPt address,Bit32u val) {
+ if ((address & 0xfff)<0xffd) {
+ HostPt tlb_addr=get_tlb_write(address);
+ if (tlb_addr) host_writed(tlb_addr+address,val);
+ else (get_tlb_writehandler(address))->writed(address,val);
+ } else mem_unalignedwrited(address,val);
+}
+
+
+static INLINE bool mem_readb_checked(PhysPt address, Bit8u * val) {
+ HostPt tlb_addr=get_tlb_read(address);
+ if (tlb_addr) {
+ *val=host_readb(tlb_addr+address);
+ return false;
+ } else return (get_tlb_readhandler(address))->readb_checked(address, val);
+}
+
+static INLINE bool mem_readw_checked(PhysPt address, Bit16u * val) {
+ if ((address & 0xfff)<0xfff) {
+ HostPt tlb_addr=get_tlb_read(address);
+ if (tlb_addr) {
+ *val=host_readw(tlb_addr+address);
+ return false;
+ } else return (get_tlb_readhandler(address))->readw_checked(address, val);
+ } else return mem_unalignedreadw_checked(address, val);
+}
+
+static INLINE bool mem_readd_checked(PhysPt address, Bit32u * val) {
+ if ((address & 0xfff)<0xffd) {
+ HostPt tlb_addr=get_tlb_read(address);
+ if (tlb_addr) {
+ *val=host_readd(tlb_addr+address);
+ return false;
+ } else return (get_tlb_readhandler(address))->readd_checked(address, val);
+ } else return mem_unalignedreadd_checked(address, val);
+}
+
+static INLINE bool mem_writeb_checked(PhysPt address,Bit8u val) {
+ HostPt tlb_addr=get_tlb_write(address);
+ if (tlb_addr) {
+ host_writeb(tlb_addr+address,val);
+ return false;
+ } else return (get_tlb_writehandler(address))->writeb_checked(address,val);
+}
+
+static INLINE bool mem_writew_checked(PhysPt address,Bit16u val) {
+ if ((address & 0xfff)<0xfff) {
+ HostPt tlb_addr=get_tlb_write(address);
+ if (tlb_addr) {
+ host_writew(tlb_addr+address,val);
+ return false;
+ } else return (get_tlb_writehandler(address))->writew_checked(address,val);
+ } else return mem_unalignedwritew_checked(address,val);
+}
+
+static INLINE bool mem_writed_checked(PhysPt address,Bit32u val) {
+ if ((address & 0xfff)<0xffd) {
+ HostPt tlb_addr=get_tlb_write(address);
+ if (tlb_addr) {
+ host_writed(tlb_addr+address,val);
+ return false;
+ } else return (get_tlb_writehandler(address))->writed_checked(address,val);
+ } else return mem_unalignedwrited_checked(address,val);
+}
+
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_PCI_H
+#define DOSBOX_PCI_H
+
+//#define PCI_FUNCTIONALITY_ENABLED 0
+
+#if defined PCI_FUNCTIONALITY_ENABLED
+
+#define PCI_MAX_PCIDEVICES 10
+#define PCI_MAX_PCIFUNCTIONS 8
+
+
+class PCI_Device {
+private:
+ Bits pci_id, pci_subfunction;
+ Bit16u vendor_id, device_id;
+
+ // subdevices declarations, they will respond to pci functions 1 to 7
+ // (main device is attached to function 0)
+ Bitu num_subdevices;
+ PCI_Device* subdevices[PCI_MAX_PCIFUNCTIONS-1];
+
+public:
+ PCI_Device(Bit16u vendor, Bit16u device);
+
+ Bits PCIId(void) {
+ return pci_id;
+ }
+ Bits PCISubfunction(void) {
+ return pci_subfunction;
+ }
+ Bit16u VendorID(void) {
+ return vendor_id;
+ }
+ Bit16u DeviceID(void) {
+ return device_id;
+ }
+
+ void SetPCIId(Bitu number, Bits subfct);
+
+ bool AddSubdevice(PCI_Device* dev);
+ void RemoveSubdevice(Bits subfct);
+
+ PCI_Device* GetSubdevice(Bits subfct);
+
+ Bit16u NumSubdevices(void) {
+ if (num_subdevices>PCI_MAX_PCIFUNCTIONS-1) return (Bit16u)(PCI_MAX_PCIFUNCTIONS-1);
+ return (Bit16u)num_subdevices;
+ }
+
+ Bits GetNextSubdeviceNumber(void) {
+ if (num_subdevices>=PCI_MAX_PCIFUNCTIONS-1) return -1;
+ return (Bits)num_subdevices+1;
+ }
+
+ virtual Bits ParseReadRegister(Bit8u regnum)=0;
+ virtual bool OverrideReadRegister(Bit8u regnum, Bit8u* rval, Bit8u* rval_mask)=0;
+ virtual Bits ParseWriteRegister(Bit8u regnum,Bit8u value)=0;
+ virtual bool InitializeRegisters(Bit8u registers[256])=0;
+
+};
+
+bool PCI_IsInitialized();
+
+RealPt PCI_GetPModeInterface(void);
+
+#endif
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_PIC_H
+#define DOSBOX_PIC_H
+
+
+/* CPU Cycle Timing */
+extern Bit32s CPU_Cycles;
+extern Bit32s CPU_CycleLeft;
+extern Bit32s CPU_CycleMax;
+
+typedef void (PIC_EOIHandler) (void);
+typedef void (* PIC_EventHandler)(Bitu val);
+
+
+extern Bitu PIC_IRQCheck;
+extern Bitu PIC_Ticks;
+
+static INLINE float PIC_TickIndex(void) {
+ return (CPU_CycleMax-CPU_CycleLeft-CPU_Cycles)/(float)CPU_CycleMax;
+}
+
+static INLINE Bits PIC_TickIndexND(void) {
+ return CPU_CycleMax-CPU_CycleLeft-CPU_Cycles;
+}
+
+static INLINE Bits PIC_MakeCycles(double amount) {
+ return (Bits)(CPU_CycleMax*amount);
+}
+
+static INLINE double PIC_FullIndex(void) {
+ return PIC_Ticks+(double)PIC_TickIndex();
+}
+
+void PIC_ActivateIRQ(Bitu irq);
+void PIC_DeActivateIRQ(Bitu irq);
+
+void PIC_runIRQs(void);
+bool PIC_RunQueue(void);
+
+//Delay in milliseconds
+void PIC_AddEvent(PIC_EventHandler handler,float delay,Bitu val=0);
+void PIC_RemoveEvents(PIC_EventHandler handler);
+void PIC_RemoveSpecificEvents(PIC_EventHandler handler, Bitu val);
+
+void PIC_SetIRQMask(Bitu irq, bool masked);
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_PROGRAMS_H
+#define DOSBOX_PROGRAMS_H
+
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+#ifndef DOSBOX_DOS_INC_H
+#include "dos_inc.h"
+#endif
+
+#ifndef CH_LIST
+#define CH_LIST
+#include <list>
+#endif
+
+#ifndef CH_STRING
+#define CH_STRING
+#include <string>
+#endif
+
+class CommandLine {
+public:
+ CommandLine(int argc,char const * const argv[]);
+ CommandLine(char const * const name,char const * const cmdline);
+ const char * GetFileName(){ return file_name.c_str();}
+
+ bool FindExist(char const * const name,bool remove=false);
+ bool FindHex(char const * const name,int & value,bool remove=false);
+ bool FindInt(char const * const name,int & value,bool remove=false);
+ bool FindString(char const * const name,std::string & value,bool remove=false);
+ bool FindCommand(unsigned int which,std::string & value);
+ bool FindStringBegin(char const * const begin,std::string & value, bool remove=false);
+ bool FindStringRemain(char const * const name,std::string & value);
+ bool FindStringRemainBegin(char const * const name,std::string & value);
+ bool GetStringRemain(std::string & value);
+ int GetParameterFromList(const char* const params[], std::vector<std::string> & output);
+ void FillVector(std::vector<std::string> & vector);
+ unsigned int GetCount(void);
+ void Shift(unsigned int amount=1);
+ Bit16u Get_arglength();
+
+private:
+ typedef std::list<std::string>::iterator cmd_it;
+ std::list<std::string> cmds;
+ std::string file_name;
+ bool FindEntry(char const * const name,cmd_it & it,bool neednext=false);
+};
+
+class Program {
+public:
+ Program();
+ virtual ~Program(){
+ delete cmd;
+ delete psp;
+ }
+ std::string temp_line;
+ CommandLine * cmd;
+ DOS_PSP * psp;
+ virtual void Run(void)=0;
+ bool GetEnvStr(const char * entry,std::string & result);
+ bool GetEnvNum(Bitu num,std::string & result);
+ Bitu GetEnvCount(void);
+ bool SetEnv(const char * entry,const char * new_string);
+ void WriteOut(const char * format,...); /* Write to standard output */
+ void WriteOut_NoParsing(const char * format); /* Write to standard output, no parsing */
+ void ChangeToLongCmd();
+
+};
+
+typedef void (PROGRAMS_Main)(Program * * make);
+void PROGRAMS_MakeFile(char const * const name,PROGRAMS_Main * main);
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_REGS_H
+#define DOSBOX_REGS_H
+
+#ifndef DOSBOX_MEM_H
+#include "mem.h"
+#endif
+
+#define FLAG_CF 0x00000001
+#define FLAG_PF 0x00000004
+#define FLAG_AF 0x00000010
+#define FLAG_ZF 0x00000040
+#define FLAG_SF 0x00000080
+#define FLAG_OF 0x00000800
+
+#define FLAG_TF 0x00000100
+#define FLAG_IF 0x00000200
+#define FLAG_DF 0x00000400
+
+#define FLAG_IOPL 0x00003000
+#define FLAG_NT 0x00004000
+#define FLAG_VM 0x00020000
+#define FLAG_AC 0x00040000
+#define FLAG_ID 0x00200000
+
+#define FMASK_TEST (FLAG_CF | FLAG_PF | FLAG_AF | FLAG_ZF | FLAG_SF | FLAG_OF)
+#define FMASK_NORMAL (FMASK_TEST | FLAG_DF | FLAG_TF | FLAG_IF )
+#define FMASK_ALL (FMASK_NORMAL | FLAG_IOPL | FLAG_NT)
+
+#define SETFLAGBIT(TYPE,TEST) if (TEST) reg_flags|=FLAG_ ## TYPE; else reg_flags&=~FLAG_ ## TYPE
+
+#define GETFLAG(TYPE) (reg_flags & FLAG_ ## TYPE)
+#define GETFLAGBOOL(TYPE) ((reg_flags & FLAG_ ## TYPE) ? true : false )
+
+#define GETFLAG_IOPL ((reg_flags & FLAG_IOPL) >> 12)
+
+struct Segment {
+ Bit16u val;
+ PhysPt phys; /* The phyiscal address start in emulated machine */
+};
+
+enum SegNames { es=0,cs,ss,ds,fs,gs};
+
+struct Segments {
+ Bit16u val[8];
+ PhysPt phys[8];
+};
+
+union GenReg32 {
+ Bit32u dword[1];
+ Bit16u word[2];
+ Bit8u byte[4];
+};
+
+#ifdef WORDS_BIGENDIAN
+
+#define DW_INDEX 0
+#define W_INDEX 1
+#define BH_INDEX 2
+#define BL_INDEX 3
+
+#else
+
+#define DW_INDEX 0
+#define W_INDEX 0
+#define BH_INDEX 1
+#define BL_INDEX 0
+
+#endif
+
+struct CPU_Regs {
+ GenReg32 regs[8],ip;
+ Bitu flags;
+};
+
+extern Segments Segs;
+extern CPU_Regs cpu_regs;
+
+static INLINE PhysPt SegPhys(SegNames index) {
+ return Segs.phys[index];
+}
+
+static INLINE Bit16u SegValue(SegNames index) {
+ return (Bit16u)Segs.val[index];
+}
+
+static INLINE RealPt RealMakeSeg(SegNames index,Bit16u off) {
+ return RealMake(SegValue(index),off);
+}
+
+
+static INLINE void SegSet16(Bitu index,Bit16u val) {
+ Segs.val[index]=val;
+ Segs.phys[index]=val << 4;
+}
+
+enum {
+ REGI_AX, REGI_CX, REGI_DX, REGI_BX,
+ REGI_SP, REGI_BP, REGI_SI, REGI_DI
+};
+
+enum {
+ REGI_AL, REGI_CL, REGI_DL, REGI_BL,
+ REGI_AH, REGI_CH, REGI_DH, REGI_BH
+};
+
+
+//macros to convert a 3-bit register index to the correct register
+#define reg_8l(reg) (cpu_regs.regs[(reg)].byte[BL_INDEX])
+#define reg_8h(reg) (cpu_regs.regs[(reg)].byte[BH_INDEX])
+#define reg_8(reg) ((reg) & 4 ? reg_8h((reg) & 3) : reg_8l((reg) & 3))
+#define reg_16(reg) (cpu_regs.regs[(reg)].word[W_INDEX])
+#define reg_32(reg) (cpu_regs.regs[(reg)].dword[DW_INDEX])
+
+#define reg_al cpu_regs.regs[REGI_AX].byte[BL_INDEX]
+#define reg_ah cpu_regs.regs[REGI_AX].byte[BH_INDEX]
+#define reg_ax cpu_regs.regs[REGI_AX].word[W_INDEX]
+#define reg_eax cpu_regs.regs[REGI_AX].dword[DW_INDEX]
+
+#define reg_bl cpu_regs.regs[REGI_BX].byte[BL_INDEX]
+#define reg_bh cpu_regs.regs[REGI_BX].byte[BH_INDEX]
+#define reg_bx cpu_regs.regs[REGI_BX].word[W_INDEX]
+#define reg_ebx cpu_regs.regs[REGI_BX].dword[DW_INDEX]
+
+#define reg_cl cpu_regs.regs[REGI_CX].byte[BL_INDEX]
+#define reg_ch cpu_regs.regs[REGI_CX].byte[BH_INDEX]
+#define reg_cx cpu_regs.regs[REGI_CX].word[W_INDEX]
+#define reg_ecx cpu_regs.regs[REGI_CX].dword[DW_INDEX]
+
+#define reg_dl cpu_regs.regs[REGI_DX].byte[BL_INDEX]
+#define reg_dh cpu_regs.regs[REGI_DX].byte[BH_INDEX]
+#define reg_dx cpu_regs.regs[REGI_DX].word[W_INDEX]
+#define reg_edx cpu_regs.regs[REGI_DX].dword[DW_INDEX]
+
+#define reg_si cpu_regs.regs[REGI_SI].word[W_INDEX]
+#define reg_esi cpu_regs.regs[REGI_SI].dword[DW_INDEX]
+
+#define reg_di cpu_regs.regs[REGI_DI].word[W_INDEX]
+#define reg_edi cpu_regs.regs[REGI_DI].dword[DW_INDEX]
+
+#define reg_sp cpu_regs.regs[REGI_SP].word[W_INDEX]
+#define reg_esp cpu_regs.regs[REGI_SP].dword[DW_INDEX]
+
+#define reg_bp cpu_regs.regs[REGI_BP].word[W_INDEX]
+#define reg_ebp cpu_regs.regs[REGI_BP].dword[DW_INDEX]
+
+#define reg_ip cpu_regs.ip.word[W_INDEX]
+#define reg_eip cpu_regs.ip.dword[DW_INDEX]
+
+#define reg_flags cpu_regs.flags
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_RENDER_H
+#define DOSBOX_RENDER_H
+
+// 0: complex scalers off, scaler cache off, some simple scalers off, memory requirements reduced
+// 1: complex scalers off, scaler cache off, all simple scalers on
+// 2: complex scalers off, scaler cache on
+// 3: complex scalers on
+#define RENDER_USE_ADVANCED_SCALERS 3
+
+#include "../src/gui/render_scalers.h"
+
+#define RENDER_SKIP_CACHE 16
+//Enable this for scalers to support 0 input for empty lines
+//#define RENDER_NULL_INPUT
+
+typedef struct {
+ struct {
+ Bit8u red;
+ Bit8u green;
+ Bit8u blue;
+ Bit8u unused;
+ } rgb[256];
+ union {
+ Bit16u b16[256];
+ Bit32u b32[256];
+ } lut;
+ bool changed;
+ Bit8u modified[256];
+ Bitu first;
+ Bitu last;
+} RenderPal_t;
+
+typedef struct {
+ struct {
+ Bitu width, start;
+ Bitu height;
+ Bitu bpp;
+ bool dblw,dblh;
+ double ratio;
+ float fps;
+ } src;
+ struct {
+ Bitu count;
+ Bitu max;
+ Bitu index;
+ Bit8u hadSkip[RENDER_SKIP_CACHE];
+ } frameskip;
+ struct {
+ Bitu size;
+ scalerMode_t inMode;
+ scalerMode_t outMode;
+ scalerOperation_t op;
+ bool clearCache;
+ bool forced;
+ ScalerLineHandler_t lineHandler;
+ ScalerLineHandler_t linePalHandler;
+ ScalerComplexHandler_t complexHandler;
+ Bitu blocks, lastBlock;
+ Bitu outPitch;
+ Bit8u *outWrite;
+ Bitu cachePitch;
+ Bit8u *cacheRead;
+ Bitu inHeight, inLine, outLine;
+ } scale;
+ RenderPal_t pal;
+ bool updating;
+ bool active;
+ bool aspect;
+ bool fullFrame;
+} Render_t;
+
+extern Render_t render;
+extern ScalerLineHandler_t RENDER_DrawLine;
+void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double ratio,bool dblw,bool dblh);
+bool RENDER_StartUpdate(void);
+void RENDER_EndUpdate(bool abort);
+void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue);
+
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_SERIALPORT_H
+#define DOSBOX_SERIALPORT_H
+
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+#ifndef DOSBOX_INOUT_H
+#include "inout.h"
+#endif
+#ifndef DOSBOX_TIMER_H
+#include "timer.h"
+#endif
+#ifndef DOSBOX_DOS_INC_H
+#include "dos_inc.h"
+#endif
+#ifndef DOSBOX_PROGRAMS_H
+#include "programs.h"
+#endif
+
+// set this to 1 for serial debugging in release mode
+#define SERIAL_DBG_FORCED 0
+
+#if (C_DEBUG || SERIAL_DBG_FORCED)
+#define SERIAL_DEBUG 1
+#endif
+
+#if SERIAL_DEBUG
+#include "hardware.h"
+#endif
+
+// Serial port interface
+
+class MyFifo {
+public:
+ MyFifo(Bitu maxsize_) {
+ maxsize=size=maxsize_;
+ pos=used=0;
+ data=new Bit8u[size];
+ }
+ ~MyFifo() {
+ delete[] data;
+ }
+ INLINE Bitu getFree(void) {
+ return size-used;
+ }
+ bool isEmpty() {
+ return used==0;
+ }
+ bool isFull() {
+ return (size-used)==0;
+ }
+
+ INLINE Bitu getUsage(void) {
+ return used;
+ }
+ void setSize(Bitu newsize)
+ {
+ size=newsize;
+ pos=used=0;
+ }
+ void clear(void) {
+ pos=used=0;
+ data[0]=0;
+ }
+
+ bool addb(Bit8u _val) {
+ Bitu where=pos+used;
+ if (where>=size) where-=size;
+ if(used>=size) {
+ // overwrite last byte
+ if(where==0) where=size-1;
+ else where--;
+ data[where]=_val;
+ return false;
+ }
+ data[where]=_val;
+ used++;
+ return true;
+ }
+ Bit8u getb() {
+ if (!used) return data[pos];
+ Bitu where=pos;
+ used--;
+ if(used) pos++;
+ if (pos>=size) pos-=size;
+ return data[where];
+ }
+ Bit8u getTop() {
+ Bitu where=pos+used;
+ if (where>=size) where-=size;
+ if(used>=size) {
+ if(where==0) where=size-1;
+ else where--;
+ }
+ return data[where];
+ }
+
+ Bit8u probeByte() {
+ return data[pos];
+ }
+private:
+ Bit8u * data;
+ Bitu maxsize,size,pos,used;
+};
+
+class CSerial {
+public:
+
+#if SERIAL_DEBUG
+ FILE * debugfp;
+ bool dbg_modemcontrol; // RTS,CTS,DTR,DSR,RI,CD
+ bool dbg_serialtraffic;
+ bool dbg_register;
+ bool dbg_interrupt;
+ bool dbg_aux;
+ void log_ser(bool active, char const* format,...);
+#endif
+
+ static bool getBituSubstring(const char* name,Bitu* data, CommandLine* cmd);
+
+ bool InstallationSuccessful;// check after constructing. If
+ // something was wrong, delete it right away.
+
+ // Constructor takes com port number (0-3)
+ CSerial(Bitu id, CommandLine* cmd);
+
+ virtual ~CSerial();
+
+ IO_ReadHandleObject ReadHandler[8];
+ IO_WriteHandleObject WriteHandler[8];
+
+ float bytetime; // how long a byte takes to transmit/receive in milliseconds
+ void changeLineProperties();
+ Bitu idnumber;
+
+ void setEvent(Bit16u type, float duration);
+ void removeEvent(Bit16u type);
+ void handleEvent(Bit16u type);
+ virtual void handleUpperEvent(Bit16u type)=0;
+
+ // defines for event type
+#define SERIAL_TX_LOOPBACK_EVENT 0
+#define SERIAL_THR_LOOPBACK_EVENT 1
+#define SERIAL_ERRMSG_EVENT 2
+
+#define SERIAL_TX_EVENT 3
+#define SERIAL_RX_EVENT 4
+#define SERIAL_POLLING_EVENT 5
+#define SERIAL_THR_EVENT 6
+#define SERIAL_RX_TIMEOUT_EVENT 7
+
+#define SERIAL_BASE_EVENT_COUNT 7
+
+#define COMNUMBER idnumber+1
+
+ Bitu irq;
+
+ // CSerial requests an update of the input lines
+ virtual void updateMSR()=0;
+
+ // Control lines from prepherial to serial port
+ bool getDTR();
+ bool getRTS();
+
+ bool getRI();
+ bool getCD();
+ bool getDSR();
+ bool getCTS();
+
+ void setRI(bool value);
+ void setDSR(bool value);
+ void setCD(bool value);
+ void setCTS(bool value);
+
+ // From serial port to prepherial
+ // set output lines
+ virtual void setRTSDTR(bool rts, bool dtr)=0;
+ virtual void setRTS(bool val)=0;
+ virtual void setDTR(bool val)=0;
+
+ // Register access
+ void Write_THR(Bit8u data);
+ void Write_IER(Bit8u data);
+ void Write_FCR(Bit8u data);
+ void Write_LCR(Bit8u data);
+ void Write_MCR(Bit8u data);
+ // Really old hardware seems to have the delta part of this register writable
+ void Write_MSR(Bit8u data);
+ void Write_SPR(Bit8u data);
+ void Write_reserved(Bit8u data, Bit8u address);
+
+ Bitu Read_RHR();
+ Bitu Read_IER();
+ Bitu Read_ISR();
+ Bitu Read_LCR();
+ Bitu Read_MCR();
+ Bitu Read_LSR();
+ Bitu Read_MSR();
+ Bitu Read_SPR();
+
+ // If a byte comes from loopback or prepherial, put it in here.
+ void receiveByte(Bit8u data);
+ void receiveByteEx(Bit8u data, Bit8u error);
+
+ // If an error was received, put it here (in LSR register format)
+ void receiveError(Bit8u errorword);
+
+ // depratched
+ // connected device checks, if port can receive data:
+ bool CanReceiveByte();
+
+ // when THR was shifted to TX
+ void ByteTransmitting();
+
+ // When done sending, notify here
+ void ByteTransmitted();
+
+ // Transmit byte to prepherial
+ virtual void transmitByte(Bit8u val, bool first)=0;
+
+ // switch break state to the passed value
+ virtual void setBreak(bool value)=0;
+
+ // change baudrate, number of bits, parity, word length al at once
+ virtual void updatePortConfig(Bit16u divider, Bit8u lcr)=0;
+
+ void Init_Registers();
+
+ bool Putchar(Bit8u data, bool wait_dtr, bool wait_rts, Bitu timeout);
+ bool Getchar(Bit8u* data, Bit8u* lsr, bool wait_dsr, Bitu timeout);
+
+
+private:
+
+ DOS_Device* mydosdevice;
+
+ // I used this spec: st16c450v420.pdf
+
+ void ComputeInterrupts();
+
+ // a sub-interrupt is triggered
+ void rise(Bit8u priority);
+
+ // clears the pending sub-interrupt
+ void clear(Bit8u priority);
+
+ #define ERROR_PRIORITY 4 // overrun, parity error, frame error, break
+ #define RX_PRIORITY 1 // a byte has been received
+ #define TX_PRIORITY 2 // tx buffer has become empty
+ #define MSR_PRIORITY 8 // CRS, DSR, RI, DCD change
+ #define TIMEOUT_PRIORITY 0x10
+ #define NONE_PRIORITY 0
+
+ Bit8u waiting_interrupts; // these are on, but maybe not enabled
+
+ // 16C550
+ // read/write name
+
+ Bit16u baud_divider;
+ #define RHR_OFFSET 0 // r Receive Holding Register, also LSB of Divisor Latch (r/w)
+ // Data: whole byte
+ #define THR_OFFSET 0 // w Transmit Holding Register
+ // Data: whole byte
+ Bit8u IER; // r/w Interrupt Enable Register, also MSB of Divisor Latch
+ #define IER_OFFSET 1
+
+ bool irq_active;
+
+ #define RHR_INT_Enable_MASK 0x1
+ #define THR_INT_Enable_MASK 0x2
+ #define Receive_Line_INT_Enable_MASK 0x4
+ #define Modem_Status_INT_Enable_MASK 0x8
+
+ Bit8u ISR; // r Interrupt Status Register
+ #define ISR_OFFSET 2
+
+ #define ISR_CLEAR_VAL 0x1
+ #define ISR_FIFOTIMEOUT_VAL 0xc
+ #define ISR_ERROR_VAL 0x6
+ #define ISR_RX_VAL 0x4
+ #define ISR_TX_VAL 0x2
+ #define ISR_MSR_VAL 0x0
+public:
+ Bit8u LCR; // r/w Line Control Register
+private:
+ #define LCR_OFFSET 3
+ // bit0: word length bit0
+ // bit1: word length bit1
+ // bit2: stop bits
+ // bit3: parity enable
+ // bit4: even parity
+ // bit5: set parity
+ // bit6: set break
+ // bit7: divisor latch enable
+
+
+ #define LCR_BREAK_MASK 0x40
+ #define LCR_DIVISOR_Enable_MASK 0x80
+ #define LCR_PORTCONFIG_MASK 0x3F
+
+ #define LCR_PARITY_NONE 0x0
+ #define LCR_PARITY_ODD 0x8
+ #define LCR_PARITY_EVEN 0x18
+ #define LCR_PARITY_MARK 0x28
+ #define LCR_PARITY_SPACE 0x38
+
+ #define LCR_DATABITS_5 0x0
+ #define LCR_DATABITS_6 0x1
+ #define LCR_DATABITS_7 0x2
+ #define LCR_DATABITS_8 0x3
+
+ #define LCR_STOPBITS_1 0x0
+ #define LCR_STOPBITS_MORE_THAN_1 0x4
+
+ // Modem Control Register
+ // r/w
+ #define MCR_OFFSET 4
+ bool dtr; // bit0: DTR
+ bool rts; // bit1: RTS
+ bool op1; // bit2: OP1
+ bool op2; // bit3: OP2
+ bool loopback; // bit4: loop back enable
+
+ #define MCR_DTR_MASK 0x1
+ #define MCR_RTS_MASK 0x2
+ #define MCR_OP1_MASK 0x4
+ #define MCR_OP2_MASK 0x8
+ #define MCR_LOOPBACK_Enable_MASK 0x10
+public:
+ Bit8u LSR; // r Line Status Register
+private:
+
+ #define LSR_OFFSET 5
+
+ #define LSR_RX_DATA_READY_MASK 0x1
+ #define LSR_OVERRUN_ERROR_MASK 0x2
+ #define LSR_PARITY_ERROR_MASK 0x4
+ #define LSR_FRAMING_ERROR_MASK 0x8
+ #define LSR_RX_BREAK_MASK 0x10
+ #define LSR_TX_HOLDING_EMPTY_MASK 0x20
+ #define LSR_TX_EMPTY_MASK 0x40
+
+ #define LSR_ERROR_MASK 0x1e
+
+ // error printing
+ bool errormsg_pending;
+ Bitu framingErrors;
+ Bitu parityErrors;
+ Bitu overrunErrors;
+ Bitu txOverrunErrors;
+ Bitu overrunIF0;
+ Bitu breakErrors;
+
+
+ // Modem Status Register
+ // r
+ #define MSR_OFFSET 6
+ bool d_cts; // bit0: deltaCTS
+ bool d_dsr; // bit1: deltaDSR
+ bool d_ri; // bit2: deltaRI
+ bool d_cd; // bit3: deltaCD
+ bool cts; // bit4: CTS
+ bool dsr; // bit5: DSR
+ bool ri; // bit6: RI
+ bool cd; // bit7: CD
+
+ #define MSR_delta_MASK 0xf
+ #define MSR_LINE_MASK 0xf0
+
+ #define MSR_dCTS_MASK 0x1
+ #define MSR_dDSR_MASK 0x2
+ #define MSR_dRI_MASK 0x4
+ #define MSR_dCD_MASK 0x8
+ #define MSR_CTS_MASK 0x10
+ #define MSR_DSR_MASK 0x20
+ #define MSR_RI_MASK 0x40
+ #define MSR_CD_MASK 0x80
+
+ Bit8u SPR; // r/w Scratchpad Register
+ #define SPR_OFFSET 7
+
+
+ // For loopback purposes...
+ Bit8u loopback_data;
+ void transmitLoopbackByte(Bit8u val, bool value);
+
+ // 16C550 (FIFO)
+ public: // todo remove
+ MyFifo* rxfifo;
+ private:
+ MyFifo* txfifo;
+ MyFifo* errorfifo;
+ Bitu errors_in_fifo;
+ Bitu rx_interrupt_threshold;
+ Bitu fifosize;
+ Bit8u FCR;
+ bool sync_guardtime;
+ #define FIFO_STATUS_ACTIVE 0xc0 // FIFO is active AND works ;)
+ #define FIFO_ERROR 0x80
+ #define FCR_ACTIVATE 0x01
+ #define FCR_CLEAR_RX 0x02
+ #define FCR_CLEAR_TX 0x04
+ #define FCR_OFFSET 2
+ #define FIFO_FLOWCONTROL 0x20
+};
+
+extern CSerial* serialports[];
+const Bit8u serial_defaultirq[] = { 4, 3, 4, 3 };
+const Bit16u serial_baseaddr[] = {0x3f8,0x2f8,0x3e8,0x2e8};
+const char* const serial_comname[]={"COM1","COM2","COM3","COM4"};
+
+// the COM devices
+
+class device_COM : public DOS_Device {
+public:
+ // Creates a COM device that communicates with the num-th parallel port, i.e. is LPTnum
+ device_COM(class CSerial* sc);
+ ~device_COM();
+ bool Read(Bit8u * data,Bit16u * size);
+ bool Write(Bit8u * data,Bit16u * size);
+ bool Seek(Bit32u * pos,Bit32u type);
+ bool Close();
+ Bit16u GetInformation(void);
+private:
+ CSerial* sclass;
+};
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_SETUP_H
+#define DOSBOX_SETUP_H
+
+#ifdef _MSC_VER
+#pragma warning ( disable : 4786 )
+#pragma warning ( disable : 4290 )
+#endif
+
+
+#ifndef CH_LIST
+#define CH_LIST
+#include <list>
+#endif
+
+#ifndef CH_VECTOR
+#define CH_VECTOR
+#include <vector>
+#endif
+
+#ifndef CH_STRING
+#define CH_STRING
+#include <string>
+#endif
+
+#ifndef CH_CSTDIO
+#define CH_CSTDIO
+#include <cstdio>
+#endif
+
+
+class Hex {
+private:
+ int _hex;
+public:
+ Hex(int in):_hex(in) { };
+ Hex():_hex(0) { };
+ bool operator==(Hex const& other) {return _hex == other._hex;}
+ operator int () const { return _hex; }
+
+};
+
+class Value {
+/*
+ * Multitype storage container that is aware of the currently stored type in it.
+ * Value st = "hello";
+ * Value in = 1;
+ * st = 12 //Exception
+ * in = 12 //works
+ */
+private:
+ Hex _hex;
+ bool _bool;
+ int _int;
+ std::string* _string;
+ double _double;
+public:
+ class WrongType { }; // Conversion error class
+ enum Etype { V_NONE, V_HEX, V_BOOL, V_INT, V_STRING, V_DOUBLE,V_CURRENT} type;
+
+ /* Constructors */
+ Value() :_string(0), type(V_NONE) { };
+ Value(Hex in) :_hex(in), type(V_HEX) { };
+ Value(int in) :_int(in), type(V_INT) { };
+ Value(bool in) :_bool(in), type(V_BOOL) { };
+ Value(double in) :_double(in), type(V_DOUBLE) { };
+ Value(std::string const& in) :_string(new std::string(in)),type(V_STRING) { };
+ Value(char const * const in) :_string(new std::string(in)),type(V_STRING) { };
+ Value(Value const& in):_string(0) {plaincopy(in);}
+ ~Value() { destroy();};
+ Value(std::string const& in,Etype _t) :_hex(0),_bool(false),_int(0),_string(0),_double(0),type(V_NONE) {SetValue(in,_t);}
+
+ /* Assigment operators */
+ Value& operator= (Hex in) throw(WrongType) { return copy(Value(in));}
+ Value& operator= (int in) throw(WrongType) { return copy(Value(in));}
+ Value& operator= (bool in) throw(WrongType) { return copy(Value(in));}
+ Value& operator= (double in) throw(WrongType) { return copy(Value(in));}
+ Value& operator= (std::string const& in) throw(WrongType) { return copy(Value(in));}
+ Value& operator= (char const * const in) throw(WrongType) { return copy(Value(in));}
+ Value& operator= (Value const& in) throw(WrongType) { return copy(Value(in));}
+
+ bool operator== (Value const & other);
+ operator bool () const throw(WrongType);
+ operator Hex () const throw(WrongType);
+ operator int () const throw(WrongType);
+ operator double () const throw(WrongType);
+ operator char const* () const throw(WrongType);
+ bool SetValue(std::string const& in,Etype _type = V_CURRENT) throw(WrongType);
+ std::string ToString() const;
+
+private:
+ void destroy() throw();
+ Value& copy(Value const& in) throw(WrongType);
+ void plaincopy(Value const& in) throw();
+ bool set_hex(std::string const& in);
+ bool set_int(std::string const&in);
+ bool set_bool(std::string const& in);
+ void set_string(std::string const& in);
+ bool set_double(std::string const& in);
+};
+
+class Property {
+public:
+ struct Changeable { enum Value {Always, WhenIdle,OnlyAtStart};};
+ const std::string propname;
+
+ Property(std::string const& _propname, Changeable::Value when):propname(_propname),change(when) { }
+ void Set_values(const char * const * in);
+ void Set_help(std::string const& str);
+ char const* Get_help();
+ virtual bool SetValue(std::string const& str)=0;
+ Value const& GetValue() const { return value;}
+ Value const& Get_Default_Value() const { return default_value; }
+ //CheckValue returns true, if value is in suggested_values;
+ //Type specific properties are encouraged to override this and check for type
+ //specific features.
+ virtual bool CheckValue(Value const& in, bool warn);
+public:
+ virtual ~Property(){ }
+ virtual const std::vector<Value>& GetValues() const;
+ Value::Etype Get_type(){return default_value.type;}
+ Changeable::Value getChange() {return change;}
+
+protected:
+ //Set interval value to in or default if in is invalid. force always sets the value.
+ //Can be overriden to set a different value if invalid.
+ virtual bool SetVal(Value const& in, bool forced,bool warn=true) {
+ if(forced || CheckValue(in,warn)) {
+ value = in; return true;
+ } else {
+ value = default_value; return false;
+ }
+ }
+ Value value;
+ std::vector<Value> suggested_values;
+ typedef std::vector<Value>::iterator iter;
+ Value default_value;
+ const Changeable::Value change;
+};
+
+class Prop_int:public Property {
+public:
+ Prop_int(std::string const& _propname,Changeable::Value when, int _value)
+ :Property(_propname,when) {
+ default_value = value = _value;
+ min = max = -1;
+ }
+ Prop_int(std::string const& _propname,Changeable::Value when, int _min,int _max,int _value)
+ :Property(_propname,when) {
+ default_value = value = _value;
+ min = _min;
+ max = _max;
+ }
+ int getMin() { return min;}
+ int getMax() { return max;}
+ void SetMinMax(Value const& min,Value const& max) {this->min = min; this->max=max;}
+ bool SetValue(std::string const& in);
+ ~Prop_int(){ }
+ virtual bool CheckValue(Value const& in, bool warn);
+ // Override SetVal, so it takes min,max in account when there are no suggested values
+ virtual bool SetVal(Value const& in, bool forced,bool warn=true);
+
+private:
+ Value min,max;
+};
+
+class Prop_double:public Property {
+public:
+ Prop_double(std::string const & _propname, Changeable::Value when, double _value)
+ :Property(_propname,when){
+ default_value = value = _value;
+ }
+ bool SetValue(std::string const& input);
+ ~Prop_double(){ }
+};
+
+class Prop_bool:public Property {
+public:
+ Prop_bool(std::string const& _propname, Changeable::Value when, bool _value)
+ :Property(_propname,when) {
+ default_value = value = _value;
+ }
+ bool SetValue(std::string const& in);
+ ~Prop_bool(){ }
+};
+
+class Prop_string:public Property{
+public:
+ Prop_string(std::string const& _propname, Changeable::Value when, char const * const _value)
+ :Property(_propname,when) {
+ default_value = value = _value;
+ }
+ bool SetValue(std::string const& in);
+ virtual bool CheckValue(Value const& in, bool warn);
+ ~Prop_string(){ }
+};
+class Prop_path:public Prop_string{
+public:
+ std::string realpath;
+ Prop_path(std::string const& _propname, Changeable::Value when, char const * const _value)
+ :Prop_string(_propname,when,_value) {
+ default_value = value = _value;
+ realpath = _value;
+ }
+ bool SetValue(std::string const& in);
+ ~Prop_path(){ }
+};
+
+class Prop_hex:public Property {
+public:
+ Prop_hex(std::string const& _propname, Changeable::Value when, Hex _value)
+ :Property(_propname,when) {
+ default_value = value = _value;
+ }
+ bool SetValue(std::string const& in);
+ ~Prop_hex(){ }
+};
+
+#define NO_SUCH_PROPERTY "PROP_NOT_EXIST"
+class Section {
+private:
+ typedef void (*SectionFunction)(Section*);
+ /* Wrapper class around startup and shutdown functions. the variable
+ * canchange indicates it can be called on configuration changes */
+ struct Function_wrapper {
+ SectionFunction function;
+ bool canchange;
+ Function_wrapper(SectionFunction const _fun,bool _ch){
+ function=_fun;
+ canchange=_ch;
+ }
+ };
+ std::list<Function_wrapper> initfunctions;
+ std::list<Function_wrapper> destroyfunctions;
+ std::string sectionname;
+public:
+ Section(std::string const& _sectionname):sectionname(_sectionname) { }
+
+ void AddInitFunction(SectionFunction func,bool canchange=false);
+ void AddDestroyFunction(SectionFunction func,bool canchange=false);
+ void ExecuteInit(bool initall=true);
+ void ExecuteDestroy(bool destroyall=true);
+ const char* GetName() const {return sectionname.c_str();}
+
+ virtual std::string GetPropValue(std::string const& _property) const =0;
+ virtual bool HandleInputline(std::string const& _line)=0;
+ virtual void PrintData(FILE* outfile) const =0;
+ virtual ~Section() { /*Children must call executedestroy ! */}
+};
+
+class Prop_multival;
+class Prop_multival_remain;
+class Section_prop:public Section {
+private:
+ std::list<Property*> properties;
+ typedef std::list<Property*>::iterator it;
+ typedef std::list<Property*>::const_iterator const_it;
+
+public:
+ Section_prop(std::string const& _sectionname):Section(_sectionname){}
+ Prop_int* Add_int(std::string const& _propname, Property::Changeable::Value when, int _value=0);
+ Prop_string* Add_string(std::string const& _propname, Property::Changeable::Value when, char const * const _value=NULL);
+ Prop_path* Add_path(std::string const& _propname, Property::Changeable::Value when, char const * const _value=NULL);
+ Prop_bool* Add_bool(std::string const& _propname, Property::Changeable::Value when, bool _value=false);
+ Prop_hex* Add_hex(std::string const& _propname, Property::Changeable::Value when, Hex _value=0);
+// void Add_double(char const * const _propname, double _value=0.0);
+ Prop_multival *Add_multi(std::string const& _propname, Property::Changeable::Value when,std::string const& sep);
+ Prop_multival_remain *Add_multiremain(std::string const& _propname, Property::Changeable::Value when,std::string const& sep);
+
+ Property* Get_prop(int index);
+ int Get_int(std::string const& _propname) const;
+ const char* Get_string(std::string const& _propname) const;
+ bool Get_bool(std::string const& _propname) const;
+ Hex Get_hex(std::string const& _propname) const;
+ double Get_double(std::string const& _propname) const;
+ Prop_path* Get_path(std::string const& _propname) const;
+ Prop_multival* Get_multival(std::string const& _propname) const;
+ Prop_multival_remain* Get_multivalremain(std::string const& _propname) const;
+ bool HandleInputline(std::string const& gegevens);
+ void PrintData(FILE* outfile) const;
+ virtual std::string GetPropValue(std::string const& _property) const;
+ //ExecuteDestroy should be here else the destroy functions use destroyed properties
+ virtual ~Section_prop();
+};
+
+class Prop_multival:public Property{
+protected:
+ Section_prop* section;
+ std::string separator;
+ void make_default_value();
+public:
+ Prop_multival(std::string const& _propname, Changeable::Value when,std::string const& sep):Property(_propname,when), section(new Section_prop("")),separator(sep) {
+ default_value = value = "";
+ }
+ Section_prop *GetSection() { return section; }
+ const Section_prop *GetSection() const { return section; }
+ virtual bool SetValue(std::string const& input);
+ virtual const std::vector<Value>& GetValues() const;
+ ~Prop_multival() { delete section; }
+}; //value bevat totale string. setvalue zet elk van de sub properties en checked die.
+
+class Prop_multival_remain:public Prop_multival{
+public:
+ Prop_multival_remain(std::string const& _propname, Changeable::Value when,std::string const& sep):Prop_multival(_propname,when,sep){ }
+
+ virtual bool SetValue(std::string const& input);
+};
+
+
+class Section_line: public Section{
+public:
+ Section_line(std::string const& _sectionname):Section(_sectionname){}
+ ~Section_line(){ExecuteDestroy(true);}
+ bool HandleInputline(std::string const& gegevens);
+ void PrintData(FILE* outfile) const;
+ virtual std::string GetPropValue(std::string const& _property) const;
+ std::string data;
+};
+
+class Module_base {
+ /* Base for all hardware and software "devices" */
+protected:
+ Section* m_configuration;
+public:
+ Module_base(Section* configuration){m_configuration=configuration;};
+// Module_base(Section* configuration, SaveState* state) {};
+ virtual ~Module_base(){/*LOG_MSG("executed")*/;};//Destructors are required
+ /* Returns true if succesful.*/
+ virtual bool Change_Config(Section* /*newconfig*/) {return false;} ;
+};
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2002-2017 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 DOSBOX_SHELL_H
+#define DOSBOX_SHELL_H
+
+#include <ctype.h>
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+#ifndef DOSBOX_PROGRAMS_H
+#include "programs.h"
+#endif
+
+#include <string>
+#include <list>
+
+#define CMD_MAXLINE 4096
+#define CMD_MAXCMDS 20
+#define CMD_OLDSIZE 4096
+extern Bitu call_shellstop;
+/* first_shell is used to add and delete stuff from the shell env
+ * by "external" programs. (config) */
+extern Program * first_shell;
+
+class DOS_Shell;
+
+class BatchFile {
+public:
+ BatchFile(DOS_Shell * host,char const* const resolved_name,char const* const entered_name, char const * const cmd_line);
+ virtual ~BatchFile();
+ virtual bool ReadLine(char * line);
+ bool Goto(char * where);
+ void Shift(void);
+ Bit16u file_handle;
+ Bit32u location;
+ bool echo;
+ DOS_Shell * shell;
+ BatchFile * prev;
+ CommandLine * cmd;
+ std::string filename;
+};
+
+class AutoexecEditor;
+class DOS_Shell : public Program {
+private:
+ friend class AutoexecEditor;
+ std::list<std::string> l_history, l_completion;
+
+ char *completion_start;
+ Bit16u completion_index;
+
+public:
+
+ DOS_Shell();
+
+ void Run(void);
+ void RunInternal(void); //for command /C
+/* A load of subfunctions */
+ void ParseLine(char * line);
+ Bitu GetRedirection(char *s, char **ifn, char **ofn, char **toc, bool * append);
+ void InputCommand(char * line);
+ void ShowPrompt();
+ void DoCommand(char * cmd);
+ bool Execute(char * name,char * args);
+ /* Checks if it matches a hardware-property */
+ bool CheckConfig(char* cmd_in,char*line);
+/* Some internal used functions */
+ char * Which(char * name);
+/* Some supported commands */
+ void CMD_HELP(char * args);
+ void CMD_CHCP(char * args);
+ void CMD_CLS(char * args);
+ void CMD_COPY(char * args);
+ void CMD_DATE(char * args);
+ void CMD_TIME(char * args);
+ void CMD_DIR(char * args);
+ void CMD_DELETE(char * args);
+ void CMD_ECHO(char * args);
+ void CMD_EXIT(char * args);
+ void CMD_MKDIR(char * args);
+ void CMD_CHDIR(char * args);
+ void CMD_RMDIR(char * args);
+ void CMD_SET(char * args);
+ void CMD_IF(char * args);
+ void CMD_FOR(char * args);
+ void CMD_GOTO(char * args);
+ void CMD_TYPE(char * args);
+ void CMD_REM(char * args);
+ void CMD_RENAME(char * args);
+ void CMD_CALL(char * args);
+ void SyntaxError(void);
+ void CMD_PAUSE(char * args);
+ void CMD_SUBST(char* args);
+ void CMD_LOADHIGH(char* args);
+ void CMD_CHOICE(char * args);
+ void CMD_ATTRIB(char * args);
+ void CMD_PROMPT(char * args);
+ void CMD_PATH(char * args);
+ void CMD_SHIFT(char * args);
+ void CMD_VER(char * args);
+ void CMD_CHEV(char * args);
+ /* The shell's variables */
+ Bit16u input_handle;
+ BatchFile * bf;
+ bool echo;
+ bool exit;
+ bool call;
+};
+
+struct SHELL_Cmd {
+ const char * name; /* Command name*/
+ Bit32u flags; /* Flags about the command */
+ void (DOS_Shell::*handler)(char * args); /* Handler for this command */
+ const char * help; /* String with command help */
+};
+
+/* Object to manage lines in the autoexec.bat The lines get removed from
+ * the file if the object gets destroyed. The environment is updated
+ * as well if the line set a a variable */
+class AutoexecObject{
+private:
+ bool installed;
+ std::string buf;
+public:
+ AutoexecObject():installed(false){ };
+ void Install(std::string const &in);
+ void InstallBefore(std::string const &in);
+ ~AutoexecObject();
+private:
+ void CreateAutoexec(void);
+};
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2002-2017 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.
+ *
+ * Wengier: LFN support
+ */
+
+
+#ifndef DOSBOX_SUPPORT_H
+#define DOSBOX_SUPPORT_H
+
+#include <string.h>
+#include <string>
+#include <ctype.h>
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+
+#if defined (_MSC_VER) /* MS Visual C++ */
+#define strcasecmp(a,b) stricmp(a,b)
+#define strncasecmp(a,b,n) _strnicmp(a,b,n)
+#endif
+
+#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0)
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+void strreplace(char * str,char o,char n);
+char *ltrim(char *str);
+char *rtrim(char *str);
+char *trim(char * str);
+char * upcase(char * str);
+char * lowcase(char * str);
+
+bool ScanCMDBool(char * cmd,char const * const check);
+char * ScanCMDRemain(char * cmd);
+char * StripWord(char *&cmd);
+char * StripArg(char *&cmd);
+bool IsDecWord(char * word);
+bool IsHexWord(char * word);
+Bits ConvDecWord(char * word);
+Bits ConvHexWord(char * word);
+
+void upcase(std::string &str);
+void lowcase(std::string &str);
+
+#if defined(LINUX)
+void utf8_to_sjis_copy(char *dst, char *src, int len);
+void sjis_to_utf8_copy(char *dst, char *src, int len);
+void sjis_to_utf16_copy(char *dst, char *src, int len);
+void ChangeUtf8FileName(char *fullname);
+#endif
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_TIMER_H
+#define DOSBOX_TIMER_H
+
+/* underlying clock rate in HZ */
+#include <SDL.h>
+
+#define PIT_TICK_RATE 1193182
+
+#define GetTicks() SDL_GetTicks()
+
+typedef void (*TIMER_TickHandler)(void);
+
+/* Register a function that gets called everytime if 1 or more ticks pass */
+void TIMER_AddTickHandler(TIMER_TickHandler handler);
+void TIMER_DelTickHandler(TIMER_TickHandler handler);
+
+/* This will add 1 milliscond to all timers */
+void TIMER_AddTick(void);
+
+#endif
--- /dev/null
+ /*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_VGA_H
+#define DOSBOX_VGA_H
+
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+
+//Don't enable keeping changes and mapping lfb probably...
+#define VGA_LFB_MAPPED
+//#define VGA_KEEP_CHANGES
+#define VGA_CHANGE_SHIFT 9
+
+class PageHandler;
+
+
+enum VGAModes {
+ M_CGA2, M_CGA4,
+ M_EGA, M_VGA,
+ M_LIN4, M_LIN8, M_LIN15, M_LIN16, M_LIN32,
+ M_TEXT,
+ M_HERC_GFX, M_HERC_TEXT,
+ M_CGA16, M_TANDY2, M_TANDY4, M_TANDY16, M_TANDY_TEXT,
+ M_DCGA,
+ M_ERROR
+};
+
+
+#define CLK_25 25175
+#define CLK_28 28322
+
+#define MIN_VCO 180000
+#define MAX_VCO 360000
+
+#define S3_CLOCK_REF 14318 /* KHz */
+#define S3_CLOCK(_M,_N,_R) ((S3_CLOCK_REF * ((_M) + 2)) / (((_N) + 2) * (1 << (_R))))
+#define S3_MAX_CLOCK 150000 /* KHz */
+
+#define S3_XGA_1024 0x00
+#define S3_XGA_1152 0x01
+#define S3_XGA_640 0x40
+#define S3_XGA_800 0x80
+#define S3_XGA_1280 0xc0
+#define S3_XGA_WMASK (S3_XGA_640|S3_XGA_800|S3_XGA_1024|S3_XGA_1152|S3_XGA_1280)
+
+#define S3_XGA_8BPP 0x00
+#define S3_XGA_16BPP 0x10
+#define S3_XGA_32BPP 0x30
+#define S3_XGA_CMASK (S3_XGA_8BPP|S3_XGA_16BPP|S3_XGA_32BPP)
+
+typedef struct {
+ bool attrindex;
+} VGA_Internal;
+
+typedef struct {
+/* Memory handlers */
+ Bitu mh_mask;
+
+/* Video drawing */
+ Bitu display_start;
+ Bitu real_start;
+ bool retrace; /* A retrace is active */
+ Bitu scan_len;
+ Bitu cursor_start;
+
+/* Some other screen related variables */
+ Bitu line_compare;
+ bool chained; /* Enable or Disabled Chain 4 Mode */
+ bool compatible_chain4;
+
+ /* Pixel Scrolling */
+ Bit8u pel_panning; /* Amount of pixels to skip when starting horizontal line */
+ Bit8u hlines_skip;
+ Bit8u bytes_skip;
+ Bit8u addr_shift;
+
+/* Specific stuff memory write/read handling */
+
+ Bit8u read_mode;
+ Bit8u write_mode;
+ Bit8u read_map_select;
+ Bit8u color_dont_care;
+ Bit8u color_compare;
+ Bit8u data_rotate;
+ Bit8u raster_op;
+
+ Bit32u full_bit_mask;
+ Bit32u full_map_mask;
+ Bit32u full_not_map_mask;
+ Bit32u full_set_reset;
+ Bit32u full_not_enable_set_reset;
+ Bit32u full_enable_set_reset;
+ Bit32u full_enable_and_set_reset;
+} VGA_Config;
+
+typedef enum {
+ PART,
+ DRAWLINE,
+ EGALINE
+} Drawmode;
+
+typedef struct {
+ bool resizing;
+ Bitu width;
+ Bitu height;
+ Bitu blocks;
+ Bitu address;
+ Bitu panning;
+ Bitu bytes_skip;
+ Bit8u *linear_base;
+ Bitu linear_mask;
+ Bitu address_add;
+ Bitu line_length;
+ Bitu address_line_total;
+ Bitu address_line;
+ Bitu lines_total;
+ Bitu vblank_skip;
+ Bitu lines_done;
+ Bitu lines_scaled;
+ Bitu split_line;
+ Bitu parts_total;
+ Bitu parts_lines;
+ Bitu parts_left;
+ Bitu byte_panning_shift;
+ struct {
+ double framestart;
+ double vrstart, vrend; // V-retrace
+ double hrstart, hrend; // H-retrace
+ double hblkstart, hblkend; // H-blanking
+ double vblkstart, vblkend; // V-Blanking
+ double vdend, vtotal;
+ double hdend, htotal;
+ double parts;
+ } delay;
+ Bitu bpp;
+ double aspect_ratio;
+ bool double_scan;
+ bool doublewidth,doubleheight;
+ Bit8u font[64*1024];
+ Bit8u * font_tables[2];
+ Bitu blinking;
+ bool blink;
+ bool char9dot;
+ struct {
+ Bitu address;
+ Bit8u sline,eline;
+ Bit8u count,delay;
+ Bit8u enabled;
+ } cursor;
+ Drawmode mode;
+ bool vret_triggered;
+ bool vga_override;
+} VGA_Draw;
+
+typedef struct {
+ Bit8u curmode;
+ Bit16u originx, originy;
+ Bit8u fstackpos, bstackpos;
+ Bit8u forestack[4];
+ Bit8u backstack[4];
+ Bit16u startaddr;
+ Bit8u posx, posy;
+ Bit8u mc[64][64];
+} VGA_HWCURSOR;
+
+typedef struct {
+ Bit8u reg_lock1;
+ Bit8u reg_lock2;
+ Bit8u reg_31;
+ Bit8u reg_35;
+ Bit8u reg_36; // RAM size
+ Bit8u reg_3a; // 4/8/doublepixel bit in there
+ Bit8u reg_40; // 8415/A functionality register
+ Bit8u reg_41; // BIOS flags
+ Bit8u reg_43;
+ Bit8u reg_45; // Hardware graphics cursor
+ Bit8u reg_50;
+ Bit8u reg_51;
+ Bit8u reg_52;
+ Bit8u reg_55;
+ Bit8u reg_58;
+ Bit8u reg_6b; // LFB BIOS scratchpad
+ Bit8u ex_hor_overflow;
+ Bit8u ex_ver_overflow;
+ Bit16u la_window;
+ Bit8u misc_control_2;
+ Bit8u ext_mem_ctrl;
+ Bitu xga_screen_width;
+ VGAModes xga_color_mode;
+ struct {
+ Bit8u r;
+ Bit8u n;
+ Bit8u m;
+ } clk[4],mclk;
+ struct {
+ Bit8u lock;
+ Bit8u cmd;
+ } pll;
+ VGA_HWCURSOR hgc;
+} VGA_S3;
+
+typedef struct {
+ Bit8u mode_control;
+ Bit8u enable_bits;
+} VGA_HERC;
+
+typedef struct {
+ Bit8u index;
+ Bit8u htotal;
+ Bit8u hdend;
+ Bit8u hsyncp;
+ Bit8u hsyncw;
+ Bit8u vtotal;
+ Bit8u vdend;
+ Bit8u vadjust;
+ Bit8u vsyncp;
+ Bit8u vsyncw;
+ Bit8u max_scanline;
+ Bit16u lightpen;
+ bool lightpen_triggered;
+ Bit8u cursor_start;
+ Bit8u cursor_end;
+} VGA_OTHER;
+
+typedef struct {
+ Bit8u pcjr_flipflop;
+ Bit8u mode_control;
+ Bit8u color_select;
+ Bit8u disp_bank;
+ Bit8u reg_index;
+ Bit8u gfx_control;
+ Bit8u palette_mask;
+ Bit8u extended_ram;
+ Bit8u border_color;
+ Bit8u line_mask, line_shift;
+ Bit8u draw_bank, mem_bank;
+ Bit8u *draw_base, *mem_base;
+ Bitu addr_mask;
+} VGA_TANDY;
+
+typedef struct {
+ Bit8u index;
+ Bit8u reset;
+ Bit8u clocking_mode;
+ Bit8u map_mask;
+ Bit8u character_map_select;
+ Bit8u memory_mode;
+} VGA_Seq;
+
+typedef struct {
+ Bit8u palette[16];
+ Bit8u mode_control;
+ Bit8u horizontal_pel_panning;
+ Bit8u overscan_color;
+ Bit8u color_plane_enable;
+ Bit8u color_select;
+ Bit8u index;
+ Bit8u disabled; // Used for disabling the screen.
+ // Bit0: screen disabled by attribute controller index
+ // Bit1: screen disabled by sequencer index 1 bit 5
+ // These are put together in one variable for performance reasons:
+ // the line drawing function is called maybe 60*480=28800 times/s,
+ // and we only need to check one variable for zero this way.
+} VGA_Attr;
+
+typedef struct {
+ Bit8u horizontal_total;
+ Bit8u horizontal_display_end;
+ Bit8u start_horizontal_blanking;
+ Bit8u end_horizontal_blanking;
+ Bit8u start_horizontal_retrace;
+ Bit8u end_horizontal_retrace;
+ Bit8u vertical_total;
+ Bit8u overflow;
+ Bit8u preset_row_scan;
+ Bit8u maximum_scan_line;
+ Bit8u cursor_start;
+ Bit8u cursor_end;
+ Bit8u start_address_high;
+ Bit8u start_address_low;
+ Bit8u cursor_location_high;
+ Bit8u cursor_location_low;
+ Bit8u vertical_retrace_start;
+ Bit8u vertical_retrace_end;
+ Bit8u vertical_display_end;
+ Bit8u offset;
+ Bit8u underline_location;
+ Bit8u start_vertical_blanking;
+ Bit8u end_vertical_blanking;
+ Bit8u mode_control;
+ Bit8u line_compare;
+
+ Bit8u index;
+ bool read_only;
+} VGA_Crtc;
+
+typedef struct {
+ Bit8u index;
+ Bit8u set_reset;
+ Bit8u enable_set_reset;
+ Bit8u color_compare;
+ Bit8u data_rotate;
+ Bit8u read_map_select;
+ Bit8u mode;
+ Bit8u miscellaneous;
+ Bit8u color_dont_care;
+ Bit8u bit_mask;
+} VGA_Gfx;
+
+typedef struct {
+ Bit8u red;
+ Bit8u green;
+ Bit8u blue;
+} RGBEntry;
+
+typedef struct {
+ Bit8u bits; /* DAC bits, usually 6 or 8 */
+ Bit8u pel_mask;
+ Bit8u pel_index;
+ Bit8u state;
+ Bit8u write_index;
+ Bit8u read_index;
+ Bitu first_changed;
+ Bit8u combine[16];
+ RGBEntry rgb[0x100];
+ Bit16u xlat16[256];
+} VGA_Dac;
+
+typedef struct {
+ Bitu readStart, writeStart;
+ Bitu bankMask;
+ Bitu bank_read_full;
+ Bitu bank_write_full;
+ Bit8u bank_read;
+ Bit8u bank_write;
+ Bitu bank_size;
+} VGA_SVGA;
+
+typedef union {
+ Bit32u d;
+ Bit8u b[4];
+} VGA_Latch;
+
+typedef struct {
+ Bit8u* linear;
+ Bit8u* linear_orgptr;
+} VGA_Memory;
+
+typedef struct {
+ //Add a few more just to be safe
+ Bit8u* map; /* allocated dynamically: [(VGA_MEMORY >> VGA_CHANGE_SHIFT) + 32] */
+ Bit8u checkMask, frame, writeMask;
+ bool active;
+ Bit32u clearMask;
+ Bit32u start, last;
+ Bit32u lastAddress;
+} VGA_Changes;
+
+typedef struct {
+ Bit32u page;
+ Bit32u addr;
+ Bit32u mask;
+ PageHandler *handler;
+} VGA_LFB;
+
+typedef struct {
+ VGAModes mode; /* The mode the vga system is in */
+ Bit8u misc_output;
+ VGA_Draw draw;
+ VGA_Config config;
+ VGA_Internal internal;
+/* Internal module groups */
+ VGA_Seq seq;
+ VGA_Attr attr;
+ VGA_Crtc crtc;
+ VGA_Gfx gfx;
+ VGA_Dac dac;
+ VGA_Latch latch;
+ VGA_S3 s3;
+ VGA_SVGA svga;
+ VGA_HERC herc;
+ VGA_TANDY tandy;
+ VGA_OTHER other;
+ VGA_Memory mem;
+ Bit32u vmemwrap; /* this is assumed to be power of 2 */
+ Bit8u* fastmem; /* memory for fast (usually 16-color) rendering, always twice as big as vmemsize */
+ Bit8u* fastmem_orgptr;
+ Bit32u vmemsize;
+#ifdef VGA_KEEP_CHANGES
+ VGA_Changes changes;
+#endif
+ VGA_LFB lfb;
+} VGA_Type;
+
+
+/* Hercules Palette function */
+void Herc_Palette(void);
+
+/* Functions for different resolutions */
+void VGA_SetMode(VGAModes mode);
+void VGA_DetermineMode(void);
+void VGA_SetupHandlers(void);
+void VGA_StartResize(Bitu delay=50);
+void VGA_SetupDrawing(Bitu val);
+void VGA_CheckScanLength(void);
+void VGA_ChangedBank(void);
+
+/* Some DAC/Attribute functions */
+void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal);
+void VGA_DAC_SetEntry(Bitu entry,Bit8u red,Bit8u green,Bit8u blue);
+void VGA_ATTR_SetPalette(Bit8u index,Bit8u val);
+
+typedef enum {CGA, EGA, MONO} EGAMonitorMode;
+
+void VGA_ATTR_SetEGAMonitorPalette(EGAMonitorMode m);
+
+/* The VGA Subfunction startups */
+void VGA_SetupAttr(void);
+void VGA_SetupMemory(Section* sec);
+void VGA_SetupDAC(void);
+void VGA_SetupCRTC(void);
+void VGA_SetupMisc(void);
+void VGA_SetupGFX(void);
+void VGA_SetupSEQ(void);
+void VGA_SetupOther(void);
+void VGA_SetupXGA(void);
+
+void JEGA_setupAX(void);
+
+/* Some Support Functions */
+void VGA_SetClock(Bitu which,Bitu target);
+void VGA_DACSetEntirePalette(void);
+void VGA_StartRetrace(void);
+void VGA_StartUpdateLFB(void);
+void VGA_SetBlinking(Bitu enabled);
+void VGA_SetCGA2Table(Bit8u val0,Bit8u val1);
+void VGA_SetCGA4Table(Bit8u val0,Bit8u val1,Bit8u val2,Bit8u val3);
+void VGA_ActivateHardwareCursor(void);
+void VGA_KillDrawing(void);
+
+void VGA_SetOverride(bool vga_override);
+
+extern VGA_Type vga;
+
+/* Support for modular SVGA implementation */
+/* Video mode extra data to be passed to FinishSetMode_SVGA().
+ This structure will be in flux until all drivers (including S3)
+ are properly separated. Right now it contains only three overflow
+ fields in S3 format and relies on drivers re-interpreting those.
+ For reference:
+ ver_overflow:X|line_comp10|X|vretrace10|X|vbstart10|vdispend10|vtotal10
+ hor_overflow:X|X|X|hretrace8|X|hblank8|hdispend8|htotal8
+ offset is not currently used by drivers (useful only for S3 itself)
+ It also contains basic int10 mode data - number, vtotal, htotal
+ */
+typedef struct {
+ Bit8u ver_overflow;
+ Bit8u hor_overflow;
+ Bitu offset;
+ Bitu modeNo;
+ Bitu htotal;
+ Bitu vtotal;
+} VGA_ModeExtraData;
+
+// Vector function prototypes
+typedef void (*tWritePort)(Bitu reg,Bitu val,Bitu iolen);
+typedef Bitu (*tReadPort)(Bitu reg,Bitu iolen);
+typedef void (*tFinishSetMode)(Bitu crtc_base, VGA_ModeExtraData* modeData);
+typedef void (*tDetermineMode)();
+typedef void (*tSetClock)(Bitu which,Bitu target);
+typedef Bitu (*tGetClock)();
+typedef bool (*tHWCursorActive)();
+typedef bool (*tAcceptsMode)(Bitu modeNo);
+
+struct SVGA_Driver {
+ tWritePort write_p3d5;
+ tReadPort read_p3d5;
+ tWritePort write_p3c5;
+ tReadPort read_p3c5;
+ tWritePort write_p3c0;
+ tReadPort read_p3c1;
+ tWritePort write_p3cf;
+ tReadPort read_p3cf;
+
+ tFinishSetMode set_video_mode;
+ tDetermineMode determine_mode;
+ tSetClock set_clock;
+ tGetClock get_clock;
+ tHWCursorActive hardware_cursor_active;
+ tAcceptsMode accepts_mode;
+};
+
+extern SVGA_Driver svga;
+
+void SVGA_Setup_S3Trio(void);
+void SVGA_Setup_TsengET4K(void);
+void SVGA_Setup_TsengET3K(void);
+void SVGA_Setup_ParadisePVGA1A(void);
+void SVGA_Setup_Driver(void);
+
+// Amount of video memory required for a mode, implemented in int10_modes.cpp
+Bitu VideoModeMemSize(Bitu mode);
+
+extern Bit32u ExpandTable[256];
+extern Bit32u FillTable[16];
+extern Bit32u CGA_2_Table[16];
+extern Bit32u CGA_4_Table[256];
+extern Bit32u CGA_4_HiRes_Table[256];
+extern Bit32u CGA_16_Table[256];
+extern Bit32u TXT_Font_Table[16];
+extern Bit32u TXT_FG_Table[16];
+extern Bit32u TXT_BG_Table[16];
+extern Bit32u Expand16Table[4][16];
+extern Bit32u Expand16BigTable[0x10000];
+
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#ifndef DOSBOX_VIDEO_H
+#define DOSBOX_VIDEO_H
+
+#define REDUCE_JOYSTICK_POLLING
+
+typedef enum {
+ GFX_CallBackReset,
+ GFX_CallBackStop,
+ GFX_CallBackRedraw
+} GFX_CallBackFunctions_t;
+
+typedef void (*GFX_CallBack_t)( GFX_CallBackFunctions_t function );
+
+struct GFX_PalEntry {
+ Bit8u r;
+ Bit8u g;
+ Bit8u b;
+ Bit8u unused;
+};
+
+#define GFX_CAN_8 0x0001
+#define GFX_CAN_15 0x0002
+#define GFX_CAN_16 0x0004
+#define GFX_CAN_32 0x0008
+
+#define GFX_LOVE_8 0x0010
+#define GFX_LOVE_15 0x0020
+#define GFX_LOVE_16 0x0040
+#define GFX_LOVE_32 0x0080
+
+#define GFX_RGBONLY 0x0100
+
+#define GFX_SCALING 0x1000
+#define GFX_HARDWARE 0x2000
+
+#define GFX_CAN_RANDOM 0x4000 //If the interface can also do random access surface
+
+void GFX_Events(void);
+void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries);
+Bitu GFX_GetBestMode(Bitu flags);
+Bitu GFX_GetRGB(Bit8u red,Bit8u green,Bit8u blue);
+Bitu GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,GFX_CallBack_t cb);
+
+void GFX_ResetScreen(void);
+void GFX_Start(void);
+void GFX_Stop(void);
+void GFX_SwitchFullScreen(void);
+bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch);
+void GFX_EndUpdate( const Bit16u *changedLines );
+void GFX_GetSize(int &width, int &height, bool &fullscreen);
+void GFX_LosingFocus(void);
+
+#if defined (WIN32)
+bool GFX_SDLUsingWinDIB(void);
+#endif
+
+#if defined (REDUCE_JOYSTICK_POLLING)
+void MAPPER_UpdateJoysticks(void);
+#endif
+
+/* Mouse related */
+void GFX_CaptureMouse(void);
+extern bool mouselocked; //true if mouse is confined to window
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+/* Jumps */
+
+/* All Byte general instructions */
+#define ADDB(op1,op2,load,save) \
+ lf_var1b=load(op1);lf_var2b=op2; \
+ lf_resb=lf_var1b+lf_var2b; \
+ save(op1,lf_resb); \
+ lflags.type=t_ADDb;
+
+#define ADCB(op1,op2,load,save) \
+ lflags.oldcf=get_CF()!=0; \
+ lf_var1b=load(op1);lf_var2b=op2; \
+ lf_resb=lf_var1b+lf_var2b+lflags.oldcf; \
+ save(op1,lf_resb); \
+ lflags.type=t_ADCb;
+
+#define SBBB(op1,op2,load,save) \
+ lflags.oldcf=get_CF()!=0; \
+ lf_var1b=load(op1);lf_var2b=op2; \
+ lf_resb=lf_var1b-(lf_var2b+lflags.oldcf); \
+ save(op1,lf_resb); \
+ lflags.type=t_SBBb;
+
+#define SUBB(op1,op2,load,save) \
+ lf_var1b=load(op1);lf_var2b=op2; \
+ lf_resb=lf_var1b-lf_var2b; \
+ save(op1,lf_resb); \
+ lflags.type=t_SUBb;
+
+#define ORB(op1,op2,load,save) \
+ lf_var1b=load(op1);lf_var2b=op2; \
+ lf_resb=lf_var1b | lf_var2b; \
+ save(op1,lf_resb); \
+ lflags.type=t_ORb;
+
+#define XORB(op1,op2,load,save) \
+ lf_var1b=load(op1);lf_var2b=op2; \
+ lf_resb=lf_var1b ^ lf_var2b; \
+ save(op1,lf_resb); \
+ lflags.type=t_XORb;
+
+#define ANDB(op1,op2,load,save) \
+ lf_var1b=load(op1);lf_var2b=op2; \
+ lf_resb=lf_var1b & lf_var2b; \
+ save(op1,lf_resb); \
+ lflags.type=t_ANDb;
+
+#define CMPB(op1,op2,load,save) \
+ lf_var1b=load(op1);lf_var2b=op2; \
+ lf_resb=lf_var1b-lf_var2b; \
+ lflags.type=t_CMPb;
+
+#define TESTB(op1,op2,load,save) \
+ lf_var1b=load(op1);lf_var2b=op2; \
+ lf_resb=lf_var1b & lf_var2b; \
+ lflags.type=t_TESTb;
+
+/* All Word General instructions */
+
+#define ADDW(op1,op2,load,save) \
+ lf_var1w=load(op1);lf_var2w=op2; \
+ lf_resw=lf_var1w+lf_var2w; \
+ save(op1,lf_resw); \
+ lflags.type=t_ADDw;
+
+#define ADCW(op1,op2,load,save) \
+ lflags.oldcf=get_CF()!=0; \
+ lf_var1w=load(op1);lf_var2w=op2; \
+ lf_resw=lf_var1w+lf_var2w+lflags.oldcf; \
+ save(op1,lf_resw); \
+ lflags.type=t_ADCw;
+
+#define SBBW(op1,op2,load,save) \
+ lflags.oldcf=get_CF()!=0; \
+ lf_var1w=load(op1);lf_var2w=op2; \
+ lf_resw=lf_var1w-(lf_var2w+lflags.oldcf); \
+ save(op1,lf_resw); \
+ lflags.type=t_SBBw;
+
+#define SUBW(op1,op2,load,save) \
+ lf_var1w=load(op1);lf_var2w=op2; \
+ lf_resw=lf_var1w-lf_var2w; \
+ save(op1,lf_resw); \
+ lflags.type=t_SUBw;
+
+#define ORW(op1,op2,load,save) \
+ lf_var1w=load(op1);lf_var2w=op2; \
+ lf_resw=lf_var1w | lf_var2w; \
+ save(op1,lf_resw); \
+ lflags.type=t_ORw;
+
+#define XORW(op1,op2,load,save) \
+ lf_var1w=load(op1);lf_var2w=op2; \
+ lf_resw=lf_var1w ^ lf_var2w; \
+ save(op1,lf_resw); \
+ lflags.type=t_XORw;
+
+#define ANDW(op1,op2,load,save) \
+ lf_var1w=load(op1);lf_var2w=op2; \
+ lf_resw=lf_var1w & lf_var2w; \
+ save(op1,lf_resw); \
+ lflags.type=t_ANDw;
+
+#define CMPW(op1,op2,load,save) \
+ lf_var1w=load(op1);lf_var2w=op2; \
+ lf_resw=lf_var1w-lf_var2w; \
+ lflags.type=t_CMPw;
+
+#define TESTW(op1,op2,load,save) \
+ lf_var1w=load(op1);lf_var2w=op2; \
+ lf_resw=lf_var1w & lf_var2w; \
+ lflags.type=t_TESTw;
+
+/* All DWORD General Instructions */
+
+#define ADDD(op1,op2,load,save) \
+ lf_var1d=load(op1);lf_var2d=op2; \
+ lf_resd=lf_var1d+lf_var2d; \
+ save(op1,lf_resd); \
+ lflags.type=t_ADDd;
+
+#define ADCD(op1,op2,load,save) \
+ lflags.oldcf=get_CF()!=0; \
+ lf_var1d=load(op1);lf_var2d=op2; \
+ lf_resd=lf_var1d+lf_var2d+lflags.oldcf; \
+ save(op1,lf_resd); \
+ lflags.type=t_ADCd;
+
+#define SBBD(op1,op2,load,save) \
+ lflags.oldcf=get_CF()!=0; \
+ lf_var1d=load(op1);lf_var2d=op2; \
+ lf_resd=lf_var1d-(lf_var2d+lflags.oldcf); \
+ save(op1,lf_resd); \
+ lflags.type=t_SBBd;
+
+#define SUBD(op1,op2,load,save) \
+ lf_var1d=load(op1);lf_var2d=op2; \
+ lf_resd=lf_var1d-lf_var2d; \
+ save(op1,lf_resd); \
+ lflags.type=t_SUBd;
+
+#define ORD(op1,op2,load,save) \
+ lf_var1d=load(op1);lf_var2d=op2; \
+ lf_resd=lf_var1d | lf_var2d; \
+ save(op1,lf_resd); \
+ lflags.type=t_ORd;
+
+#define XORD(op1,op2,load,save) \
+ lf_var1d=load(op1);lf_var2d=op2; \
+ lf_resd=lf_var1d ^ lf_var2d; \
+ save(op1,lf_resd); \
+ lflags.type=t_XORd;
+
+#define ANDD(op1,op2,load,save) \
+ lf_var1d=load(op1);lf_var2d=op2; \
+ lf_resd=lf_var1d & lf_var2d; \
+ save(op1,lf_resd); \
+ lflags.type=t_ANDd;
+
+#define CMPD(op1,op2,load,save) \
+ lf_var1d=load(op1);lf_var2d=op2; \
+ lf_resd=lf_var1d-lf_var2d; \
+ lflags.type=t_CMPd;
+
+
+#define TESTD(op1,op2,load,save) \
+ lf_var1d=load(op1);lf_var2d=op2; \
+ lf_resd=lf_var1d & lf_var2d; \
+ lflags.type=t_TESTd;
+
+
+
+
+#define INCB(op1,load,save) \
+ LoadCF;lf_var1b=load(op1); \
+ lf_resb=lf_var1b+1; \
+ save(op1,lf_resb); \
+ lflags.type=t_INCb; \
+
+#define INCW(op1,load,save) \
+ LoadCF;lf_var1w=load(op1); \
+ lf_resw=lf_var1w+1; \
+ save(op1,lf_resw); \
+ lflags.type=t_INCw;
+
+#define INCD(op1,load,save) \
+ LoadCF;lf_var1d=load(op1); \
+ lf_resd=lf_var1d+1; \
+ save(op1,lf_resd); \
+ lflags.type=t_INCd;
+
+#define DECB(op1,load,save) \
+ LoadCF;lf_var1b=load(op1); \
+ lf_resb=lf_var1b-1; \
+ save(op1,lf_resb); \
+ lflags.type=t_DECb;
+
+#define DECW(op1,load,save) \
+ LoadCF;lf_var1w=load(op1); \
+ lf_resw=lf_var1w-1; \
+ save(op1,lf_resw); \
+ lflags.type=t_DECw;
+
+#define DECD(op1,load,save) \
+ LoadCF;lf_var1d=load(op1); \
+ lf_resd=lf_var1d-1; \
+ save(op1,lf_resd); \
+ lflags.type=t_DECd;
+
+
+
+#define ROLB(op1,op2,load,save) \
+ if (!(op2&0x7)) { \
+ if (op2&0x18) { \
+ FillFlagsNoCFOF(); \
+ SETFLAGBIT(CF,op1 & 1); \
+ SETFLAGBIT(OF,(op1 & 1) ^ (op1 >> 7)); \
+ } \
+ break; \
+ } \
+ FillFlagsNoCFOF(); \
+ lf_var1b=load(op1); \
+ lf_var2b=op2&0x07; \
+ lf_resb=(lf_var1b << lf_var2b) | \
+ (lf_var1b >> (8-lf_var2b)); \
+ save(op1,lf_resb); \
+ SETFLAGBIT(CF,lf_resb & 1); \
+ SETFLAGBIT(OF,(lf_resb & 1) ^ (lf_resb >> 7));
+
+#define ROLW(op1,op2,load,save) \
+ if (!(op2&0xf)) { \
+ if (op2&0x10) { \
+ FillFlagsNoCFOF(); \
+ SETFLAGBIT(CF,op1 & 1); \
+ SETFLAGBIT(OF,(op1 & 1) ^ (op1 >> 15)); \
+ } \
+ break; \
+ } \
+ FillFlagsNoCFOF(); \
+ lf_var1w=load(op1); \
+ lf_var2b=op2&0xf; \
+ lf_resw=(lf_var1w << lf_var2b) | \
+ (lf_var1w >> (16-lf_var2b)); \
+ save(op1,lf_resw); \
+ SETFLAGBIT(CF,lf_resw & 1); \
+ SETFLAGBIT(OF,(lf_resw & 1) ^ (lf_resw >> 15));
+
+#define ROLD(op1,op2,load,save) \
+ if (!op2) break; \
+ FillFlagsNoCFOF(); \
+ lf_var1d=load(op1); \
+ lf_var2b=op2; \
+ lf_resd=(lf_var1d << lf_var2b) | \
+ (lf_var1d >> (32-lf_var2b)); \
+ save(op1,lf_resd); \
+ SETFLAGBIT(CF,lf_resd & 1); \
+ SETFLAGBIT(OF,(lf_resd & 1) ^ (lf_resd >> 31));
+
+
+#define RORB(op1,op2,load,save) \
+ if (!(op2&0x7)) { \
+ if (op2&0x18) { \
+ FillFlagsNoCFOF(); \
+ SETFLAGBIT(CF,op1>>7); \
+ SETFLAGBIT(OF,(op1>>7) ^ ((op1>>6) & 1)); \
+ } \
+ break; \
+ } \
+ FillFlagsNoCFOF(); \
+ lf_var1b=load(op1); \
+ lf_var2b=op2&0x07; \
+ lf_resb=(lf_var1b >> lf_var2b) | \
+ (lf_var1b << (8-lf_var2b)); \
+ save(op1,lf_resb); \
+ SETFLAGBIT(CF,lf_resb & 0x80); \
+ SETFLAGBIT(OF,(lf_resb ^ (lf_resb<<1)) & 0x80);
+
+#define RORW(op1,op2,load,save) \
+ if (!(op2&0xf)) { \
+ if (op2&0x10) { \
+ FillFlagsNoCFOF(); \
+ SETFLAGBIT(CF,op1>>15); \
+ SETFLAGBIT(OF,(op1>>15) ^ ((op1>>14) & 1)); \
+ } \
+ break; \
+ } \
+ FillFlagsNoCFOF(); \
+ lf_var1w=load(op1); \
+ lf_var2b=op2&0xf; \
+ lf_resw=(lf_var1w >> lf_var2b) | \
+ (lf_var1w << (16-lf_var2b)); \
+ save(op1,lf_resw); \
+ SETFLAGBIT(CF,lf_resw & 0x8000); \
+ SETFLAGBIT(OF,(lf_resw ^ (lf_resw<<1)) & 0x8000);
+
+#define RORD(op1,op2,load,save) \
+ if (!op2) break; \
+ FillFlagsNoCFOF(); \
+ lf_var1d=load(op1); \
+ lf_var2b=op2; \
+ lf_resd=(lf_var1d >> lf_var2b) | \
+ (lf_var1d << (32-lf_var2b)); \
+ save(op1,lf_resd); \
+ SETFLAGBIT(CF,lf_resd & 0x80000000); \
+ SETFLAGBIT(OF,(lf_resd ^ (lf_resd<<1)) & 0x80000000);
+
+
+#define RCLB(op1,op2,load,save) \
+ if (!(op2%9)) break; \
+{ Bit8u cf=(Bit8u)FillFlags()&0x1; \
+ lf_var1b=load(op1); \
+ lf_var2b=op2%9; \
+ lf_resb=(lf_var1b << lf_var2b) | \
+ (cf << (lf_var2b-1)) | \
+ (lf_var1b >> (9-lf_var2b)); \
+ save(op1,lf_resb); \
+ SETFLAGBIT(CF,((lf_var1b >> (8-lf_var2b)) & 1)); \
+ SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resb >> 7)); \
+}
+
+#define RCLW(op1,op2,load,save) \
+ if (!(op2%17)) break; \
+{ Bit16u cf=(Bit16u)FillFlags()&0x1; \
+ lf_var1w=load(op1); \
+ lf_var2b=op2%17; \
+ lf_resw=(lf_var1w << lf_var2b) | \
+ (cf << (lf_var2b-1)) | \
+ (lf_var1w >> (17-lf_var2b)); \
+ save(op1,lf_resw); \
+ SETFLAGBIT(CF,((lf_var1w >> (16-lf_var2b)) & 1)); \
+ SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resw >> 15)); \
+}
+
+#define RCLD(op1,op2,load,save) \
+ if (!op2) break; \
+{ Bit32u cf=(Bit32u)FillFlags()&0x1; \
+ lf_var1d=load(op1); \
+ lf_var2b=op2; \
+ if (lf_var2b==1) { \
+ lf_resd=(lf_var1d << 1) | cf; \
+ } else { \
+ lf_resd=(lf_var1d << lf_var2b) | \
+ (cf << (lf_var2b-1)) | \
+ (lf_var1d >> (33-lf_var2b)); \
+ } \
+ save(op1,lf_resd); \
+ SETFLAGBIT(CF,((lf_var1d >> (32-lf_var2b)) & 1)); \
+ SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resd >> 31)); \
+}
+
+
+
+#define RCRB(op1,op2,load,save) \
+ if (op2%9) { \
+ Bit8u cf=(Bit8u)FillFlags()&0x1; \
+ lf_var1b=load(op1); \
+ lf_var2b=op2%9; \
+ lf_resb=(lf_var1b >> lf_var2b) | \
+ (cf << (8-lf_var2b)) | \
+ (lf_var1b << (9-lf_var2b)); \
+ save(op1,lf_resb); \
+ SETFLAGBIT(CF,(lf_var1b >> (lf_var2b - 1)) & 1); \
+ SETFLAGBIT(OF,(lf_resb ^ (lf_resb<<1)) & 0x80); \
+ }
+
+#define RCRW(op1,op2,load,save) \
+ if (op2%17) { \
+ Bit16u cf=(Bit16u)FillFlags()&0x1; \
+ lf_var1w=load(op1); \
+ lf_var2b=op2%17; \
+ lf_resw=(lf_var1w >> lf_var2b) | \
+ (cf << (16-lf_var2b)) | \
+ (lf_var1w << (17-lf_var2b)); \
+ save(op1,lf_resw); \
+ SETFLAGBIT(CF,(lf_var1w >> (lf_var2b - 1)) & 1); \
+ SETFLAGBIT(OF,(lf_resw ^ (lf_resw<<1)) & 0x8000); \
+ }
+
+#define RCRD(op1,op2,load,save) \
+ if (op2) { \
+ Bit32u cf=(Bit32u)FillFlags()&0x1; \
+ lf_var1d=load(op1); \
+ lf_var2b=op2; \
+ if (lf_var2b==1) { \
+ lf_resd=lf_var1d >> 1 | cf << 31; \
+ } else { \
+ lf_resd=(lf_var1d >> lf_var2b) | \
+ (cf << (32-lf_var2b)) | \
+ (lf_var1d << (33-lf_var2b)); \
+ } \
+ save(op1,lf_resd); \
+ SETFLAGBIT(CF,(lf_var1d >> (lf_var2b - 1)) & 1); \
+ SETFLAGBIT(OF,(lf_resd ^ (lf_resd<<1)) & 0x80000000); \
+ }
+
+
+#define SHLB(op1,op2,load,save) \
+ if (!op2) break; \
+ lf_var1b=load(op1);lf_var2b=op2; \
+ lf_resb=lf_var1b << lf_var2b; \
+ save(op1,lf_resb); \
+ lflags.type=t_SHLb;
+
+#define SHLW(op1,op2,load,save) \
+ if (!op2) break; \
+ lf_var1w=load(op1);lf_var2b=op2 ; \
+ lf_resw=lf_var1w << lf_var2b; \
+ save(op1,lf_resw); \
+ lflags.type=t_SHLw;
+
+#define SHLD(op1,op2,load,save) \
+ if (!op2) break; \
+ lf_var1d=load(op1);lf_var2b=op2; \
+ lf_resd=lf_var1d << lf_var2b; \
+ save(op1,lf_resd); \
+ lflags.type=t_SHLd;
+
+
+#define SHRB(op1,op2,load,save) \
+ if (!op2) break; \
+ lf_var1b=load(op1);lf_var2b=op2; \
+ lf_resb=lf_var1b >> lf_var2b; \
+ save(op1,lf_resb); \
+ lflags.type=t_SHRb;
+
+#define SHRW(op1,op2,load,save) \
+ if (!op2) break; \
+ lf_var1w=load(op1);lf_var2b=op2; \
+ lf_resw=lf_var1w >> lf_var2b; \
+ save(op1,lf_resw); \
+ lflags.type=t_SHRw;
+
+#define SHRD(op1,op2,load,save) \
+ if (!op2) break; \
+ lf_var1d=load(op1);lf_var2b=op2; \
+ lf_resd=lf_var1d >> lf_var2b; \
+ save(op1,lf_resd); \
+ lflags.type=t_SHRd;
+
+
+#define SARB(op1,op2,load,save) \
+ if (!op2) break; \
+ lf_var1b=load(op1);lf_var2b=op2; \
+ if (lf_var2b>8) lf_var2b=8; \
+ if (lf_var1b & 0x80) { \
+ lf_resb=(lf_var1b >> lf_var2b)| \
+ (0xff << (8 - lf_var2b)); \
+ } else { \
+ lf_resb=lf_var1b >> lf_var2b; \
+ } \
+ save(op1,lf_resb); \
+ lflags.type=t_SARb;
+
+#define SARW(op1,op2,load,save) \
+ if (!op2) break; \
+ lf_var1w=load(op1);lf_var2b=op2; \
+ if (lf_var2b>16) lf_var2b=16; \
+ if (lf_var1w & 0x8000) { \
+ lf_resw=(lf_var1w >> lf_var2b)| \
+ (0xffff << (16 - lf_var2b)); \
+ } else { \
+ lf_resw=lf_var1w >> lf_var2b; \
+ } \
+ save(op1,lf_resw); \
+ lflags.type=t_SARw;
+
+#define SARD(op1,op2,load,save) \
+ if (!op2) break; \
+ lf_var2b=op2;lf_var1d=load(op1); \
+ if (lf_var1d & 0x80000000) { \
+ lf_resd=(lf_var1d >> lf_var2b)| \
+ (0xffffffff << (32 - lf_var2b)); \
+ } else { \
+ lf_resd=lf_var1d >> lf_var2b; \
+ } \
+ save(op1,lf_resd); \
+ lflags.type=t_SARd;
+
+
+
+#define DAA() \
+ if (((reg_al & 0x0F)>0x09) || get_AF()) { \
+ if ((reg_al > 0x99) || get_CF()) { \
+ reg_al+=0x60; \
+ SETFLAGBIT(CF,true); \
+ } else { \
+ SETFLAGBIT(CF,false); \
+ } \
+ reg_al+=0x06; \
+ SETFLAGBIT(AF,true); \
+ } else { \
+ if ((reg_al > 0x99) || get_CF()) { \
+ reg_al+=0x60; \
+ SETFLAGBIT(CF,true); \
+ } else { \
+ SETFLAGBIT(CF,false); \
+ } \
+ SETFLAGBIT(AF,false); \
+ } \
+ SETFLAGBIT(SF,(reg_al&0x80)); \
+ SETFLAGBIT(ZF,(reg_al==0)); \
+ SETFLAGBIT(PF,parity_lookup[reg_al]); \
+ lflags.type=t_UNKNOWN;
+
+
+#define DAS() \
+{ \
+ Bit8u osigned=reg_al & 0x80; \
+ if (((reg_al & 0x0f) > 9) || get_AF()) { \
+ if ((reg_al>0x99) || get_CF()) { \
+ reg_al-=0x60; \
+ SETFLAGBIT(CF,true); \
+ } else { \
+ SETFLAGBIT(CF,(reg_al<=0x05)); \
+ } \
+ reg_al-=6; \
+ SETFLAGBIT(AF,true); \
+ } else { \
+ if ((reg_al>0x99) || get_CF()) { \
+ reg_al-=0x60; \
+ SETFLAGBIT(CF,true); \
+ } else { \
+ SETFLAGBIT(CF,false); \
+ } \
+ SETFLAGBIT(AF,false); \
+ } \
+ SETFLAGBIT(OF,osigned && ((reg_al&0x80)==0)); \
+ SETFLAGBIT(SF,(reg_al&0x80)); \
+ SETFLAGBIT(ZF,(reg_al==0)); \
+ SETFLAGBIT(PF,parity_lookup[reg_al]); \
+ lflags.type=t_UNKNOWN; \
+}
+
+
+#define AAA() \
+ SETFLAGBIT(SF,((reg_al>=0x7a) && (reg_al<=0xf9))); \
+ if ((reg_al & 0xf) > 9) { \
+ SETFLAGBIT(OF,(reg_al&0xf0)==0x70); \
+ reg_ax += 0x106; \
+ SETFLAGBIT(CF,true); \
+ SETFLAGBIT(ZF,(reg_al == 0)); \
+ SETFLAGBIT(AF,true); \
+ } else if (get_AF()) { \
+ reg_ax += 0x106; \
+ SETFLAGBIT(OF,false); \
+ SETFLAGBIT(CF,true); \
+ SETFLAGBIT(ZF,false); \
+ SETFLAGBIT(AF,true); \
+ } else { \
+ SETFLAGBIT(OF,false); \
+ SETFLAGBIT(CF,false); \
+ SETFLAGBIT(ZF,(reg_al == 0)); \
+ SETFLAGBIT(AF,false); \
+ } \
+ SETFLAGBIT(PF,parity_lookup[reg_al]); \
+ reg_al &= 0x0F; \
+ lflags.type=t_UNKNOWN;
+
+#define AAS() \
+ if ((reg_al & 0x0f)>9) { \
+ SETFLAGBIT(SF,(reg_al>0x85)); \
+ reg_ax -= 0x106; \
+ SETFLAGBIT(OF,false); \
+ SETFLAGBIT(CF,true); \
+ SETFLAGBIT(AF,true); \
+ } else if (get_AF()) { \
+ SETFLAGBIT(OF,((reg_al>=0x80) && (reg_al<=0x85))); \
+ SETFLAGBIT(SF,(reg_al<0x06) || (reg_al>0x85)); \
+ reg_ax -= 0x106; \
+ SETFLAGBIT(CF,true); \
+ SETFLAGBIT(AF,true); \
+ } else { \
+ SETFLAGBIT(SF,(reg_al>=0x80)); \
+ SETFLAGBIT(OF,false); \
+ SETFLAGBIT(CF,false); \
+ SETFLAGBIT(AF,false); \
+ } \
+ SETFLAGBIT(ZF,(reg_al == 0)); \
+ SETFLAGBIT(PF,parity_lookup[reg_al]); \
+ reg_al &= 0x0F; \
+ lflags.type=t_UNKNOWN;
+
+#define AAM(op1) \
+{ \
+ Bit8u dv=op1; \
+ if (dv!=0) { \
+ reg_ah=reg_al / dv; \
+ reg_al=reg_al % dv; \
+ SETFLAGBIT(SF,(reg_al & 0x80)); \
+ SETFLAGBIT(ZF,(reg_al == 0)); \
+ SETFLAGBIT(PF,parity_lookup[reg_al]); \
+ SETFLAGBIT(CF,false); \
+ SETFLAGBIT(OF,false); \
+ SETFLAGBIT(AF,false); \
+ lflags.type=t_UNKNOWN; \
+ } else EXCEPTION(0); \
+}
+
+
+//Took this from bochs, i seriously hate these weird bcd opcodes
+#define AAD(op1) \
+ { \
+ Bit16u ax1 = reg_ah * op1; \
+ Bit16u ax2 = ax1 + reg_al; \
+ reg_al = (Bit8u) ax2; \
+ reg_ah = 0; \
+ SETFLAGBIT(CF,false); \
+ SETFLAGBIT(OF,false); \
+ SETFLAGBIT(AF,false); \
+ SETFLAGBIT(SF,reg_al >= 0x80); \
+ SETFLAGBIT(ZF,reg_al == 0); \
+ SETFLAGBIT(PF,parity_lookup[reg_al]); \
+ lflags.type=t_UNKNOWN; \
+ }
+
+#define MULB(op1,load,save) \
+ reg_ax=reg_al*load(op1); \
+ FillFlagsNoCFOF(); \
+ SETFLAGBIT(ZF,reg_al == 0); \
+ if (reg_ax & 0xff00) { \
+ SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \
+ } else { \
+ SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \
+ }
+
+#define MULW(op1,load,save) \
+{ \
+ Bitu tempu=(Bitu)reg_ax*(Bitu)(load(op1)); \
+ reg_ax=(Bit16u)(tempu); \
+ reg_dx=(Bit16u)(tempu >> 16); \
+ FillFlagsNoCFOF(); \
+ SETFLAGBIT(ZF,reg_ax == 0); \
+ if (reg_dx) { \
+ SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \
+ } else { \
+ SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \
+ } \
+}
+
+#define MULD(op1,load,save) \
+{ \
+ Bit64u tempu=(Bit64u)reg_eax*(Bit64u)(load(op1)); \
+ reg_eax=(Bit32u)(tempu); \
+ reg_edx=(Bit32u)(tempu >> 32); \
+ FillFlagsNoCFOF(); \
+ SETFLAGBIT(ZF,reg_eax == 0); \
+ if (reg_edx) { \
+ SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \
+ } else { \
+ SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \
+ } \
+}
+
+#define DIVB(op1,load,save) \
+{ \
+ Bitu val=load(op1); \
+ if (val==0) EXCEPTION(0); \
+ Bitu quo=reg_ax / val; \
+ Bit8u rem=(Bit8u)(reg_ax % val); \
+ Bit8u quo8=(Bit8u)(quo&0xff); \
+ if (quo>0xff) EXCEPTION(0); \
+ reg_ah=rem; \
+ reg_al=quo8; \
+}
+
+
+#define DIVW(op1,load,save) \
+{ \
+ Bitu val=load(op1); \
+ if (val==0) EXCEPTION(0); \
+ Bitu num=((Bit32u)reg_dx<<16)|reg_ax; \
+ Bitu quo=num/val; \
+ Bit16u rem=(Bit16u)(num % val); \
+ Bit16u quo16=(Bit16u)(quo&0xffff); \
+ if (quo!=(Bit32u)quo16) EXCEPTION(0); \
+ reg_dx=rem; \
+ reg_ax=quo16; \
+}
+
+#define DIVD(op1,load,save) \
+{ \
+ Bitu val=load(op1); \
+ if (val==0) EXCEPTION(0); \
+ Bit64u num=(((Bit64u)reg_edx)<<32)|reg_eax; \
+ Bit64u quo=num/val; \
+ Bit32u rem=(Bit32u)(num % val); \
+ Bit32u quo32=(Bit32u)(quo&0xffffffff); \
+ if (quo!=(Bit64u)quo32) EXCEPTION(0); \
+ reg_edx=rem; \
+ reg_eax=quo32; \
+}
+
+
+#define IDIVB(op1,load,save) \
+{ \
+ Bits val=(Bit8s)(load(op1)); \
+ if (val==0) EXCEPTION(0); \
+ Bits quo=((Bit16s)reg_ax) / val; \
+ Bit8s rem=(Bit8s)((Bit16s)reg_ax % val); \
+ Bit8s quo8s=(Bit8s)(quo&0xff); \
+ if (quo!=(Bit16s)quo8s) EXCEPTION(0); \
+ reg_ah=rem; \
+ reg_al=quo8s; \
+}
+
+
+#define IDIVW(op1,load,save) \
+{ \
+ Bits val=(Bit16s)(load(op1)); \
+ if (val==0) EXCEPTION(0); \
+ Bits num=(Bit32s)((reg_dx<<16)|reg_ax); \
+ Bits quo=num/val; \
+ Bit16s rem=(Bit16s)(num % val); \
+ Bit16s quo16s=(Bit16s)quo; \
+ if (quo!=(Bit32s)quo16s) EXCEPTION(0); \
+ reg_dx=rem; \
+ reg_ax=quo16s; \
+}
+
+#define IDIVD(op1,load,save) \
+{ \
+ Bits val=(Bit32s)(load(op1)); \
+ if (val==0) EXCEPTION(0); \
+ Bit64s num=(((Bit64u)reg_edx)<<32)|reg_eax; \
+ Bit64s quo=num/val; \
+ Bit32s rem=(Bit32s)(num % val); \
+ Bit32s quo32s=(Bit32s)(quo&0xffffffff); \
+ if (quo!=(Bit64s)quo32s) EXCEPTION(0); \
+ reg_edx=rem; \
+ reg_eax=quo32s; \
+}
+
+#define IMULB(op1,load,save) \
+{ \
+ reg_ax=((Bit8s)reg_al) * ((Bit8s)(load(op1))); \
+ FillFlagsNoCFOF(); \
+ if ((reg_ax & 0xff80)==0xff80 || \
+ (reg_ax & 0xff80)==0x0000) { \
+ SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \
+ } else { \
+ SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \
+ } \
+}
+
+
+#define IMULW(op1,load,save) \
+{ \
+ Bits temps=((Bit16s)reg_ax)*((Bit16s)(load(op1))); \
+ reg_ax=(Bit16s)(temps); \
+ reg_dx=(Bit16s)(temps >> 16); \
+ FillFlagsNoCFOF(); \
+ if (((temps & 0xffff8000)==0xffff8000 || \
+ (temps & 0xffff8000)==0x0000)) { \
+ SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \
+ } else { \
+ SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \
+ } \
+}
+
+#define IMULD(op1,load,save) \
+{ \
+ Bit64s temps=((Bit64s)((Bit32s)reg_eax))* \
+ ((Bit64s)((Bit32s)(load(op1)))); \
+ reg_eax=(Bit32u)(temps); \
+ reg_edx=(Bit32u)(temps >> 32); \
+ FillFlagsNoCFOF(); \
+ if ((reg_edx==0xffffffff) && \
+ (reg_eax & 0x80000000) ) { \
+ SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \
+ } else if ( (reg_edx==0x00000000) && \
+ (reg_eax< 0x80000000) ) { \
+ SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \
+ } else { \
+ SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \
+ } \
+}
+
+#define DIMULW(op1,op2,op3,load,save) \
+{ \
+ Bits res=((Bit16s)op2) * ((Bit16s)op3); \
+ save(op1,res & 0xffff); \
+ FillFlagsNoCFOF(); \
+ if ((res>= -32768) && (res<=32767)) { \
+ SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \
+ } else { \
+ SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \
+ } \
+}
+
+#define DIMULD(op1,op2,op3,load,save) \
+{ \
+ Bit64s res=((Bit64s)((Bit32s)op2))*((Bit64s)((Bit32s)op3)); \
+ save(op1,(Bit32s)res); \
+ FillFlagsNoCFOF(); \
+ if ((res>=-((Bit64s)(2147483647)+1)) && \
+ (res<=(Bit64s)2147483647)) { \
+ SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \
+ } else { \
+ SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \
+ } \
+}
+
+#define GRP2B(blah) \
+{ \
+ GetRM;Bitu which=(rm>>3)&7; \
+ if (rm >= 0xc0) { \
+ GetEArb; \
+ Bit8u val=blah & 0x1f; \
+ switch (which) { \
+ case 0x00:ROLB(*earb,val,LoadRb,SaveRb);break; \
+ case 0x01:RORB(*earb,val,LoadRb,SaveRb);break; \
+ case 0x02:RCLB(*earb,val,LoadRb,SaveRb);break; \
+ case 0x03:RCRB(*earb,val,LoadRb,SaveRb);break; \
+ case 0x04:/* SHL and SAL are the same */ \
+ case 0x06:SHLB(*earb,val,LoadRb,SaveRb);break; \
+ case 0x05:SHRB(*earb,val,LoadRb,SaveRb);break; \
+ case 0x07:SARB(*earb,val,LoadRb,SaveRb);break; \
+ } \
+ } else { \
+ GetEAa; \
+ Bit8u val=blah & 0x1f; \
+ switch (which) { \
+ case 0x00:ROLB(eaa,val,LoadMb,SaveMb);break; \
+ case 0x01:RORB(eaa,val,LoadMb,SaveMb);break; \
+ case 0x02:RCLB(eaa,val,LoadMb,SaveMb);break; \
+ case 0x03:RCRB(eaa,val,LoadMb,SaveMb);break; \
+ case 0x04:/* SHL and SAL are the same */ \
+ case 0x06:SHLB(eaa,val,LoadMb,SaveMb);break; \
+ case 0x05:SHRB(eaa,val,LoadMb,SaveMb);break; \
+ case 0x07:SARB(eaa,val,LoadMb,SaveMb);break; \
+ } \
+ } \
+}
+
+
+
+#define GRP2W(blah) \
+{ \
+ GetRM;Bitu which=(rm>>3)&7; \
+ if (rm >= 0xc0) { \
+ GetEArw; \
+ Bit8u val=blah & 0x1f; \
+ switch (which) { \
+ case 0x00:ROLW(*earw,val,LoadRw,SaveRw);break; \
+ case 0x01:RORW(*earw,val,LoadRw,SaveRw);break; \
+ case 0x02:RCLW(*earw,val,LoadRw,SaveRw);break; \
+ case 0x03:RCRW(*earw,val,LoadRw,SaveRw);break; \
+ case 0x04:/* SHL and SAL are the same */ \
+ case 0x06:SHLW(*earw,val,LoadRw,SaveRw);break; \
+ case 0x05:SHRW(*earw,val,LoadRw,SaveRw);break; \
+ case 0x07:SARW(*earw,val,LoadRw,SaveRw);break; \
+ } \
+ } else { \
+ GetEAa; \
+ Bit8u val=blah & 0x1f; \
+ switch (which) { \
+ case 0x00:ROLW(eaa,val,LoadMw,SaveMw);break; \
+ case 0x01:RORW(eaa,val,LoadMw,SaveMw);break; \
+ case 0x02:RCLW(eaa,val,LoadMw,SaveMw);break; \
+ case 0x03:RCRW(eaa,val,LoadMw,SaveMw);break; \
+ case 0x04:/* SHL and SAL are the same */ \
+ case 0x06:SHLW(eaa,val,LoadMw,SaveMw);break; \
+ case 0x05:SHRW(eaa,val,LoadMw,SaveMw);break; \
+ case 0x07:SARW(eaa,val,LoadMw,SaveMw);break; \
+ } \
+ } \
+}
+
+
+#define GRP2D(blah) \
+{ \
+ GetRM;Bitu which=(rm>>3)&7; \
+ if (rm >= 0xc0) { \
+ GetEArd; \
+ Bit8u val=blah & 0x1f; \
+ switch (which) { \
+ case 0x00:ROLD(*eard,val,LoadRd,SaveRd);break; \
+ case 0x01:RORD(*eard,val,LoadRd,SaveRd);break; \
+ case 0x02:RCLD(*eard,val,LoadRd,SaveRd);break; \
+ case 0x03:RCRD(*eard,val,LoadRd,SaveRd);break; \
+ case 0x04:/* SHL and SAL are the same */ \
+ case 0x06:SHLD(*eard,val,LoadRd,SaveRd);break; \
+ case 0x05:SHRD(*eard,val,LoadRd,SaveRd);break; \
+ case 0x07:SARD(*eard,val,LoadRd,SaveRd);break; \
+ } \
+ } else { \
+ GetEAa; \
+ Bit8u val=blah & 0x1f; \
+ switch (which) { \
+ case 0x00:ROLD(eaa,val,LoadMd,SaveMd);break; \
+ case 0x01:RORD(eaa,val,LoadMd,SaveMd);break; \
+ case 0x02:RCLD(eaa,val,LoadMd,SaveMd);break; \
+ case 0x03:RCRD(eaa,val,LoadMd,SaveMd);break; \
+ case 0x04:/* SHL and SAL are the same */ \
+ case 0x06:SHLD(eaa,val,LoadMd,SaveMd);break; \
+ case 0x05:SHRD(eaa,val,LoadMd,SaveMd);break; \
+ case 0x07:SARD(eaa,val,LoadMd,SaveMd);break; \
+ } \
+ } \
+}
+
+/* let's hope bochs has it correct with the higher than 16 shifts */
+/* double-precision shift left has low bits in second argument */
+#define DSHLW(op1,op2,op3,load,save) \
+ Bit8u val=op3 & 0x1F; \
+ if (!val) break; \
+ lf_var2b=val;lf_var1d=(load(op1)<<16)|op2; \
+ Bit32u tempd=lf_var1d << lf_var2b; \
+ if (lf_var2b>16) tempd |= (op2 << (lf_var2b - 16)); \
+ lf_resw=(Bit16u)(tempd >> 16); \
+ save(op1,lf_resw); \
+ lflags.type=t_DSHLw;
+
+#define DSHLD(op1,op2,op3,load,save) \
+ Bit8u val=op3 & 0x1F; \
+ if (!val) break; \
+ lf_var2b=val;lf_var1d=load(op1); \
+ lf_resd=(lf_var1d << lf_var2b) | (op2 >> (32-lf_var2b)); \
+ save(op1,lf_resd); \
+ lflags.type=t_DSHLd;
+
+/* double-precision shift right has high bits in second argument */
+#define DSHRW(op1,op2,op3,load,save) \
+ Bit8u val=op3 & 0x1F; \
+ if (!val) break; \
+ lf_var2b=val;lf_var1d=(op2<<16)|load(op1); \
+ Bit32u tempd=lf_var1d >> lf_var2b; \
+ if (lf_var2b>16) tempd |= (op2 << (32-lf_var2b )); \
+ lf_resw=(Bit16u)(tempd); \
+ save(op1,lf_resw); \
+ lflags.type=t_DSHRw;
+
+#define DSHRD(op1,op2,op3,load,save) \
+ Bit8u val=op3 & 0x1F; \
+ if (!val) break; \
+ lf_var2b=val;lf_var1d=load(op1); \
+ lf_resd=(lf_var1d >> lf_var2b) | (op2 << (32-lf_var2b)); \
+ save(op1,lf_resd); \
+ lflags.type=t_DSHRd;
+
+#define BSWAPW(op1) \
+ op1 = 0;
+
+#define BSWAPD(op1) \
+ op1 = (op1>>24)|((op1>>8)&0xFF00)|((op1<<8)&0xFF0000)|((op1<<24)&0xFF000000);
--- /dev/null
+/*
+ * 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.
+ */
+
+#ifndef DOSBOX_LAZYFLAGS_H
+#define DOSBOX_LAZYFLAGS_H
+
+//Flag Handling
+Bit32u get_CF(void);
+Bit32u get_AF(void);
+Bit32u get_ZF(void);
+Bit32u get_SF(void);
+Bit32u get_OF(void);
+Bit32u get_PF(void);
+
+Bitu FillFlags(void);
+void FillFlagsNoCFOF(void);
+void DestroyConditionFlags(void);
+
+#ifndef DOSBOX_REGS_H
+#include "regs.h"
+#endif
+
+struct LazyFlags {
+ GenReg32 var1,var2,res;
+ Bitu type;
+ Bitu prev_type;
+ Bitu oldcf;
+};
+
+extern LazyFlags lfags;
+
+#define lf_var1b lflags.var1.byte[BL_INDEX]
+#define lf_var2b lflags.var2.byte[BL_INDEX]
+#define lf_resb lflags.res.byte[BL_INDEX]
+
+#define lf_var1w lflags.var1.word[W_INDEX]
+#define lf_var2w lflags.var2.word[W_INDEX]
+#define lf_resw lflags.res.word[W_INDEX]
+
+#define lf_var1d lflags.var1.dword[DW_INDEX]
+#define lf_var2d lflags.var2.dword[DW_INDEX]
+#define lf_resd lflags.res.dword[DW_INDEX]
+
+
+extern LazyFlags lflags;
+
+#define SETFLAGSb(FLAGB) \
+{ \
+ SETFLAGBIT(OF,get_OF()); \
+ lflags.type=t_UNKNOWN; \
+ CPU_SetFlags(FLAGB,FMASK_NORMAL & 0xff); \
+}
+
+#define SETFLAGSw(FLAGW) \
+{ \
+ lflags.type=t_UNKNOWN; \
+ CPU_SetFlagsw(FLAGW); \
+}
+
+#define SETFLAGSd(FLAGD) \
+{ \
+ lflags.type=t_UNKNOWN; \
+ CPU_SetFlagsd(FLAGD); \
+}
+
+#define LoadCF SETFLAGBIT(CF,get_CF());
+#define LoadZF SETFLAGBIT(ZF,get_ZF());
+#define LoadSF SETFLAGBIT(SF,get_SF());
+#define LoadOF SETFLAGBIT(OF,get_OF());
+#define LoadAF SETFLAGBIT(AF,get_AF());
+
+#define TFLG_O (get_OF())
+#define TFLG_NO (!get_OF())
+#define TFLG_B (get_CF())
+#define TFLG_NB (!get_CF())
+#define TFLG_Z (get_ZF())
+#define TFLG_NZ (!get_ZF())
+#define TFLG_BE (get_CF() || get_ZF())
+#define TFLG_NBE (!get_CF() && !get_ZF())
+#define TFLG_S (get_SF())
+#define TFLG_NS (!get_SF())
+#define TFLG_P (get_PF())
+#define TFLG_NP (!get_PF())
+#define TFLG_L ((get_SF()!=0) != (get_OF()!=0))
+#define TFLG_NL ((get_SF()!=0) == (get_OF()!=0))
+#define TFLG_LE (get_ZF() || ((get_SF()!=0) != (get_OF()!=0)))
+#define TFLG_NLE (!get_ZF() && ((get_SF()!=0) == (get_OF()!=0)))
+
+//Types of Flag changing instructions
+enum {
+ t_UNKNOWN=0,
+ t_ADDb,t_ADDw,t_ADDd,
+ t_ORb,t_ORw,t_ORd,
+ t_ADCb,t_ADCw,t_ADCd,
+ t_SBBb,t_SBBw,t_SBBd,
+ t_ANDb,t_ANDw,t_ANDd,
+ t_SUBb,t_SUBw,t_SUBd,
+ t_XORb,t_XORw,t_XORd,
+ t_CMPb,t_CMPw,t_CMPd,
+ t_INCb,t_INCw,t_INCd,
+ t_DECb,t_DECw,t_DECd,
+ t_TESTb,t_TESTw,t_TESTd,
+ t_SHLb,t_SHLw,t_SHLd,
+ t_SHRb,t_SHRw,t_SHRd,
+ t_SARb,t_SARw,t_SARd,
+ t_ROLb,t_ROLw,t_ROLd,
+ t_RORb,t_RORw,t_RORd,
+ t_RCLb,t_RCLw,t_RCLd,
+ t_RCRb,t_RCRw,t_RCRd,
+ t_NEGb,t_NEGw,t_NEGd,
+
+ t_DSHLw,t_DSHLd,
+ t_DSHRw,t_DSHRd,
+ t_MUL,t_DIV,
+ t_NOTDONE,
+ t_LASTFLAG
+};
+
+#endif
--- /dev/null
+/*
+ * 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.
+ */
+
+#include "cpu.h"
+
+
+Bit8u * lookupRMregb[]=
+{
+ ®_al,®_al,®_al,®_al,®_al,®_al,®_al,®_al,
+ ®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,
+ ®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,
+ ®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,
+ ®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,
+ ®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,
+ ®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,
+ ®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,
+
+ ®_al,®_al,®_al,®_al,®_al,®_al,®_al,®_al,
+ ®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,
+ ®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,
+ ®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,
+ ®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,
+ ®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,
+ ®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,
+ ®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,
+
+ ®_al,®_al,®_al,®_al,®_al,®_al,®_al,®_al,
+ ®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,
+ ®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,
+ ®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,
+ ®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,
+ ®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,
+ ®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,
+ ®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,
+
+ ®_al,®_al,®_al,®_al,®_al,®_al,®_al,®_al,
+ ®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,
+ ®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,
+ ®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,
+ ®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,
+ ®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,
+ ®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,
+ ®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh
+};
+
+Bit16u * lookupRMregw[]={
+ ®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,
+ ®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,
+ ®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,
+ ®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,
+ ®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,
+ ®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,
+ ®_si,®_si,®_si,®_si,®_si,®_si,®_si,®_si,
+ ®_di,®_di,®_di,®_di,®_di,®_di,®_di,®_di,
+
+ ®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,
+ ®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,
+ ®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,
+ ®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,
+ ®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,
+ ®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,
+ ®_si,®_si,®_si,®_si,®_si,®_si,®_si,®_si,
+ ®_di,®_di,®_di,®_di,®_di,®_di,®_di,®_di,
+
+ ®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,
+ ®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,
+ ®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,
+ ®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,
+ ®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,
+ ®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,
+ ®_si,®_si,®_si,®_si,®_si,®_si,®_si,®_si,
+ ®_di,®_di,®_di,®_di,®_di,®_di,®_di,®_di,
+
+ ®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,
+ ®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,
+ ®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,
+ ®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,
+ ®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,
+ ®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,
+ ®_si,®_si,®_si,®_si,®_si,®_si,®_si,®_si,
+ ®_di,®_di,®_di,®_di,®_di,®_di,®_di,®_di
+};
+
+Bit32u * lookupRMregd[256]={
+ ®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,
+ ®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,
+ ®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,
+ ®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,
+ ®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,
+ ®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,
+ ®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,
+ ®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,
+
+ ®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,
+ ®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,
+ ®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,
+ ®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,
+ ®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,
+ ®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,
+ ®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,
+ ®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,
+
+ ®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,
+ ®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,
+ ®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,
+ ®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,
+ ®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,
+ ®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,
+ ®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,
+ ®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,
+
+ ®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,
+ ®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,
+ ®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,
+ ®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,
+ ®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,
+ ®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,
+ ®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,
+ ®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi
+};
+
+
+Bit8u * lookupRMEAregb[256]={
+/* 12 lines of 16*0 should give nice errors when used */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh,
+ ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh,
+ ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh,
+ ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh,
+ ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh,
+ ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh,
+ ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh,
+ ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh
+};
+
+Bit16u * lookupRMEAregw[256]={
+/* 12 lines of 16*0 should give nice errors when used */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di,
+ ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di,
+ ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di,
+ ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di,
+ ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di,
+ ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di,
+ ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di,
+ ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di
+};
+
+Bit32u * lookupRMEAregd[256]={
+/* 12 lines of 16*0 should give nice errors when used */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi,
+ ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi,
+ ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi,
+ ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi,
+ ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi,
+ ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi,
+ ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi,
+ ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi
+};
+
+
--- /dev/null
+/*
+ * 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.
+ */
+
+extern Bit8u * lookupRMregb[];
+extern Bit16u * lookupRMregw[];
+extern Bit32u * lookupRMregd[];
+extern Bit8u * lookupRMEAregb[256];
+extern Bit16u * lookupRMEAregw[256];
+extern Bit32u * lookupRMEAregd[256];
+
+#define GetRM \
+ Bit8u rm=Fetchb();
+
+#define Getrb \
+ Bit8u * rmrb; \
+ rmrb=lookupRMregb[rm];
+
+#define Getrw \
+ Bit16u * rmrw; \
+ rmrw=lookupRMregw[rm];
+
+#define Getrd \
+ Bit32u * rmrd; \
+ rmrd=lookupRMregd[rm];
+
+
+#define GetRMrb \
+ GetRM; \
+ Getrb;
+
+#define GetRMrw \
+ GetRM; \
+ Getrw;
+
+#define GetRMrd \
+ GetRM; \
+ Getrd;
+
+
+#define GetEArb \
+ Bit8u * earb=lookupRMEAregb[rm];
+
+#define GetEArw \
+ Bit16u * earw=lookupRMEAregw[rm];
+
+#define GetEArd \
+ Bit32u * eard=lookupRMEAregd[rm];
+
+
--- /dev/null
+/*
+ * 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.
+ */
+
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#include "dosbox.h"
+#include "mem.h"
+#include "paging.h"
+#include "regs.h"
+#include "lazyflags.h"
+#include "cpu.h"
+#include "debug.h"
+#include "setup.h"
+
+#define LINK_TOTAL (64*1024)
+
+#define USERWRITE_PROHIBITED ((cpu.cpl&cpu.mpl)==3)
+
+
+PagingBlock paging;
+
+
+Bitu PageHandler::readb(PhysPt addr) {
+ E_Exit("No byte handler for read from %d",addr);
+ return 0;
+}
+Bitu PageHandler::readw(PhysPt addr) {
+ Bitu ret = (readb(addr+0) << 0);
+ ret |= (readb(addr+1) << 8);
+ return ret;
+}
+Bitu PageHandler::readd(PhysPt addr) {
+ Bitu ret = (readb(addr+0) << 0);
+ ret |= (readb(addr+1) << 8);
+ ret |= (readb(addr+2) << 16);
+ ret |= (readb(addr+3) << 24);
+ return ret;
+}
+
+void PageHandler::writeb(PhysPt addr,Bitu /*val*/) {
+ E_Exit("No byte handler for write to %d",addr);
+}
+
+void PageHandler::writew(PhysPt addr,Bitu val) {
+ writeb(addr+0,(Bit8u) (val >> 0));
+ writeb(addr+1,(Bit8u) (val >> 8));
+}
+void PageHandler::writed(PhysPt addr,Bitu val) {
+ writeb(addr+0,(Bit8u) (val >> 0));
+ writeb(addr+1,(Bit8u) (val >> 8));
+ writeb(addr+2,(Bit8u) (val >> 16));
+ writeb(addr+3,(Bit8u) (val >> 24));
+}
+
+HostPt PageHandler::GetHostReadPt(Bitu /*phys_page*/) {
+ return 0;
+}
+
+HostPt PageHandler::GetHostWritePt(Bitu /*phys_page*/) {
+ return 0;
+}
+
+bool PageHandler::readb_checked(PhysPt addr, Bit8u * val) {
+ *val=(Bit8u)readb(addr); return false;
+}
+bool PageHandler::readw_checked(PhysPt addr, Bit16u * val) {
+ *val=(Bit16u)readw(addr); return false;
+}
+bool PageHandler::readd_checked(PhysPt addr, Bit32u * val) {
+ *val=(Bit32u)readd(addr); return false;
+}
+bool PageHandler::writeb_checked(PhysPt addr,Bitu val) {
+ writeb(addr,val); return false;
+}
+bool PageHandler::writew_checked(PhysPt addr,Bitu val) {
+ writew(addr,val); return false;
+}
+bool PageHandler::writed_checked(PhysPt addr,Bitu val) {
+ writed(addr,val); return false;
+}
+
+
+
+struct PF_Entry {
+ Bitu cs;
+ Bitu eip;
+ Bitu page_addr;
+ Bitu mpl;
+};
+
+#define PF_QUEUESIZE 16
+static struct {
+ Bitu used;
+ PF_Entry entries[PF_QUEUESIZE];
+} pf_queue;
+
+static Bits PageFaultCore(void) {
+ CPU_CycleLeft+=CPU_Cycles;
+ CPU_Cycles=1;
+ Bits ret=CPU_Core_Full_Run();
+ CPU_CycleLeft+=CPU_Cycles;
+ if (ret<0) E_Exit("Got a dosbox close machine in pagefault core?");
+ if (ret)
+ return ret;
+ if (!pf_queue.used) E_Exit("PF Core without PF");
+ PF_Entry * entry=&pf_queue.entries[pf_queue.used-1];
+ X86PageEntry pentry;
+ pentry.load=phys_readd(entry->page_addr);
+ if (pentry.block.p && entry->cs == SegValue(cs) && entry->eip==reg_eip) {
+ cpu.mpl=entry->mpl;
+ return -1;
+ }
+ return 0;
+}
+#if C_DEBUG
+Bitu DEBUG_EnableDebugger(void);
+#endif
+
+bool first=false;
+
+void PAGING_PageFault(PhysPt lin_addr,Bitu page_addr,Bitu faultcode) {
+ /* Save the state of the cpu cores */
+ LazyFlags old_lflags;
+ memcpy(&old_lflags,&lflags,sizeof(LazyFlags));
+ CPU_Decoder * old_cpudecoder;
+ old_cpudecoder=cpudecoder;
+ cpudecoder=&PageFaultCore;
+ paging.cr2=lin_addr;
+ PF_Entry * entry=&pf_queue.entries[pf_queue.used++];
+ LOG(LOG_PAGING,LOG_NORMAL)("PageFault at %X type [%x] queue %d",lin_addr,faultcode,pf_queue.used);
+// LOG_MSG("EAX:%04X ECX:%04X EDX:%04X EBX:%04X",reg_eax,reg_ecx,reg_edx,reg_ebx);
+// LOG_MSG("CS:%04X EIP:%08X SS:%04x SP:%08X",SegValue(cs),reg_eip,SegValue(ss),reg_esp);
+ entry->cs=SegValue(cs);
+ entry->eip=reg_eip;
+ entry->page_addr=page_addr;
+ entry->mpl=cpu.mpl;
+ cpu.mpl=3;
+
+ CPU_Exception(EXCEPTION_PF,faultcode);
+#if C_DEBUG
+// DEBUG_EnableDebugger();
+#endif
+ DOSBOX_RunMachine();
+ pf_queue.used--;
+ LOG(LOG_PAGING,LOG_NORMAL)("Left PageFault for %x queue %d",lin_addr,pf_queue.used);
+ memcpy(&lflags,&old_lflags,sizeof(LazyFlags));
+ cpudecoder=old_cpudecoder;
+// LOG_MSG("SS:%04x SP:%08X",SegValue(ss),reg_esp);
+}
+
+static INLINE void InitPageUpdateLink(Bitu relink,PhysPt addr) {
+ if (relink==0) return;
+ if (paging.links.used) {
+ if (paging.links.entries[paging.links.used-1]==(addr>>12)) {
+ paging.links.used--;
+ PAGING_UnlinkPages(addr>>12,1);
+ }
+ }
+ if (relink>1) PAGING_LinkPage_ReadOnly(addr>>12,relink);
+}
+
+static INLINE void InitPageCheckPresence(PhysPt lin_addr,bool writing,X86PageEntry& table,X86PageEntry& entry) {
+ Bitu lin_page=lin_addr >> 12;
+ Bitu d_index=lin_page >> 10;
+ Bitu t_index=lin_page & 0x3ff;
+ Bitu table_addr=(paging.base.page<<12)+d_index*4;
+ table.load=phys_readd(table_addr);
+ if (!table.block.p) {
+ LOG(LOG_PAGING,LOG_NORMAL)("NP Table");
+ PAGING_PageFault(lin_addr,table_addr,
+ (writing?0x02:0x00) | (((cpu.cpl&cpu.mpl)==0)?0x00:0x04));
+ table.load=phys_readd(table_addr);
+ if (GCC_UNLIKELY(!table.block.p))
+ E_Exit("Pagefault didn't correct table");
+ }
+ Bitu entry_addr=(table.block.base<<12)+t_index*4;
+ entry.load=phys_readd(entry_addr);
+ if (!entry.block.p) {
+// LOG(LOG_PAGING,LOG_NORMAL)("NP Page");
+ PAGING_PageFault(lin_addr,entry_addr,
+ (writing?0x02:0x00) | (((cpu.cpl&cpu.mpl)==0)?0x00:0x04));
+ entry.load=phys_readd(entry_addr);
+ if (GCC_UNLIKELY(!entry.block.p))
+ E_Exit("Pagefault didn't correct page");
+ }
+}
+
+static INLINE bool InitPageCheckPresence_CheckOnly(PhysPt lin_addr,bool writing,X86PageEntry& table,X86PageEntry& entry) {
+ Bitu lin_page=lin_addr >> 12;
+ Bitu d_index=lin_page >> 10;
+ Bitu t_index=lin_page & 0x3ff;
+ Bitu table_addr=(paging.base.page<<12)+d_index*4;
+ table.load=phys_readd(table_addr);
+ if (!table.block.p) {
+ paging.cr2=lin_addr;
+ cpu.exception.which=EXCEPTION_PF;
+ cpu.exception.error=(writing?0x02:0x00) | (((cpu.cpl&cpu.mpl)==0)?0x00:0x04);
+ return false;
+ }
+ Bitu entry_addr=(table.block.base<<12)+t_index*4;
+ entry.load=phys_readd(entry_addr);
+ if (!entry.block.p) {
+ paging.cr2=lin_addr;
+ cpu.exception.which=EXCEPTION_PF;
+ cpu.exception.error=(writing?0x02:0x00) | (((cpu.cpl&cpu.mpl)==0)?0x00:0x04);
+ return false;
+ }
+ return true;
+}
+
+// check if a user-level memory access would trigger a privilege page fault
+static INLINE bool InitPage_CheckUseraccess(Bitu u1,Bitu u2) {
+ switch (CPU_ArchitectureType) {
+ case CPU_ARCHTYPE_MIXED:
+ case CPU_ARCHTYPE_386SLOW:
+ case CPU_ARCHTYPE_386FAST:
+ default:
+ return ((u1)==0) && ((u2)==0);
+ case CPU_ARCHTYPE_486OLDSLOW:
+ case CPU_ARCHTYPE_486NEWSLOW:
+ case CPU_ARCHTYPE_PENTIUMSLOW:
+ return ((u1)==0) || ((u2)==0);
+ }
+}
+
+
+class InitPageHandler : public PageHandler {
+public:
+ InitPageHandler() {
+ flags=PFLAG_INIT|PFLAG_NOCODE;
+ }
+ Bitu readb(PhysPt addr) {
+ Bitu needs_reset=InitPage(addr,false);
+ Bit8u val=mem_readb(addr);
+ InitPageUpdateLink(needs_reset,addr);
+ return val;
+ }
+ Bitu readw(PhysPt addr) {
+ Bitu needs_reset=InitPage(addr,false);
+ Bit16u val=mem_readw(addr);
+ InitPageUpdateLink(needs_reset,addr);
+ return val;
+ }
+ Bitu readd(PhysPt addr) {
+ Bitu needs_reset=InitPage(addr,false);
+ Bit32u val=mem_readd(addr);
+ InitPageUpdateLink(needs_reset,addr);
+ return val;
+ }
+ void writeb(PhysPt addr,Bitu val) {
+ Bitu needs_reset=InitPage(addr,true);
+ mem_writeb(addr,val);
+ InitPageUpdateLink(needs_reset,addr);
+ }
+ void writew(PhysPt addr,Bitu val) {
+ Bitu needs_reset=InitPage(addr,true);
+ mem_writew(addr,val);
+ InitPageUpdateLink(needs_reset,addr);
+ }
+ void writed(PhysPt addr,Bitu val) {
+ Bitu needs_reset=InitPage(addr,true);
+ mem_writed(addr,val);
+ InitPageUpdateLink(needs_reset,addr);
+ }
+ bool readb_checked(PhysPt addr, Bit8u * val) {
+ if (InitPageCheckOnly(addr,false)) {
+ *val=mem_readb(addr);
+ return false;
+ } else return true;
+ }
+ bool readw_checked(PhysPt addr, Bit16u * val) {
+ if (InitPageCheckOnly(addr,false)){
+ *val=mem_readw(addr);
+ return false;
+ } else return true;
+ }
+ bool readd_checked(PhysPt addr, Bit32u * val) {
+ if (InitPageCheckOnly(addr,false)) {
+ *val=mem_readd(addr);
+ return false;
+ } else return true;
+ }
+ bool writeb_checked(PhysPt addr,Bitu val) {
+ if (InitPageCheckOnly(addr,true)) {
+ mem_writeb(addr,val);
+ return false;
+ } else return true;
+ }
+ bool writew_checked(PhysPt addr,Bitu val) {
+ if (InitPageCheckOnly(addr,true)) {
+ mem_writew(addr,val);
+ return false;
+ } else return true;
+ }
+ bool writed_checked(PhysPt addr,Bitu val) {
+ if (InitPageCheckOnly(addr,true)) {
+ mem_writed(addr,val);
+ return false;
+ } else return true;
+ }
+ Bitu InitPage(Bitu lin_addr,bool writing) {
+ Bitu lin_page=lin_addr >> 12;
+ Bitu phys_page;
+ if (paging.enabled) {
+ X86PageEntry table;
+ X86PageEntry entry;
+ InitPageCheckPresence(lin_addr,writing,table,entry);
+
+ // 0: no action
+ // 1: can (but currently does not) fail a user-level access privilege check
+ // 2: can (but currently does not) fail a write privilege check
+ // 3: fails a privilege check
+ Bitu priv_check=0;
+ if (InitPage_CheckUseraccess(entry.block.us,table.block.us)) {
+ if ((cpu.cpl&cpu.mpl)==3) priv_check=3;
+ else {
+ switch (CPU_ArchitectureType) {
+ case CPU_ARCHTYPE_MIXED:
+ case CPU_ARCHTYPE_386FAST:
+ default:
+// priv_check=0; // default
+ break;
+ case CPU_ARCHTYPE_386SLOW:
+ case CPU_ARCHTYPE_486OLDSLOW:
+ case CPU_ARCHTYPE_486NEWSLOW:
+ case CPU_ARCHTYPE_PENTIUMSLOW:
+ priv_check=1;
+ break;
+ }
+ }
+ }
+ if ((entry.block.wr==0) || (table.block.wr==0)) {
+ // page is write-protected for user mode
+ if (priv_check==0) {
+ switch (CPU_ArchitectureType) {
+ case CPU_ARCHTYPE_MIXED:
+ case CPU_ARCHTYPE_386FAST:
+ default:
+// priv_check=0; // default
+ break;
+ case CPU_ARCHTYPE_386SLOW:
+ case CPU_ARCHTYPE_486OLDSLOW:
+ case CPU_ARCHTYPE_486NEWSLOW:
+ case CPU_ARCHTYPE_PENTIUMSLOW:
+ priv_check=2;
+ break;
+ }
+ }
+ // check if actually failing the write-protected check
+ if (writing && USERWRITE_PROHIBITED) priv_check=3;
+ }
+ if (priv_check==3) {
+ LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x",
+ cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr);
+ PAGING_PageFault(lin_addr,(table.block.base<<12)+(lin_page & 0x3ff)*4,0x05 | (writing?0x02:0x00));
+ priv_check=0;
+ }
+
+ if (!table.block.a) {
+ table.block.a=1; // set page table accessed
+ phys_writed((paging.base.page<<12)+(lin_page >> 10)*4,table.load);
+ }
+ if ((!entry.block.a) || (!entry.block.d)) {
+ entry.block.a=1; // set page accessed
+
+ // page is dirty if we're writing to it, or if we're reading but the
+ // page will be fully linked so we can't track later writes
+ if (writing || (priv_check==0)) entry.block.d=1; // mark page as dirty
+
+ phys_writed((table.block.base<<12)+(lin_page & 0x3ff)*4,entry.load);
+ }
+
+ phys_page=entry.block.base;
+
+ // now see how the page should be linked best, if we need to catch privilege
+ // checks later on it should be linked as read-only page
+ if (priv_check==0) {
+ // if reading we could link the page as read-only to later cacth writes,
+ // will slow down pretty much but allows catching all dirty events
+ PAGING_LinkPage(lin_page,phys_page);
+ } else {
+ if (priv_check==1) {
+ PAGING_LinkPage(lin_page,phys_page);
+ return 1;
+ } else if (writing) {
+ PageHandler * handler=MEM_GetPageHandler(phys_page);
+ PAGING_LinkPage(lin_page,phys_page);
+ if (!(handler->flags & PFLAG_READABLE)) return 1;
+ if (!(handler->flags & PFLAG_WRITEABLE)) return 1;
+ if (get_tlb_read(lin_addr)!=get_tlb_write(lin_addr)) return 1;
+ if (phys_page>1) return phys_page;
+ else return 1;
+ } else {
+ PAGING_LinkPage_ReadOnly(lin_page,phys_page);
+ }
+ }
+ } else {
+ if (lin_page<LINK_START) phys_page=paging.firstmb[lin_page];
+ else phys_page=lin_page;
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+ return 0;
+ }
+ bool InitPageCheckOnly(Bitu lin_addr,bool writing) {
+ Bitu lin_page=lin_addr >> 12;
+ if (paging.enabled) {
+ X86PageEntry table;
+ X86PageEntry entry;
+ if (!InitPageCheckPresence_CheckOnly(lin_addr,writing,table,entry)) return false;
+
+ if (!USERWRITE_PROHIBITED) return true;
+
+ if (InitPage_CheckUseraccess(entry.block.us,table.block.us) ||
+ (((entry.block.wr==0) || (table.block.wr==0)) && writing)) {
+ LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x",
+ cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr);
+ paging.cr2=lin_addr;
+ cpu.exception.which=EXCEPTION_PF;
+ cpu.exception.error=0x05 | (writing?0x02:0x00);
+ return false;
+ }
+ } else {
+ Bitu phys_page;
+ if (lin_page<LINK_START) phys_page=paging.firstmb[lin_page];
+ else phys_page=lin_page;
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+ return true;
+ }
+ void InitPageForced(Bitu lin_addr) {
+ Bitu lin_page=lin_addr >> 12;
+ Bitu phys_page;
+ if (paging.enabled) {
+ X86PageEntry table;
+ X86PageEntry entry;
+ InitPageCheckPresence(lin_addr,false,table,entry);
+
+ if (!table.block.a) {
+ table.block.a=1; //Set access
+ phys_writed((paging.base.page<<12)+(lin_page >> 10)*4,table.load);
+ }
+ if (!entry.block.a) {
+ entry.block.a=1; //Set access
+ phys_writed((table.block.base<<12)+(lin_page & 0x3ff)*4,entry.load);
+ }
+ phys_page=entry.block.base;
+ // maybe use read-only page here if possible
+ } else {
+ if (lin_page<LINK_START) phys_page=paging.firstmb[lin_page];
+ else phys_page=lin_page;
+ }
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+};
+
+class InitPageUserROHandler : public PageHandler {
+public:
+ InitPageUserROHandler() {
+ flags=PFLAG_INIT|PFLAG_NOCODE;
+ }
+ void writeb(PhysPt addr,Bitu val) {
+ InitPage(addr,(Bit8u)(val&0xff));
+ host_writeb(get_tlb_read(addr)+addr,(Bit8u)(val&0xff));
+ }
+ void writew(PhysPt addr,Bitu val) {
+ InitPage(addr,(Bit16u)(val&0xffff));
+ host_writew(get_tlb_read(addr)+addr,(Bit16u)(val&0xffff));
+ }
+ void writed(PhysPt addr,Bitu val) {
+ InitPage(addr,(Bit32u)val);
+ host_writed(get_tlb_read(addr)+addr,(Bit32u)val);
+ }
+ bool writeb_checked(PhysPt addr,Bitu val) {
+ Bitu writecode=InitPageCheckOnly(addr,(Bit8u)(val&0xff));
+ if (writecode) {
+ HostPt tlb_addr;
+ if (writecode>1) tlb_addr=get_tlb_read(addr);
+ else tlb_addr=get_tlb_write(addr);
+ host_writeb(tlb_addr+addr,(Bit8u)(val&0xff));
+ return false;
+ }
+ return true;
+ }
+ bool writew_checked(PhysPt addr,Bitu val) {
+ Bitu writecode=InitPageCheckOnly(addr,(Bit16u)(val&0xffff));
+ if (writecode) {
+ HostPt tlb_addr;
+ if (writecode>1) tlb_addr=get_tlb_read(addr);
+ else tlb_addr=get_tlb_write(addr);
+ host_writew(tlb_addr+addr,(Bit16u)(val&0xffff));
+ return false;
+ }
+ return true;
+ }
+ bool writed_checked(PhysPt addr,Bitu val) {
+ Bitu writecode=InitPageCheckOnly(addr,(Bit32u)val);
+ if (writecode) {
+ HostPt tlb_addr;
+ if (writecode>1) tlb_addr=get_tlb_read(addr);
+ else tlb_addr=get_tlb_write(addr);
+ host_writed(tlb_addr+addr,(Bit32u)val);
+ return false;
+ }
+ return true;
+ }
+ void InitPage(Bitu lin_addr,Bitu val) {
+ Bitu lin_page=lin_addr >> 12;
+ Bitu phys_page;
+ if (paging.enabled) {
+ if (!USERWRITE_PROHIBITED) return;
+
+ X86PageEntry table;
+ X86PageEntry entry;
+ InitPageCheckPresence(lin_addr,true,table,entry);
+
+ LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x",
+ cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr);
+ PAGING_PageFault(lin_addr,(table.block.base<<12)+(lin_page & 0x3ff)*4,0x07);
+
+ if (!table.block.a) {
+ table.block.a=1; //Set access
+ phys_writed((paging.base.page<<12)+(lin_page >> 10)*4,table.load);
+ }
+ if ((!entry.block.a) || (!entry.block.d)) {
+ entry.block.a=1; //Set access
+ entry.block.d=1; //Set dirty
+ phys_writed((table.block.base<<12)+(lin_page & 0x3ff)*4,entry.load);
+ }
+ phys_page=entry.block.base;
+ PAGING_LinkPage(lin_page,phys_page);
+ } else {
+ if (lin_page<LINK_START) phys_page=paging.firstmb[lin_page];
+ else phys_page=lin_page;
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+ }
+ Bitu InitPageCheckOnly(Bitu lin_addr,Bitu val) {
+ Bitu lin_page=lin_addr >> 12;
+ if (paging.enabled) {
+ if (!USERWRITE_PROHIBITED) return 2;
+
+ X86PageEntry table;
+ X86PageEntry entry;
+ if (!InitPageCheckPresence_CheckOnly(lin_addr,true,table,entry)) return 0;
+
+ if (InitPage_CheckUseraccess(entry.block.us,table.block.us) || (((entry.block.wr==0) || (table.block.wr==0)))) {
+ LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x",
+ cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr);
+ paging.cr2=lin_addr;
+ cpu.exception.which=EXCEPTION_PF;
+ cpu.exception.error=0x07;
+ return 0;
+ }
+ PAGING_LinkPage(lin_page,entry.block.base);
+ } else {
+ Bitu phys_page;
+ if (lin_page<LINK_START) phys_page=paging.firstmb[lin_page];
+ else phys_page=lin_page;
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+ return 1;
+ }
+ void InitPageForced(Bitu lin_addr) {
+ Bitu lin_page=lin_addr >> 12;
+ Bitu phys_page;
+ if (paging.enabled) {
+ X86PageEntry table;
+ X86PageEntry entry;
+ InitPageCheckPresence(lin_addr,true,table,entry);
+
+ if (!table.block.a) {
+ table.block.a=1; //Set access
+ phys_writed((paging.base.page<<12)+(lin_page >> 10)*4,table.load);
+ }
+ if (!entry.block.a) {
+ entry.block.a=1; //Set access
+ phys_writed((table.block.base<<12)+(lin_page & 0x3ff)*4,entry.load);
+ }
+ phys_page=entry.block.base;
+ } else {
+ if (lin_page<LINK_START) phys_page=paging.firstmb[lin_page];
+ else phys_page=lin_page;
+ }
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+};
+
+
+bool PAGING_MakePhysPage(Bitu & page) {
+ if (paging.enabled) {
+ Bitu d_index=page >> 10;
+ Bitu t_index=page & 0x3ff;
+ X86PageEntry table;
+ table.load=phys_readd((paging.base.page<<12)+d_index*4);
+ if (!table.block.p) return false;
+ X86PageEntry entry;
+ entry.load=phys_readd((table.block.base<<12)+t_index*4);
+ if (!entry.block.p) return false;
+ page=entry.block.base;
+ } else {
+ if (page<LINK_START) page=paging.firstmb[page];
+ //Else keep it the same
+ }
+ return true;
+}
+
+static InitPageHandler init_page_handler;
+static InitPageUserROHandler init_page_handler_userro;
+
+
+Bitu PAGING_GetDirBase(void) {
+ return paging.cr3;
+}
+
+bool PAGING_ForcePageInit(Bitu lin_addr) {
+ PageHandler * handler=get_tlb_readhandler(lin_addr);
+ if (handler==&init_page_handler) {
+ init_page_handler.InitPageForced(lin_addr);
+ return true;
+ } else if (handler==&init_page_handler_userro) {
+ PAGING_UnlinkPages(lin_addr>>12,1);
+ init_page_handler_userro.InitPageForced(lin_addr);
+ return true;
+ }
+ return false;
+}
+
+#if defined(USE_FULL_TLB)
+void PAGING_InitTLB(void) {
+ for (Bitu i=0;i<TLB_SIZE;i++) {
+ paging.tlb.read[i]=0;
+ paging.tlb.write[i]=0;
+ paging.tlb.readhandler[i]=&init_page_handler;
+ paging.tlb.writehandler[i]=&init_page_handler;
+ }
+ paging.links.used=0;
+}
+
+void PAGING_ClearTLB(void) {
+ Bit32u * entries=&paging.links.entries[0];
+ for (;paging.links.used>0;paging.links.used--) {
+ Bitu page=*entries++;
+ paging.tlb.read[page]=0;
+ paging.tlb.write[page]=0;
+ paging.tlb.readhandler[page]=&init_page_handler;
+ paging.tlb.writehandler[page]=&init_page_handler;
+ }
+ paging.links.used=0;
+}
+
+void PAGING_UnlinkPages(Bitu lin_page,Bitu pages) {
+ for (;pages>0;pages--) {
+ paging.tlb.read[lin_page]=0;
+ paging.tlb.write[lin_page]=0;
+ paging.tlb.readhandler[lin_page]=&init_page_handler;
+ paging.tlb.writehandler[lin_page]=&init_page_handler;
+ lin_page++;
+ }
+}
+
+void PAGING_MapPage(Bitu lin_page,Bitu phys_page) {
+ if (lin_page<LINK_START) {
+ paging.firstmb[lin_page]=phys_page;
+ paging.tlb.read[lin_page]=0;
+ paging.tlb.write[lin_page]=0;
+ paging.tlb.readhandler[lin_page]=&init_page_handler;
+ paging.tlb.writehandler[lin_page]=&init_page_handler;
+ } else {
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+}
+
+void PAGING_LinkPage(Bitu lin_page,Bitu phys_page) {
+ PageHandler * handler=MEM_GetPageHandler(phys_page);
+ Bitu lin_base=lin_page << 12;
+ if (lin_page>=TLB_SIZE || phys_page>=TLB_SIZE)
+ E_Exit("Illegal page");
+
+ if (paging.links.used>=PAGING_LINKS) {
+ LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache");
+ PAGING_ClearTLB();
+ }
+
+ paging.tlb.phys_page[lin_page]=phys_page;
+ if (handler->flags & PFLAG_READABLE) paging.tlb.read[lin_page]=handler->GetHostReadPt(phys_page)-lin_base;
+ else paging.tlb.read[lin_page]=0;
+ if (handler->flags & PFLAG_WRITEABLE) paging.tlb.write[lin_page]=handler->GetHostWritePt(phys_page)-lin_base;
+ else paging.tlb.write[lin_page]=0;
+
+ paging.links.entries[paging.links.used++]=lin_page;
+ paging.tlb.readhandler[lin_page]=handler;
+ paging.tlb.writehandler[lin_page]=handler;
+}
+
+void PAGING_LinkPage_ReadOnly(Bitu lin_page,Bitu phys_page) {
+ PageHandler * handler=MEM_GetPageHandler(phys_page);
+ Bitu lin_base=lin_page << 12;
+ if (lin_page>=TLB_SIZE || phys_page>=TLB_SIZE)
+ E_Exit("Illegal page");
+
+ if (paging.links.used>=PAGING_LINKS) {
+ LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache");
+ PAGING_ClearTLB();
+ }
+
+ paging.tlb.phys_page[lin_page]=phys_page;
+ if (handler->flags & PFLAG_READABLE) paging.tlb.read[lin_page]=handler->GetHostReadPt(phys_page)-lin_base;
+ else paging.tlb.read[lin_page]=0;
+ paging.tlb.write[lin_page]=0;
+
+ paging.links.entries[paging.links.used++]=lin_page;
+ paging.tlb.readhandler[lin_page]=handler;
+ paging.tlb.writehandler[lin_page]=&init_page_handler_userro;
+}
+
+#else
+
+static INLINE void InitTLBInt(tlb_entry *bank) {
+ for (Bitu i=0;i<TLB_SIZE;i++) {
+ bank[i].read=0;
+ bank[i].write=0;
+ bank[i].readhandler=&init_page_handler;
+ bank[i].writehandler=&init_page_handler;
+ }
+}
+
+void PAGING_InitTLBBank(tlb_entry **bank) {
+ *bank = (tlb_entry *)malloc(sizeof(tlb_entry)*TLB_SIZE);
+ if(!*bank) E_Exit("Out of Memory");
+ InitTLBInt(*bank);
+}
+
+void PAGING_InitTLB(void) {
+ InitTLBInt(paging.tlbh);
+ paging.links.used=0;
+}
+
+void PAGING_ClearTLB(void) {
+ Bit32u * entries=&paging.links.entries[0];
+ for (;paging.links.used>0;paging.links.used--) {
+ Bitu page=*entries++;
+ tlb_entry *entry = get_tlb_entry(page<<12);
+ entry->read=0;
+ entry->write=0;
+ entry->readhandler=&init_page_handler;
+ entry->writehandler=&init_page_handler;
+ }
+ paging.links.used=0;
+}
+
+void PAGING_UnlinkPages(Bitu lin_page,Bitu pages) {
+ for (;pages>0;pages--) {
+ tlb_entry *entry = get_tlb_entry(lin_page<<12);
+ entry->read=0;
+ entry->write=0;
+ entry->readhandler=&init_page_handler;
+ entry->writehandler=&init_page_handler;
+ lin_page++;
+ }
+}
+
+void PAGING_MapPage(Bitu lin_page,Bitu phys_page) {
+ if (lin_page<LINK_START) {
+ paging.firstmb[lin_page]=phys_page;
+ paging.tlbh[lin_page].read=0;
+ paging.tlbh[lin_page].write=0;
+ paging.tlbh[lin_page].readhandler=&init_page_handler;
+ paging.tlbh[lin_page].writehandler=&init_page_handler;
+ } else {
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+}
+
+void PAGING_LinkPage(Bitu lin_page,Bitu phys_page) {
+ PageHandler * handler=MEM_GetPageHandler(phys_page);
+ Bitu lin_base=lin_page << 12;
+ if (lin_page>=(TLB_SIZE*(TLB_BANKS+1)) || phys_page>=(TLB_SIZE*(TLB_BANKS+1)))
+ E_Exit("Illegal page");
+
+ if (paging.links.used>=PAGING_LINKS) {
+ LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache");
+ PAGING_ClearTLB();
+ }
+
+ tlb_entry *entry = get_tlb_entry(lin_base);
+ entry->phys_page=phys_page;
+ if (handler->flags & PFLAG_READABLE) entry->read=handler->GetHostReadPt(phys_page)-lin_base;
+ else entry->read=0;
+ if (handler->flags & PFLAG_WRITEABLE) entry->write=handler->GetHostWritePt(phys_page)-lin_base;
+ else entry->write=0;
+
+ paging.links.entries[paging.links.used++]=lin_page;
+ entry->readhandler=handler;
+ entry->writehandler=handler;
+}
+
+void PAGING_LinkPage_ReadOnly(Bitu lin_page,Bitu phys_page) {
+ PageHandler * handler=MEM_GetPageHandler(phys_page);
+ Bitu lin_base=lin_page << 12;
+ if (lin_page>=(TLB_SIZE*(TLB_BANKS+1)) || phys_page>=(TLB_SIZE*(TLB_BANKS+1)))
+ E_Exit("Illegal page");
+
+ if (paging.links.used>=PAGING_LINKS) {
+ LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache");
+ PAGING_ClearTLB();
+ }
+
+ tlb_entry *entry = get_tlb_entry(lin_base);
+ entry->phys_page=phys_page;
+ if (handler->flags & PFLAG_READABLE) entry->read=handler->GetHostReadPt(phys_page)-lin_base;
+ else entry->read=0;
+ entry->write=0;
+
+ paging.links.entries[paging.links.used++]=lin_page;
+ entry->readhandler=handler;
+ entry->writehandler=&init_page_handler_userro;
+}
+
+#endif
+
+
+void PAGING_SetDirBase(Bitu cr3) {
+ paging.cr3=cr3;
+
+ paging.base.page=cr3 >> 12;
+ paging.base.addr=cr3 & ~4095;
+// LOG(LOG_PAGING,LOG_NORMAL)("CR3:%X Base %X",cr3,paging.base.page);
+ if (paging.enabled) {
+ PAGING_ClearTLB();
+ }
+}
+
+void PAGING_Enable(bool enabled) {
+ /* If paging is disabled, we work from a default paging table */
+ if (paging.enabled==enabled) return;
+ paging.enabled=enabled;
+ if (enabled) {
+ if (GCC_UNLIKELY(cpudecoder==CPU_Core_Simple_Run)) {
+// LOG_MSG("CPU core simple won't run this game,switching to normal");
+ cpudecoder=CPU_Core_Normal_Run;
+ CPU_CycleLeft+=CPU_Cycles;
+ CPU_Cycles=0;
+ }
+// LOG(LOG_PAGING,LOG_NORMAL)("Enabled");
+ PAGING_SetDirBase(paging.cr3);
+ }
+ PAGING_ClearTLB();
+}
+
+bool PAGING_Enabled(void) {
+ return paging.enabled;
+}
+
+class PAGING:public Module_base{
+public:
+ PAGING(Section* configuration):Module_base(configuration){
+ /* Setup default Page Directory, force it to update */
+ paging.enabled=false;
+ PAGING_InitTLB();
+ Bitu i;
+ for (i=0;i<LINK_START;i++) {
+ paging.firstmb[i]=i;
+ }
+ pf_queue.used=0;
+ }
+ ~PAGING(){}
+};
+
+static PAGING* test;
+void PAGING_Init(Section * sec) {
+ test = new PAGING(sec);
+}