remove C_DYNREC dynamic core

This commit is contained in:
Jonathan Campbell 2013-10-20 12:03:12 -07:00
parent a77a5e33c9
commit d6f3d82f8b
27 changed files with 10 additions and 16305 deletions

View File

@ -51,10 +51,6 @@
/* Define to 1 to use x86 dynamic cpu core */
#undef C_DYNAMIC_X86
/* Define to 1 to use recompiling cpu core. Can not be used together with the
dynamic-x86 core */
#undef C_DYNREC
/* Define to 1 to enable fluidsynth MIDI synthesis */
#undef C_FLUIDSYNTH

42
configure vendored
View File

@ -748,7 +748,6 @@ enable_debug
enable_core_inline
enable_dynamic_core
enable_dynamic_x86
enable_dynrec
enable_fpu
enable_fpu_x86
enable_unaligned_memory
@ -1400,7 +1399,6 @@ Optional Features:
--enable-core-inline Enable inlined memory handling in CPU Core
--disable-dynamic-core Disable all dynamic cores
--disable-dynamic-x86 Disable x86 dynamic cpu core
--disable-dynrec Disable recompiling cpu core
--disable-fpu Disable fpu support
--disable-fpu-x86 Disable x86 assembly fpu core
--disable-unaligned-memory
@ -6829,43 +6827,6 @@ $as_echo "no" >&6; }
fi
# Check whether --enable-dynrec was given.
if test "${enable_dynrec+set}" = set; then :
enableval=$enable_dynrec;
else
enable_dynrec=yes
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether recompiling cpu core will be enabled" >&5
$as_echo_n "checking whether recompiling cpu core will be enabled... " >&6; }
if test x$enable_dynrec = xno -o x$enable_dynamic_core = xno; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
else
if test x$c_targetcpu = xx86 ; then
if test x$enable_dynamic_x86 = xno ; then
$as_echo "#define C_DYNREC 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using dynamic-x86" >&5
$as_echo "no, using dynamic-x86" >&6; }
fi
else
if test x$c_targetcpu = xx86_64 ; then
$as_echo "#define C_DYNREC 1" >>confdefs.h
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
fi
fi
# Check whether --enable-fpu was given.
if test "${enable_fpu+set}" = set; then :
enableval=$enable_fpu;
@ -7693,7 +7654,7 @@ fi
ac_config_files="$ac_config_files Makefile src/Makefile src/cpu/Makefile src/cpu/core_full/Makefile src/cpu/core_normal/Makefile src/cpu/core_dyn_x86/Makefile src/cpu/core_dynrec/Makefile src/debug/Makefile src/dos/Makefile src/fpu/Makefile src/gui/Makefile src/hardware/Makefile src/hardware/serialport/Makefile src/hardware/reSID/Makefile src/hardware/parport/Makefile src/ints/Makefile src/libs/Makefile src/libs/zmbv/Makefile src/libs/gui_tk/Makefile src/libs/porttalk/Makefile src/misc/Makefile src/shell/Makefile src/platform/Makefile include/Makefile"
ac_config_files="$ac_config_files Makefile src/Makefile src/cpu/Makefile src/cpu/core_full/Makefile src/cpu/core_normal/Makefile src/cpu/core_dyn_x86/Makefile src/debug/Makefile src/dos/Makefile src/fpu/Makefile src/gui/Makefile src/hardware/Makefile src/hardware/serialport/Makefile src/hardware/reSID/Makefile src/hardware/parport/Makefile src/ints/Makefile src/libs/Makefile src/libs/zmbv/Makefile src/libs/gui_tk/Makefile src/libs/porttalk/Makefile src/misc/Makefile src/shell/Makefile src/platform/Makefile include/Makefile"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@ -8437,7 +8398,6 @@ do
"src/cpu/core_full/Makefile") CONFIG_FILES="$CONFIG_FILES src/cpu/core_full/Makefile" ;;
"src/cpu/core_normal/Makefile") CONFIG_FILES="$CONFIG_FILES src/cpu/core_normal/Makefile" ;;
"src/cpu/core_dyn_x86/Makefile") CONFIG_FILES="$CONFIG_FILES src/cpu/core_dyn_x86/Makefile" ;;
"src/cpu/core_dynrec/Makefile") CONFIG_FILES="$CONFIG_FILES src/cpu/core_dynrec/Makefile" ;;
"src/debug/Makefile") CONFIG_FILES="$CONFIG_FILES src/debug/Makefile" ;;
"src/dos/Makefile") CONFIG_FILES="$CONFIG_FILES src/dos/Makefile" ;;
"src/fpu/Makefile") CONFIG_FILES="$CONFIG_FILES src/fpu/Makefile" ;;

View File

@ -285,30 +285,6 @@ else
fi
fi
AH_TEMPLATE(C_DYNREC,[Define to 1 to use recompiling cpu core. Can not be used together with the dynamic-x86 core])
AC_ARG_ENABLE(dynrec,AC_HELP_STRING([--disable-dynrec],[Disable recompiling cpu core]),,enable_dynrec=yes)
AC_MSG_CHECKING(whether recompiling cpu core will be enabled)
if test x$enable_dynrec = xno -o x$enable_dynamic_core = xno; then
AC_MSG_RESULT(no)
else
dnl x86 only enable it if dynamic-x86 is disabled.
if test x$c_targetcpu = xx86 ; then
if test x$enable_dynamic_x86 = xno ; then
AC_DEFINE(C_DYNREC,1)
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT([no, using dynamic-x86])
fi
else
if test x$c_targetcpu = xx86_64 ; then
AC_DEFINE(C_DYNREC,1)
AC_MSG_RESULT(yes)
else
AC_MSG_RESULT(no)
fi
fi
fi
AH_TEMPLATE(C_FPU,[Define to 1 to enable floating point emulation])
AC_ARG_ENABLE(fpu,AC_HELP_STRING([--disable-fpu],[Disable fpu support]),,enable_fpu=yes)
AC_MSG_CHECKING(whether fpu emulation will be enabled)
@ -528,7 +504,6 @@ src/cpu/Makefile
src/cpu/core_full/Makefile
src/cpu/core_normal/Makefile
src/cpu/core_dyn_x86/Makefile
src/cpu/core_dynrec/Makefile
src/debug/Makefile
src/dos/Makefile
src/fpu/Makefile

View File

@ -1,7 +1,7 @@
SUBDIRS = core_full core_normal core_dyn_x86 core_dynrec
SUBDIRS = core_full core_normal core_dyn_x86
AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libcpu.a
libcpu_a_SOURCES = callback.cpp cpu.cpp flags.cpp modrm.cpp modrm.h core_full.cpp instructions.h \
paging.cpp lazyflags.h core_normal.cpp core_simple.cpp core_prefetch.cpp \
core_dyn_x86.cpp core_dynrec.cpp mmx.cpp
core_dyn_x86.cpp mmx.cpp

View File

@ -74,8 +74,7 @@ libcpu_a_LIBADD =
am_libcpu_a_OBJECTS = callback.$(OBJEXT) cpu.$(OBJEXT) flags.$(OBJEXT) \
modrm.$(OBJEXT) core_full.$(OBJEXT) paging.$(OBJEXT) \
core_normal.$(OBJEXT) core_simple.$(OBJEXT) \
core_prefetch.$(OBJEXT) core_dyn_x86.$(OBJEXT) \
core_dynrec.$(OBJEXT) mmx.$(OBJEXT)
core_prefetch.$(OBJEXT) core_dyn_x86.$(OBJEXT) mmx.$(OBJEXT)
libcpu_a_OBJECTS = $(am_libcpu_a_OBJECTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@ -294,12 +293,12 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
SUBDIRS = core_full core_normal core_dyn_x86 core_dynrec
SUBDIRS = core_full core_normal core_dyn_x86
AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LIBRARIES = libcpu.a
libcpu_a_SOURCES = callback.cpp cpu.cpp flags.cpp modrm.cpp modrm.h core_full.cpp instructions.h \
paging.cpp lazyflags.h core_normal.cpp core_simple.cpp core_prefetch.cpp \
core_dyn_x86.cpp core_dynrec.cpp mmx.cpp
core_dyn_x86.cpp mmx.cpp
all: all-recursive
@ -351,7 +350,6 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callback.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core_dyn_x86.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core_dynrec.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core_full.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core_normal.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/core_prefetch.Po@am__quote@

View File

@ -1,334 +0,0 @@
/*
* Copyright (C) 2002-2013 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;
Bitu CPU_CyclesOld = CPU_Cycles;
// 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);
cycle_count += CPU_CyclesOld - CPU_Cycles;
switch (ret) {
case BR_Iret:
#if C_HEAVY_DEBUG
if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
#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_HEAVY_DEBUG
if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
#endif
break;
case BR_Cycles:
// cycles went negative, return from the core to handle
// external events, schedule the pic...
#if C_HEAVY_DEBUG
if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
#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

View File

@ -1,5 +0,0 @@
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

View File

@ -1,451 +0,0 @@
# Makefile.in generated by automake 1.13.1 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2012 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__make_dryrun = \
{ \
am__dry=no; \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
| grep '^AM OK$$' >/dev/null || am__dry=yes;; \
*) \
for am__flg in $$MAKEFLAGS; do \
case $$am__flg in \
*=*|--*) ;; \
*n*) am__dry=yes; break;; \
esac; \
done;; \
esac; \
test $$am__dry = yes; \
}
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
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(noinst_HEADERS)
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
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
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@
CXXCPP = @CXXCPP@
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@
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
.PRECIOUS: 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__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
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: $(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
# 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:

View File

@ -1,665 +0,0 @@
/*
* Copyright (C) 2002-2013 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*)(((long)cache_code_start_ptr + PAGESIZE_TEMP-1) & ~(PAGESIZE_TEMP-1)); //MEM LEAK. store old pointer if you want to free it.
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; */
}

View File

@ -1,615 +0,0 @@
/*
* Copyright (C) 2002-2013 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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,687 +0,0 @@
/*
* Copyright (C) 2002-2013 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),true);
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

File diff suppressed because it is too large Load Diff

View File

@ -1,113 +0,0 @@
/*
* Copyright (C) 2002-2013 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
}

File diff suppressed because it is too large Load Diff

View File

@ -1,918 +0,0 @@
/*
* Copyright (C) 2002-2013 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 (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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,36 +0,0 @@
/*
* Copyright (C) 2002-2013 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

View File

@ -1,750 +0,0 @@
/*
* Copyright (C) 2002-2013 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

View File

@ -1,730 +0,0 @@
/*
* Copyright (C) 2002-2013 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);
}
static INLINE void gen_reg_memaddr(HostReg reg,void* data) {
Bit64s diff = (Bit64s)data-((Bit64s)cache.pos+5);
if ((diff<0x80000000LL) && (diff>-0x80000000LL)) {
cache_addb(0x05+(reg<<3));
// RIP-relative addressing is offset after the instruction
cache_addd((Bit32u)(((Bit64u)diff)&0xffffffffLL));
} else if ((Bit64u)data<0x100000000LL) {
cache_addw(0x2504+(reg<<3));
cache_addd((Bit32u)(((Bit64u)data)&0xffffffffLL));
} else {
E_Exit("DRC64:Unhandled memory reference");
}
}
static INLINE void gen_memaddr(Bitu op,void* data,Bitu off) {
Bit64s diff;
diff = (Bit64s)data-((Bit64s)cache.pos+off+5);
if ((diff<0x80000000LL) && (diff>-0x80000000LL)) {
// RIP-relative addressing is offset after the instruction
cache_addb(op+1);
cache_addd((Bit32u)(((Bit64u)diff)&0xffffffffLL));
} else if ((Bit64u)data<0x100000000LL) {
cache_addb(op);
cache_addb(0x25);
cache_addd((Bit32u)(((Bit64u)data)&0xffffffffLL));
} else {
E_Exit("DRC64:Unhandled memory reference");
}
}
// 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_addb(0x8b); // mov reg,[data]
gen_reg_memaddr(dest_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(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_addb(0x89); // mov [data],reg
gen_reg_memaddr(src_reg,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_addb(0x8a); // mov reg,[data]
gen_reg_memaddr(dest_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) {
cache_addb(0x66);
cache_addb(0x8b); // mov reg,[data]
gen_reg_memaddr(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_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_addb(0x88); // mov [data],reg
gen_reg_memaddr(src_reg,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_addb(0x03); // add reg,[data]
gen_reg_memaddr(reg,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_addb(0xc7); // mov [data],imm
gen_memaddr(0x04,dest,4);
cache_addd(imm);
}
// 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);
}
// 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);
cache_addb(0x48);
gen_mov_word_from_reg(HOST_EAX,dest,true);
}
// add an 8bit constant value to a memory value
static void gen_add_direct_byte(void* dest,Bit8s imm) {
cache_addb(0x83); // add [data],imm
gen_memaddr(0x4,dest,1);
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_addb(0x81); // add [data],imm
if (dword) {
gen_memaddr(0x4,dest,4); // size of following immediate value
cache_addd((Bit32u)imm);
} else {
gen_memaddr(0x4,dest,2); // size of following immediate value
cache_addw((Bit16u)imm);
}
}
// subtract an 8bit constant value from a memory value
static void gen_sub_direct_byte(void* dest,Bit8s imm) {
cache_addb(0x83); // sub [data],imm
gen_memaddr(0x2c,dest,1);
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(0x81); // sub [data],imm
if (dword) {
gen_memaddr(0x2c,dest,4); // size of following immediate value
cache_addd((Bit32u)imm);
} else {
gen_memaddr(0x2c,dest,2); // size of following immediate value
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(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]
cache_addb(0x49);
gen_mov_word_to_reg(0,(void*)mem,true);
break;
case 3: // mov r9,[mem]
cache_addb(0x49);
gen_mov_word_to_reg(1,(void*)mem,true);
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) { }

View File

@ -1,516 +0,0 @@
/*
* Copyright (C) 2002-2013 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) { }

View File

@ -81,10 +81,6 @@ 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
@ -1602,11 +1598,6 @@ void CPU_SET_CRX(Bitu cr,Bitu value) {
cpudecoder=&CPU_Core_Dyn_X86_Run;
strcpy(core_mode, "dynamic");
}
#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 {
@ -2231,7 +2222,7 @@ static void CPU_ToggleNormalCore(bool pressed) {
}
}
#if ((C_DYNAMIC_X86) || (C_DYNREC))
#if (C_DYNAMIC_X86)
static void CPU_ToggleDynamicCore(bool pressed) {
if (!pressed)
return;
@ -2335,15 +2326,13 @@ public:
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");
MAPPER_AddHandler(CPU_ToggleAutoCycles,MK_equals,MMOD1,"cycauto","Tog. Cycles Auto");
MAPPER_AddHandler(CPU_ToggleNormalCore,MK_1,MMOD1,"normal" ,"Tog. Normal Core");
MAPPER_AddHandler(CPU_ToggleFullCore,MK_2,MMOD1,"full","Tog. Full Core");
#if ((C_DYNAMIC_X86) || (C_DYNREC))
#if (C_DYNAMIC_X86)
MAPPER_AddHandler(CPU_ToggleDynamicCore,MK_3,MMOD1,"dynamic","Tog. Dynamic Core");
#endif
MAPPER_AddHandler(CPU_ToggleSimpleCore,MK_4,MMOD1,"simple","Tog. Simple Core");
@ -2457,13 +2446,7 @@ public:
} 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
} else {
strcpy(core_mode,"normal");
@ -2473,8 +2456,6 @@ public:
#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;
@ -2535,8 +2516,6 @@ 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;
}
@ -2622,15 +2601,9 @@ Bit16u CPU_FindDecoderType( CPU_Decoder *decoder )
else if( cpudecoder == &CPU_Core_Simple_Run ) decoder_idx = 2;
else if( cpudecoder == &CPU_Core_Full_Run ) decoder_idx = 3;
else if( cpudecoder == &CPU_Core_Dyn_X86_Run ) decoder_idx = 4;
#if (C_DYNREC)
else if( cpudecoder == &CPU_Core_Dynrec_Run ) decoder_idx = 5;
#endif
else if( cpudecoder == &CPU_Core_Normal_Trap_Run ) decoder_idx = 100;
else if( cpudecoder == &CPU_Core_Dyn_X86_Trap_Run ) decoder_idx = 101;
#if(C_DYNREC)
else if( cpudecoder == &CPU_Core_Dynrec_Trap_Run ) decoder_idx = 102;
#endif
else if( cpudecoder == &HLT_Decode ) decoder_idx = 200;
@ -2651,15 +2624,9 @@ CPU_Decoder *CPU_IndexDecoderType( Bit16u decoder_idx )
case 2: cpudecoder = &CPU_Core_Simple_Run; break;
case 3: cpudecoder = &CPU_Core_Full_Run; break;
case 4: cpudecoder = &CPU_Core_Dyn_X86_Run; break;
#if (C_DYNREC)
case 5: cpudecoder = &CPU_Core_Dynrec_Run; break;
#endif
case 100: cpudecoder = &CPU_Core_Normal_Trap_Run; break;
case 101: cpudecoder = &CPU_Core_Dyn_X86_Trap_Run; break;
#if (C_DYNREC)
case 102: cpudecoder = &CPU_Core_Dynrec_Trap_Run; break;
#endif
case 200: cpudecoder = &HLT_Decode; break;
}

View File

@ -148,7 +148,7 @@ void DOS_Terminate(Bit16u pspseg,bool tsr,Bit8u exitcode) {
} else {
GFX_SetTitle(-1,-1,-1,false);
}
#if (C_DYNAMIC_X86) || (C_DYNREC)
#if (C_DYNAMIC_X86)
if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CORE) {
cpudecoder=&CPU_Core_Normal_Run;
CPU_CycleLeft=0;

View File

@ -707,7 +707,7 @@ void DOSBOX_Init(void) {
secprop=control->AddSection_prop("cpu",&CPU_Init,true);//done
const char* cores[] = { "auto",
#if (C_DYNAMIC_X86) || (C_DYNREC)
#if (C_DYNAMIC_X86)
"dynamic",
#endif
"normal", "full", "simple", 0 };