[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC][PATCH] NeXT emulation on QEMU
From: |
Bryce Lanham |
Subject: |
[Qemu-devel] [RFC][PATCH] NeXT emulation on QEMU |
Date: |
Wed, 17 Aug 2011 14:19:34 -0500 |
Hi,
I have been working on adding NeXT black hardware support to QEMU for
Google Summer of Code. While only a base level of hardware is
implemented, I need to have the code in upstream before the end of the
program. I based my work off of Laurent Vivier's work on the m68k
core, so that work would also need to be upstreamed as well.
It's a bit rough, and could use a bit of polishing, but Natalia wants
to have this upstream by the Monday deadline. I wanted to post this
earlier, but I've been sick the past couple of days.
Bryce Lanham
diff --git .gitignore .gitignore
index 59c343c..fed07c5 100644
--- .gitignore
+++ .gitignore
@@ -71,3 +71,12 @@ cscope.*
tags
TAGS
*~
+tests/m68k/fabs
+tests/m68k/fdiv
+tests/m68k/fmove
+tests/m68k/fmovecr
+tests/m68k/fmovem
+tests/m68k/fmul
+tests/m68k/fsub
+tests/m68k/fgetexp
+tests/m68k/fscale
diff --git Makefile.target Makefile.target
index 096214a..af02b41 100644
--- Makefile.target
+++ Makefile.target
@@ -25,6 +25,7 @@ include $(SRC_PATH)/Makefile.objs
ifdef CONFIG_USER_ONLY
# user emulator name
QEMU_PROG=qemu-$(TARGET_ARCH2)
+USER_TOOLS=$(TARGET_TOOLS)
else
# system emulator name
ifeq ($(TARGET_ARCH), i386)
@@ -32,9 +33,10 @@ QEMU_PROG=qemu$(EXESUF)
else
QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF)
endif
+USER_TOOLS=
endif
-PROGS=$(QEMU_PROG)
+PROGS=$(QEMU_PROG) $(USER_TOOLS)
STPFILES=
ifndef CONFIG_HAIKU
@@ -64,6 +66,10 @@ else
stap:
endif
+qemu-wrapper.o: $(SRC_PATH)/linux-user/qemu-wrapper.c
+qemu-wrapper$(EXESUF): qemu-wrapper.o
+
+
all: $(PROGS) stap
# Dummy command so that make thinks it has done something
@@ -367,6 +373,8 @@ obj-sh4-y += ide/mmio.o
obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
obj-m68k-y += m68k-semi.o dummy_m68k.o
+obj-m68k-y += m68k_mac.o
+obj-m68k-y += next-cube.o next-kbd.o next-fb.o next-net.o framebuffer.o
obj-s390x-y = s390-virtio-bus.o s390-virtio.o
diff --git bswap.h bswap.h
index f41bebe..13fd5cf 100644
--- bswap.h
+++ bswap.h
@@ -533,7 +533,7 @@ static inline int lduw_be_p(const void *ptr)
: "m" (*(uint16_t *)ptr));
return val;
#else
- const uint8_t *b = ptr;
+ const uint8_t *b = (const uint8_t *)ptr;
return ((b[0] << 8) | b[1]);
#endif
}
@@ -548,7 +548,7 @@ static inline int ldsw_be_p(const void *ptr)
: "m" (*(uint16_t *)ptr));
return (int16_t)val;
#else
- const uint8_t *b = ptr;
+ const uint8_t *b = (const uint8_t *)ptr;
return (int16_t)((b[0] << 8) | b[1]);
#endif
}
@@ -563,7 +563,7 @@ static inline int ldl_be_p(const void *ptr)
: "m" (*(uint32_t *)ptr));
return val;
#else
- const uint8_t *b = ptr;
+ const uint8_t *b = (const uint8_t *)ptr;
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
#endif
}
diff --git configure configure
index 6873e13..b635a6b 100755
--- configure
+++ configure
@@ -135,6 +135,7 @@ kvm="no"
gprof="no"
debug_tcg="no"
debug_mon="no"
+emulop="no"
debug="no"
strip_opt="yes"
bigendian="no"
@@ -531,6 +532,10 @@ for opt do
;;
--target-list=*) target_list="$optarg"
;;
+ --*-default-cpu=*)
+ tmp=`expr "x$opt" : 'x--\(.*\)-default-cpu=.*'`
+ eval ${tmp}_default_cpu="$optarg"
+ ;;
--enable-trace-backend=*) trace_backend="$optarg"
;;
--with-trace-file=*) trace_file="$optarg"
@@ -579,6 +584,10 @@ for opt do
;;
--disable-debug-tcg) debug_tcg="no"
;;
+ --enable-emulop) emulop="yes"
+ ;;
+ --disable-emulop) emulop="no"
+ ;;
--enable-debug-mon) debug_mon="yes"
;;
--disable-debug-mon) debug_mon="no"
@@ -927,6 +936,7 @@ echo " use %M for cpu
name [$interp_prefix]"
echo " --target-list=LIST set target list (default: build everything)"
echo "Available targets: $default_target_list" | \
fold -s -w 53 | sed -e 's/^/ /'
+echo " --ARCH-default-cpu=CPU set the default cpu for a given architecture"
echo ""
echo "Advanced options (experts only):"
echo " --source-path=PATH path of source code [$source_path]"
@@ -1042,6 +1052,8 @@ echo " --disable-usb-redir disable usb
network redirection support"
echo " --enable-usb-redir enable usb network redirection support"
echo " --disable-guest-agent disable building of the QEMU Guest Agent"
echo " --enable-guest-agent enable building of the QEMU Guest Agent"
+echo " --enable-emulop enable emulation tester helper"
+echo " --disable-emulop disable emulation tester helper"
echo ""
echo "NOTE: The object files are built at the place where configure
is launched"
exit 1
@@ -2635,6 +2647,14 @@ if test "$softmmu" = yes ; then
fi
fi
fi
+target_tools=
+if test "$linux_user" = yes ; then
+ for target in $target_list ; do
+ case $target in
+ *-linux-user) target_tools="qemu-wrapper\$(EXESUF) $target_tools" ;;
+ esac
+ done
+fi
# Mac OS X ships with a broken assembler
roms=
@@ -2670,6 +2690,7 @@ echo "host CPU $cpu"
echo "host big endian $bigendian"
echo "target list $target_list"
echo "tcg debug enabled $debug_tcg"
+echo "emulop enabled $emulop"
echo "Mon debug enabled $debug_mon"
echo "gprof enabled $gprof"
echo "sparse enabled $sparse"
@@ -3078,6 +3099,7 @@ fi
echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
echo "TOOLS=$tools" >> $config_host_mak
+echo "TARGET_TOOLS=$target_tools" >> $config_host_mak
echo "ROMS=$roms" >> $config_host_mak
echo "MAKE=$make" >> $config_host_mak
echo "INSTALL=$install" >> $config_host_mak
@@ -3135,6 +3157,7 @@ target_dir="$target"
config_target_mak=$target_dir/config-target.mak
target_arch2=`echo $target | cut -d '-' -f 1`
target_bigendian="no"
+target_default_cpu="any"
case "$target_arch2" in
armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus)
@@ -3211,11 +3234,13 @@ TARGET_ABI_DIR=""
case "$target_arch2" in
i386)
target_phys_bits=64
+ target_default_cpu="qemu32"
;;
x86_64)
TARGET_BASE_ARCH=i386
target_phys_bits=64
target_long_alignment=8
+ target_default_cpu="qemu64"
;;
alpha)
target_phys_bits=64
@@ -3233,6 +3258,7 @@ case "$target_arch2" in
cris)
target_nptl="yes"
target_phys_bits=32
+ target_default_cpu=""
;;
lm32)
target_phys_bits=32
@@ -3258,12 +3284,14 @@ case "$target_arch2" in
echo "TARGET_ABI_MIPSO32=y" >> $config_target_mak
target_nptl="yes"
target_phys_bits=64
+ target_default_cpu="24Kf"
;;
mipsn32|mipsn32el)
TARGET_ARCH=mipsn32
TARGET_BASE_ARCH=mips
echo "TARGET_ABI_MIPSN32=y" >> $config_target_mak
target_phys_bits=64
+ target_default_cpu="20Kc"
;;
mips64|mips64el)
TARGET_ARCH=mips64
@@ -3271,12 +3299,14 @@ case "$target_arch2" in
echo "TARGET_ABI_MIPSN64=y" >> $config_target_mak
target_phys_bits=64
target_long_alignment=8
+ target_default_cpu="20Kc"
;;
ppc)
gdb_xml_files="power-core.xml power-fpu.xml power-altivec.xml
power-spe.xml"
target_phys_bits=32
target_nptl="yes"
target_libs_softmmu="$fdt_libs"
+ target_default_cpu="750"
;;
ppcemb)
TARGET_BASE_ARCH=ppc
@@ -3285,6 +3315,7 @@ case "$target_arch2" in
target_phys_bits=64
target_nptl="yes"
target_libs_softmmu="$fdt_libs"
+ target_default_cpu="750"
;;
ppc64)
TARGET_BASE_ARCH=ppc
@@ -3293,6 +3324,7 @@ case "$target_arch2" in
target_phys_bits=64
target_long_alignment=8
target_libs_softmmu="$fdt_libs"
+ target_default_cpu="970fx"
;;
ppc64abi32)
TARGET_ARCH=ppc64
@@ -3302,6 +3334,7 @@ case "$target_arch2" in
gdb_xml_files="power64-core.xml power-fpu.xml power-altivec.xml
power-spe.xml"
target_phys_bits=64
target_libs_softmmu="$fdt_libs"
+ target_default_cpu="750"
;;
sh4|sh4eb)
TARGET_ARCH=sh4
@@ -3311,11 +3344,13 @@ case "$target_arch2" in
;;
sparc)
target_phys_bits=64
+ target_default_cpu="Fujitsu MB86904"
;;
sparc64)
TARGET_BASE_ARCH=sparc
target_phys_bits=64
target_long_alignment=8
+ target_default_cpu="TI UltraSparc II"
;;
sparc32plus)
TARGET_ARCH=sparc64
@@ -3323,6 +3358,7 @@ case "$target_arch2" in
TARGET_ABI_DIR=sparc
echo "TARGET_ABI32=y" >> $config_target_mak
target_phys_bits=64
+ target_default_cpu="Fujitsu MB86904"
;;
s390x)
target_nptl="yes"
@@ -3337,10 +3373,15 @@ case "$target_arch2" in
exit 1
;;
esac
+tmp_target_default_cpu=`eval echo \\$${target_arch2}_default_cpu`
+if [ "x$tmp_target_default_cpu" != "x" ] ; then
+ target_default_cpu="$tmp_target_default_cpu"
+fi
echo "TARGET_SHORT_ALIGNMENT=$target_short_alignment" >> $config_target_mak
echo "TARGET_INT_ALIGNMENT=$target_int_alignment" >> $config_target_mak
echo "TARGET_LONG_ALIGNMENT=$target_long_alignment" >> $config_target_mak
echo "TARGET_LLONG_ALIGNMENT=$target_llong_alignment" >> $config_target_mak
+echo "TARGET_DEFAULT_CPU=\"$target_default_cpu\"" >> $config_target_mak
echo "TARGET_ARCH=$TARGET_ARCH" >> $config_target_mak
target_arch_name="`echo $TARGET_ARCH | tr '[:lower:]' '[:upper:]'`"
echo "TARGET_$target_arch_name=y" >> $config_target_mak
@@ -3415,6 +3456,9 @@ if test ! -z "$gdb_xml_files" ; then
echo "TARGET_XML_FILES=$list" >> $config_target_mak
fi
+if test "$target_user_only" = "yes" -a "$target_arch2" = "m68k" -a
"$emulop" = "yes" ; then
+ echo "CONFIG_EMULOP=y" >> $config_target_mak
+fi
if test "$target_user_only" = "yes" -a "$bflt" = "yes"; then
echo "TARGET_HAS_BFLT=y" >> $config_target_mak
fi
diff --git fpu/softfloat-specialize.h fpu/softfloat-specialize.h
index c165205..4a4863c 100644
--- fpu/softfloat-specialize.h
+++ fpu/softfloat-specialize.h
@@ -85,9 +85,14 @@ const float64 float64_default_nan =
const_float64(LIT64( 0xFFF8000000000000 ));
#define floatx80_default_nan_high 0x7FFF
#define floatx80_default_nan_low LIT64( 0xBFFFFFFFFFFFFFFF )
#else
+#if defined(TARGET_M68K)
+#define floatx80_default_nan_high 0x7FFF
+#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
+#else
#define floatx80_default_nan_high 0xFFFF
#define floatx80_default_nan_low LIT64( 0xC000000000000000 )
#endif
+#endif
const floatx80 floatx80_default_nan = make_floatx80(floatx80_default_nan_high,
floatx80_default_nan_low);
@@ -387,6 +392,26 @@ static int pickNaN(flag aIsQNaN, flag aIsSNaN,
flag bIsQNaN, flag bIsSNaN,
return 1;
}
}
+#elif defined(TARGET_M68K)
+static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
+ flag aIsLargerSignificand)
+{
+ /* If either operand, but not both operands, of an operation is a
+ * nonsignaling NAN, then that NAN is returned as the result. If both
+ * operands are nonsignaling NANs, then the destination operand
+ * nonsignaling NAN is returned as the result.
+ */
+
+ if (aIsSNaN) {
+ return 0;
+ } else if (bIsSNaN) {
+ return 1;
+ } else if (bIsQNaN) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
#else
static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN,
flag aIsLargerSignificand)
diff --git fpu/softfloat.c fpu/softfloat.c
index 7951a0e..dbce683 100644
--- fpu/softfloat.c
+++ fpu/softfloat.c
@@ -768,7 +768,9 @@ static floatx80
) {
return packFloatx80( zSign, 0x7FFE, ~ roundMask );
}
- return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ return packFloatx80( zSign,
+ floatx80_default_inf_high,
+ floatx80_default_inf_low );
}
if ( zExp <= 0 ) {
isTiny =
@@ -1583,7 +1585,9 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM )
aSign = extractFloat32Sign( a );
if ( aExp == 0xFF ) {
if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a
STATUS_VAR ) STATUS_VAR );
- return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ return packFloatx80( aSign,
+ floatx80_default_inf_high,
+ floatx80_default_inf_low);
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
@@ -2924,7 +2928,9 @@ floatx80 float64_to_floatx80( float64 a STATUS_PARAM )
aSign = extractFloat64Sign( a );
if ( aExp == 0x7FF ) {
if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a
STATUS_VAR ) STATUS_VAR );
- return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ return packFloatx80( aSign,
+ floatx80_default_inf_high,
+ floatx80_default_inf_low );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
@@ -3870,8 +3876,8 @@ int64 floatx80_to_int64( floatx80 a STATUS_PARAM )
if ( shiftCount ) {
float_raise( float_flag_invalid STATUS_VAR);
if ( ! aSign
- || ( ( aExp == 0x7FFF )
- && ( aSig != LIT64( 0x8000000000000000 ) ) )
+ || ( ( aExp == floatx80_default_inf_high )
+ && ( aSig != floatx80_default_inf_low ) )
) {
return LIT64( 0x7FFFFFFFFFFFFFFF );
}
@@ -4114,7 +4120,9 @@ static floatx80 addFloatx80Sigs( floatx80 a,
floatx80 b, flag zSign STATUS_PARAM
else if ( expDiff < 0 ) {
if ( bExp == 0x7FFF ) {
if ( (uint64_t) ( bSig<<1 ) ) return
propagateFloatx80NaN( a, b STATUS_VAR );
- return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ return packFloatx80( zSign,
+ floatx80_default_inf_high,
+ floatx80_default_inf_low );
}
if ( aExp == 0 ) ++expDiff;
shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
@@ -4191,7 +4199,8 @@ static floatx80 subFloatx80Sigs( floatx80 a,
floatx80 b, flag zSign STATUS_PARAM
bExpBigger:
if ( bExp == 0x7FFF ) {
if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a,
b STATUS_VAR );
- return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ return packFloatx80( zSign ^ 1, floatx80_default_inf_high,
+ floatx80_default_inf_low );
}
if ( aExp == 0 ) ++expDiff;
shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
@@ -4285,7 +4294,8 @@ floatx80 floatx80_mul( floatx80 a, floatx80 b
STATUS_PARAM )
return propagateFloatx80NaN( a, b STATUS_VAR );
}
if ( ( bExp | bSig ) == 0 ) goto invalid;
- return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ return packFloatx80( zSign, floatx80_default_inf_high,
+ floatx80_default_inf_low );
}
if ( bExp == 0x7FFF ) {
if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a,
b STATUS_VAR );
@@ -4296,7 +4306,8 @@ floatx80 floatx80_mul( floatx80 a, floatx80 b
STATUS_PARAM )
z.high = floatx80_default_nan_high;
return z;
}
- return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ return packFloatx80( zSign, floatx80_default_inf_high,
+ floatx80_default_inf_high );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
@@ -4345,7 +4356,8 @@ floatx80 floatx80_div( floatx80 a, floatx80 b
STATUS_PARAM )
if ( (uint64_t) ( bSig<<1 ) ) return
propagateFloatx80NaN( a, b STATUS_VAR );
goto invalid;
}
- return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ return packFloatx80( zSign, floatx80_default_inf_high,
+ floatx80_default_inf_low );
}
if ( bExp == 0x7FFF ) {
if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a,
b STATUS_VAR );
@@ -4361,7 +4373,8 @@ floatx80 floatx80_div( floatx80 a, floatx80 b
STATUS_PARAM )
return z;
}
float_raise( float_flag_divbyzero STATUS_VAR);
- return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ return packFloatx80( zSign, floatx80_default_inf_high,
+ floatx80_default_inf_low );
}
normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
}
@@ -5071,7 +5084,8 @@ floatx80 float128_to_floatx80( float128 a STATUS_PARAM )
if ( aSig0 | aSig1 ) {
return commonNaNToFloatx80( float128ToCommonNaN( a
STATUS_VAR ) STATUS_VAR );
}
- return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
+ return packFloatx80( aSign, floatx80_default_inf_high,
+ floatx80_default_inf_low );
}
if ( aExp == 0 ) {
if ( ( aSig0 | aSig1 ) == 0 ) return packFloatx80( aSign, 0, 0 );
diff --git fpu/softfloat.h fpu/softfloat.h
index 3bb7d8f..7a1fa7e 100644
--- fpu/softfloat.h
+++ fpu/softfloat.h
@@ -532,12 +532,23 @@ INLINE int floatx80_is_any_nan(floatx80 a)
#define floatx80_pi make_floatx80(0x4000, 0xc90fdaa22168c235LL)
#define floatx80_half make_floatx80(0x3ffe, 0x8000000000000000LL)
#define floatx80_infinity make_floatx80(0x7fff, 0x8000000000000000LL)
+#define floatx80_e make_floatx80(0x4000, 0xadf85458a2bb4a9aULL)
+#define floatx80_log2e make_floatx80(0x3fff, 0xb8aa3b295c17f0bcULL)
+#define floatx80_10 make_floatx80(0x4002, 0xa000000000000000ULL)
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN.
*----------------------------------------------------------------------------*/
extern const floatx80 floatx80_default_nan;
+#if defined(TARGET_M68K)
+#define floatx80_default_inf_high 0x7FFF
+#define floatx80_default_inf_low LIT64( 0x0000000000000000 )
+#else
+#define floatx80_default_inf_high 0x7FFF
+#define floatx80_default_inf_low LIT64( 0x8000000000000000 )
+#endif
+
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision conversion routines.
*----------------------------------------------------------------------------*/
diff --git gdb-xml/m68k-fp.xml gdb-xml/m68k-fp.xml
new file mode 100644
index 0000000..64290d1
--- /dev/null
+++ gdb-xml/m68k-fp.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2008 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.coldfire.fp">
+ <reg name="fp0" bitsize="96" type="float" group="float"/>
+ <reg name="fp1" bitsize="96" type="float" group="float"/>
+ <reg name="fp2" bitsize="96" type="float" group="float"/>
+ <reg name="fp3" bitsize="96" type="float" group="float"/>
+ <reg name="fp4" bitsize="96" type="float" group="float"/>
+ <reg name="fp5" bitsize="96" type="float" group="float"/>
+ <reg name="fp6" bitsize="96" type="float" group="float"/>
+ <reg name="fp7" bitsize="96" type="float" group="float"/>
+
+ <reg name="fpcontrol" bitsize="32" group="float"/>
+ <reg name="fpstatus" bitsize="32" group="float"/>,
+ <reg name="fpiaddr" bitsize="32" type="code_ptr" group="float"/>
+</feature>
diff --git hw/m68k_mac.c hw/m68k_mac.c
new file mode 100644
index 0000000..c1daff0
--- /dev/null
+++ hw/m68k_mac.c
@@ -0,0 +1,176 @@
+/*
+ * QEMU Motorla 680x0 Macintosh hardware System Emulator
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the
"Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "boards.h"
+#include "elf.h"
+#include "loader.h"
+
+static void q800_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ CPUState *env = NULL;
+ int linux_boot;
+ ram_addr_t ram_offset;
+ int32_t kernel_size;
+ uint64_t elf_entry;
+#if 0
+ char *filename;
+ qemu_irq *pic, **heathrow_irqs;
+ int i;
+ ram_addr_t bios_offset;
+ uint32_t kernel_base, initrd_base;
+ int32_t initrd_size;
+ PCIBus *pci_bus;
+ MacIONVRAMState *nvr;
+ int bios_size;
+ int pic_mem_index, nvram_mem_index, dbdma_mem_index, cuda_mem_index;
+ int escc_mem_index, ide_mem_index[2];
+ uint16_t ppc_boot_device;
+ DriveInfo * hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+ void *fw_cfg;
+ void *dbdma;
+#endif
+
+ linux_boot = (kernel_filename != NULL);
+
+ /* init CPUs */
+ if (cpu_model == NULL) {
+ cpu_model = "m68040";
+ }
+ env = cpu_init(cpu_model);
+ if (!env) {
+ hw_error("qemu: unable to find m68k CPU definition\n");
+ exit(1);
+ }
+ qemu_register_reset((QEMUResetHandler *)&cpu_reset, env);
+
+ ram_offset = qemu_ram_alloc(NULL, "m68k_mac.ram", ram_size);
+ cpu_register_physical_memory(0, ram_size, ram_offset | IO_MEM_RAM);
+
+#if 0
+ /* allocate and load BIOS */
+ bios_offset = qemu_ram_alloc(NULL, "ppc_heathrow.bios", BIOS_SIZE);
+ if (bios_name == NULL) {
+ bios_name = PROM_FILENAME;
+ }
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+ cpu_register_physical_memory(PROM_ADDR, BIOS_SIZE,
+ bios_offset | IO_MEM_ROM);
+
+ /* Load OpenBIOS (ELF) */
+ if (filename) {
+ bios_size = load_elf(filename, 0, NULL, NULL, NULL, NULL,
+ 1, ELF_MACHINE, 0);
+ qemu_free(filename);
+ } else {
+ bios_size = -1;
+ }
+ if (bios_size < 0 || bios_size > BIOS_SIZE) {
+ hw_error("qemu: could not load PowerPC bios '%s'\n", bios_name);
+ exit(1);
+ }
+#endif
+
+ if (linux_boot) {
+
+ kernel_size = load_elf(kernel_filename, NULL, NULL,
+ &elf_entry, NULL, NULL, 1,
+ ELF_MACHINE, 0);
+ if (kernel_size < 0) {
+ hw_error("qemu: could not load kernel '%s'\n",
+ kernel_filename);
+ exit(1);
+ }
+ env->pc = elf_entry;
+#if 0
+ /* load initrd */
+ if (initrd_filename) {
+ initrd_base = INITRD_LOAD_ADDR;
+ initrd_size = load_image_targphys(initrd_filename, initrd_base,
+ ram_size - initrd_base);
+ if (initrd_size < 0) {
+ hw_error("qemu: could not load initial ram disk '%s'\n",
+ initrd_filename);
+ exit(1);
+ }
+ } else {
+ initrd_base = 0;
+ initrd_size = 0;
+ }
+#endif
+ }
+
+#if 0
+ /* XXX: we register only 1 output pin for heathrow PIC */
+ heathrow_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
+ heathrow_irqs[0] =
+ qemu_mallocz(smp_cpus * sizeof(qemu_irq)*1);
+ /* Connect the heathrow PIC outputs to the 6xx bus */
+ for (i = 0; i < smp_cpus; i++) {
+ switch (PPC_INPUT(env)) {
+ case PPC_FLAGS_INPUT_6xx:
+ heathrow_irqs[i] = heathrow_irqs[0] + (i * 1);
+ heathrow_irqs[i][0] =
+ ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
+ break;
+ default:
+ hw_error("Bus model not supported on OldWorld Mac machine\n");
+ }
+ }
+
+ escc_mem_index = escc_init(0x80013000, pic[0x0f], pic[0x10], serial_hds[0],
+ serial_hds[1], ESCC_CLOCK, 4);
+
+ /* cuda also initialize ADB */
+ cuda_init(&cuda_mem_index, pic[0x12]);
+
+ adb_kbd_init(&adb_bus);
+ adb_mouse_init(&adb_bus);
+
+ macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem_index,
+ dbdma_mem_index, cuda_mem_index, nvr, 2, ide_mem_index,
+ escc_mem_index);
+
+ if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) {
+ graphic_depth = 15;
+ }
+#endif
+}
+
+static QEMUMachine q800_machine = {
+ .name = "q800",
+ .desc = "Macintosh Quadra 800",
+ .init = q800_init,
+ .max_cpus = 1,
+ .is_default = 1,
+};
+
+static void q800_machine_init(void)
+{
+ qemu_register_machine(&q800_machine);
+}
+
+machine_init(q800_machine_init);
diff --git hw/mcf5208.c hw/mcf5208.c
index 78fbc5f..8425bca 100644
--- hw/mcf5208.c
+++ hw/mcf5208.c
@@ -295,7 +295,7 @@ static QEMUMachine mcf5208evb_machine = {
.name = "mcf5208evb",
.desc = "MCF5206EVB",
.init = mcf5208evb_init,
- .is_default = 1,
+ .is_default = 0,
};
static void mcf5208evb_machine_init(void)
diff --git hw/next-cube.c hw/next-cube.c
new file mode 100644
index 0000000..ba58066
--- /dev/null
+++ hw/next-cube.c
@@ -0,0 +1,474 @@
+/*
+ * Next Cube System Driver
+ * Copyright (c) 2011 Bryce Lanham
+ *
+ * Based on dummy_m68k.c Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+
+/*
+ *
+ *
+ *
+ * */
+
+#include "hw.h"
+#include "next-fb.h"
+#include "next-kbd.h"
+#include "next-net.h"
+
+#include "monitor.h"
+#include "sysemu.h"
+#include "boards.h"
+#include "console.h"
+#include "loader.h"//probably not needed
+#include "elf.h"
+#include "esp.h" //SCSI ESP should work out of the box
+#include "escc.h" //ZILOG 8530 Serial Emulation
+#define ENTRY 0x0100001e
+
+/* Board init. */
+#define ROM_FILE "rom66.bin"
+/* these need to be in machine state */
+uint32_t scr1 = 0;
+uint32_t scr2 = 0;
+uint32_t int_status = 4;//from previous
+uint32_t int_mask = 0;
+uint32_t event_test = 0;
+/* Thanks to NeXT forums for this */
+uint8_t rtc_ram3[32]={
+0x94,0x0f,0x40,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0xfb,0x6d,0x00,0x00,0x7B,0x00,
+0x00,0x00,0x65,0x6e,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x13
+};
+uint8_t *rtc_ram;
+uint8_t rtc_ram2[32]={
+0x94,0x0f,0x40,0x03,0x00,0x00,0x00,0x00,
+0x00,0x00,0xfb,0x6d,0x00,0x00,0x4b,0x00,
+0x41,0x00,0x20,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x84,0x7e,
+};
+
+next_state_t next_state;
+
+static uint32_t mmio_readb(void*opaque, target_phys_addr_t addr);
+static uint32_t mmio_readw(void*opaque, target_phys_addr_t addr);
+static uint32_t mmio_readl(void*opaque, target_phys_addr_t addr);
+
+static void mmio_writeb(void*opaque, target_phys_addr_t addr, uint32_t val);
+static void mmio_writew(void*opaque, target_phys_addr_t addr, uint32_t val);
+static void mmio_writel(void*opaque, target_phys_addr_t addr, uint32_t val);
+static CPUReadMemoryFunc *mmio_read[3] = {
+ mmio_readb,
+ mmio_readw,
+ mmio_readl
+};
+
+static CPUWriteMemoryFunc *mmio_write[3] = {
+ mmio_writeb,
+ mmio_writew,
+ mmio_writel
+};
+static uint32_t mmio_readb(void*opaque, target_phys_addr_t addr)
+{
+ switch(addr)
+ {
+ case 0xc002:
+ return (scr1 >> 8) & 0xFF;
+ case 0xc0008:
+ return 0xff;//hack to hide memory error
+ default:
+ fprintf(stderr,"MMIO Read B @ %x\n",addr);
+ return 0x0;
+ }
+}
+static uint32_t mmio_readw(void*opaque, target_phys_addr_t addr)
+{
+ switch(addr)
+ {
+ default:
+ fprintf(stderr,"MMIO Read W @ %x\n",addr);
+ return 0x0;
+ }
+}
+
+static uint32_t mmio_readl(void*opaque, target_phys_addr_t addr)
+{
+
+ switch(addr)
+ {
+ case 0x7000:
+ // fprintf(stderr,"INTSTAT\n");
+ return int_status;
+
+ case 0x7800:
+ //fprintf(stderr,"INTMASK\n");
+ return int_mask;
+
+ case 0xc000:
+ // fprintf(stderr, "SCR1 Read: @ %X\n",((CPUM68KState
*)opaque)->pc);
+ return scr1;
+
+ case 0xd000:
+ // fprintf(stderr, "SCR2 Read: @ %X %X\n",((CPUM68KState
*)opaque)->pc,scr2);
+ return scr2;
+
+ case 0xc0000:
+ return 0x01;
+
+ case 0xc0034:
+ return 0x560;
+
+ default:
+ fprintf(stderr,"MMIO Read L @ %x\n",addr);
+ return 0x0;
+ }
+}
+static void mmio_writeb(void*opaque, target_phys_addr_t addr, uint32_t val)
+{
+
+ switch(addr)
+ {
+ default:
+ fprintf(stderr,"MMIO Write B @ %x with %x\n",addr,val);
+ }
+
+}
+static void mmio_writew(void*opaque, target_phys_addr_t addr, uint32_t val)
+{
+ fprintf(stderr,"MMIO Write W\n" );
+}
+int led = 0;
+
+static void mmio_writel(void*opaque, target_phys_addr_t addr, uint32_t val)
+{
+ static int phase = 0;
+ static uint8_t old_scr2;
+ static uint8_t rtc_command = 0;
+ static uint8_t rtc_value = 0;
+ static uint8_t rtc_status = 0x90;
+ static uint8_t rtc_return = 0;
+ uint8_t scr2_2;
+ switch(addr)
+ {
+ case 0x10:
+ break;
+ case 0x7000:
+ fprintf(stderr,"INT Status old: %x new: %x\n",int_status,val);
+ int_status = val;
+ break;
+ case 0x7800:
+ fprintf(stderr,"INT Status old: %x new: %x\n",int_mask,val);
+ int_mask = val;
+ break;
+ case 0xc000:
+ fprintf(stderr, "SCR1 Write: %x @ %X\n",val,((CPUM68KState
*)opaque)->pc);
+ break;
+ case 0xd000:
+ //old_scr2 = val;
+ scr2_2 = (val >> 8) & 0xFF;
+ if(val &0x1)
+ {
+ printf("fault!\n");
+ led++;
+ if(led == 10)
+ {
+ fprintf(stderr,"LED flashing, possible fault,
pausing emulation\n");
+ led = 0;
+ vm_stop(VMSTOP_DEBUG);
+ }
+
+ }
+
+ if (scr2_2& 0x1) {
+ // fprintf(stderr,"RTC %x phase %i\n",scr2_2,phase);
+ if (phase==-1) phase=0;
+ // if we are in going down clock... do something
+ #define SCR2_RTCLK 0x2
+ #define SCR2_RTDATA 0x4
+ if
(((old_scr2&SCR2_RTCLK)!=(scr2_2&SCR2_RTCLK)) &&
((scr2_2&SCR2_RTCLK)==0) ) {
+ if (phase<8)
+
rtc_command=(rtc_command<<1)|((scr2_2&SCR2_RTDATA)?1:0);
+ if ((phase>=8) && (phase<16)) {
+
rtc_value=(rtc_value<<1)|((scr2_2&SCR2_RTDATA)?1:0);
+
+ // if we read RAM register, output
RT_DATA bit
+ if (rtc_command<=0x1F) {
+ scr2_2=scr2_2&(~SCR2_RTDATA);
+ if
(rtc_ram[rtc_command]&(0x80>>(phase-8)))
+ scr2_2 |=SCR2_RTDATA;
+
+
rtc_return=(rtc_return<<1)|((scr2_2&SCR2_RTDATA)?1:0);
+ }
+ // read the status 0x30
+ if (rtc_command==0x30) {
+ scr2_2=scr2_2&(~SCR2_RTDATA);
+ // for now status = 0x98 (new
rtc + FTU)
+ if
(rtc_status&(0x80>>(phase-8)))
+ scr2_2|=SCR2_RTDATA;
+
+
rtc_return=(rtc_return<<1)|((scr2_2&SCR2_RTDATA)?1:0);
+ }
+ // read the status 0x31
+ if (rtc_command==0x31) {
+ scr2_2=scr2_2&(~SCR2_RTDATA);
+ // for now 0x00
+ if (0x00&(0x80>>(phase-8)))
+ scr2_2|=SCR2_RTDATA;
+
rtc_return=(rtc_return<<1)|((scr2_2&SCR2_RTDATA)?1:0);
+ }
+
+ if ((rtc_command>=0x20) && (rtc_command<=0x2F))
{
+ scr2_2=scr2_2&(~SCR2_RTDATA);
+ // for now 0x00
+ if (0x00&(0x80>>(phase-8)))
+ scr2_2|=SCR2_RTDATA;
+
rtc_return=(rtc_return<<1)|((scr2_2&SCR2_RTDATA)?1:0);
+ }
+
+ }
+
+ phase++;
+ if (phase==16) {
+ // fprintf(stderr,"SCR2 RTC command complete %x %x %x at
PC=$%08x\n",
+ // rtc_command,rtc_value,rtc_return,0);
+ if ((rtc_command>=0x80) &&
(rtc_command<=0x9F))
+ {
+
rtc_ram[rtc_command-0x80]=rtc_value;
+ #ifdef READ_RTC
+ FILE *fp =
fopen("rtc.ram","wb+");
+ int ret = fwrite(rtc_ram,1,32,fp);
+ if(ret != 32)
+ abort();
+ fclose(fp);
+ #endif
+ }
+ // write to x30 register
+ if (rtc_command==0xB1) {
+ // clear FTU
+ if (rtc_value & 0x04) {
+
rtc_status=rtc_status&(~0x18);
+
int_status=int_status&(~0x04);
+ }
+ }
+ }
+ }
+ } else {
+ // else end or abort
+ phase=-1;
+ rtc_command=0;
+ rtc_value=0;
+ }
+ scr2 = val & 0xFFFF00FF;
+ scr2 |= scr2_2<< 8;
+ old_scr2 = scr2_2;
+
+ break;
+ case 0xc0034:
+ // if(val == 0x90000560)
+ // vm_stop(VMSTOP_DEBUG);
+ default:
+ fprintf(stderr,"MMIO Write l @ %x with %x\n",addr,val);
+
+ }
+}
+
+
+static uint32_t scr_readb(void*opaque, target_phys_addr_t addr);
+static uint32_t scr_readw(void*opaque, target_phys_addr_t addr);
+static uint32_t scr_readl(void*opaque, target_phys_addr_t addr);
+static CPUReadMemoryFunc *scr_read[3] = {
+ scr_readb,
+ scr_readw,
+ scr_readl
+
+};
+
+static void scr_writeb(void*opaque, target_phys_addr_t addr, uint32_t value);
+static void scr_writew(void*opaque, target_phys_addr_t addr, uint32_t value);
+static void scr_writel(void*opaque, target_phys_addr_t addr, uint32_t value);
+static CPUWriteMemoryFunc * const scr_write[3] = {
+ scr_writeb,
+ scr_writew,
+ scr_writel
+};
+
+static uint32_t scr_readb(void*opaque, target_phys_addr_t addr)
+{
+ // CPUState *s = (CPUState *)opaque;
+ switch(addr)
+ {
+
+ case 0x14000: case 0x14005:
+ fprintf(stderr,"SCSI read b\n");
+ return 0x0;
+
+ case 0x14104://FDD
+ // return 0x0;
+
+ case 0x14108:
+ return 0x0;
+
+ case 0x18001:
+ // fprintf(stderr, "SCC @ %X\n",((CPUM68KState *)opaque)->pc);
+ return 0;
+ case 0x1a000:
+ // return 0;
+ case 0x1a001:
+ // return 0;
+ case 0x1a002:
+ // return 0;
+ case 0x1a003:
+ // fprintf(stderr,"event #%x @ %x\n",addr &0x3,s->pc);
+ // event_test++;
+ // if(event_test == 200) event_test = 0;
+ return event_test;
+ default:
+ fprintf(stderr,"BMAP Read B @ %x\n",addr);
+ return 0;
+ }
+ return 0;
+}
+static uint32_t scr_readw(void*opaque, target_phys_addr_t addr)
+{
+ fprintf(stderr,"S Read W @ %x\n",addr);
+ return 0;
+}
+static uint32_t scr_readl(void*opaque, target_phys_addr_t addr)
+{
+ fprintf(stderr,"SRead L @ %x\n",addr);
+ return 0;
+}
+static void scr_writeb(void*opaque, target_phys_addr_t addr, uint32_t value)
+{
+ switch(addr)
+ {
+ case 0x10000: break;//Screen brightness
+ case 0x18000:
+ case 0x18001:
+ case 0x18004:
+ break;
+ default:
+ fprintf(stderr,"BMAP Write B @ %x with %x\n",addr,value);
+ }
+}
+static void scr_writew(void*opaque, target_phys_addr_t addr, uint32_t value)
+{
+ fprintf(stderr,"SWrite w @ %x with %x\n",addr,value);
+}
+static void scr_writel(void*opaque, target_phys_addr_t addr, uint32_t value)
+{
+
+ fprintf(stderr,"SWrite l @ %x with %x\n",addr,value);
+}
+
+/* need to make more defines, put them into a header */
+#define RAM_SIZE 0x4000000
+
+void serial_irq(void *opaque, int n, int level);
+static void next_cube_init(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ /* Initialize the cpu core */
+ CPUState *env = cpu_init("m68040");
+ if (env == NULL) {
+ fprintf(stderr, "Unable to find m68k CPU definition\n");
+ exit(1);
+ }
+
+ /* Initialize CPU registers. */
+ env->vbr = 0;
+ env->pc = 0x100001e; //technically should read vector
+ env->sr = 0x2700;
+
+ /* Set internal registers to initial values */
+ scr1 = 0x01000220;
+ scr2 = 0x00ff8880;
+
+ int_mask = 0x88027640;
+ int_status= 0x200;
+
+ /* Load RTC ram, needs to be in a function probably */
+ {
+ rtc_ram = malloc(32);
+ #ifdef LOAD_RTC
+ FILE *fp = fopen("rtc.ram","rb");
+ if(fread(rtc_ram,1,32,fp) != 32)
+ abort();
+ fclose(fp);
+ #endif
+ memcpy(rtc_ram,rtc_ram2,32);
+ }
+
+
+ /* 64MB RAM starting at 0x4000000 */
+ cpu_register_physical_memory(0x4000000, RAM_SIZE,
+ qemu_ram_alloc(NULL, "next-cube.ram", RAM_SIZE) | IO_MEM_RAM);
+
+ /* Framebuffer */
+ nextfb_init(&next_state);
+
+ /* MMIO */
+ cpu_register_physical_memory((uint32_t)0x2000000,0xD0000,
+ cpu_register_io_memory(mmio_read,mmio_write, (void
*)env,DEVICE_NATIVE_ENDIAN));
+
+ /* BMAP */ //acts as a catch-all for now
+ cpu_register_physical_memory((uint32_t)0x2100000,0x3A7FF,
+ cpu_register_io_memory(scr_read,scr_write, (void
*)env,DEVICE_NATIVE_ENDIAN));
+
+ /* KBD */
+ nextkbd_init((void *)env);
+
+ /* Serial */
+ //CharDriverState *console = text_console_init(NULL);
+ //qemu_irq *serial = qemu_allocate_irqs(serial_irq, env, 2);
+ //escc_init(0x2118000, serial[0], serial[1],
+ // console, NULL, (9600*384),0);
+
+
+ /* Load ROM here */
+ if(get_image_size(ROM_FILE) != 0x20000)
+ {
+ fprintf(stderr,"Failed to load rom file!\n");
+ exit(1);
+ }
+
+ rom_add_file_fixed(ROM_FILE,0x1000000,0);
+ rom_add_file_fixed(ROM_FILE,0x000000,1);
+ cpu_register_physical_memory((uint32_t)0x1000000, 0x20000,
+ qemu_ram_alloc(NULL, "next.rom", 0x20000) | IO_MEM_ROM);
+ cpu_register_physical_memory((uint32_t)0x000000, 0x20000,
+ qemu_ram_alloc(NULL, "nex.rom", 0x20000) | IO_MEM_ROM);
+
+ /* Ethernet */
+ nextnet_init((void *)env);
+
+
+}
+
+void serial_irq(void *opaque, int n, int level)
+{
+ // fprintf(stderr,"IRQQQQQ\n");
+ // int_status |= 0xFFFFFF00;
+// int_status |= 1<<17;
+//CPUM68KState *env = (CPUM68KState *)opaque;
+//env->exception_index = 10;
+//m68k_set_irq_level((CPUM68KState *)opaque, 5,29);//25);
+
+}
+static QEMUMachine next_machine = {
+ .name = "next-cube",
+ .desc = "NeXT Cube",
+ .init = next_cube_init,
+};
+
+static void next_machine_init(void)
+{
+ qemu_register_machine(&next_machine);
+}
+
+machine_init(next_machine_init);
diff --git hw/next-cube.h hw/next-cube.h
new file mode 100644
index 0000000..e69de29
diff --git hw/next-fb.c hw/next-fb.c
new file mode 100644
index 0000000..0cccae3
--- /dev/null
+++ hw/next-fb.c
@@ -0,0 +1,102 @@
+/*
+ * NeXT Cube/Staion Framebuffer Emulation
+ *
+ * Copyright (c) 2011 Bryce Lanham
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the
"Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "hw.h"
+#include "loader.h"
+#include "console.h"
+#include "framebuffer.h"
+#define BITS 8
+#include "pixel_ops.h"
+#include "next-fb.h"
+/*
+typedef struct NextVGAState {
+ VGACommonState vga;
+ target_phys_addr_t vram_base;
+ };*/
+//need a function to register the mm i/o for fb and to register vram
+
+void nextfb_draw_line(void *opaque, uint8_t *d, const uint8_t *s, int
width, int pitch)
+{
+ uint32_t pal[4] = {0xFFFFFFFF, 0xFFAAAAAA, 0xFF555555,0xFF000000};
+ uint32_t*buf = qemu_malloc(1120*4);
+ int i = 0;
+ for(;i<280; i++)
+ {
+ int j=i*4;
+ uint8_t src = s[i];
+ buf[j+3]= pal[src & 0x3];
+ src >>=2;
+ buf[j+2]= pal[src & 0x3];
+ src >>=2;
+ buf[j+1]= pal[src & 0x3];
+ src >>=2;
+ buf[j+0]= pal[src & 0x3];
+ }
+
+ memcpy(d,buf,1120*4);
+ free(buf);
+}
+
+
+static void nextfb_update(void * opaque)
+{
+ next_state_t *s = (next_state_t *)opaque;
+ DisplaySurface *info = s->ds->surface;
+
+
+
+ int dest_width = 4;
+ int src_width;
+ int first = 0;
+ int last = 0;
+ src_width = s->cols = 1120;
+ src_width = 288;
+ dest_width = 1120;
+ dest_width = info->linesize;
+ framebuffer_update_display(s->ds,
+ 0xB000000,1120,832,
+ src_width,dest_width, 0,
+ 1,
+ nextfb_draw_line,
+ NULL,
+ &first, &last);
+
+ dpy_update(s->ds,0,0,1120,832);
+}
+
+static void nextfb_invalidate(void *opaque)
+{
+}
+
+void nextfb_init(next_state_t *s)
+{
+ s->ds = graphic_console_init(nextfb_update,nextfb_invalidate,
NULL, NULL, s);
+ qemu_console_resize(s->ds,1120,832);
+ s->cols = 1120;
+ s->rows = 832;
+ s->invalidate = 1;
+
+ cpu_register_physical_memory(0xB000000, 0x1CB100,
+ qemu_ram_alloc(NULL,"next-vram.ram",0x1CB100) | IO_MEM_RAM);
+
+}
diff --git hw/next-fb.h hw/next-fb.h
new file mode 100644
index 0000000..9d2b547
--- /dev/null
+++ hw/next-fb.h
@@ -0,0 +1,14 @@
+typedef struct {
+ DisplayState *ds;
+ uint32_t base;
+ uint32_t pitch;
+ uint32_t cols;
+ uint32_t rows;
+ int invalidate;
+
+
+} next_state_t;
+
+void nextfb_draw_line(void *opaque, uint8_t *d, const uint8_t *s, int
width, int pitch);
+
+void nextfb_init(next_state_t *s);
diff --git hw/next-kbd.c hw/next-kbd.c
new file mode 100644
index 0000000..31bda7d
--- /dev/null
+++ hw/next-kbd.c
@@ -0,0 +1,243 @@
+/*
+ * QEMU NeXT Keyboard/Mouse emulation
+ *
+ * Copyright (c) 2011 Bryce Lanham
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the
"Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/* This is admittedly hackish, but works well enough for basic input
+ Mouse support will be added once we can boot something that needs
+ the mouse. */
+
+#include "hw.h"
+#include "console.h"
+#include "next-kbd.h"
+
+/* debug NeXT keyboard */
+//#define DEBUG_KBD
+
+#ifdef DEBUG_KBD
+#define DPRINTF(fmt, ...) \
+ do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0);
+#else
+#define DPRINTF(fmt, ...)
+#endif
+/* follwoing defintions from next68k netbsd */
+#define CSR_INT 0x00800000
+#define CSR_DATA 0x00400000
+
+#define KD_KEYMASK 0x007f
+#define KD_DIRECTION 0x0080 /* pressed or released */
+#define KD_CNTL 0x0100
+#define KD_LSHIFT 0x0200
+#define KD_RSHIFT 0x0400
+#define KD_LCOMM 0x0800
+#define KD_RCOMM 0x1000
+#define KD_LALT 0x2000
+#define KD_RALT 0x4000
+#define KD_VALID 0x8000 /* only set for scancode keys ? */
+#define KD_MODS 0x4f00
+
+#define KBD_QUEUE_SIZE 256
+
+typedef struct {
+ uint8_t data[KBD_QUEUE_SIZE];
+ int rptr, wptr, count;
+} KBDQueue;
+
+
+typedef struct KBDState {
+ KBDQueue queue;
+ uint8_t blank;
+ int shift;//make this an unsigned short, and set it to the modifier value
+
+} KBDState;
+KBDState *kbd_env;
+static void nextkbd_event(void *opaque, int ch);
+
+static void queue_code(void *opaque, int code);
+static uint32_t kbd_read_byte(void *opaque, target_phys_addr_t addr);
+static uint32_t kbd_read_word(void *opaque, target_phys_addr_t addr);
+static uint32_t kbd_read_long(void *opaque, target_phys_addr_t addr);
+
+static void kbd_write_byte(void *opaque, target_phys_addr_t addr,
uint32_t val);
+static void kbd_write_word(void *opaque, target_phys_addr_t addr,
uint32_t val);
+static void kbd_write_long(void *opaque, target_phys_addr_t addr,
uint32_t val);
+
+static CPUWriteMemoryFunc *kbd_write[3] = {
+ kbd_write_byte,
+ kbd_write_word,
+ kbd_write_long
+};
+static CPUReadMemoryFunc *kbd_read[3] = {
+ kbd_read_byte,
+ kbd_read_word,
+ kbd_read_long
+};
+
+
+
+
+void nextkbd_init(void *opaque)
+{
+ KBDState *s = qemu_mallocz(sizeof(KBDState));
+
+ s->shift = 0;
+
+ int kbd_addr = cpu_register_io_memory(kbd_read,kbd_write, (void
*)s,DEVICE_NATIVE_ENDIAN);
+
+ cpu_register_physical_memory((uint32_t)0x200e000,0x1000,kbd_addr);//from
netbsd's cpu.h
+
+ qemu_add_kbd_event_handler(nextkbd_event, s);
+}
+
+static uint32_t kbd_read_byte(void *opaque, target_phys_addr_t addr)
+{
+ addr = addr & 0xe003;
+ switch(addr)
+ {
+
+ case 0xe000:
+ return 0x80|0x20;
+
+ case 0xe001:
+ return 0x80|0x40|0x20|0x10;
+
+ case 0xe002:
+ return 0x40|0x10|0x2|0x1;
+
+ default:
+ DPRINTF("RB ADDR %x\n",addr);
+ return 0;
+ }
+ return 0;
+}
+static uint32_t kbd_read_word(void *opaque, target_phys_addr_t addr)
+{
+ DPRINTF("RW ADDR %x\n",addr);
+ return 0;
+}
+static uint32_t kbd_read_long(void *opaque, target_phys_addr_t addr)
+{
+ int key = 0;
+ KBDState *s = (KBDState *)opaque;
+ KBDQueue *q = &s->queue;
+ switch(addr & 0xe00f)
+ {
+ case 0xe000:
+ // fprintf(stderr,"KB L Read: @ %X\n",((CPUM68KState
*)opaque)->pc);
+ return 0xA0F09300;
+
+ case 0xe008:
+ /* get keycode from buffer */
+ if(q->count > 0)
+ {
+
+ key = q->data[q->rptr];
+ if (++q->rptr == KBD_QUEUE_SIZE)
+ q->rptr = 0;
+
+ q->count--;
+
+
+ if(s->shift)
+ key |= KD_LSHIFT;
+ if(key & 0x80)
+ return 0;
+ else
+ return 0x10000000 | KD_VALID | key;
+ }
+ else
+ return 0;
+ // return 0x10009026;
+
+ default:
+ DPRINTF("RL ADDR %x\n",addr);
+ return 0;
+ }
+}
+
+static void kbd_write_byte(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ //DPRINTF("WB ADDR %x\n",addr);
+}
+static void kbd_write_word(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ DPRINTF("WW ADDR %x\n",addr);
+}
+static void kbd_write_long(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ // DPRINTF("WL ADDR %x\n",addr);
+}
+
+
+static void nextkbd_event(void *opaque, int ch)
+{
+ /*will want to set vars for caps/num lock*/
+ /*if (ch & 0x80) -> key release */
+ /* there's also e0 escaped scancodes that might need to be handled */
+ DPRINTF("EVENT %X\n",ch);
+
+ queue_code(opaque, ch);
+
+}
+
+static const unsigned char next_keycodes[128] = {
+ 0, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x50, 0x4F, 0x4E, 0x1E,
0x1F, 0x20, 0x1D, 0x1C, 0x1B, 0,
+ 0x42, 0x43, 0x44, 0x45, 0x48, 0x47, 0x46, 0x06, 0x07, 0x08,
0x0, 0, 0x2A, 0, 0x39, 0x3A,
+ 0x3B, 0x3C, 0x3D, 0x40, 0x3F, 0x3E, 0x2D, 0x2C, 0x2B,
0x26, 0, 0, 0x31, 0x32, 0x33, 0x34,
+ 0x35, 0x37, 0x36, 0x2e, 0x2f, 0x30, 0, 0, 0, 0x38, 0, 0,
0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static void queue_code(void *opaque, int code)
+{
+
+ KBDState *s = (KBDState *)opaque;
+ KBDQueue *q = &s->queue;
+ int key = code & 0x7F;
+ int release = code & 0x80;
+ if(code == 0x2A)
+ {
+ s->shift = 1;
+ return;
+ }
+ else if(code == (0x2A | 0x80))
+ {
+ s->shift = 0;
+ return;
+ }
+
+
+
+
+ if (q->count >= KBD_QUEUE_SIZE)
+ return;
+
+ q->data[q->wptr] = next_keycodes[key] | release;
+ if (++q->wptr == KBD_QUEUE_SIZE)
+ q->wptr = 0;
+ q->count++;
+ //s->update_irq(s->update_arg, 1);
+ s->blank += 1;
+}
diff --git hw/next-kbd.h hw/next-kbd.h
new file mode 100644
index 0000000..efee144
--- /dev/null
+++ hw/next-kbd.h
@@ -0,0 +1,2 @@
+
+void nextkbd_init(void *opaque);
diff --git hw/next-net.c hw/next-net.c
new file mode 100644
index 0000000..94739a1
--- /dev/null
+++ hw/next-net.c
@@ -0,0 +1,513 @@
+/*
+ * QEMU NeXT Network (MB8795) emulation
+ *
+ * Copyright (c) 2011 Bryce Lanham
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the
"Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "sysemu.h"//only needed for vm_stop
+#include "hw.h"
+#include "net.h"
+#include "next-net.h"
+#include "sysbus.h"
+/* debug NeXT ethernet */
+#define DEBUG_NET
+
+#ifdef DEBUG_NET
+#define DPRINTF(fmt, ...) \
+ do { printf("NET: " fmt , ## __VA_ARGS__); } while (0);
+#else
+#define DPRINTF(fmt, ...)
+#endif
+
+/* IRQs should be moved to header later */
+#define TX_I_DMA 0
+#define RX_I_DMA 1
+#define TX_I 2
+#define RX_I 3
+/* names could be better */
+typedef struct NextDMA {
+ uint32_t csr;
+ uint32_t savedbase;
+ uint32_t savedlimit;
+
+ uint32_t baser;
+ uint32_t base;
+ uint32_t limit;
+ uint32_t chainbase;
+ uint32_t chainlimit;
+ uint32_t basew;
+
+
+} NextDMA;
+
+typedef struct NextNetState {
+ uint8_t mac[6];
+
+ qemu_irq *irq;
+
+ NICState *nic;
+ NICConf c;
+
+ NextDMA tx_dma;
+ uint8_t tx_stat;
+ uint8_t tx_mask;
+ uint8_t tx_mode;
+
+ NextDMA rx_dma;
+ uint8_t rx_stat;
+ uint8_t rx_mask;
+ uint8_t rx_mode;
+
+ uint8_t rst_mode;
+
+} NextNetState;
+
+NextNetState nextnet_state;
+
+void *env_g;
+
+void nextnet_irq(void *opaque, int n, int level);
+static int nextnet_can_rx(VLANClientState *nc);
+static ssize_t nextnet_rx(VLANClientState *nc, const uint8_t *buf,
size_t size);
+static void nextnet_cleanup(VLANClientState *nc);
+
+static NetClientInfo nextnet_info = {
+ .type = NET_CLIENT_TYPE_NIC,
+ .size = sizeof(NICState),
+ .can_receive = nextnet_can_rx,
+ .receive = nextnet_rx,
+ .cleanup = nextnet_cleanup,
+};
+/* these need to be somewhere else */
+extern uint32_t int_status;//should be set in a global irq handler
+extern uint32_t int_mask;
+extern uint32_t event_test;
+
+void nextnet_reset(NextNetState *s);
+void nextnet_reset(NextNetState *s)
+{
+
+
+}
+
+static uint32_t net_readb(void*opaque, target_phys_addr_t addr);
+static uint32_t net_readw(void*opaque, target_phys_addr_t addr);
+static uint32_t net_readl(void*opaque, target_phys_addr_t addr);
+static CPUReadMemoryFunc *net_read[3] = {
+ net_readb,
+ net_readw,
+ net_readl
+};
+
+static void net_writeb(void*opaque, target_phys_addr_t addr, uint32_t value);
+static void net_writew(void*opaque, target_phys_addr_t addr, uint32_t value);
+static void net_writel(void*opaque, target_phys_addr_t addr, uint32_t value);
+static CPUWriteMemoryFunc * const net_write[3] = {
+ net_writeb,
+ net_writew,
+ net_writel
+};
+
+
+void nextnet_init(void *opaque)
+{
+ NextNetState *s = &nextnet_state;
+ CPUState *env = (CPUState *)opaque;
+ env_g = opaque;//used this as a global during testing, should be removed
+
+ /*register device register space */
+ cpu_register_physical_memory((uint32_t)0x2106000,0x1000,
+ cpu_register_io_memory(net_read,net_write, (void
*)&nextnet_state,DEVICE_NATIVE_ENDIAN));
+ cpu_register_physical_memory((uint32_t)0x2006000,0x1000,
+ cpu_register_io_memory(net_read,net_write, (void
*)&nextnet_state,DEVICE_NATIVE_ENDIAN));
+
+
+ /* and ethernet control/status registers *///including DMA for
now, will seperate out later
+ cpu_register_physical_memory((uint32_t)0x2000110,0x4400,
+ cpu_register_io_memory(net_read,net_write, (void
*)&nextnet_state,DEVICE_NATIVE_ENDIAN));
+
+ /* connect to virtual lan */
+ s->c.vlan = qemu_find_vlan(0,1);
+
+ /* register nic */
+ s->nic = qemu_new_nic(&nextnet_info,&s->c, "NeXT MB8795\0", NULL, s);
+
+ /* this needs to be read, will have to load rom file i guess */
+ uint8_t mac[6] = {0,0,0xf,0,0xf3,0x2};
+ memcpy(&s->mac,mac,6);
+
+ /* allocate TX/RX and DMA irqs - will be global later */
+ s->irq = qemu_allocate_irqs(nextnet_irq, env, 4);
+
+ /* this sets the nic's info */
+ qemu_format_nic_info_str(&s->nic->nc, mac);
+
+
+}
+/* It is likely that all register reads are bytes, while all CSR r/w
are longs */
+static uint32_t net_readb(void*opaque, target_phys_addr_t addr)
+{
+ NextNetState *s = (NextNetState *)opaque;
+
+// CPUState *env = (CPUState *)env_g;
+ switch(addr)
+ {
+ case 0x6000://TXSTAT
+ // DPRINTF("TXSTAT \tRead\n");
+ return s->tx_stat;
+
+ case 0x6001:
+ DPRINTF("TXMASK \tRead\n");
+ return s->tx_mask;
+
+ case 0x6002:
+ // DPRINTF("RXSTAT \tRead %x @ %x\n",s->rx_stat,env->pc);
+ return s->rx_stat;
+
+ case 0x6003:
+ // DPRINTF("RXMASK \tRead\n");
+ return s->rx_mask;
+
+ case 0x6004:
+ DPRINTF("TXMODE \tRead\n");
+ return s->tx_mode;
+
+ case 0x6005:
+ // DPRINTF("RXMODE \tRead\n");
+ return s->rx_mode;
+
+ case 0x6006:
+ DPRINTF("RSTMODE \tRead\n");
+ return s->rst_mode;
+
+ default:
+ fprintf(stderr,"NET Read B @ %x\n",addr);
+ return 0;
+ }
+}
+static uint32_t net_readw(void*opaque, target_phys_addr_t addr)
+{
+ fprintf(stderr,"S Read W @ %x\n",addr);
+ return 0;
+}
+static uint32_t net_readl(void*opaque, target_phys_addr_t addr)
+{
+ NextNetState *s = (NextNetState *)opaque;
+ CPUState *env = (CPUState *)env_g;
+ switch(addr)
+ {
+ case 0x110:
+
+ //DPRINTF("TXCSR Read\n");
+ return s->tx_dma.csr;
+ case 0x4100:
+ fprintf(stderr,"SAVEDBASE Read\n");
+ return s->tx_dma.savedbase;
+ case 0x4104:
+ fprintf(stderr,"SAVELIMIT Read\n");
+ return s->tx_dma.savedlimit;
+ case 0x4114:
+ fprintf(stderr,"TXLIMIT Read\n");
+ return s->tx_dma.limit;
+ case 0x4310:
+ fprintf(stderr,"TXBASE Read\n");
+ /* FUTURE :return nextdma_read(device, addr); */
+ return s->tx_dma.basew;
+
+ case 0x150:
+ // fprintf(stderr,"RXCSR Read %x\n",s->rx_dma.csr);
+ return s->rx_dma.csr;
+
+ case 0x4140:
+ return s->rx_dma.savedbase;
+ case 0x4144:
+ DPRINTF("SAVELIMIT %x @ %x\n",s->rx_dma.savedlimit,env->pc);
+ return s->rx_dma.savedlimit;
+
+ default:
+ fprintf(stderr,"NET Read l @ %x\n",addr);
+ return 0;
+ }
+}
+#define NET_TXSTAT_CLEAR 0xFF
+#define NET_RXSTAT_CLEAR 0xFF
+static void net_writeb(void*opaque, target_phys_addr_t addr, uint32_t value)
+{
+// CPUState *env = (CPUState *)env_g;
+ NextNetState *s = (NextNetState *)opaque;
+ switch(addr)
+ {
+ case 0x6000:
+ DPRINTF("TXSTAT \tWrite: %x\n",value);
+ if(value == NET_TXSTAT_CLEAR)
+ s->tx_stat = 0x80;
+ else
+ s->tx_stat = value;
+ break;
+ case 0x6001:
+ DPRINTF("TXMASK \tWrite: %x\n",value);
+ s->tx_mask = value;
+ break;
+ case 0x6002:
+ // DPRINTF("RXSTAT \tWrite: %x @ %x\n",value,env->pc);
+ if(value == NET_RXSTAT_CLEAR)
+ s->rx_stat = 0;
+ else
+ s->rx_stat = value;
+ break;
+ case 0x6003:
+ // DPRINTF("RXMASK \tWrite: %x\n",value);
+ s->rx_mask = value;
+ break;
+ case 0x6004:
+ DPRINTF("TXMODE \tWrite: %x\n",value);
+ s->tx_mode = value;
+ break;
+ case 0x6005:
+ // DPRINTF("RXMODE \tWrite: %x\n",value);
+ s->rx_mode = value;
+ break;
+ case 0x6006:
+ DPRINTF("RSTMODE \tWrite: %x\n",value);
+ s->rst_mode = value;
+ break;
+ case 0x600d:
+ s->mac[(addr&0xF)-8] = value;
+ DPRINTF("Set MAC ADDR %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+ s->mac[0],s->mac[1],s->mac[2],s->mac[3],s->mac[4],s->mac[5]);
+ qemu_macaddr_default_if_unset((MACAddr *)&s->mac);
+ break;
+ case 0x6008:case 0x6009:case 0x600a: case 0x600b: case 0x600c:
+ s->mac[(addr&0xF)-8] = value;
+ break;
+ case 0x6010:case 0x6011: case 0x6012: case 0x6013: case 0x6014:
+ // break;
+ default:
+ fprintf(stderr,"NET Write B @ %x with %x\n",addr,value);
+ }
+}
+static void net_writew(void*opaque, target_phys_addr_t addr, uint32_t value)
+{
+ fprintf(stderr,"NET W w @ %x with %x\n",addr,value);
+}
+#define DMA_ENABLE 0x01000000
+#define DMA_SUPDATE 0x02000000
+#define DMA_COMPLETE 0x08000000
+
+#define DMA_M2DEV 0x0
+#define DMA_SETENABLE 0x00010000
+#define DMA_SETSUPDATE 0x00020000
+#define DMA_DEV2M 0x00040000
+#define DMA_CLRCOMPLETE 0x00080000
+#define DMA_RESET 0x00100000
+static void net_writel(void*opaque, target_phys_addr_t addr, uint32_t value)
+{
+ static int tx_count = 0;
+ NextNetState *s = (NextNetState *)opaque;
+ switch(addr)
+ {
+ case 0x110:
+ {
+
+
+ if(value & DMA_SETENABLE)
+ {
+ tx_count++;
+ // if(tx_count % 4) return;
+ size_t len = (0xFFFFFFF & s->tx_dma.limit) -
s->tx_dma.base;
+ DPRINTF("TXDMA ENABLE: %x len: %zu\n",s->tx_dma.base, len);
+ DPRINTF("TX Enable\n");
+ uint8_t buf[1600];//needs to be in dma struct?
+ cpu_physical_memory_read(s->tx_dma.base, buf, len);
+
+ qemu_send_packet(&s->nic->nc, buf,len);
+ s->tx_dma.csr |= DMA_COMPLETE | DMA_SUPDATE;
+ s->tx_stat = 0x80;
+ // if(tx_count > 1510) vm_stop(VMSTOP_DEBUG);
+
+ qemu_set_irq(s->irq[TX_I_DMA],3);
+
+ }
+ if(value & DMA_SETSUPDATE)
+ s->tx_dma.csr |= DMA_SUPDATE;
+
+ if(value & DMA_CLRCOMPLETE)
+ s->tx_dma.csr &= ~DMA_COMPLETE;
+
+ if(value & DMA_RESET)
+ s->tx_dma.csr &= ~(DMA_COMPLETE |
DMA_SUPDATE | DMA_ENABLE);
+ }
+ break;
+
+ case 0x4100:
+ DPRINTF("Write l @ %x with %x\n",addr,value);
+ s->tx_dma.savedbase = value;
+ break;
+
+ case 0x4104:
+ DPRINTF("Write l @ %x with %x\n",addr,value);
+ s->tx_dma.savedlimit = value;
+ break;
+ case 0x4110:
+ DPRINTF("Write l @ %x with %x\n",addr,value);
+ s->tx_dma.base = value;
+ break;
+ case 0x4114:
+ DPRINTF("Write l @ %x with %x\n",addr,value);
+ s->tx_dma.limit = value;
+ break;
+
+ case 0x4310:
+ DPRINTF("Write l @ %x with %x\n",addr,value);
+ s->tx_dma.base = value;
+ /* FUTURE :nextdma_write(device, addr, value); */
+ break;
+
+ case 0x150:
+ if(value & DMA_DEV2M)
+ {
+ DPRINTF("RX Dev to Memory\n");
+ }
+
+ if(value & DMA_SETENABLE)
+ s->rx_dma.csr |= DMA_ENABLE;
+
+ if(value & DMA_SETSUPDATE)
+ s->rx_dma.csr |= DMA_SUPDATE;
+
+ if(value & DMA_CLRCOMPLETE)
+ s->rx_dma.csr &= ~DMA_COMPLETE;
+
+ if(value & DMA_RESET)
+ s->rx_dma.csr &= ~(DMA_COMPLETE |
DMA_SUPDATE | DMA_ENABLE);
+ //
+
+ DPRINTF("RXCSR \tWrite: %x\n",value);
+ break;
+
+ case 0x4150:
+
+ // DPRINTF("Write l @ %x with %x\n",addr,value);
+ s->rx_dma.base = value;
+ // s->rx_dma.savedbase = value;
+ break;
+
+ case 0x4154:
+ s->rx_dma.limit = value;
+ // DPRINTF("Write l @ %x with %x\n",addr,value);
+ break;
+
+ case 0x4158:
+ s->rx_dma.chainbase = value;
+ // DPRINTF("Write l @ %x with %x\n",addr,value);
+ break;
+
+ case 0x415c:
+ s->rx_dma.chainlimit = value;
+ // DPRINTF("Write l @ %x with %x\n",addr,value);
+ //DPRINTF("Pointer write %x w %x\n",addr,value);
+ break;
+ default:
+ DPRINTF("Write l @ %x with %x\n",addr,value);
+ }
+
+}
+
+static int nextnet_can_rx(VLANClientState *nc)
+{
+ NextNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+ if(s->rx_mode & 0x3)
+ return 1;
+ else
+ return -1;
+}
+
+static ssize_t nextnet_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
+{
+ NextNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+ DPRINTF("received packet %zu\n",size);
+
+ /* Ethernet DMA is supposedly 32 byte aligned */
+ if((size % 32) != 0)
+ {
+ size -= size % 32;
+ size += 32;
+ }
+
+ /* write the packet into memory */
+ cpu_physical_memory_write(s->rx_dma.base,buf,size);
+
+ /* saved limit is checked to calculate packet size
+ by both the rom and netbsd */
+ s->rx_dma.savedlimit = (s->rx_dma.base + size);
+ s->rx_dma.savedbase = (s->rx_dma.base);
+
+ /*32 bytes under savedbase seems to be some kind of register
+ of which the purpose is unknown as of yet*/
+ //stl_phys(s->rx_dma.base-32,0xFFFFFFFF);
+
+ if((s->rx_dma.csr & DMA_SUPDATE)){
+ s->rx_dma.base = s->rx_dma.chainbase;
+ s->rx_dma.limit = s->rx_dma.chainlimit;
+ }
+ //we received a packet
+ s->rx_stat = 0x80;
+
+ //Set dma registers and raise an irq
+ s->rx_dma.csr |= DMA_COMPLETE; //DON'T CHANGE THIS!!!!
+ qemu_set_irq(s->irq[RX_I_DMA],6);
+
+ return size;
+}
+
+static void nextnet_cleanup(VLANClientState *nc)
+{
+}
+
+/* level and vector values taken from Plan 9 source */
+void nextnet_irq(void *opaque, int n, int level)
+{
+ CPUM68KState *s = (CPUM68KState *)opaque;
+ switch(n)
+ {
+ case TX_I:
+ int_status = 1<<10;
+ m68k_set_irq_level(s,3,27);
+ break;
+
+ case RX_I:
+ int_status = 1<<9;
+ m68k_set_irq_level(s,3,27);
+ break;
+
+ case TX_I_DMA:
+ int_status = 1<<28;
+ m68k_set_irq_level(s,6,30);
+ break;
+
+ case RX_I_DMA:
+ int_status = 1<<27;
+ m68k_set_irq_level(s,6,30);
+ break;
+ }
+
+
+}
diff --git hw/next-net.h hw/next-net.h
new file mode 100644
index 0000000..28b7358
--- /dev/null
+++ hw/next-net.h
@@ -0,0 +1,2 @@
+
+void nextnet_init(void *opaque);
diff --git linux-user/main.c linux-user/main.c
index 8e15474..62aa983 100644
--- linux-user/main.c
+++ linux-user/main.c
@@ -2815,8 +2815,10 @@ static void usage(void)
"-strace log system calls\n"
"\n"
"Environment variables:\n"
- "QEMU_STRACE Print system calls and arguments
similar to the\n"
- " 'strace' program. Enable by setting to
any value.\n"
+ "QEMU_STRACE Print system calls and arguments
similar to the\n"
+ " 'strace' program. Enable by setting
to any value.\n"
+ "QEMU_DEBUG=options Activate log. Use same options as '-d'
options\n"
+ "QEMU_GDB=port Wait gdb connection to port\n"
"You can use -E and -U options to set/unset environment variables\n"
"for target process. It is possible to provide several variables\n"
"by repeating the option. For example:\n"
@@ -2872,7 +2874,7 @@ int main(int argc, char **argv, char **envp)
const char *filename;
const char *cpu_model;
const char *log_file = DEBUG_LOGFILE;
- const char *log_mask = NULL;
+ const char *log_mask = getenv("QEMU_DEBUG");
struct target_pt_regs regs1, *regs = ®s1;
struct image_info info1, *info = &info1;
struct linux_binprm bprm;
@@ -2919,6 +2921,12 @@ int main(int argc, char **argv, char **envp)
#if defined(cpudef_setup)
cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
#endif
+ if (getenv("QEMU_GDB")) {
+ gdbstub_port = atoi(getenv("QEMU_GDB"));
+ }
+ /* don't propagate QEMU_DEBUG and _GDB to children */
+ unsetenv("QEMU_DEBUG");
+ unsetenv("QEMU_GDB");
optind = 1;
for(;;) {
@@ -3083,39 +3091,7 @@ int main(int argc, char **argv, char **envp)
init_paths(interp_prefix);
if (cpu_model == NULL) {
-#if defined(TARGET_I386)
-#ifdef TARGET_X86_64
- cpu_model = "qemu64";
-#else
- cpu_model = "qemu32";
-#endif
-#elif defined(TARGET_ARM)
- cpu_model = "any";
-#elif defined(TARGET_UNICORE32)
- cpu_model = "any";
-#elif defined(TARGET_M68K)
- cpu_model = "any";
-#elif defined(TARGET_SPARC)
-#ifdef TARGET_SPARC64
- cpu_model = "TI UltraSparc II";
-#else
- cpu_model = "Fujitsu MB86904";
-#endif
-#elif defined(TARGET_MIPS)
-#if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64)
- cpu_model = "20Kc";
-#else
- cpu_model = "24Kf";
-#endif
-#elif defined(TARGET_PPC)
-#ifdef TARGET_PPC64
- cpu_model = "970fx";
-#else
- cpu_model = "750";
-#endif
-#else
- cpu_model = "any";
-#endif
+ cpu_model = TARGET_DEFAULT_CPU;
}
tcg_exec_init(0);
cpu_exec_init_all();
diff --git linux-user/qemu-wrapper.c linux-user/qemu-wrapper.c
new file mode 100644
index 0000000..6926a6c
--- /dev/null
+++ linux-user/qemu-wrapper.c
@@ -0,0 +1,97 @@
+/*
+ * qemu-wrapper
+ *
+ * Copyright (c) 2011 Laurent Vivier
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * HOWTO
+ *
+ * for instance, for m68k target.
+ *
+ * copy qemu-wrapper and qemu-m68 into the m68k filesystem:
+ *
+ * cd m68k-linux-user
+ * sudo cp qemu-m68k qemu-wrapper /m68k/usr/bin/qemu-wrapper
+ *
+ * update binfmts:
+ *
+ * update-binfmts --install m68k /usr/bin/qemu-wrapper \
+ * --magic \
+ * \x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04 \
+ * --mask \
+ *
\xff\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff
+ *
+ * chroot the m68k filesystem:
+ *
+ * sudo QEMU_CPU=m68020 chroot /m68k
+ *
+ * ******** IMPORTANT NOTE ********
+ *
+ * qemu-m68k and qemu-wrapper must be linked staticaly:
+ *
+ * ./configure --target-list=m68k-linux-user --static
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "config-target.h"
+
+int main(int argc, char **argv, char **envp) {
+ char *wrapper[argc + 7];
+ int current = 0;
+ char *cpu, *debug, *port;
+
+ wrapper[current] = argv[0];
+ current++;
+
+ cpu = getenv("QEMU_CPU");
+ if (cpu) {
+ wrapper[current] = (char*)"-cpu";
+ current++;
+ wrapper[current] = cpu;
+ current++;
+ }
+
+ debug = getenv("QEMU_DEBUG");
+ if (debug) {
+ wrapper[current] = (char*)"-d";
+ current++;
+ wrapper[current] = debug;
+ current++;
+ }
+ unsetenv("QEMU_DEBUG");
+
+ port = getenv("QEMU_GDB");
+ if (port) {
+ wrapper[current] = (char*)"-g";
+ current++;
+ wrapper[current] = port;
+ current++;
+ }
+ unsetenv("QEMU_GDB");
+
+ memcpy(&wrapper[current], &argv[1], sizeof(*argv) * (argc - 1));
+ current += argc - 1;
+
+ wrapper[current] = NULL;
+
+ return execve("/usr/bin/qemu-" TARGET_ARCH, wrapper, envp);
+}
diff --git linux-user/qemu.h linux-user/qemu.h
index 627c8b3..ae87149 100644
--- linux-user/qemu.h
+++ linux-user/qemu.h
@@ -87,6 +87,7 @@ struct vm86_saved_state {
struct sigqueue {
struct sigqueue *next;
target_siginfo_t info;
+ pid_t pid;
};
struct emulated_sigtable {
diff --git linux-user/signal.c linux-user/signal.c
index 07ad07a..0ba11bd 100644
--- linux-user/signal.c
+++ linux-user/signal.c
@@ -472,6 +472,7 @@ int queue_signal(CPUState *env, int sig,
target_siginfo_t *info)
*pq = q;
q->info = *info;
q->next = NULL;
+ q->pid = getpid();
k->pending = 1;
/* signal that a new signal is pending */
ts->signal_pending = 1;
@@ -5231,21 +5232,34 @@ void process_pending_signals(CPUState *cpu_env)
target_sigset_t target_old_set;
struct emulated_sigtable *k;
struct target_sigaction *sa;
- struct sigqueue *q;
- TaskState *ts = cpu_env->opaque;
+ struct sigqueue *q, *q_prev;
+ TaskState *ts = thread_env->opaque;
if (!ts->signal_pending)
return;
- /* FIXME: This is not threadsafe. */
k = ts->sigtab;
+ int signal_pending = 0;
for(sig = 1; sig <= TARGET_NSIG; sig++) {
if (k->pending)
- goto handle_signal;
+ {
+ q = k->first;
+ q_prev = NULL;
+ while (q)
+ {
+ if (q->pid == getpid())
+ goto handle_signal;
+ else
+ signal_pending = 1;
+ q_prev = q;
+ q = q->next;
+ }
+ }
k++;
}
+
/* if no signal is pending, just return */
- ts->signal_pending = 0;
+ ts->signal_pending = signal_pending;
return;
handle_signal:
@@ -5253,9 +5267,18 @@ void process_pending_signals(CPUState *cpu_env)
fprintf(stderr, "qemu: process signal %d\n", sig);
#endif
/* dequeue signal */
- q = k->first;
- k->first = q->next;
- if (!k->first)
+ if (q_prev == k->first)
+ {
+ q = k->first;
+ k->first = q->next;
+ if (!k->first)
+ {
+ k->pending = 0;
+ }
+ }
+ else if (q_prev)
+ q_prev->next = q->next;
+ else
k->pending = 0;
sig = gdb_handlesig (cpu_env, sig);
diff --git linux-user/syscall_defs.h linux-user/syscall_defs.h
index a117407..aa94a14 100644
--- linux-user/syscall_defs.h
+++ linux-user/syscall_defs.h
@@ -2058,6 +2058,24 @@ struct target_statfs64 {
#define TARGET_O_NOFOLLOW 0x10000 /* don't follow links */
#define TARGET_O_NOATIME 0x100000
#define TARGET_O_NDELAY TARGET_O_NONBLOCK
+#elif defined (TARGET_M68K)
+#define TARGET_O_ACCMODE 0003
+#define TARGET_O_RDONLY 00
+#define TARGET_O_WRONLY 01
+#define TARGET_O_RDWR 02
+#define TARGET_O_CREAT 0100 /* not fcntl */
+#define TARGET_O_EXCL 0200 /* not fcntl */
+#define TARGET_O_NOCTTY 0400 /* not fcntl */
+#define TARGET_O_TRUNC 01000 /* not fcntl */
+#define TARGET_O_APPEND 02000
+#define TARGET_O_NONBLOCK 04000
+#define TARGET_O_NDELAY TARGET_O_NONBLOCK
+#define TARGET_O_SYNC 010000
+#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
+#define TARGET_O_DIRECTORY 040000 /* must be a directory */
+#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */
+#define TARGET_O_DIRECT 0200000 /* direct disk access hint */
+#define TARGET_O_LARGEFILE 0400000
#else
#define TARGET_O_ACCMODE 0003
#define TARGET_O_RDONLY 00
diff --git qemu-doc.texi qemu-doc.texi
index 31199f6..2193463 100644
--- qemu-doc.texi
+++ qemu-doc.texi
@@ -2293,6 +2293,10 @@ space emulator hasn't implemented ptrace). At
the moment this is
incomplete. All system calls that don't have a specific argument
format are printed with information for six arguments. Many
flag-style arguments don't have decoders and will show up as numbers.
address@hidden QEMU_DEBUG=options
+Activate log. Use same options as '-d' options.
address@hidden QEMU_GDB=port
+Wait gdb connection to port.
@end table
@node Other binaries
diff --git scripts/set_binfmt_m68k scripts/set_binfmt_m68k
new file mode 100755
index 0000000..fb3d720
--- /dev/null
+++ scripts/set_binfmt_m68k
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+name="m68k"
+magic="\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04"
+mask="\xff\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff"
+
+update-binfmts --install $name /usr/bin/qemu-m68k \
+ --magic $magic --mask $mask
diff --git target-m68k/cpu.h target-m68k/cpu.h
index 0667f82..006ecdc 100644
--- target-m68k/cpu.h
+++ target-m68k/cpu.h
@@ -54,9 +54,42 @@
#define EXCP_RTE 0x100
#define EXCP_HALT_INSN 0x101
+#ifdef CONFIG_EMULOP
+#define EXCP_EXEC_RETURN 0x20000
+#endif
#define NB_MMU_MODES 2
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+
+#ifdef CONFIG_USER_ONLY
+/* Linux uses 4k pages. */
+#define TARGET_PAGE_BITS 12
+#else
+/* Smallest TLB entry size is 1k. */
+#define TARGET_PAGE_BITS 10
+#endif
+
+#include "cpu-all.h"
+
+typedef uint32_t CPUM68K_SingleU;
+typedef uint64_t CPUM68K_DoubleU;
+
+typedef struct {
+ uint32_t high;
+ uint64_t low;
+} __attribute__((packed)) CPUM68K_XDoubleU;
+
+typedef struct {
+ uint8_t high[2];
+ uint8_t low[10];
+} __attribute__((packed)) CPUM68K_PDoubleU;
+
+typedef CPU_LDoubleU FPReg;
+#define PRIxFPH PRIx16
+#define PRIxFPL PRIx64
+
typedef struct CPUM68KState {
uint32_t dregs[8];
uint32_t aregs[8];
@@ -66,15 +99,18 @@ typedef struct CPUM68KState {
/* SSP and USP. The current_sp is stored in aregs[7], the other here. */
int current_sp;
uint32_t sp[2];
-
/* Condition flags. */
uint32_t cc_op;
uint32_t cc_dest;
uint32_t cc_src;
uint32_t cc_x;
-
- float64 fregs[8];
- float64 fp_result;
+ /* Control Registers */
+ uint32_t sfc;
+ uint32_t dfc;
+ uint32_t itt0,itt1;
+ uint32_t dtt0,dtt1;
+ /* FPU Registers */
+ FPReg fregs[8];
uint32_t fpcr;
uint32_t fpsr;
float_status fp_status;
@@ -87,14 +123,25 @@ typedef struct CPUM68KState {
uint32_t macsr;
uint32_t mac_mask;
+ /* Temporary storage for FPU */
+
+ uint32_t fp0h;
+ uint64_t fp0l;
+ uint32_t fp1h;
+ uint64_t fp1l;
+
/* Temporary storage for DIV helpers. */
uint32_t div1;
uint32_t div2;
+ /* Upper 32 bits of a 64bit operand for quad MUL/DIV. */
+ uint32_t quadh;
+
/* MMU status. */
struct {
uint32_t ar;
- } mmu;
+ uint32_t tc;
+ } mmu;
/* Control registers. */
uint32_t vbr;
@@ -131,13 +178,23 @@ void cpu_m68k_flush_flags(CPUM68KState *, int);
enum {
CC_OP_DYNAMIC, /* Use env->cc_op */
CC_OP_FLAGS, /* CC_DEST = CVZN, CC_SRC = unused */
+ CC_OP_LOGICB, /* CC_DEST = result, CC_SRC = unused */
+ CC_OP_LOGICW, /* CC_DEST = result, CC_SRC = unused */
CC_OP_LOGIC, /* CC_DEST = result, CC_SRC = unused */
+ CC_OP_ADDB, /* CC_DEST = result, CC_SRC = source */
+ CC_OP_ADDW, /* CC_DEST = result, CC_SRC = source */
CC_OP_ADD, /* CC_DEST = result, CC_SRC = source */
+ CC_OP_SUBB, /* CC_DEST = result, CC_SRC = source */
+ CC_OP_SUBW, /* CC_DEST = result, CC_SRC = source */
CC_OP_SUB, /* CC_DEST = result, CC_SRC = source */
- CC_OP_CMPB, /* CC_DEST = result, CC_SRC = source */
- CC_OP_CMPW, /* CC_DEST = result, CC_SRC = source */
+ CC_OP_ADDXB, /* CC_DEST = result, CC_SRC = source */
+ CC_OP_ADDXW, /* CC_DEST = result, CC_SRC = source */
CC_OP_ADDX, /* CC_DEST = result, CC_SRC = source */
+ CC_OP_SUBXB, /* CC_DEST = result, CC_SRC = source */
+ CC_OP_SUBXW, /* CC_DEST = result, CC_SRC = source */
CC_OP_SUBX, /* CC_DEST = result, CC_SRC = source */
+ CC_OP_SHIFTB, /* CC_DEST = result, CC_SRC = carry */
+ CC_OP_SHIFTW, /* CC_DEST = result, CC_SRC = carry */
CC_OP_SHIFT, /* CC_DEST = result, CC_SRC = carry */
};
@@ -182,6 +239,7 @@ void do_m68k_semihosting(CPUM68KState *env, int nr);
ISA revisions mentioned. */
enum m68k_features {
+ M68K_FEATURE_M68000,
M68K_FEATURE_CF_ISA_A,
M68K_FEATURE_CF_ISA_B, /* (ISA B or C). */
M68K_FEATURE_CF_ISA_APLUSC, /* BIT/BITREV, FF1, STRLDSR (ISA A+ or C). */
@@ -192,7 +250,14 @@ enum m68k_features {
M68K_FEATURE_CF_EMAC_B, /* Revision B EMAC (dual accumulate). */
M68K_FEATURE_USP, /* User Stack Pointer. (ISA A+, B or C). */
M68K_FEATURE_EXT_FULL, /* 68020+ full extension word. */
- M68K_FEATURE_WORD_INDEX /* word sized address index registers. */
+ M68K_FEATURE_WORD_INDEX, /* word sized address index registers. */
+ M68K_FEATURE_SCALED_INDEX, /* scaled address index registers. */
+ M68K_FEATURE_LONG_MULDIV, /* 32 bit multiply/divide. */
+ M68K_FEATURE_QUAD_MULDIV, /* 64 bit multiply/divide. */
+ M68K_FEATURE_BCCL, /* Long conditional branches. */
+ M68K_FEATURE_BITFIELD, /* Bit field insns. */
+ M68K_FEATURE_FPU,
+ M68K_FEATURE_CAS
};
static inline int m68k_feature(CPUM68KState *env, int feature)
@@ -204,17 +269,6 @@ void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf);
void register_m68k_insns (CPUM68KState *env);
-#ifdef CONFIG_USER_ONLY
-/* Linux uses 8k pages. */
-#define TARGET_PAGE_BITS 13
-#else
-/* Smallest TLB entry size is 1k. */
-#define TARGET_PAGE_BITS 10
-#endif
-
-#define TARGET_PHYS_ADDR_SPACE_BITS 32
-#define TARGET_VIRT_ADDR_SPACE_BITS 32
-
#define cpu_init cpu_m68k_init
#define cpu_exec cpu_m68k_exec
#define cpu_gen_code cpu_m68k_gen_code
@@ -243,8 +297,6 @@ static inline void cpu_clone_regs(CPUState *env,
target_ulong newsp)
}
#endif
-#include "cpu-all.h"
-
static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
@@ -267,4 +319,5 @@ static inline void cpu_pc_from_tb(CPUState *env,
TranslationBlock *tb)
env->pc = tb->pc;
}
+
#endif
diff --git target-m68k/helper.c target-m68k/helper.c
index 7ca75fb..5fa5b06 100644
--- target-m68k/helper.c
+++ target-m68k/helper.c
@@ -27,10 +27,32 @@
#include "gdbstub.h"
#include "helpers.h"
+#include <math.h>
+
+#if 0
+#define DBG_FPUH(...) do { fprintf(stderr, "0x%08x: ", env->pc);
fprintf(stderr, __VA_ARGS__); } while(0)
+#define DBG_FPU(...) do { fprintf(stderr, __VA_ARGS__); } while(0)
+#else
+#define DBG_FPUH(...)
+#define DBG_FPU(...)
+#endif
+static inline float FLOAT(float32 x)
+{
+ return *(float *)&x;
+}
+static inline double DOUBLE(float64 x)
+{
+ return *(double *)&x;
+}
#define SIGNBIT (1u << 31)
enum m68k_cpuid {
+ M68K_CPUID_M68000,
+ M68K_CPUID_M68020,
+ M68K_CPUID_M68030,
+ M68K_CPUID_M68040,
+ M68K_CPUID_M68060,
M68K_CPUID_M5206,
M68K_CPUID_M5208,
M68K_CPUID_CFV4E,
@@ -45,6 +67,11 @@ struct m68k_def_t {
};
static m68k_def_t m68k_cpu_defs[] = {
+ {"m68000", M68K_CPUID_M68000},
+ {"m68020", M68K_CPUID_M68020},
+ {"m68030", M68K_CPUID_M68030},
+ {"m68040", M68K_CPUID_M68040},
+ {"m68060", M68K_CPUID_M68060},
{"m5206", M68K_CPUID_M5206},
{"m5208", M68K_CPUID_M5208},
{"cfv4e", M68K_CPUID_CFV4E},
@@ -52,19 +79,61 @@ static m68k_def_t m68k_cpu_defs[] = {
{NULL, 0},
};
+/* modulo 33 table */
+const uint8_t rox32_table[64] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9,10,11,12,13,14,15,
+ 16,17,18,19,20,21,22,23,
+ 24,25,26,27,28,29,30,31,
+ 32, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9,10,11,12,13,14,
+ 15,16,17,18,19,20,21,22,
+ 23,24,25,26,27,28,29,30,
+};
+
+/* modulo 17 table */
+const uint8_t rox16_table[64] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9,10,11,12,13,14,15,
+ 16, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9,10,11,12,13,14,
+ 15,16, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9,10,11,12,13,
+ 14,15,16, 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9,10,11,12,
+};
+
+/* modulo 9 table */
+const uint8_t rox8_table[64] = {
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 0, 1, 2, 3, 4, 5,
+ 6, 7, 8, 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 0, 1, 2, 3,
+ 4, 5, 6, 7, 8, 0, 1, 2,
+ 3, 4, 5, 6, 7, 8, 0, 1,
+ 2, 3, 4, 5, 6, 7, 8, 0,
+};
+
void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
{
unsigned int i;
for (i = 0; m68k_cpu_defs[i].name; i++) {
+ if (strcmp(m68k_cpu_defs[i].name, TARGET_DEFAULT_CPU) == 0) {
+ (*cpu_fprintf)(f, " >");
+ } else {
+ (*cpu_fprintf)(f, " ");
+ }
(*cpu_fprintf)(f, "%s\n", m68k_cpu_defs[i].name);
}
}
-static int fpu_gdb_get_reg(CPUState *env, uint8_t *mem_buf, int n)
+static int cf_fpu_gdb_get_reg(CPUState *env, uint8_t *mem_buf, int n)
{
if (n < 8) {
- stfq_p(mem_buf, env->fregs[n]);
+ float_status s;
+ stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
return 8;
}
if (n < 11) {
@@ -75,10 +144,11 @@ static int fpu_gdb_get_reg(CPUState *env, uint8_t
*mem_buf, int n)
return 0;
}
-static int fpu_gdb_set_reg(CPUState *env, uint8_t *mem_buf, int n)
+static int cf_fpu_gdb_set_reg(CPUState *env, uint8_t *mem_buf, int n)
{
if (n < 8) {
- env->fregs[n] = ldfq_p(mem_buf);
+ float_status s;
+ env->fregs[n].d = float64_to_floatx80(ldfq_p(mem_buf), &s);
return 8;
}
if (n < 11) {
@@ -88,6 +158,36 @@ static int fpu_gdb_set_reg(CPUState *env, uint8_t
*mem_buf, int n)
return 0;
}
+static int m68k_fpu_gdb_get_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 8) {
+ stw_be_p(mem_buf, env->fregs[n].l.upper);
+ memset(mem_buf + 2, 0, 2);
+ stq_be_p(mem_buf + 4, env->fregs[n].l.lower);
+ return 12;
+ }
+ if (n < 11) {
+ /* FP control registers (not implemented) */
+ memset(mem_buf, 0, 4);
+ return 4;
+ }
+ return 0;
+}
+
+static int m68k_fpu_gdb_set_reg(CPUState *env, uint8_t *mem_buf, int n)
+{
+ if (n < 8) {
+ env->fregs[n].l.upper = lduw_be_p(mem_buf);
+ env->fregs[n].l.lower = ldq_be_p(mem_buf + 4);
+ return 12;
+ }
+ if (n < 11) {
+ /* FP control registers (not implemented) */
+ return 4;
+ }
+ return 0;
+}
+
static void m68k_set_feature(CPUM68KState *env, int feature)
{
env->features |= (1u << feature);
@@ -105,12 +205,32 @@ static int cpu_m68k_set_model(CPUM68KState *env,
const char *name)
return -1;
switch (def->id) {
+ case M68K_CPUID_M68020:
+ case M68K_CPUID_M68030:
+ case M68K_CPUID_M68040:
+ m68k_set_feature(env, M68K_FEATURE_QUAD_MULDIV);
+ case M68K_CPUID_M68060:
+ m68k_set_feature(env, M68K_FEATURE_BRAL);
+ m68k_set_feature(env, M68K_FEATURE_BCCL);
+ m68k_set_feature(env, M68K_FEATURE_BITFIELD);
+ m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
+ m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX);
+ m68k_set_feature(env, M68K_FEATURE_LONG_MULDIV);
+ m68k_set_feature(env, M68K_FEATURE_FPU);
+ m68k_set_feature(env, M68K_FEATURE_CAS);
+ case M68K_CPUID_M68000:
+ m68k_set_feature(env, M68K_FEATURE_M68000);
+ m68k_set_feature(env, M68K_FEATURE_USP);
+ m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
+ break;
case M68K_CPUID_M5206:
m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
+ m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX);
break;
case M68K_CPUID_M5208:
m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
+ m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX);
m68k_set_feature(env, M68K_FEATURE_BRAL);
m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
m68k_set_feature(env, M68K_FEATURE_USP);
@@ -118,16 +238,19 @@ static int cpu_m68k_set_model(CPUM68KState *env,
const char *name)
case M68K_CPUID_CFV4E:
m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
+ m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX);
m68k_set_feature(env, M68K_FEATURE_BRAL);
m68k_set_feature(env, M68K_FEATURE_CF_FPU);
m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
m68k_set_feature(env, M68K_FEATURE_USP);
break;
case M68K_CPUID_ANY:
+ m68k_set_feature(env, M68K_FEATURE_M68000);
m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
m68k_set_feature(env, M68K_FEATURE_BRAL);
+ m68k_set_feature(env, M68K_FEATURE_BCCL);
m68k_set_feature(env, M68K_FEATURE_CF_FPU);
/* MAC and EMAC are mututally exclusive, so pick EMAC.
It's mostly backwards compatible. */
@@ -135,35 +258,47 @@ static int cpu_m68k_set_model(CPUM68KState *env,
const char *name)
m68k_set_feature(env, M68K_FEATURE_CF_EMAC_B);
m68k_set_feature(env, M68K_FEATURE_USP);
m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
+ m68k_set_feature(env, M68K_FEATURE_SCALED_INDEX);
m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
+ m68k_set_feature(env, M68K_FEATURE_BITFIELD);
+ m68k_set_feature(env, M68K_FEATURE_LONG_MULDIV);
+ m68k_set_feature(env, M68K_FEATURE_QUAD_MULDIV);
+ m68k_set_feature(env, M68K_FEATURE_CAS);
break;
}
register_m68k_insns(env);
- if (m68k_feature (env, M68K_FEATURE_CF_FPU)) {
- gdb_register_coprocessor(env, fpu_gdb_get_reg, fpu_gdb_set_reg,
- 11, "cf-fp.xml", 18);
- }
/* TODO: Add [E]MAC registers. */
return 0;
}
void cpu_reset(CPUM68KState *env)
{
+ int i;
+
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
log_cpu_state(env, 0);
}
+#if defined(CONFIG_USER_ONLY)
memset(env, 0, offsetof(CPUM68KState, breakpoints));
-#if !defined (CONFIG_USER_ONLY)
+ /* TODO: We should set PC from the interrupt vector. */
+ env->pc = 0;
+#else
env->sr = 0x2700;
#endif
m68k_switch_sp(env);
- /* ??? FP regs should be initialized to NaN. */
+
+ for (i = 0; i < 8; i++) {
+ env->fregs[i].d = floatx80_default_nan;
+ }
+ env->fp0h = floatx80_default_nan.high;
+ env->fp0l = floatx80_default_nan.low;
+ env->fp1h = floatx80_default_nan.high;
+ env->fp1l = floatx80_default_nan.low;
+
env->cc_op = CC_OP_FLAGS;
- /* TODO: We should set PC from the interrupt vector. */
- env->pc = 0;
tlb_flush(env, 1);
}
@@ -175,7 +310,6 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model)
env = qemu_mallocz(sizeof(CPUM68KState));
cpu_exec_init(env);
if (!inited) {
- inited = 1;
m68k_tcg_init();
}
@@ -187,7 +321,18 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model)
}
cpu_reset(env);
+ if (!inited) {
+ if (m68k_feature (env, M68K_FEATURE_CF_FPU)) {
+ gdb_register_coprocessor(env, cf_fpu_gdb_get_reg, cf_fpu_gdb_set_reg,
+ 11, "cf-fp.xml", 18);
+ }
+ if (m68k_feature (env, M68K_FEATURE_FPU)) {
+ gdb_register_coprocessor(env, m68k_fpu_gdb_get_reg,
+ m68k_fpu_gdb_set_reg, 11, "m68k-fp.xml", 18);
+ }
+ }
qemu_init_vcpu(env);
+ inited = 1;
return env;
}
@@ -203,24 +348,56 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
uint32_t dest;
uint32_t tmp;
-#define HIGHBIT 0x80000000u
+#define HIGHBIT(type) (1u << (sizeof(type) * 8 - 1))
-#define SET_NZ(x) do { \
- if ((x) == 0) \
+#define SET_NZ(x, type) do { \
+ if ((type)(x) == 0) \
flags |= CCF_Z; \
- else if ((int32_t)(x) < 0) \
+ else if ((type)(x) < 0) \
flags |= CCF_N; \
} while (0)
#define SET_FLAGS_SUB(type, utype) do { \
- SET_NZ((type)dest); \
+ SET_NZ(dest, type); \
tmp = dest + src; \
if ((utype) tmp < (utype) src) \
flags |= CCF_C; \
- if ((1u << (sizeof(type) * 8 - 1)) & (tmp ^ dest) & (tmp ^ src)) \
+ if (HIGHBIT(type) & (tmp ^ dest) & (tmp ^ src)) \
flags |= CCF_V; \
} while (0)
+#define SET_FLAGS_ADD(type, utype) do { \
+ SET_NZ(dest, type); \
+ if ((utype) dest < (utype) src) \
+ flags |= CCF_C; \
+ tmp = dest - src; \
+ if (HIGHBIT(type) & (src ^ dest) & ~(tmp ^ src)) \
+ flags |= CCF_V; \
+ } while (0)
+
+#define SET_FLAGS_ADDX(type, utype) do { \
+ SET_NZ(dest, type); \
+ if ((utype) dest <= (utype) src) \
+ flags |= CCF_C; \
+ tmp = dest - src - 1; \
+ if (HIGHBIT(type) & (src ^ dest) & ~(tmp ^ src)) \
+ flags |= CCF_V; \
+ } while (0)
+
+#define SET_FLAGS_SUBX(type, utype) do { \
+ SET_NZ(dest, type); \
+ tmp = dest + src + 1; \
+ if ((utype) tmp <= (utype) src) \
+ flags |= CCF_C; \
+ if (HIGHBIT(type) & (tmp ^ dest) & (tmp ^ src)) \
+ flags |= CCF_V; \
+ } while (0)
+
+#define SET_FLAGS_SHIFT(type) do { \
+ SET_NZ(dest, type); \
+ flags |= src; \
+ } while(0)
+
flags = 0;
src = env->cc_src;
dest = env->cc_dest;
@@ -228,46 +405,66 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
case CC_OP_FLAGS:
flags = dest;
break;
+ case CC_OP_LOGICB:
+ SET_NZ(dest, int8_t);
+ goto set_x;
+ break;
+ case CC_OP_LOGICW:
+ SET_NZ(dest, int16_t);
+ goto set_x;
+ break;
case CC_OP_LOGIC:
- SET_NZ(dest);
+ SET_NZ(dest, int32_t);
+set_x:
+ if (env->cc_x && m68k_feature(env, M68K_FEATURE_M68000)) {
+ /* Unlike m68k, coldfire always clears the overflow bit. */
+ flags |= CCF_X;
+ }
+ break;
+ case CC_OP_ADDB:
+ SET_FLAGS_ADD(int8_t, uint8_t);
+ break;
+ case CC_OP_ADDW:
+ SET_FLAGS_ADD(int16_t, uint16_t);
break;
case CC_OP_ADD:
- SET_NZ(dest);
- if (dest < src)
- flags |= CCF_C;
- tmp = dest - src;
- if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
- flags |= CCF_V;
+ SET_FLAGS_ADD(int32_t, uint32_t);
+ break;
+ case CC_OP_SUBB:
+ SET_FLAGS_SUB(int8_t, uint8_t);
+ break;
+ case CC_OP_SUBW:
+ SET_FLAGS_SUB(int16_t, uint16_t);
break;
case CC_OP_SUB:
SET_FLAGS_SUB(int32_t, uint32_t);
break;
- case CC_OP_CMPB:
- SET_FLAGS_SUB(int8_t, uint8_t);
+ case CC_OP_ADDXB:
+ SET_FLAGS_ADDX(int8_t, uint8_t);
break;
- case CC_OP_CMPW:
- SET_FLAGS_SUB(int16_t, uint16_t);
+ case CC_OP_ADDXW:
+ SET_FLAGS_ADDX(int16_t, uint16_t);
break;
case CC_OP_ADDX:
- SET_NZ(dest);
- if (dest <= src)
- flags |= CCF_C;
- tmp = dest - src - 1;
- if (HIGHBIT & (src ^ dest) & ~(tmp ^ src))
- flags |= CCF_V;
+ SET_FLAGS_ADDX(int32_t, uint32_t);
+ break;
+ case CC_OP_SUBXB:
+ SET_FLAGS_SUBX(int8_t, uint8_t);
+ break;
+ case CC_OP_SUBXW:
+ SET_FLAGS_SUBX(int16_t, uint16_t);
break;
case CC_OP_SUBX:
- SET_NZ(dest);
- tmp = dest + src + 1;
- if (tmp <= src)
- flags |= CCF_C;
- if (HIGHBIT & (tmp ^ dest) & (tmp ^ src))
- flags |= CCF_V;
+ SET_FLAGS_SUBX(int32_t, uint32_t);
break;
+ case CC_OP_SHIFTB:
+ SET_FLAGS_SHIFT(int8_t);
+ break;
+ case CC_OP_SHIFTW:
+ SET_FLAGS_SHIFT(int16_t);
+ break;
case CC_OP_SHIFT:
- SET_NZ(dest);
- if (src)
- flags |= CCF_C;
+ SET_FLAGS_SHIFT(int32_t);
break;
default:
cpu_abort(env, "Bad CC_OP %d", cc_op);
@@ -276,16 +473,32 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
env->cc_dest = flags;
}
-void HELPER(movec)(CPUM68KState *env, uint32_t reg, uint32_t val)
+void HELPER(movec_to)(CPUM68KState * env, uint32_t reg, uint32_t val)
{
switch (reg) {
case 0x02: /* CACR */
env->cacr = val;
m68k_switch_sp(env);
break;
- case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
- /* TODO: Implement Access Control Registers. */
- break;
+ case 0x03: /* MMU Translation Control */
+ env->mmu.tc = val;
+ break;
+ /*Translation/Access Control Registers*/
+ case 0x04:
+ env->itt0 = val;
+ return;
+ case 0x05:
+ env->itt1 = val;
+ break;
+ case 0x06:
+ env->dtt0 = val;
+ break;
+ case 0x07:
+ env->dtt1 = val;
+ break;
+ case 0x800: /* USP */
+ env->sp[M68K_USP] = val;
+ break;
case 0x801: /* VBR */
env->vbr = val;
break;
@@ -296,6 +509,36 @@ void HELPER(movec)(CPUM68KState *env, uint32_t
reg, uint32_t val)
}
}
+uint32_t HELPER(movec_from)(CPUM68KState * env, uint32_t reg)
+{
+ switch (reg) {
+ case 0x00: /* SFC */
+ return env->sfc;
+ case 0x01: /* DFC */
+ return env->dfc;
+ case 0x02: /* CACR */
+ return env->cacr;
+ case 0x03: /*MMU TC*/
+ return env->mmu.tc;
+ case 0x04:
+ return env->itt0;
+ case 0x05:
+ return env->itt1;
+ case 0x06:
+ return env->dtt0;
+ case 0x07:
+ return env->dtt1;
+ case 0x800:/*USP*/
+ return env->sp[M68K_USP];
+ case 0x801: /* VBR */
+ return env->vbr;
+ /* TODO: Implement control registers. */
+ default:
+ cpu_abort(env, "Unimplemented control register read 0x%x\n",
+ reg);
+ }
+}
+
void HELPER(set_macsr)(CPUM68KState *env, uint32_t val)
{
uint32_t acc;
@@ -404,6 +647,37 @@ uint32_t HELPER(ff1)(uint32_t x)
return n;
}
+uint32_t HELPER(bfffo)(uint32_t arg, uint32_t width)
+{
+ int n;
+ uint32_t mask;
+ mask = 0x80000000;
+ for (n = 0; n < width; n++) {
+ if (arg & mask)
+ break;
+ mask >>= 1;
+ }
+ return n;
+}
+
+uint32_t HELPER(rol32)(uint32_t val, uint32_t shift)
+{
+ uint32_t result;
+ if (shift == 0 || shift == 32)
+ return val;
+ result = (val << shift) | (val >> (32 - shift));
+ return result;
+}
+
+uint32_t HELPER(ror32)(uint32_t val, uint32_t shift)
+{
+ uint32_t result;
+ if (shift == 0 || shift == 32)
+ return val;
+ result = (val >> shift) | (val << (32 - shift));
+ return result;
+}
+
uint32_t HELPER(sats)(uint32_t val, uint32_t ccr)
{
/* The result has the opposite sign to the original value. */
@@ -412,7 +686,53 @@ uint32_t HELPER(sats)(uint32_t val, uint32_t ccr)
return val;
}
-uint32_t HELPER(subx_cc)(CPUState *env, uint32_t op1, uint32_t op2)
+uint32_t HELPER(subx8_cc)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+ uint8_t res;
+ uint32_t old_flags;
+
+ old_flags = env->cc_dest;
+ if (env->cc_x) {
+ env->cc_x = ((uint8_t)op1 <= (uint8_t)op2);
+ env->cc_op = CC_OP_SUBXB;
+ res = (uint8_t)op1 - ((uint8_t)op2 + 1);
+ } else {
+ env->cc_x = ((uint8_t)op1 < (uint8_t)op2);
+ env->cc_op = CC_OP_SUBB;
+ res = (uint8_t)op1 - (uint8_t)op2;
+ }
+ env->cc_dest = res;
+ env->cc_src = (uint8_t)op2;
+ cpu_m68k_flush_flags(env, env->cc_op);
+ /* !Z is sticky. */
+ env->cc_dest &= (old_flags | ~CCF_Z);
+ return (op1 & 0xffffff00) | res;
+}
+
+uint32_t HELPER(subx16_cc)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+ uint16_t res;
+ uint32_t old_flags;
+
+ old_flags = env->cc_dest;
+ if (env->cc_x) {
+ env->cc_x = ((uint16_t)op1 <= (uint16_t)op2);
+ env->cc_op = CC_OP_SUBXW;
+ res = (uint16_t)op1 - ((uint16_t)op2 + 1);
+ } else {
+ env->cc_x = ((uint16_t)op1 < (uint16_t)op2);
+ env->cc_op = CC_OP_SUBW;
+ res = (uint16_t)op1 - (uint16_t)op2;
+ }
+ env->cc_dest = res;
+ env->cc_src = (uint16_t)op2;
+ cpu_m68k_flush_flags(env, env->cc_op);
+ /* !Z is sticky. */
+ env->cc_dest &= (old_flags | ~CCF_Z);
+ return (op1 & 0xffff0000) | res;
+}
+
+uint32_t HELPER(subx32_cc)(CPUState *env, uint32_t op1, uint32_t op2)
{
uint32_t res;
uint32_t old_flags;
@@ -435,7 +755,53 @@ uint32_t HELPER(subx_cc)(CPUState *env, uint32_t
op1, uint32_t op2)
return res;
}
-uint32_t HELPER(addx_cc)(CPUState *env, uint32_t op1, uint32_t op2)
+uint32_t HELPER(addx8_cc)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+ uint8_t res;
+ uint32_t old_flags;
+
+ old_flags = env->cc_dest;
+ if (env->cc_x) {
+ res = (uint8_t)op1 + (uint8_t)op2 + 1;
+ env->cc_x = (res <= (uint8_t)op2);
+ env->cc_op = CC_OP_ADDXB;
+ } else {
+ res = (uint8_t)op1 + (uint8_t)op2;
+ env->cc_x = (res < (uint8_t)op2);
+ env->cc_op = CC_OP_ADDB;
+ }
+ env->cc_dest = res;
+ env->cc_src = (uint8_t)op2;
+ cpu_m68k_flush_flags(env, env->cc_op);
+ /* !Z is sticky. */
+ env->cc_dest &= (old_flags | ~CCF_Z);
+ return (op1 & 0xffffff00) | res;
+}
+
+uint32_t HELPER(addx16_cc)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+ uint16_t res;
+ uint32_t old_flags;
+
+ old_flags = env->cc_dest;
+ if (env->cc_x) {
+ res = (uint16_t)op1 + (uint16_t)op2 + 1;
+ env->cc_x = (res <= (uint16_t)op2);
+ env->cc_op = CC_OP_ADDXW;
+ } else {
+ res = (uint16_t)op1 + (uint16_t)op2;
+ env->cc_x = (res < (uint16_t)op2);
+ env->cc_op = CC_OP_ADDW;
+ }
+ env->cc_dest = res;
+ env->cc_src = (uint16_t)op2;
+ cpu_m68k_flush_flags(env, env->cc_op);
+ /* !Z is sticky. */
+ env->cc_dest &= (old_flags | ~CCF_Z);
+ return (op1 & 0xffff0000) | res;
+}
+
+uint32_t HELPER(addx32_cc)(CPUState *env, uint32_t op1, uint32_t op2)
{
uint32_t res;
uint32_t old_flags;
@@ -458,7 +824,17 @@ uint32_t HELPER(addx_cc)(CPUState *env, uint32_t
op1, uint32_t op2)
return res;
}
-uint32_t HELPER(xflag_lt)(uint32_t a, uint32_t b)
+uint32_t HELPER(xflag_lt_i8)(uint32_t a, uint32_t b)
+{
+ return (uint8_t)a < (uint8_t)b;
+}
+
+uint32_t HELPER(xflag_lt_i16)(uint32_t a, uint32_t b)
+{
+ return (uint16_t)a < (uint16_t)b;
+}
+
+uint32_t HELPER(xflag_lt_i32)(uint32_t a, uint32_t b)
{
return a < b;
}
@@ -469,167 +845,983 @@ void HELPER(set_sr)(CPUState *env, uint32_t val)
m68k_switch_sp(env);
}
-uint32_t HELPER(shl_cc)(CPUState *env, uint32_t val, uint32_t shift)
+#define HELPER_SHL(type, bits) \
+uint32_t HELPER(glue(glue(shl, bits),_cc))(CPUState *env, uint32_t
val, uint32_t shift) \
+{ \
+ type result; \
+ uint32_t cf; \
+ shift &= 63; \
+ if (shift == 0) { \
+ result = (type)val; \
+ cf = 0; \
+ } else if (shift < bits) { \
+ result = (type)val << shift; \
+ cf = ((type)val >> (bits - shift)) & 1; \
+ } else if (shift == bits) { \
+ result = 0; \
+ cf = val & 1; \
+ } else /* shift > bits */ { \
+ result = 0; \
+ cf = 0; \
+ } \
+ env->cc_src = cf ? CCF_C : 0; \
+ if (shift) env->cc_x = (cf != 0); \
+ env->cc_dest = result; \
+ return result; \
+}
+
+HELPER_SHL(uint8_t, 8)
+HELPER_SHL(uint16_t, 16)
+HELPER_SHL(uint32_t, 32)
+
+#define HELPER_SHR(type, bits) \
+uint32_t HELPER(glue(glue(shr, bits), _cc))(CPUState *env, uint32_t
val, uint32_t shift) \
+{ \
+ type result; \
+ uint32_t cf; \
+ shift &= 63; \
+ if (shift == 0) { \
+ result = (type)val; \
+ cf = 0; \
+ } else if (shift < bits) { \
+ result = (type)val >> shift; \
+ cf = ((type)val >> (shift - 1)) & 1; \
+ } else if (shift == bits) { \
+ result = 0; \
+ cf = (type)val >> (bits - 1); \
+ } else /* shift > bits */ { \
+ result = 0; \
+ cf = 0; \
+ } \
+ env->cc_src = cf ? CCF_C : 0; \
+ if (shift) env->cc_x = (cf != 0); \
+ env->cc_dest = result; \
+ return result; \
+}
+
+HELPER_SHR(uint8_t, 8)
+HELPER_SHR(uint16_t, 16)
+HELPER_SHR(uint32_t, 32)
+
+#define HELPER_SAL(type, bits) \
+uint32_t HELPER(glue(glue(sal, bits),_cc))(CPUState *env, uint32_t
val, uint32_t shift) \
+{ \
+ type result; \
+ uint32_t cf; \
+ uint32_t vf; \
+ uint32_t m; \
+ shift &= 63; \
+ if (shift == 0) { \
+ vf = 0; \
+ } else if (shift < bits) { \
+ m = ((1llu << (shift + 1)) - 1) << (bits - shift - 1); \
+ vf = (val & m) != m && (val & m) != 0; \
+ } else {\
+ m = (1llu << bits) - 1; \
+ vf = (val & m) != 0; \
+ }\
+ if (shift == 0) { \
+ result = (type)val; \
+ cf = 0; \
+ } else if (shift < bits) { \
+ result = (type)val << shift; \
+ cf = ((type)val >> (bits - shift)) & 1; \
+ } else if (shift == bits) { \
+ result = 0; \
+ cf = val & 1; \
+ } else /* shift > bits */ { \
+ result = 0; \
+ cf = 0; \
+ } \
+ env->cc_src = (cf ? CCF_C : 0) | (vf ? CCF_V : 0); \
+ if (shift) env->cc_x = (cf != 0); \
+ env->cc_dest = result; \
+ return result; \
+}
+
+HELPER_SAL(int8_t, 8)
+HELPER_SAL(int16_t, 16)
+HELPER_SAL(int32_t, 32)
+
+#define HELPER_SAR(type, bits) \
+uint32_t HELPER(glue(glue(sar, bits), _cc))(CPUState *env, uint32_t
val, uint32_t shift) \
+{ \
+ type result; \
+ uint32_t cf; \
+ shift &= 63; \
+ if (shift == 0) { \
+ result = (type)val; \
+ cf = 0; \
+ } else if (shift < bits) { \
+ result = (type)val >> shift; \
+ cf = ((type)val >> (shift - 1)) & 1; \
+ } else /* shift >= bits */ { \
+ result = (type)val >> (bits - 1); \
+ cf = (type)val >> (bits - 1); \
+ } \
+ env->cc_src = cf ? CCF_C : 0; \
+ if (shift) env->cc_x = (cf != 0); \
+ env->cc_dest = result; \
+ return result; \
+}
+
+HELPER_SAR(int8_t, 8)
+HELPER_SAR(int16_t, 16)
+HELPER_SAR(int32_t, 32)
+
+#define HELPER_ROL(type, bits) \
+uint32_t HELPER(glue(glue(rol,bits),_cc))(CPUState *env, uint32_t
val, uint32_t shift) \
+{ \
+ type result; \
+ uint32_t flags; \
+ int count = shift & (bits - 1); \
+ if (count) \
+ result = ((type)val << count) | ((type)val >> (bits - count)); \
+ else \
+ result = (type)val; \
+ flags = 0; \
+ if (result == 0) \
+ flags |= CCF_Z; \
+ if (result & (1 << (bits - 1))) \
+ flags |= CCF_N; \
+ if (shift && result & 1) \
+ flags |= CCF_C; \
+ env->cc_dest = flags; \
+ return result; \
+}
+
+HELPER_ROL(uint8_t, 8)
+HELPER_ROL(uint16_t, 16)
+HELPER_ROL(uint32_t, 32)
+
+#define HELPER_ROR(type, bits) \
+uint32_t HELPER(glue(glue(ror,bits),_cc))(CPUState *env, uint32_t
val, uint32_t shift) \
+{ \
+ type result; \
+ uint32_t flags; \
+ int count = shift & (bits - 1); \
+ if (count) \
+ result = ((type)val >> count) | ((type)val << (bits - count)); \
+ else \
+ result = (type)val; \
+ flags = 0; \
+ if (result == 0) \
+ flags |= CCF_Z; \
+ if (result & (1 << (bits - 1))) \
+ flags |= CCF_N; \
+ if (shift && result & (1 << (bits - 1))) \
+ flags |= CCF_C; \
+ env->cc_dest = flags; \
+ return result; \
+}
+
+HELPER_ROR(uint8_t, 8)
+HELPER_ROR(uint16_t, 16)
+HELPER_ROR(uint32_t, 32)
+
+#define HELPER_ROXR(type, bits) \
+uint32_t HELPER(glue(glue(roxr,bits),_cc))(CPUState *env, uint32_t
val, uint32_t shift) \
+{ \
+ type result; \
+ uint32_t flags; \
+ int count = shift; \
+ if (bits == 8) count = rox8_table[count]; \
+ if (bits == 16) count = rox16_table[count]; \
+ if (bits == 32) count = rox32_table[count]; \
+ if (count) { \
+ if (count == bits)\
+ result = ((type)env->cc_x << (bits - count));\
+ else \
+ result = ((type)val >> count) | ((type)env->cc_x << (bits
- count));\
+ if (count > 1) \
+ result |= (type)val << (bits + 1 - count); \
+ env->cc_x = ((type)val >> (count - 1)) & 1; \
+ } else \
+ result = (type)val; \
+ flags = 0; \
+ if (result == 0) \
+ flags |= CCF_Z; \
+ if (result & (1 << (bits - 1))) \
+ flags |= CCF_N; \
+ if (env->cc_x) \
+ flags |= CCF_C; \
+ env->cc_dest = flags; \
+ return result; \
+}
+
+HELPER_ROXR(uint8_t, 8)
+HELPER_ROXR(uint16_t, 16)
+HELPER_ROXR(uint32_t, 32)
+
+#define HELPER_ROXL(type, bits) \
+uint32_t HELPER(glue(glue(roxl,bits),_cc))(CPUState *env, uint32_t
val, uint32_t shift) \
+{ \
+ type result; \
+ uint32_t flags; \
+ int count; \
+ count = shift; \
+ if (bits == 8) count = rox8_table[count]; \
+ if (bits == 16) count = rox16_table[count]; \
+ if (bits == 32) count = rox32_table[count]; \
+ if (count) { \
+ if (count == bits) \
+ result = ((type)env->cc_x << (count - 1)); \
+ else \
+ result = ((type)val << count) | ((type)env->cc_x << (count - 1)); \
+ if (count > 1) \
+ result |= (type)val >> (bits + 1 - count); \
+ env->cc_x = ((type)val >> (bits - count)) & 1; \
+ } else \
+ result = (type)val; \
+ flags = 0; \
+ if (result == 0) \
+ flags |= CCF_Z; \
+ if (result & (1 << (bits - 1))) \
+ flags |= CCF_N; \
+ if (env->cc_x) \
+ flags |= CCF_C; \
+ env->cc_dest = flags; \
+ return result; \
+}
+
+HELPER_ROXL(uint8_t, 8)
+HELPER_ROXL(uint16_t, 16)
+HELPER_ROXL(uint32_t, 32)
+
+/* FPU helpers. */
+
+static const floatx80 fpu_rom[128] = {
+ [0x00] = floatx80_pi, /* Pi */
+
+ [0x0b] = { .high = 0x3ffd, .low = 0x9a209a84fbcff798ULL }, /* Log10(2) */
+ [0x0c] = floatx80_e, /* e */
+ [0x0d] = floatx80_log2e, /* Log2(e) */
+ [0x0e] = { .high = 0x3ffd, .low = 0xde5bd8a937287195ULL }, /* Log10(e) */
+ [0x0f] = floatx80_zero, /* Zero */
+
+ [0x30] = floatx80_ln2, /* ln(2) */
+ [0x31] = { .high = 0x4000, .low = 0x935d8dddaaa8ac17ULL }, /* ln(10) */
+ [0x32] = floatx80_one, /* 10^0 */
+ [0x33] = floatx80_10, /* 10^1 */
+ [0x34] = { .high = 0x4005, .low = 0xc800000000000000ULL }, /* 10^2 */
+ [0x35] = { .high = 0x400c, .low = 0x9c40000000000000ULL }, /* 10^4 */
+ [0x36] = { .high = 0x4019, .low = 0xbebc200000000000ULL }, /* 10^8 */
+ [0x37] = { .high = 0x4034, .low = 0x8e1bc9bf04000000ULL }, /* 10^16 */
+ [0x38] = { .high = 0x4069, .low = 0x9dc5ada82b70b59eULL }, /* 10^32 */
+ [0x39] = { .high = 0x40d3, .low = 0xc2781f49ffcfa6d5ULL }, /* 10^64 */
+ [0x3a] = { .high = 0x41a8, .low = 0x93ba47c980e98ce0ULL }, /* 10^128 */
+ [0x3b] = { .high = 0x4351, .low = 0xaa7eebfb9df9de8eULL }, /* 10^256 */
+ [0x3c] = { .high = 0x46a3, .low = 0xe319a0aea60e91c7ULL }, /* 10^512 */
+ [0x3d] = { .high = 0x4d48, .low = 0xc976758681750c17ULL }, /* 10^1024 */
+ [0x3e] = { .high = 0x5a92, .low = 0x9e8b3b5dc53d5de5ULL }, /* 10^2048 */
+ [0x3f] = { .high = 0x7525, .low = 0xc46052028a20979bULL }, /* 10^4096 */
+};
+
+static inline floatx80 FP0_to_floatx80(CPUState *env)
{
- uint32_t result;
- uint32_t cf;
-
- shift &= 63;
- if (shift == 0) {
- result = val;
- cf = env->cc_src & CCF_C;
- } else if (shift < 32) {
- result = val << shift;
- cf = (val >> (32 - shift)) & 1;
- } else if (shift == 32) {
- result = 0;
- cf = val & 1;
- } else /* shift > 32 */ {
- result = 0;
- cf = 0;
- }
- env->cc_src = cf;
- env->cc_x = (cf != 0);
- env->cc_dest = result;
- return result;
+ floatx80 res;
+
+ res.high = env->fp0h;
+ res.low = env->fp0l;
+
+ return res;
}
-uint32_t HELPER(shr_cc)(CPUState *env, uint32_t val, uint32_t shift)
+static inline void floatx80_to_FP0(CPUState *env, floatx80 res)
{
- uint32_t result;
- uint32_t cf;
-
- shift &= 63;
- if (shift == 0) {
- result = val;
- cf = env->cc_src & CCF_C;
- } else if (shift < 32) {
- result = val >> shift;
- cf = (val >> (shift - 1)) & 1;
- } else if (shift == 32) {
- result = 0;
- cf = val >> 31;
- } else /* shift > 32 */ {
- result = 0;
- cf = 0;
- }
- env->cc_src = cf;
- env->cc_x = (cf != 0);
- env->cc_dest = result;
- return result;
+ env->fp0h = res.high;
+ env->fp0l = res.low;
}
-uint32_t HELPER(sar_cc)(CPUState *env, uint32_t val, uint32_t shift)
+static inline void floatx80_to_FP1(CPUState *env, floatx80 res)
{
- uint32_t result;
- uint32_t cf;
-
- shift &= 63;
- if (shift == 0) {
- result = val;
- cf = (env->cc_src & CCF_C) != 0;
- } else if (shift < 32) {
- result = (int32_t)val >> shift;
- cf = (val >> (shift - 1)) & 1;
- } else /* shift >= 32 */ {
- result = (int32_t)val >> 31;
- cf = val >> 31;
- }
- env->cc_src = cf;
- env->cc_x = cf;
- env->cc_dest = result;
- return result;
+ env->fp1h = res.high;
+ env->fp1l = res.low;
}
-/* FPU helpers. */
-uint32_t HELPER(f64_to_i32)(CPUState *env, float64 val)
+static inline int32_t FP0_to_int32(CPUState *env)
+{
+ return env->fp0h;
+}
+
+static inline void int32_to_FP0(CPUState *env, int32_t val)
+{
+ env->fp0h = val;
+}
+
+static inline float32 FP0_to_float32(CPUState *env)
+{
+ return *(float32*)&env->fp0h;
+}
+
+static inline void float32_to_FP0(CPUState *env, float32 val)
+{
+
+ env->fp0h = *(uint32_t*)&val;
+}
+
+static inline float64 FP0_to_float64(CPUState *env)
+{
+ return *(float64*)&env->fp0l;
+}
+
+static inline void float64_to_FP0(CPUState *env, float64 val)
+{
+ env->fp0l = *(uint64_t*)&val;
+}
+
+static inline floatx80 FP1_to_floatx80(CPUState *env)
+{
+ floatx80 res;
+
+ res.high = env->fp1h;
+ res.low = env->fp1l;
+
+ return res;
+}
+
+static inline long double floatx80_to_ldouble(floatx80 val)
+{
+ if (floatx80_is_infinity(val)) {
+ if (floatx80_is_neg(val)) {
+ return -__builtin_infl();
+ }
+ return __builtin_infl();
+ }
+ if (floatx80_is_any_nan(val)) {
+ char low[20];
+ sprintf(low, "0x%016"PRIx64, val.low);
+
+ return nanl(low);
+ }
+
+ return *(long double *)&val;
+}
+
+static inline floatx80 ldouble_to_floatx80(long double val)
+{
+ floatx80 res;
+
+ if (isinf(val)) {
+ res.high = floatx80_default_nan.high;
+ res.low = 0;
+ }
+ if (isinf(val) < 0) {
+ res.high |= 0x8000;
+ }
+ if (isnan(val)) {
+ res.high = floatx80_default_nan.high;
+ res.low = *(uint64_t*)((char *)&val + 4);
+ }
+ return *(floatx80*)&val;
+}
+
+void HELPER(const_FP0)(CPUState *env, uint32_t offset)
+{
+ env->fp0h = fpu_rom[offset].high;
+ env->fp0l = fpu_rom[offset].low;
+ DBG_FPUH("ROM[0x%02x] %"PRIxFPH" %"PRIxFPL" %.17Lg\n",
+ offset, env->fp0h, env->fp0l,
floatx80_to_ldouble(FP0_to_floatx80(env)));
+}
+
+static inline void restore_precision_mode(CPUState *env)
+{
+ int rounding_precision;
+
+ rounding_precision = (env->fpcr >> 6) & 0x03;
+
+ switch (rounding_precision) {
+ case 0: /* extended */
+ set_floatx80_rounding_precision(80, &env->fp_status);
+ break;
+ case 1: /* single */
+ set_floatx80_rounding_precision(32, &env->fp_status);
+ break;
+ case 2: /* double */
+ set_floatx80_rounding_precision(64, &env->fp_status);
+ break;
+ case 3: /* reserved */
+ default:
+ break;
+ }
+}
+
+static inline void restore_rounding_mode(CPUState *env)
+{
+ int rounding_mode;
+
+ rounding_mode = (env->fpcr >> 4) & 0x03;
+
+ switch (rounding_mode) {
+ case 0: /* round to nearest */
+ set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+ break;
+ case 1: /* round to zero */
+ set_float_rounding_mode(float_round_to_zero, &env->fp_status);
+ break;
+ case 2: /* round toward minus infinity */
+ set_float_rounding_mode(float_round_down, &env->fp_status);
+ break;
+ case 3: /* round toward positive infinity */
+ set_float_rounding_mode(float_round_up, &env->fp_status);
+ break;
+ }
+}
+
+void HELPER(set_fpcr)(CPUState *env, uint32_t val)
+{
+ DBG_FPUH("set_fpcr %04x\n", val);
+
+ env->fpcr = val & 0xffff;
+
+ restore_precision_mode(env);
+ restore_rounding_mode(env);
+}
+
+void HELPER(exts32_FP0)(CPUState *env)
+{
+ floatx80 res;
+
+ DBG_FPUH("exts32_FP0 %d", FP0_to_int32(env));
+
+ res = int32_to_floatx80(FP0_to_int32(env), &env->fp_status);
+
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(extf32_FP0)(CPUState *env)
+{
+ floatx80 res;
+
+ DBG_FPUH("extf32_FP0 %f", FLOAT(FP0_to_float32(env)));
+ res = float32_to_floatx80(FP0_to_float32(env), &env->fp_status);
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(extf64_FP0)(CPUState *env)
+{
+ floatx80 res;
+ uint64_t val;
+
+ val = FP0_to_float64(env);
+ DBG_FPUH("extf64_FP0 0x%016"PRIx64", %g", val, *(double*)&val);
+ res = float64_to_floatx80(val, &env->fp_status);
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(extp96_FP0)(CPUState *env)
+{
+}
+
+void HELPER(reds32_FP0)(CPUState *env)
+{
+ floatx80 val;
+ int32_t res;
+
+ val = FP0_to_floatx80(env);
+ DBG_FPUH("reds32_FP0 %Lg (%08x %016"PRIx64")",
+ floatx80_to_ldouble(val), env->fp0h, env->fp0l);
+ res = floatx80_to_int32(val, &env->fp_status);
+ DBG_FPU(" = %d\n", res);
+
+ int32_to_FP0(env, res);
+}
+
+void HELPER(redf32_FP0)(CPUState *env)
+{
+ floatx80 val;
+ float32 res;
+
+ val = FP0_to_floatx80(env);
+ DBG_FPUH("redf32_FP0 %Lg", floatx80_to_ldouble(val));
+ res = floatx80_to_float32(val, &env->fp_status);
+ DBG_FPU(" = %f\n", FLOAT(res));
+
+ float32_to_FP0(env, res);
+}
+
+void HELPER(redf64_FP0)(CPUState *env)
+{
+ floatx80 val;
+ float64 res;
+
+ val = FP0_to_floatx80(env);
+ DBG_FPUH("redf64_FP0 %Lg", floatx80_to_ldouble(val));
+ res = floatx80_to_float64(val, &env->fp_status);
+ DBG_FPU(" = %g\n", *(double*)&res);
+
+ float64_to_FP0(env, res);
+}
+
+void HELPER(redp96_FP0)(CPUState *env)
+{
+ DBG_FPUH("redp96_FP0\n");
+}
+
+void HELPER(iround_FP0)(CPUState *env)
+{
+ floatx80 res;
+
+ res = FP0_to_floatx80(env);
+
+ DBG_FPUH("iround_FP0 %Lg", floatx80_to_ldouble(res));
+
+ res = floatx80_round_to_int(res, &env->fp_status);
+
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(sinh_FP0)(CPUState *env)
{
- return float64_to_int32(val, &env->fp_status);
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = floatx80_to_ldouble(res);
+
+ DBG_FPUH("sinh_FP0 %Lg", val);
+ val = sinhl(val);
+ DBG_FPU(" = %Lg", val);
+ res = ldouble_to_floatx80(val);
+ floatx80_to_FP0(env, res);
}
-float32 HELPER(f64_to_f32)(CPUState *env, float64 val)
+void HELPER(itrunc_FP0)(CPUState *env)
{
- return float64_to_float32(val, &env->fp_status);
+ floatx80 res;
+
+ res = FP0_to_floatx80(env);
+ DBG_FPUH("itrunc_FP0 %Lg", floatx80_to_ldouble(res));
+
+ set_float_rounding_mode(float_round_to_zero, &env->fp_status);
+ res = floatx80_round_to_int(res, &env->fp_status);
+ restore_rounding_mode(env);
+
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+
+ floatx80_to_FP0(env, res);
}
-float64 HELPER(i32_to_f64)(CPUState *env, uint32_t val)
+void HELPER(sqrt_FP0)(CPUState *env)
{
- return int32_to_float64(val, &env->fp_status);
+ floatx80 res;
+
+ res = FP0_to_floatx80(env);
+ DBG_FPUH("sqrt_FP0 %Lg", floatx80_to_ldouble(res));
+ res = floatx80_sqrt(res, &env->fp_status);
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+
+ floatx80_to_FP0(env, res);
}
-float64 HELPER(f32_to_f64)(CPUState *env, float32 val)
+void HELPER(lognp1_FP0)(CPUState *env)
{
- return float32_to_float64(val, &env->fp_status);
+ floatx80 val;
+ long double res;
+
+ val = FP0_to_floatx80(env);
+ DBG_FPUH("lognp1_FP0 %Lg", floatx80_to_ldouble(val));
+ res = logl(floatx80_to_ldouble(val) + 1.0);
+ DBG_FPU(" = %Lg\n", res);
+
+ floatx80_to_FP0(env, ldouble_to_floatx80(res));
}
-float64 HELPER(iround_f64)(CPUState *env, float64 val)
+void HELPER(ln_FP0)(CPUState *env)
{
- return float64_round_to_int(val, &env->fp_status);
+ floatx80 val;
+ long double res;
+
+ val = FP0_to_floatx80(env);
+ DBG_FPUH("ln_FP0 %Lg", floatx80_to_ldouble(val));
+ res = logl(floatx80_to_ldouble(val));
+ DBG_FPU(" = %Lg\n", res);
+
+ floatx80_to_FP0(env, ldouble_to_floatx80(res));
}
-float64 HELPER(itrunc_f64)(CPUState *env, float64 val)
+void HELPER(log10_FP0)(CPUState *env)
{
- return float64_trunc_to_int(val, &env->fp_status);
+ floatx80 val;
+ long double res;
+
+ val = FP0_to_floatx80(env);
+ DBG_FPUH("log10_FP0 %Lg", floatx80_to_ldouble(val));
+ res = log10l(floatx80_to_ldouble(val));
+ DBG_FPU(" = %Lg\n", res);
+
+ floatx80_to_FP0(env, ldouble_to_floatx80(res));
}
-float64 HELPER(sqrt_f64)(CPUState *env, float64 val)
+void HELPER(atan_FP0)(CPUState *env)
{
- return float64_sqrt(val, &env->fp_status);
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = floatx80_to_ldouble(res);
+
+ DBG_FPUH("atan_FP0 %Lg", val);
+ val = atanl(val);
+ DBG_FPU(" = %Lg", val);
+ res = ldouble_to_floatx80(val);
+ floatx80_to_FP0(env, res);
}
-float64 HELPER(abs_f64)(float64 val)
+void HELPER(asin_FP0)(CPUState *env)
{
- return float64_abs(val);
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = floatx80_to_ldouble(res);
+
+ DBG_FPUH("asin_FP0 %Lg", val);
+ val = asinl(val);
+ DBG_FPU(" = %Lg", val);
+ res = ldouble_to_floatx80(val);
+ floatx80_to_FP0(env, res);
}
-float64 HELPER(chs_f64)(float64 val)
+void HELPER(atanh_FP0)(CPUState *env)
{
- return float64_chs(val);
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = floatx80_to_ldouble(res);
+
+ DBG_FPUH("atanh_FP0 %Lg", val);
+ val = atanhl(val);
+ DBG_FPU(" = %Lg", val);
+ res = ldouble_to_floatx80(val);
+ floatx80_to_FP0(env, res);
}
-float64 HELPER(add_f64)(CPUState *env, float64 a, float64 b)
+void HELPER(sin_FP0)(CPUState *env)
{
- return float64_add(a, b, &env->fp_status);
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = floatx80_to_ldouble(res);
+
+ DBG_FPUH("sin_FP0 %Lg", val);
+ val = sinl(val);
+ DBG_FPU(" = %Lg", val);
+ res = ldouble_to_floatx80(val);
+ floatx80_to_FP0(env, res);
}
-float64 HELPER(sub_f64)(CPUState *env, float64 a, float64 b)
+void HELPER(tanh_FP0)(CPUState *env)
{
- return float64_sub(a, b, &env->fp_status);
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = floatx80_to_ldouble(res);
+
+ DBG_FPUH("tanh_FP0 %Lg", val);
+ val = tanhl(val);
+ DBG_FPU(" = %Lg", val);
+ res = ldouble_to_floatx80(val);
+ floatx80_to_FP0(env, res);
}
-float64 HELPER(mul_f64)(CPUState *env, float64 a, float64 b)
+void HELPER(tan_FP0)(CPUState *env)
{
- return float64_mul(a, b, &env->fp_status);
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = floatx80_to_ldouble(res);
+
+ DBG_FPUH("tan_FP0 %Lg", val);
+ val = tanl(val);
+ DBG_FPU(" = %Lg", val);
+ res = ldouble_to_floatx80(val);
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(exp_FP0)(CPUState *env)
+{
+ floatx80 f;
+ long double res;
+
+ f = FP0_to_floatx80(env);
+
+ DBG_FPUH("exp_FP0 %Lg", floatx80_to_ldouble(f));
+
+ res = expl(floatx80_to_ldouble(f));
+
+ DBG_FPU(" = %Lg\n", res);
+ floatx80_to_FP0(env, ldouble_to_floatx80(res));
+}
+
+void HELPER(exp2_FP0)(CPUState *env)
+{
+ floatx80 f;
+ long double res;
+
+ f = FP0_to_floatx80(env);
+
+ DBG_FPUH("exp2_FP0 %Lg", floatx80_to_ldouble(f));
+
+ res = exp2l(floatx80_to_ldouble(f));
+
+ DBG_FPU(" = %Lg\n", res);
+ floatx80_to_FP0(env, ldouble_to_floatx80(res));
}
-float64 HELPER(div_f64)(CPUState *env, float64 a, float64 b)
+void HELPER(exp10_FP0)(CPUState *env)
{
- return float64_div(a, b, &env->fp_status);
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = floatx80_to_ldouble(res);
+
+ DBG_FPUH("exp2_FP0 %Lg", val);
+ val = exp10l(val);
+ DBG_FPU(" = %Lg", val);
+ res = ldouble_to_floatx80(val);
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(abs_FP0)(CPUState *env)
+{
+ floatx80 res;
+
+ res = FP0_to_floatx80(env);
+ DBG_FPUH("abs_FP0 %Lg", floatx80_to_ldouble(res));
+ res = floatx80_abs(res);
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+
+ floatx80_to_FP0(env, res);
}
-float64 HELPER(sub_cmp_f64)(CPUState *env, float64 a, float64 b)
+void HELPER(cosh_FP0)(CPUState *env)
+{
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = floatx80_to_ldouble(res);
+
+ DBG_FPUH("cosh_FP0 %Lg", val);
+ val = coshl(val);
+ DBG_FPU(" = %Lg", val);
+ res = ldouble_to_floatx80(val);
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(chs_FP0)(CPUState *env)
+{
+ floatx80 res;
+
+ res = FP0_to_floatx80(env);
+ DBG_FPUH("chs_FP0 %Lg", floatx80_to_ldouble(res));
+ res = floatx80_chs(res);
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(acos_FP0)(CPUState *env)
+{
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = floatx80_to_ldouble(res);
+
+ DBG_FPUH("acos_FP0 %Lg", val);
+ val = acosl(val);
+ DBG_FPU(" = %Lg", val);
+ res = ldouble_to_floatx80(val);
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(cos_FP0)(CPUState *env)
+{
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = floatx80_to_ldouble(res);
+
+ DBG_FPUH("cos_FP0 %Lg", val);
+ val = cosl(val);
+ DBG_FPU(" = %Lg", val);
+ res = ldouble_to_floatx80(val);
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(getexp_FP0)(CPUState *env)
+{
+ int32_t exp;
+ floatx80 res;
+
+ DBG_FPUH("getexp_FP0 %Lg", floatx80_to_ldouble(FP0_to_floatx80(env)));
+
+ DBG_FPU(" fp0h 0x%08x fp0l 0x%016" PRIx64, env->fp0h, env->fp0l);
+
+ exp = (env->fp0h & 0x7fff) - 0x3fff;
+
+ res = int32_to_floatx80(exp, &env->fp_status);
+
+ DBG_FPU(" = %Lg", floatx80_to_ldouble(res));
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(scale_FP0_FP1)(CPUState *env)
+{
+ int32_t scale;
+ int32_t exp;
+
+ DBG_FPUH("scale_FP0 %Lg", floatx80_to_ldouble(FP0_to_floatx80(env)));
+
+ DBG_FPU(" fp0h 0x%08x fp0l 0x%016" PRIx64, env->fp0h, env->fp0l);
+
+ scale = floatx80_to_int32(FP0_to_floatx80(env), &env->fp_status);
+
+ exp = (env->fp1h & 0x7fff) + scale;
+
+ env->fp0h = (env->fp1h & 0x8000) | (exp & 0x7fff);
+ env->fp0l = env->fp1l;
+ DBG_FPU(" = %Lg", floatx80_to_ldouble(FP0_to_floatx80(env)));
+}
+
+void HELPER(add_FP0_FP1)(CPUState *env)
+{
+ floatx80 res;
+
+ DBG_FPUH("add_FP0_FP1 %Lg %Lg", floatx80_to_ldouble(FP0_to_floatx80(env)),
+ floatx80_to_ldouble(FP1_to_floatx80(env)));
+ res = floatx80_add(FP0_to_floatx80(env), FP1_to_floatx80(env),
+ &env->fp_status);
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(sub_FP0_FP1)(CPUState *env)
+{
+ floatx80 res;
+
+ DBG_FPUH("sub_FP0 %Lg %Lg", floatx80_to_ldouble(FP0_to_floatx80(env)),
+ floatx80_to_ldouble(FP1_to_floatx80(env)));
+ res = floatx80_sub(FP1_to_floatx80(env), FP0_to_floatx80(env),
+ &env->fp_status);
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(mul_FP0_FP1)(CPUState *env)
+{
+ floatx80 res;
+
+ DBG_FPUH("mul_FP0_FP1 %Lg %Lg",
+ floatx80_to_ldouble(FP0_to_floatx80(env)),
floatx80_to_ldouble(FP1_to_floatx80(env)));
+ res = floatx80_mul(FP0_to_floatx80(env), FP1_to_floatx80(env),
+ &env->fp_status);
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(div_FP0_FP1)(CPUState *env)
+{
+ floatx80 res;
+
+ DBG_FPUH("div_FP0_FP1 %Lg %Lg",
+ floatx80_to_ldouble(FP0_to_floatx80(env)),
floatx80_to_ldouble(FP1_to_floatx80(env)));
+ res = floatx80_div(FP1_to_floatx80(env), FP0_to_floatx80(env),
+ &env->fp_status);
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(mod_FP0_FP1)(CPUState *env)
+{
+ floatx80 res;
+ long double src, dst;
+
+ src = floatx80_to_ldouble(FP0_to_floatx80(env));
+ dst = floatx80_to_ldouble(FP1_to_floatx80(env));
+
+ DBG_FPUH("mod_FP0_FP1 %Lg %Lg", src, dst);
+ dst = fmodl(dst, src);
+ DBG_FPU(" = %Lg\n", dst);
+
+ res = ldouble_to_floatx80(dst);
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(sincos_FP0_FP1)(CPUState *env)
+{
+ floatx80 res;
+ long double val, valsin, valcos;
+
+ res = FP0_to_floatx80(env);
+ val = floatx80_to_ldouble(res);
+
+ DBG_FPUH("sincos_FP0 %Lg", val);
+ sincosl(val, &valsin, &valcos);
+ DBG_FPU(" = %Lg, %Lg", valsin, valcos);
+ res = ldouble_to_floatx80(valsin);
+ floatx80_to_FP0(env, res);
+ res = ldouble_to_floatx80(valcos);
+ floatx80_to_FP1(env, res);
+}
+
+void HELPER(fcmp_FP0_FP1)(CPUState *env)
{
/* ??? This may incorrectly raise exceptions. */
/* ??? Should flush denormals to zero. */
- float64 res;
- res = float64_sub(a, b, &env->fp_status);
- if (float64_is_quiet_nan(res)) {
+ floatx80 res;
+ DBG_FPUH("cmp_FP0_FP1 %Lg %Lg", floatx80_to_ldouble(FP0_to_floatx80(env)),
+ floatx80_to_ldouble(FP1_to_floatx80(env)));
+ res = floatx80_sub(FP1_to_floatx80(env), FP0_to_floatx80(env),
+ &env->fp_status);
+ if (floatx80_is_any_nan(res)) {
/* +/-inf compares equal against itself, but sub returns nan. */
- if (!float64_is_quiet_nan(a)
- && !float64_is_quiet_nan(b)) {
- res = float64_zero;
- if (float64_lt_quiet(a, res, &env->fp_status))
- res = float64_chs(res);
+ if (!floatx80_is_any_nan(FP0_to_floatx80(env))
+ && !floatx80_is_any_nan(FP1_to_floatx80(env))) {
+ res = floatx80_zero;
+ if (floatx80_lt_quiet(FP1_to_floatx80(env), res, &env->fp_status))
+ res = floatx80_chs(res);
}
}
- return res;
+ DBG_FPU(" = %Lg\n", floatx80_to_ldouble(res));
+ floatx80_to_FP0(env, res);
}
-uint32_t HELPER(compare_f64)(CPUState *env, float64 val)
+uint32_t HELPER(compare_FP0)(CPUState *env)
{
- return float64_compare_quiet(val, float64_zero, &env->fp_status);
+ uint32_t res;
+
+ DBG_FPUH("compare_FP0 %Lg", floatx80_to_ldouble(FP0_to_floatx80(env)));
+ res = float64_compare_quiet(floatx80_to_float64(FP0_to_floatx80(env),
+ &env->fp_status),
+ float64_zero, &env->fp_status);
+ DBG_FPU(" = %d\n", res);
+ return res;
}
+void HELPER(fmovem)(CPUState *env, uint32_t opsize, uint32_t mode,
uint32_t mask)
+{
+ fprintf(stderr, "MISSING HELPER fmovem\n");
+}
/* MAC unit. */
/* FIXME: The MAC unit implementation is a bit of a mess. Some helpers
take values, others take register numbers and manipulate the contents
@@ -921,3 +2113,132 @@ void HELPER(set_mac_extu)(CPUState *env,
uint32_t val, uint32_t acc)
res |= (uint64_t)(val & 0xffff0000) << 16;
env->macc[acc + 1] = res;
}
+
+/* load from a bitfield */
+
+uint64_t HELPER(bitfield_load)(uint32_t addr, uint32_t offset, uint32_t width)
+{
+ uint8_t data[8];
+ uint64_t bitfield;
+ int size;
+ int i;
+
+ size = (offset + width + 7) >> 3;
+#if defined(CONFIG_USER_ONLY)
+ cpu_memory_rw_debug(NULL, (target_ulong)addr, data, size, 0);
+#else
+ cpu_physical_memory_rw(addr, data, size, 0);
+#endif
+
+ bitfield = data[0];
+ for (i = 1; i < 8; i++)
+ bitfield = (bitfield << 8) | data[i];
+
+ return bitfield;
+}
+
+/* store to a bitfield */
+
+void HELPER(bitfield_store)(uint32_t addr, uint32_t offset, uint32_t width,
+ uint64_t bitfield)
+{
+ uint8_t data[8];
+ int size;
+ int i;
+
+ size = (offset + width + 7) >> 3;
+
+ for (i = 0; i < 8; i++) {
+ data[7 - i] = bitfield;
+ bitfield >>= 8;
+ }
+
+#if defined(CONFIG_USER_ONLY)
+ cpu_memory_rw_debug(NULL, (target_ulong)addr, data, size, 1);
+#else
+ cpu_physical_memory_rw(addr, data, size, 1);
+#endif
+}
+
+uint32_t HELPER(abcd_cc)(CPUState *env, uint32_t src, uint32_t dest)
+{
+ uint16_t hi, lo;
+ uint16_t res;
+ uint32_t flags;
+
+ flags = env->cc_dest;
+ flags &= ~(CCF_C|CCF_X);
+
+ lo = (src & 0x0f) + (dest & 0x0f);
+ if (env->cc_x)
+ lo ++;
+ hi = (src & 0xf0) + (dest & 0xf0);
+
+ res = hi + lo;
+ if (lo > 9)
+ res += 0x06;
+
+ /* C and X flags: set if decimal carry, cleared otherwise */
+
+ if ((res & 0x3F0) > 0x90) {
+ res += 0x60;
+ flags |= CCF_C|CCF_X;
+ }
+
+ /* Z flag: cleared if nonzero */
+
+ if (res & 0xff)
+ flags &= ~CCF_Z;
+
+ dest = (dest & 0xffffff00) | (res & 0xff);
+
+ env->cc_x = (flags & CCF_X) != 0;
+ env->cc_dest = flags;
+
+ return dest;
+}
+
+uint32_t HELPER(sbcd_cc)(CPUState *env, uint32_t src, uint32_t dest)
+{
+ uint16_t hi, lo;
+ uint16_t res;
+ uint32_t flags;
+ int bcd = 0, carry = 0;
+
+ flags = env->cc_dest;
+ flags &= ~(CCF_C|CCF_X);
+
+ if (env->cc_x)
+ carry = 1;
+
+ lo = (dest & 0x0f) - (src & 0x0f) - carry;
+ hi = (dest & 0xf0) - (src & 0xf0);
+
+ res = hi + lo;
+ if (lo & 0xf0) {
+ res -= 0x06;
+ bcd = 0x06;
+ }
+
+ if ((((dest & 0xff) - (src & 0xff) - carry) & 0x100) > 0xff) {
+ res -= 0x60;
+ }
+
+ /* C and X flags: set if decimal carry, cleared otherwise */
+
+ if ((((dest & 0xff) - (src & 0xff) - (bcd + carry)) & 0x300) > 0xff) {
+ flags |= CCF_C|CCF_X;
+ }
+
+ /* Z flag: cleared if nonzero */
+
+ if (res & 0xff)
+ flags &= ~CCF_Z;
+
+ dest = (dest & 0xffffff00) | (res & 0xff);
+
+ env->cc_x = (flags & CCF_X) != 0;
+ env->cc_dest = flags;
+
+ return dest;
+}
diff --git target-m68k/helpers.h target-m68k/helpers.h
index cb8a0c7..d321874 100644
--- target-m68k/helpers.h
+++ target-m68k/helpers.h
@@ -2,33 +2,98 @@
DEF_HELPER_1(bitrev, i32, i32)
DEF_HELPER_1(ff1, i32, i32)
+DEF_HELPER_2(bfffo, i32, i32, i32)
+DEF_HELPER_2(rol32, i32, i32, i32)
+DEF_HELPER_2(ror32, i32, i32, i32)
DEF_HELPER_2(sats, i32, i32, i32)
DEF_HELPER_2(divu, void, env, i32)
DEF_HELPER_2(divs, void, env, i32)
-DEF_HELPER_3(addx_cc, i32, env, i32, i32)
-DEF_HELPER_3(subx_cc, i32, env, i32, i32)
-DEF_HELPER_3(shl_cc, i32, env, i32, i32)
-DEF_HELPER_3(shr_cc, i32, env, i32, i32)
-DEF_HELPER_3(sar_cc, i32, env, i32, i32)
-DEF_HELPER_2(xflag_lt, i32, i32, i32)
+DEF_HELPER_1(divu64, void, env)
+DEF_HELPER_1(divs64, void, env)
+DEF_HELPER_3(mulu32_cc, i32, env, i32, i32)
+DEF_HELPER_3(muls32_cc, i32, env, i32, i32)
+DEF_HELPER_3(mulu64, i32, env, i32, i32)
+DEF_HELPER_3(muls64, i32, env, i32, i32)
+DEF_HELPER_3(addx8_cc, i32, env, i32, i32)
+DEF_HELPER_3(addx16_cc, i32, env, i32, i32)
+DEF_HELPER_3(addx32_cc, i32, env, i32, i32)
+DEF_HELPER_3(subx8_cc, i32, env, i32, i32)
+DEF_HELPER_3(subx16_cc, i32, env, i32, i32)
+DEF_HELPER_3(subx32_cc, i32, env, i32, i32)
+DEF_HELPER_3(shl8_cc, i32, env, i32, i32)
+DEF_HELPER_3(shl16_cc, i32, env, i32, i32)
+DEF_HELPER_3(shl32_cc, i32, env, i32, i32)
+DEF_HELPER_3(shr8_cc, i32, env, i32, i32)
+DEF_HELPER_3(shr16_cc, i32, env, i32, i32)
+DEF_HELPER_3(shr32_cc, i32, env, i32, i32)
+DEF_HELPER_3(sal8_cc, i32, env, i32, i32)
+DEF_HELPER_3(sal16_cc, i32, env, i32, i32)
+DEF_HELPER_3(sal32_cc, i32, env, i32, i32)
+DEF_HELPER_3(sar8_cc, i32, env, i32, i32)
+DEF_HELPER_3(sar16_cc, i32, env, i32, i32)
+DEF_HELPER_3(sar32_cc, i32, env, i32, i32)
+DEF_HELPER_3(rol8_cc, i32, env, i32, i32)
+DEF_HELPER_3(rol16_cc, i32, env, i32, i32)
+DEF_HELPER_3(rol32_cc, i32, env, i32, i32)
+DEF_HELPER_3(ror8_cc, i32, env, i32, i32)
+DEF_HELPER_3(ror16_cc, i32, env, i32, i32)
+DEF_HELPER_3(ror32_cc, i32, env, i32, i32)
+DEF_HELPER_3(roxr8_cc, i32, env, i32, i32)
+DEF_HELPER_3(roxr16_cc, i32, env, i32, i32)
+DEF_HELPER_3(roxr32_cc, i32, env, i32, i32)
+DEF_HELPER_3(roxl8_cc, i32, env, i32, i32)
+DEF_HELPER_3(roxl16_cc, i32, env, i32, i32)
+DEF_HELPER_3(roxl32_cc, i32, env, i32, i32)
+DEF_HELPER_2(xflag_lt_i8, i32, i32, i32)
+DEF_HELPER_2(xflag_lt_i16, i32, i32, i32)
+DEF_HELPER_2(xflag_lt_i32, i32, i32, i32)
DEF_HELPER_2(set_sr, void, env, i32)
-DEF_HELPER_3(movec, void, env, i32, i32)
+DEF_HELPER_3(movec_to, void, env, i32, i32)
+DEF_HELPER_2(movec_from, i32, env, i32)
-DEF_HELPER_2(f64_to_i32, f32, env, f64)
-DEF_HELPER_2(f64_to_f32, f32, env, f64)
-DEF_HELPER_2(i32_to_f64, f64, env, i32)
-DEF_HELPER_2(f32_to_f64, f64, env, f32)
-DEF_HELPER_2(iround_f64, f64, env, f64)
-DEF_HELPER_2(itrunc_f64, f64, env, f64)
-DEF_HELPER_2(sqrt_f64, f64, env, f64)
-DEF_HELPER_1(abs_f64, f64, f64)
-DEF_HELPER_1(chs_f64, f64, f64)
-DEF_HELPER_3(add_f64, f64, env, f64, f64)
-DEF_HELPER_3(sub_f64, f64, env, f64, f64)
-DEF_HELPER_3(mul_f64, f64, env, f64, f64)
-DEF_HELPER_3(div_f64, f64, env, f64, f64)
-DEF_HELPER_3(sub_cmp_f64, f64, env, f64, f64)
-DEF_HELPER_2(compare_f64, i32, env, f64)
+DEF_HELPER_1(exts32_FP0, void, env)
+DEF_HELPER_1(extf32_FP0, void, env)
+DEF_HELPER_1(extf64_FP0, void, env)
+DEF_HELPER_1(redf32_FP0, void, env)
+DEF_HELPER_1(redf64_FP0, void, env)
+DEF_HELPER_1(extp96_FP0, void, env)
+DEF_HELPER_1(reds32_FP0, void, env)
+DEF_HELPER_1(redp96_FP0, void, env)
+
+DEF_HELPER_4(fmovem, void, env, i32, i32, i32)
+DEF_HELPER_2(set_fpcr, void, env, i32)
+DEF_HELPER_2(const_FP0, void, env, i32)
+DEF_HELPER_1(iround_FP0, void, env)
+DEF_HELPER_1(sinh_FP0, void, env)
+DEF_HELPER_1(itrunc_FP0, void, env)
+DEF_HELPER_1(sqrt_FP0, void, env)
+DEF_HELPER_1(lognp1_FP0, void, env)
+DEF_HELPER_1(atan_FP0, void, env)
+DEF_HELPER_1(asin_FP0, void, env)
+DEF_HELPER_1(atanh_FP0, void, env)
+DEF_HELPER_1(sin_FP0, void, env)
+DEF_HELPER_1(tanh_FP0, void, env)
+DEF_HELPER_1(tan_FP0, void, env)
+DEF_HELPER_1(exp_FP0, void, env)
+DEF_HELPER_1(exp2_FP0, void, env)
+DEF_HELPER_1(exp10_FP0, void, env)
+DEF_HELPER_1(ln_FP0, void, env)
+DEF_HELPER_1(log10_FP0, void, env)
+DEF_HELPER_1(abs_FP0, void, env)
+DEF_HELPER_1(cosh_FP0, void, env)
+DEF_HELPER_1(chs_FP0, void, env)
+DEF_HELPER_1(acos_FP0, void, env)
+DEF_HELPER_1(cos_FP0, void, env)
+DEF_HELPER_1(getexp_FP0, void, env)
+DEF_HELPER_1(scale_FP0_FP1, void, env)
+DEF_HELPER_1(add_FP0_FP1, void, env)
+DEF_HELPER_1(sub_FP0_FP1, void, env)
+DEF_HELPER_1(mul_FP0_FP1, void, env)
+DEF_HELPER_1(div_FP0_FP1, void, env)
+DEF_HELPER_1(mod_FP0_FP1, void, env)
+DEF_HELPER_1(sincos_FP0_FP1, void, env)
+DEF_HELPER_1(fcmp_FP0_FP1, void, env)
+DEF_HELPER_1(compare_FP0, i32, env)
DEF_HELPER_3(mac_move, void, env, i32, i32)
DEF_HELPER_3(macmulf, i64, env, i32, i32)
@@ -51,4 +116,9 @@ DEF_HELPER_3(set_mac_extu, void, env, i32, i32)
DEF_HELPER_2(flush_flags, void, env, i32)
DEF_HELPER_1(raise_exception, void, i32)
+DEF_HELPER_3(bitfield_load, i64, i32, i32, i32);
+DEF_HELPER_4(bitfield_store, void, i32, i32, i32, i64);
+
+DEF_HELPER_3(abcd_cc, i32, env, i32, i32);
+DEF_HELPER_3(sbcd_cc, i32, env, i32, i32);
#include "def-helper.h"
diff --git target-m68k/m68k-qreg.h target-m68k/m68k-qreg.h
deleted file mode 100644
index c224d5e..0000000
--- target-m68k/m68k-qreg.h
+++ /dev/null
@@ -1,11 +0,0 @@
-enum {
-#define DEFO32(name, offset) QREG_##name,
-#define DEFR(name, reg, mode) QREG_##name,
-#define DEFF64(name, offset) QREG_##name,
- QREG_NULL,
-#include "qregs.def"
- TARGET_NUM_QREGS = 0x100
-#undef DEFO32
-#undef DEFR
-#undef DEFF64
-};
diff --git target-m68k/op_helper.c target-m68k/op_helper.c
index c66fa0c..6c3144e 100644
--- target-m68k/op_helper.c
+++ target-m68k/op_helper.c
@@ -213,12 +213,18 @@ void HELPER(divu)(CPUState *env, uint32_t word)
/* Avoid using a PARAM1 of zero. This breaks dyngen because it uses
the address of a symbol, and gcc knows symbols can't have address
zero. */
- if (word && quot > 0xffff)
- flags |= CCF_V;
- if (quot == 0)
- flags |= CCF_Z;
- else if ((int32_t)quot < 0)
- flags |= CCF_N;
+ if (word && quot > 0xffff) {
+ /* real 68040 keep Z and N on overflow,
+ * whereas documentation says "undefined"
+ */
+ flags |= CCF_V | (env->cc_dest & (CCF_Z|CCF_N));
+ } else {
+ if (quot == 0)
+ flags |= CCF_Z;
+ else if ((int16_t)quot < 0)
+ flags |= CCF_N;
+ }
+
env->div1 = quot;
env->div2 = rem;
env->cc_dest = flags;
@@ -239,13 +245,148 @@ void HELPER(divs)(CPUState *env, uint32_t word)
quot = num / den;
rem = num % den;
flags = 0;
- if (word && quot != (int16_t)quot)
- flags |= CCF_V;
- if (quot == 0)
- flags |= CCF_Z;
- else if (quot < 0)
- flags |= CCF_N;
+ if (word && quot != (int16_t)quot) {
+ /* real 68040 keep Z and N on overflow,
+ * whereas documentation says "undefined"
+ */
+ flags |= CCF_V | (env->cc_dest & (CCF_Z|CCF_N));
+ } else {
+ if (quot == 0)
+ flags |= CCF_Z;
+ else if ((int16_t)quot < 0)
+ flags |= CCF_N;
+ }
+
env->div1 = quot;
env->div2 = rem;
env->cc_dest = flags;
}
+
+void HELPER(divu64)(CPUState *env)
+{
+ uint32_t num;
+ uint32_t den;
+ uint64_t quot;
+ uint32_t rem;
+ uint32_t flags;
+ uint64_t quad;
+
+ num = env->div1;
+ den = env->div2;
+ /* ??? This needs to make sure the throwing location is accurate. */
+ if (den == 0)
+ raise_exception(EXCP_DIV0);
+ quad = num | ((uint64_t)env->quadh << 32);
+ quot = quad / den;
+ rem = quad % den;
+ if (quot > 0xffffffffULL) {
+ flags = (env->cc_dest & ~ CCF_C) | CCF_V;
+ } else {
+ flags = 0;
+ if (quot == 0)
+ flags |= CCF_Z;
+ else if ((int32_t)quot < 0)
+ flags |= CCF_N;
+ env->div1 = quot;
+ env->quadh = rem;
+ }
+ env->cc_dest = flags;
+}
+
+void HELPER(divs64)(CPUState *env)
+{
+ uint32_t num;
+ int32_t den;
+ int64_t quot;
+ int32_t rem;
+ int32_t flags;
+ int64_t quad;
+
+ num = env->div1;
+ den = env->div2;
+ if (den == 0)
+ raise_exception(EXCP_DIV0);
+ quad = num | ((int64_t)env->quadh << 32);
+ quot = quad / (int64_t)den;
+ rem = quad % (int64_t)den;
+
+ if ((quot & 0xffffffff80000000ULL) &&
+ (quot & 0xffffffff80000000ULL) != 0xffffffff80000000ULL) {
+ flags = (env->cc_dest & ~ CCF_C) | CCF_V;
+ } else {
+ flags = 0;
+ if (quot == 0)
+ flags |= CCF_Z;
+ else if ((int32_t)quot < 0)
+ flags |= CCF_N;
+ env->div1 = quot;
+ env->quadh = rem;
+ }
+ env->cc_dest = flags;
+}
+
+uint32_t HELPER(mulu32_cc)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+ uint64_t res = (uint32_t)op1 * op2;
+ uint32_t flags;
+
+ flags = 0;
+ if (res >> 32)
+ flags |= CCF_V;
+ if ((uint32_t)res == 0)
+ flags |= CCF_Z;
+ if ((int32_t)res < 0)
+ flags |= CCF_N;
+ env->cc_dest = flags;
+
+ return res;
+}
+
+uint32_t HELPER(muls32_cc)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+ int64_t res = (int32_t)op1 * (int32_t)op2;
+ uint32_t flags;
+
+ flags = 0;
+ if (res != (int64_t)(int32_t)res)
+ flags |= CCF_V;
+ if ((uint32_t)res == 0)
+ flags |= CCF_Z;
+ if ((int32_t)res < 0)
+ flags |= CCF_N;
+ env->cc_dest = flags;
+
+ return res;
+}
+
+uint32_t HELPER(mulu64)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+ uint64_t res = (uint64_t)op1 * op2;
+ uint32_t flags;
+
+ env->quadh = res >> 32;
+ flags = 0;
+ if (res == 0)
+ flags |= CCF_Z;
+ if ((int64_t)res < 0)
+ flags |= CCF_N;
+ env->cc_dest = flags;
+
+ return res;
+}
+
+uint32_t HELPER(muls64)(CPUState *env, uint32_t op1, uint32_t op2)
+{
+ int64_t res = (uint64_t)(int32_t)op1 * (int32_t)op2;
+ uint32_t flags;
+
+ env->quadh = res >> 32;
+ flags = 0;
+ if (res == 0)
+ flags |= CCF_Z;
+ if (res < 0)
+ flags |= CCF_N;
+ env->cc_dest = flags;
+
+ return res;
+}
diff --git target-m68k/qregs.def target-m68k/qregs.def
index 49400c4..13a8e5c 100644
--- target-m68k/qregs.def
+++ target-m68k/qregs.def
@@ -1,4 +1,5 @@
-DEFF64(FP_RESULT, fp_result)
+DEFF96(FP0, fp0)
+DEFF96(FP1, fp1)
DEFO32(PC, pc)
DEFO32(SR, sr)
DEFO32(CC_OP, cc_op)
@@ -7,6 +8,7 @@ DEFO32(CC_SRC, cc_src)
DEFO32(CC_X, cc_x)
DEFO32(DIV1, div1)
DEFO32(DIV2, div2)
+DEFO32(QUADH, quadh)
DEFO32(EXCEPTION, exception_index)
DEFO32(HALTED, halted)
DEFO32(MACSR, macsr)
diff --git target-m68k/translate.c target-m68k/translate.c
index 0e7f1fe..e2c88fc 100644
--- target-m68k/translate.c
+++ target-m68k/translate.c
@@ -29,36 +29,34 @@
#include "tcg-op.h"
#include "qemu-log.h"
+#include "sysemu.h"
+
#include "helpers.h"
#define GEN_HELPER 1
#include "helpers.h"
//#define DEBUG_DISPATCH 1
-/* Fake floating point. */
-#define tcg_gen_mov_f64 tcg_gen_mov_i64
-#define tcg_gen_qemu_ldf64 tcg_gen_qemu_ld64
-#define tcg_gen_qemu_stf64 tcg_gen_qemu_st64
-
#define DEFO32(name, offset) static TCGv QREG_##name;
#define DEFO64(name, offset) static TCGv_i64 QREG_##name;
-#define DEFF64(name, offset) static TCGv_i64 QREG_##name;
+#define DEFF96(name, offset) static TCGv_i32 QREG_##name##H; static
TCGv_i64 QREG_##name##L;
#include "qregs.def"
#undef DEFO32
#undef DEFO64
-#undef DEFF64
+#undef DEFF96
static TCGv_ptr cpu_env;
-static char cpu_reg_names[3*8*3 + 5*4];
+static char cpu_reg_names[2*8*3 + 5*4];
static TCGv cpu_dregs[8];
static TCGv cpu_aregs[8];
-static TCGv_i64 cpu_fregs[8];
static TCGv_i64 cpu_macc[4];
+static TCGv QEMU_FPSR;
+static TCGv QEMU_FPCR;
-#define DREG(insn, pos) cpu_dregs[((insn) >> (pos)) & 7]
-#define AREG(insn, pos) cpu_aregs[((insn) >> (pos)) & 7]
-#define FREG(insn, pos) cpu_fregs[((insn) >> (pos)) & 7]
+#define REG(insn, pos) (((insn) >> (pos)) & 7)
+#define DREG(insn, pos) cpu_dregs[REG(insn, pos)]
+#define AREG(insn, pos) cpu_aregs[REG(insn, pos)]
#define MACREG(acc) cpu_macc[acc]
#define QREG_SP cpu_aregs[7]
@@ -76,11 +74,14 @@ void m68k_tcg_init(void)
#define DEFO32(name, offset) QREG_##name =
tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState, offset), #name);
#define DEFO64(name, offset) QREG_##name =
tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState, offset), #name);
-#define DEFF64(name, offset) DEFO64(name, offset)
+#define DEFF96(name, offset) do { \
+QREG_##name##H = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUState,
offset##h), #name); \
+QREG_##name##L = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUState,
offset##l), #name); \
+} while (0);
#include "qregs.def"
#undef DEFO32
#undef DEFO64
-#undef DEFF64
+#undef DEFF96
cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
@@ -94,10 +95,6 @@ void m68k_tcg_init(void)
cpu_aregs[i] = tcg_global_mem_new(TCG_AREG0,
offsetof(CPUM68KState, aregs[i]), p);
p += 3;
- sprintf(p, "F%d", i);
- cpu_fregs[i] = tcg_global_mem_new_i64(TCG_AREG0,
- offsetof(CPUM68KState, fregs[i]), p);
- p += 3;
}
for (i = 0; i < 4; i++) {
sprintf(p, "ACC%d", i);
@@ -106,6 +103,11 @@ void m68k_tcg_init(void)
p += 5;
}
+ QEMU_FPSR = tcg_global_mem_new(TCG_AREG0, offsetof(CPUM68KState, fpsr),
+ "FPSR");
+ QEMU_FPCR = tcg_global_mem_new(TCG_AREG0, offsetof(CPUM68KState, fpcr),
+ "FPCR");
+
NULL_QREG = tcg_global_mem_new(TCG_AREG0, -4, "NULL");
store_dummy = tcg_global_mem_new(TCG_AREG0, -8, "NULL");
@@ -150,11 +152,13 @@ typedef struct DisasContext {
static void *gen_throws_exception;
#define gen_last_qop NULL
-#define OS_BYTE 0
-#define OS_WORD 1
-#define OS_LONG 2
-#define OS_SINGLE 4
-#define OS_DOUBLE 5
+#define OS_BYTE 1
+#define OS_WORD 2
+#define OS_LONG 3
+#define OS_SINGLE 4
+#define OS_DOUBLE 5
+#define OS_EXTENDED 6
+#define OS_PACKED 7
typedef void (*disas_proc)(DisasContext *, uint16_t);
@@ -170,6 +174,81 @@ typedef void (*disas_proc)(DisasContext *, uint16_t);
static void disas_##name (DisasContext *s, uint16_t insn)
#endif
+/* Update the CPU env CC_OP state. */
+static inline void gen_flush_cc_op(DisasContext *s)
+{
+ if (s->cc_op != CC_OP_DYNAMIC)
+ tcg_gen_movi_i32(QREG_CC_OP, s->cc_op);
+}
+
+
+/* Generate a jump to an immediate address. */
+static void gen_jmp_im(DisasContext *s, uint32_t dest)
+{
+ gen_flush_cc_op(s);
+ tcg_gen_movi_i32(QREG_PC, dest);
+ s->is_jmp = DISAS_JUMP;
+}
+
+static void gen_exception(DisasContext *s, uint32_t where, int nr)
+{
+ if(((where &0xFFF0) != 0x24F0) && ((where &0xFF00) != 0x5100))
+// fprintf(stderr,"Exception! %x @ 0x%X 0x%X\n",nr,where,s->pc);
+// vm_stop(VMSTOP_DEBUG);
+gen_flush_cc_op(s);
+ if(nr == 0x10002)
+ gen_jmp_im(s,where);
+// else
+// gen_jmp_im(s, s->env->vbr + nr*4);
+ gen_helper_raise_exception(tcg_const_i32(nr));
+}
+
+static inline void gen_addr_fault(DisasContext *s)
+{
+ fprintf(stderr,"address fault\n");
+ gen_exception(s, s->insn_pc, EXCP_ADDRESS);
+}
+
+static void gen_op_load_fpr_FP0(int freg)
+{
+ tcg_gen_ld16u_i32(QREG_FP0H, cpu_env,
+ offsetof(CPUM68KState, fregs[freg]) +
+ offsetof(FPReg, d.high));
+ tcg_gen_ld_i64(QREG_FP0L, cpu_env,
+ offsetof(CPUM68KState, fregs[freg]) +
+ offsetof(FPReg, d.low));
+}
+
+static void gen_op_store_fpr_FP0(int freg)
+{
+ tcg_gen_st16_i32(QREG_FP0H, cpu_env,
+ offsetof(CPUM68KState, fregs[freg]) +
+ offsetof(FPReg, d.high));
+ tcg_gen_st_i64(QREG_FP0L, cpu_env,
+ offsetof(CPUM68KState, fregs[freg]) +
+ offsetof(FPReg, d.low));
+}
+
+static void gen_op_store_fpr_FP1(int freg)
+{
+ tcg_gen_st16_i32(QREG_FP1H, cpu_env,
+ offsetof(CPUM68KState, fregs[freg]) +
+ offsetof(FPReg, d.high));
+ tcg_gen_st_i64(QREG_FP1L, cpu_env,
+ offsetof(CPUM68KState, fregs[freg]) +
+ offsetof(FPReg, d.low));
+}
+
+static void gen_op_load_fpr_FP1(int freg)
+{
+ tcg_gen_ld16u_i32(QREG_FP1H, cpu_env,
+ offsetof(CPUM68KState, fregs[freg]) +
+ offsetof(FPReg, d.high));
+ tcg_gen_ld_i64(QREG_FP1L, cpu_env,
+ offsetof(CPUM68KState, fregs[freg]) +
+ offsetof(FPReg, d.low));
+}
+
/* Generate a load from the specified address. Narrow values are
sign extended to full register width. */
static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
@@ -192,7 +271,6 @@ static inline TCGv gen_load(DisasContext * s, int
opsize, TCGv addr, int sign)
tcg_gen_qemu_ld16u(tmp, addr, index);
break;
case OS_LONG:
- case OS_SINGLE:
tcg_gen_qemu_ld32u(tmp, addr, index);
break;
default:
@@ -202,17 +280,6 @@ static inline TCGv gen_load(DisasContext * s, int
opsize, TCGv addr, int sign)
return tmp;
}
-static inline TCGv_i64 gen_load64(DisasContext * s, TCGv addr)
-{
- TCGv_i64 tmp;
- int index = IS_USER(s);
- s->is_mem = 1;
- tmp = tcg_temp_new_i64();
- tcg_gen_qemu_ldf64(tmp, addr, index);
- gen_throws_exception = gen_last_qop;
- return tmp;
-}
-
/* Generate a store. */
static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val)
{
@@ -226,7 +293,6 @@ static inline void gen_store(DisasContext *s, int
opsize, TCGv addr, TCGv val)
tcg_gen_qemu_st16(val, addr, index);
break;
case OS_LONG:
- case OS_SINGLE:
tcg_gen_qemu_st32(val, addr, index);
break;
default:
@@ -235,14 +301,6 @@ static inline void gen_store(DisasContext *s, int
opsize, TCGv addr, TCGv val)
gen_throws_exception = gen_last_qop;
}
-static inline void gen_store64(DisasContext *s, TCGv addr, TCGv_i64 val)
-{
- int index = IS_USER(s);
- s->is_mem = 1;
- tcg_gen_qemu_stf64(val, addr, index);
- gen_throws_exception = gen_last_qop;
-}
-
typedef enum {
EA_STORE,
EA_LOADU,
@@ -262,16 +320,39 @@ static TCGv gen_ldst(DisasContext *s, int
opsize, TCGv addr, TCGv val,
}
}
-/* Read a 32-bit immediate constant. */
-static inline uint32_t read_im32(DisasContext *s)
+/* Read an 8-bit immediate constant */
+static inline uint32_t read_im8(DisasContext *s)
{
uint32_t im;
- im = ((uint32_t)lduw_code(s->pc)) << 16;
+ im = ldsb_code(s->pc + 1);
s->pc += 2;
- im |= lduw_code(s->pc);
+ return im;
+}
+/* Read a 16-bit immediate constant */
+static inline uint32_t read_im16(DisasContext *s)
+{
+ uint32_t im;
+ im = ldsw_code(s->pc);
s->pc += 2;
return im;
}
+/* Read a 32-bit immediate constant. */
+static inline uint32_t read_im32(DisasContext *s)
+{
+ uint32_t im;
+ im = read_im16(s) << 16;
+ im |= 0xffff & read_im16(s);
+ return im;
+}
+
+/* Read a 64-bit immediate constant. */
+static inline uint64_t read_im64(DisasContext *s)
+{
+ uint64_t im;
+ im = (uint64_t)read_im32(s) << 32;
+ im |= (uint64_t)read_im32(s);
+ return im;
+}
/* Calculate and address index. */
static TCGv gen_addr_index(uint16_t ext, TCGv tmp)
@@ -309,6 +390,9 @@ static TCGv gen_lea_indexed(DisasContext *s, int
opsize, TCGv base)
if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX))
return NULL_QREG;
+ if (!m68k_feature(s->env, M68K_FEATURE_SCALED_INDEX))
+ ext &= ~(3 << 9);
+
if (ext & 0x100) {
/* full extension word format */
if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL))
@@ -317,7 +401,7 @@ static TCGv gen_lea_indexed(DisasContext *s, int
opsize, TCGv base)
if ((ext & 0x30) > 0x10) {
/* base displacement */
if ((ext & 0x30) == 0x20) {
- bd = (int16_t)lduw_code(s->pc);
+ bd = ldsw_code(s->pc);
s->pc += 2;
} else {
bd = read_im32(s);
@@ -366,7 +450,7 @@ static TCGv gen_lea_indexed(DisasContext *s, int
opsize, TCGv base)
if ((ext & 3) > 1) {
/* outer displacement */
if ((ext & 3) == 2) {
- od = (int16_t)lduw_code(s->pc);
+ od = ldsw_code(s->pc);
s->pc += 2;
} else {
od = read_im32(s);
@@ -395,13 +479,6 @@ static TCGv gen_lea_indexed(DisasContext *s, int
opsize, TCGv base)
return add;
}
-/* Update the CPU env CC_OP state. */
-static inline void gen_flush_cc_op(DisasContext *s)
-{
- if (s->cc_op != CC_OP_DYNAMIC)
- tcg_gen_movi_i32(QREG_CC_OP, s->cc_op);
-}
-
/* Evaluate all the CC flags. */
static inline void gen_flush_flags(DisasContext *s)
{
@@ -412,10 +489,28 @@ static inline void gen_flush_flags(DisasContext *s)
s->cc_op = CC_OP_FLAGS;
}
-static void gen_logic_cc(DisasContext *s, TCGv val)
+#define SET_CC_OP(opsize, op) do { \
+ switch (opsize) { \
+ case OS_BYTE: s->cc_op = CC_OP_##op##B; break; \
+ case OS_WORD: s->cc_op = CC_OP_##op##W; break; \
+ case OS_LONG: s->cc_op = CC_OP_##op; break; \
+ default: abort(); \
+ } \
+} while (0)
+
+#define SET_X_FLAG(opsize, a, b) do { \
+ switch (opsize) { \
+ case OS_BYTE: gen_helper_xflag_lt_i8(QREG_CC_X, a, b); break; \
+ case OS_WORD: gen_helper_xflag_lt_i16(QREG_CC_X, a, b); break; \
+ case OS_LONG: gen_helper_xflag_lt_i32(QREG_CC_X, a, b); break; \
+ default: abort(); \
+ } \
+} while (0)
+
+static void gen_logic_cc(DisasContext *s, TCGv val, int opsize)
{
tcg_gen_mov_i32(QREG_CC_DEST, val);
- s->cc_op = CC_OP_LOGIC;
+ SET_CC_OP(opsize, LOGIC);
}
static void gen_update_cc_add(TCGv dest, TCGv src)
@@ -432,12 +527,38 @@ static inline int opsize_bytes(int opsize)
case OS_LONG: return 4;
case OS_SINGLE: return 4;
case OS_DOUBLE: return 8;
+ case OS_EXTENDED: return 12;
+ case OS_PACKED: return 12;
default:
qemu_assert(0, "bad operand size");
return 0;
}
}
+static inline int insn_opsize(int insn, int pos)
+{
+ switch ((insn >> pos) & 3) {
+ case 0: return OS_BYTE;
+ case 1: return OS_WORD;
+ case 2: return OS_LONG;
+ default: abort();
+ }
+}
+
+static inline int ext_opsize(int ext, int pos)
+{
+ switch ((ext >> pos) & 7) {
+ case 0: return OS_LONG;
+ case 1: return OS_SINGLE;
+ case 2: return OS_EXTENDED;
+ case 3: return OS_PACKED;
+ case 4: return OS_WORD;
+ case 5: return OS_DOUBLE;
+ case 6: return OS_BYTE;
+ default: abort();
+ }
+}
+
/* Assign value to a register. If the width is less than the register width
only the low part of the register is set. */
static void gen_partset_reg(int opsize, TCGv reg, TCGv val)
@@ -487,7 +608,6 @@ static inline TCGv gen_extend(TCGv val, int
opsize, int sign)
tcg_gen_ext16u_i32(tmp, val);
break;
case OS_LONG:
- case OS_SINGLE:
tmp = val;
break;
default:
@@ -520,8 +640,7 @@ static TCGv gen_lea(DisasContext *s, uint16_t
insn, int opsize)
case 5: /* Indirect displacement. */
reg = AREG(insn, 0);
tmp = tcg_temp_new();
- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);
tcg_gen_addi_i32(tmp, reg, (int16_t)ext);
return tmp;
case 6: /* Indirect index + displacement. */
@@ -672,6 +791,294 @@ static TCGv gen_ea(DisasContext *s, uint16_t
insn, int opsize, TCGv val,
return NULL_QREG;
}
+static inline void gen_extend_FP0(int opsize)
+{
+ switch (opsize) {
+ case OS_BYTE:
+ tcg_gen_ext8s_i32(QREG_FP0H, QREG_FP0H);
+ gen_helper_exts32_FP0(cpu_env);
+ break;
+ case OS_WORD:
+ tcg_gen_ext16s_i32(QREG_FP0H, QREG_FP0H);
+ gen_helper_exts32_FP0(cpu_env);
+ break;
+ case OS_LONG:
+ gen_helper_exts32_FP0(cpu_env);
+ break;
+ case OS_SINGLE:
+ gen_helper_extf32_FP0(cpu_env);
+ break;
+ case OS_DOUBLE:
+ gen_helper_extf64_FP0(cpu_env);
+ break;
+ case OS_EXTENDED:
+ tcg_gen_shri_i32(QREG_FP0H, QREG_FP0H, 16);
+ break;
+ case OS_PACKED:
+ gen_helper_extp96_FP0(cpu_env);
+ break;
+ default:
+ qemu_assert(0, "FPU: Bad operand size");
+ }
+}
+
+static inline void gen_reduce_FP0(int opsize)
+{
+ switch (opsize) {
+ case OS_BYTE:
+ case OS_WORD:
+ case OS_LONG:
+ gen_helper_reds32_FP0(cpu_env);
+ break;
+ case OS_SINGLE:
+ gen_helper_redf32_FP0(cpu_env);
+ break;
+ case OS_DOUBLE:
+ gen_helper_redf64_FP0(cpu_env);
+ break;
+ case OS_EXTENDED:
+ tcg_gen_shli_i32(QREG_FP0H, QREG_FP0H, 16);
+ break;
+ case OS_PACKED:
+ gen_helper_redp96_FP0(cpu_env);
+ break;
+ default:
+ qemu_assert(0, "FPU: Bad operand size");
+ }
+}
+
+static inline void gen_load_FP0(DisasContext * s, int opsize, TCGv addr)
+{
+ TCGv tmp;
+ int index = IS_USER(s);
+ s->is_mem = 1;
+ switch(opsize) {
+ case OS_BYTE:
+ tcg_gen_qemu_ld8s(QREG_FP0H, addr, index);
+ gen_helper_exts32_FP0(cpu_env);
+ break;
+ case OS_WORD:
+ tcg_gen_qemu_ld16s(QREG_FP0H, addr, index);
+ gen_helper_exts32_FP0(cpu_env);
+ break;
+ case OS_LONG:
+ tcg_gen_qemu_ld32u(QREG_FP0H, addr, index);
+ gen_helper_exts32_FP0(cpu_env);
+ break;
+ case OS_SINGLE:
+ tcg_gen_qemu_ld32u(QREG_FP0H, addr, index);
+ gen_helper_extf32_FP0(cpu_env);
+ break;
+ case OS_DOUBLE:
+ tcg_gen_qemu_ld64(QREG_FP0L, addr, index);
+ gen_helper_extf64_FP0(cpu_env);
+ break;
+ case OS_EXTENDED:
+ tcg_gen_qemu_ld32u(QREG_FP0H, addr, index);
+ tcg_gen_shri_i32(QREG_FP0H, QREG_FP0H, 16);
+ tmp = tcg_temp_new();
+ tcg_gen_addi_i32(tmp, addr, 4);
+ tcg_gen_qemu_ld64(QREG_FP0L, tmp, index);
+ tcg_temp_free(tmp);
+ break;
+ case OS_PACKED:
+ tcg_gen_qemu_ld32u(QREG_FP0H, addr, index);
+ tmp = tcg_temp_new();
+ tcg_gen_addi_i32(tmp, addr, 4);
+ tcg_gen_qemu_ld64(QREG_FP0L, tmp, index);
+ tcg_temp_free(tmp);
+ gen_helper_extp96_FP0(cpu_env);
+ break;
+ default:
+ qemu_assert(0, "Bad operand size");
+ }
+ gen_throws_exception = gen_last_qop;
+}
+
+static inline void gen_store_FP0(DisasContext *s, int opsize, TCGv addr)
+{
+ TCGv tmp;
+ int index = IS_USER(s);
+ s->is_mem = 1;
+ switch(opsize) {
+ case OS_BYTE:
+ gen_helper_reds32_FP0(cpu_env);
+ tcg_gen_qemu_st8(QREG_FP0H, addr, index);
+ break;
+ case OS_WORD:
+ gen_helper_reds32_FP0(cpu_env);
+ tcg_gen_qemu_st16(QREG_FP0H, addr, index);
+ break;
+ case OS_LONG:
+ gen_helper_reds32_FP0(cpu_env);
+ tcg_gen_qemu_st32(QREG_FP0H, addr, index);
+ break;
+ case OS_SINGLE:
+ gen_helper_redf32_FP0(cpu_env);
+ tcg_gen_qemu_st32(QREG_FP0H, addr, index);
+ break;
+ case OS_DOUBLE:
+ gen_helper_redf64_FP0(cpu_env);
+ tcg_gen_qemu_st64(QREG_FP0L, addr, index);
+ break;
+ case OS_EXTENDED:
+ tcg_gen_shli_i32(QREG_FP0H, QREG_FP0H, 16);
+ tcg_gen_qemu_st32(QREG_FP0H, addr, index);
+ tmp = tcg_temp_new();
+ tcg_gen_addi_i32(tmp, addr, 4);
+ tcg_gen_qemu_st64(QREG_FP0L, tmp, index);
+ tcg_temp_free(tmp);
+ break;
+ case OS_PACKED:
+ gen_helper_redp96_FP0(cpu_env);
+ tcg_gen_qemu_st32(QREG_FP0H, addr, index);
+ tmp = tcg_temp_new();
+ tcg_gen_addi_i32(tmp, addr, 4);
+ tcg_gen_qemu_st64(QREG_FP0L, tmp, index);
+ tcg_temp_free(tmp);
+ break;
+ default:
+ qemu_assert(0, "Bad operand size");
+ }
+ gen_throws_exception = gen_last_qop;
+}
+
+static void gen_op_load_ea_FP0(DisasContext *s, uint16_t insn, int opsize)
+{
+ TCGv reg;
+ TCGv addr;
+ uint64_t val;
+
+ switch ((insn >> 3) & 7) {
+ case 0: /* Data register direct. */
+ tcg_gen_mov_i32(QREG_FP0H, DREG(insn, 0));
+ gen_extend_FP0(opsize);
+ break;
+ case 1: /* Address register direct. */
+ gen_addr_fault(s);
+ break;
+ case 2: /* Indirect register */
+ gen_load_FP0(s, opsize, AREG(insn, 0));
+ break;
+ case 3: /* Indirect postincrement. */
+ reg = AREG(insn, 0);
+ gen_load_FP0(s, opsize, reg);
+ tcg_gen_addi_i32(reg, reg, opsize_bytes(opsize));
+ break;
+ case 4: /* Indirect predecrememnt. */
+ addr = gen_lea(s, insn, opsize);
+ gen_load_FP0(s, opsize, addr);
+ tcg_gen_mov_i32(AREG(insn, 0), addr);
+ break;
+ case 5: /* Indirect displacement. */
+ case 6: /* Indirect index + displacement. */
+ addr = gen_lea(s, insn, opsize);
+ gen_load_FP0(s, opsize, addr);
+ break;
+ case 7: /* Other */
+ switch (insn & 7) {
+ case 0: /* Absolute short. */
+ case 1: /* Absolute long. */
+ case 2: /* pc displacement */
+ case 3: /* pc index+displacement. */
+ addr = gen_lea(s, insn, opsize);
+ gen_load_FP0(s, opsize, addr);
+ break;
+ case 4: /* Immediate. */
+ switch (opsize) {
+ case OS_BYTE:
+ val = read_im8(s);
+ tcg_gen_movi_i32(QREG_FP0H, val);
+ break;
+ case OS_WORD:
+ val = read_im16(s);
+ tcg_gen_movi_i32(QREG_FP0H, val);
+ break;
+ case OS_LONG:
+ val = read_im32(s);
+ tcg_gen_movi_i32(QREG_FP0H, val);
+ break;
+ case OS_SINGLE:
+ val = read_im32(s);
+ tcg_gen_movi_i32(QREG_FP0H, val);
+ break;
+ case OS_DOUBLE:
+ val = read_im64(s);
+ tcg_gen_movi_i64(QREG_FP0L, val);
+ break;
+ case OS_EXTENDED:
+ val = read_im32(s);
+ tcg_gen_movi_i32(QREG_FP0H, val);
+ val = read_im64(s);
+ tcg_gen_movi_i64(QREG_FP0L, val);
+ break;
+ case OS_PACKED:
+ val = read_im32(s);
+ tcg_gen_movi_i32(QREG_FP0H, val);
+ val = read_im64(s);
+ tcg_gen_movi_i64(QREG_FP0L, val);
+ break;
+ default:
+ qemu_assert(0, "Bad immediate operand");
+ }
+ gen_extend_FP0(opsize);
+ break;
+ default:
+ qemu_assert(0, "Bad FP addressing mode");
+ }
+ }
+}
+
+static void gen_op_store_ea_FP0(DisasContext *s, uint16_t insn, int opsize)
+{
+ TCGv reg;
+ TCGv addr;
+
+ switch ((insn >> 3) & 7) {
+ case 0: /* Data register direct. */
+ gen_reduce_FP0(opsize);
+ tcg_gen_mov_i32(DREG(insn, 0), QREG_FP0H);
+ break;
+ case 1: /* Address register direct. */
+ gen_addr_fault(s);
+ break;
+ case 2: /* Indirect register */
+ reg = AREG(insn, 0);
+ gen_store_FP0(s, opsize, reg);
+ break;
+ case 3: /* Indirect postincrement. */
+ reg = AREG(insn, 0);
+ gen_store_FP0(s, opsize, reg);
+ tcg_gen_addi_i32(reg, reg, opsize_bytes(opsize));
+ break;
+ case 4: /* Indirect predecrememnt. */
+ addr = gen_lea(s, insn, opsize);
+ gen_store_FP0(s, opsize, addr);
+ tcg_gen_mov_i32(AREG(insn, 0), addr);
+ break;
+ case 5: /* Indirect displacement. */
+ case 6: /* Indirect index + displacement. */
+ addr = gen_lea(s, insn, opsize);
+ gen_store_FP0(s, opsize, addr);
+ break;
+ case 7: /* Other */
+ switch (insn & 7) {
+ case 0: /* Absolute short. */
+ case 1: /* Absolute long. */
+ addr = gen_lea(s, insn, opsize);
+ gen_store_FP0(s, opsize, addr);
+ break;
+ case 2: /* pc displacement */
+ case 3: /* pc index+displacement. */
+ case 4: /* Immediate. */
+ gen_addr_fault(s);
+ break;
+ default:
+ qemu_assert(0, "Bad FP addressing mode");
+ }
+ }
+}
+
/* This generates a conditional branch, clobbering all temporaries. */
static void gen_jmpcc(DisasContext *s, int cond, int l1)
{
@@ -801,14 +1208,6 @@ static void gen_lookup_tb(DisasContext *s)
s->is_jmp = DISAS_UPDATE;
}
-/* Generate a jump to an immediate address. */
-static void gen_jmp_im(DisasContext *s, uint32_t dest)
-{
- gen_flush_cc_op(s);
- tcg_gen_movi_i32(QREG_PC, dest);
- s->is_jmp = DISAS_JUMP;
-}
-
/* Generate a jump to the address in qreg DEST. */
static void gen_jmp(DisasContext *s, TCGv dest)
{
@@ -817,18 +1216,6 @@ static void gen_jmp(DisasContext *s, TCGv dest)
s->is_jmp = DISAS_JUMP;
}
-static void gen_exception(DisasContext *s, uint32_t where, int nr)
-{
- gen_flush_cc_op(s);
- gen_jmp_im(s, where);
- gen_helper_raise_exception(tcg_const_i32(nr));
-}
-
-static inline void gen_addr_fault(DisasContext *s)
-{
- gen_exception(s, s->insn_pc, EXCP_ADDRESS);
-}
-
#define SRC_EA(result, opsize, op_sign, addrp) do { \
result = gen_ea(s, insn, opsize, NULL_QREG, addrp, op_sign ?
EA_LOADS : EA_LOADU); \
if (IS_NULL_QREG(result)) { \
@@ -865,6 +1252,48 @@ static void gen_jmp_tb(DisasContext *s, int n,
uint32_t dest)
s->is_jmp = DISAS_TB_JUMP;
}
+DISAS_INSN(scc_mem)
+{
+ int l1;
+ int cond;
+ TCGv dest;
+
+ l1 = gen_new_label();
+ cond = (insn >> 8) & 0xf;
+ dest = tcg_temp_local_new();
+ tcg_gen_movi_i32(dest, 0);
+ gen_jmpcc(s, cond ^ 1, l1);
+ tcg_gen_movi_i32(dest, 0xff);
+ gen_set_label(l1);
+ DEST_EA(insn, OS_BYTE, dest, NULL);
+ tcg_temp_free(dest);
+}
+
+DISAS_INSN(dbcc)
+{
+ int l1;
+ TCGv reg;
+ TCGv tmp;
+ int16_t offset;
+ uint32_t base;
+
+ reg = DREG(insn, 0);
+ base = s->pc;
+ offset = ldsw_code(s->pc);
+ s->pc += 2;
+ l1 = gen_new_label();
+ gen_jmpcc(s, (insn >> 8) & 0xf, l1);
+
+ tmp = tcg_temp_new();
+ tcg_gen_ext16s_i32(tmp, reg);
+ tcg_gen_addi_i32(tmp, tmp, -1);
+ gen_partset_reg(OS_WORD, reg, tmp);
+ tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, -1, l1);
+ gen_jmp_tb(s, 1, base + offset);
+ gen_set_label(l1);
+ gen_jmp_tb(s, 0, s->pc);
+}
+
DISAS_INSN(undef_mac)
{
gen_exception(s, s->pc - 2, EXCP_LINEA);
@@ -899,38 +1328,45 @@ DISAS_INSN(mulw)
SRC_EA(src, OS_WORD, sign, NULL);
tcg_gen_mul_i32(tmp, tmp, src);
tcg_gen_mov_i32(reg, tmp);
- /* Unlike m68k, coldfire always clears the overflow bit. */
- gen_logic_cc(s, tmp);
+ gen_logic_cc(s, tmp, OS_WORD);
}
DISAS_INSN(divw)
{
- TCGv reg;
+ TCGv dest;
TCGv tmp;
TCGv src;
int sign;
+ int l1;
sign = (insn & 0x100) != 0;
- reg = DREG(insn, 9);
- if (sign) {
- tcg_gen_ext16s_i32(QREG_DIV1, reg);
- } else {
- tcg_gen_ext16u_i32(QREG_DIV1, reg);
- }
+
+ /* dest.l / src.w */
+
+ dest = DREG(insn, 9);
+ tcg_gen_mov_i32(QREG_DIV1, dest);
+
SRC_EA(src, OS_WORD, sign, NULL);
tcg_gen_mov_i32(QREG_DIV2, src);
+
+ /* div1 / div2 */
+
if (sign) {
gen_helper_divs(cpu_env, tcg_const_i32(1));
} else {
gen_helper_divu(cpu_env, tcg_const_i32(1));
}
+ s->cc_op = CC_OP_FLAGS;
+
+ l1 = gen_new_label();
+ gen_jmpcc(s, 9 /* V */, l1);
tmp = tcg_temp_new();
src = tcg_temp_new();
tcg_gen_ext16u_i32(tmp, QREG_DIV1);
tcg_gen_shli_i32(src, QREG_DIV2, 16);
- tcg_gen_or_i32(reg, tmp, src);
- s->cc_op = CC_OP_FLAGS;
+ tcg_gen_or_i32(dest, tmp, src);
+ gen_set_label(l1);
}
DISAS_INSN(divl)
@@ -940,10 +1376,27 @@ DISAS_INSN(divl)
TCGv reg;
uint16_t ext;
- ext = lduw_code(s->pc);
- s->pc += 2;
- if (ext & 0x87f8) {
- gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+ ext = read_im16(s);
+ if (ext & 0x400) {
+ if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
+ gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+ return;
+ }
+ num = DREG(ext, 12);
+ reg = DREG(ext, 0);
+ tcg_gen_mov_i32(QREG_DIV1, num);
+ tcg_gen_mov_i32(QREG_QUADH, reg);
+ SRC_EA(den, OS_LONG, 0, NULL);
+ tcg_gen_mov_i32(QREG_DIV2, den);
+ if (ext & 0x0800) {
+ gen_helper_divs64(cpu_env);
+ } else {
+ gen_helper_divu64(cpu_env);
+ }
+ tcg_gen_mov_i32(num, QREG_DIV1);
+ if (!TCGV_EQUAL(num, reg))
+ tcg_gen_mov_i32(reg, QREG_QUADH);
+ s->cc_op = CC_OP_FLAGS;
return;
}
num = DREG(ext, 12);
@@ -956,16 +1409,90 @@ DISAS_INSN(divl)
} else {
gen_helper_divu(cpu_env, tcg_const_i32(0));
}
- if ((ext & 7) == ((ext >> 12) & 7)) {
+ if (TCGV_EQUAL(num, reg) ||
+ m68k_feature(s->env, M68K_FEATURE_LONG_MULDIV)) {
/* div */
- tcg_gen_mov_i32 (reg, QREG_DIV1);
- } else {
+ tcg_gen_mov_i32 (num, QREG_DIV1);
+ }
+ if (!TCGV_EQUAL(num, reg)) {
/* rem */
tcg_gen_mov_i32 (reg, QREG_DIV2);
}
s->cc_op = CC_OP_FLAGS;
}
+DISAS_INSN(abcd_reg)
+{
+ TCGv src;
+ TCGv dest;
+
+ src = DREG(insn, 0);
+ dest = DREG(insn, 9);
+ gen_helper_abcd_cc(dest, cpu_env, src, dest);
+}
+
+DISAS_INSN(abcd_mem)
+{
+ TCGv src;
+ TCGv addr_src;
+ TCGv dest;
+ TCGv addr_dest;
+
+ addr_src = AREG(insn, 0);
+ tcg_gen_subi_i32(addr_src, addr_src, OS_BYTE);
+ src = gen_load(s, OS_BYTE, addr_src, 0);
+
+ addr_dest = AREG(insn, 9);
+ tcg_gen_subi_i32(addr_dest, addr_dest, OS_BYTE);
+ dest = gen_load(s, OS_BYTE, addr_dest, 0);
+
+ gen_helper_abcd_cc(dest, cpu_env, src, dest);
+
+ gen_store(s, OS_BYTE, addr_dest, dest);
+}
+
+DISAS_INSN(sbcd_reg)
+{
+ TCGv src;
+ TCGv dest;
+
+ src = DREG(insn, 0);
+ dest = DREG(insn, 9);
+ gen_helper_sbcd_cc(dest, cpu_env, src, dest);
+}
+
+DISAS_INSN(sbcd_mem)
+{
+ TCGv src;
+ TCGv addr_src;
+ TCGv dest;
+ TCGv addr_dest;
+
+ addr_src = AREG(insn, 0);
+ tcg_gen_subi_i32(addr_src, addr_src, OS_BYTE);
+ src = gen_load(s, OS_BYTE, addr_src, 0);
+
+ addr_dest = AREG(insn, 9);
+ tcg_gen_subi_i32(addr_dest, addr_dest, OS_BYTE);
+ dest = gen_load(s, OS_BYTE, addr_dest, 0);
+
+ gen_helper_sbcd_cc(dest, cpu_env, src, dest);
+
+ gen_store(s, OS_BYTE, addr_dest, dest);
+}
+
+DISAS_INSN(nbcd)
+{
+ TCGv dest;
+ TCGv addr;
+
+ SRC_EA(dest, OS_BYTE, -1, &addr);
+
+ gen_helper_sbcd_cc(dest, cpu_env, dest, tcg_const_i32(0));
+
+ DEST_EA(insn, OS_BYTE, dest, &addr);
+}
+
DISAS_INSN(addsub)
{
TCGv reg;
@@ -974,31 +1501,33 @@ DISAS_INSN(addsub)
TCGv tmp;
TCGv addr;
int add;
+ int opsize;
add = (insn & 0x4000) != 0;
+ opsize = insn_opsize(insn, 6);
reg = DREG(insn, 9);
dest = tcg_temp_new();
if (insn & 0x100) {
- SRC_EA(tmp, OS_LONG, 0, &addr);
+ SRC_EA(tmp, opsize, -1, &addr);
src = reg;
} else {
tmp = reg;
- SRC_EA(src, OS_LONG, 0, NULL);
+ SRC_EA(src, opsize, -1, NULL);
}
if (add) {
tcg_gen_add_i32(dest, tmp, src);
- gen_helper_xflag_lt(QREG_CC_X, dest, src);
- s->cc_op = CC_OP_ADD;
+ SET_X_FLAG(opsize, dest, src);
+ SET_CC_OP(opsize, ADD);
} else {
- gen_helper_xflag_lt(QREG_CC_X, tmp, src);
+ SET_X_FLAG(opsize, tmp, src);
tcg_gen_sub_i32(dest, tmp, src);
- s->cc_op = CC_OP_SUB;
+ SET_CC_OP(opsize, SUB);
}
gen_update_cc_add(dest, src);
if (insn & 0x100) {
- DEST_EA(insn, OS_LONG, dest, &addr);
+ DEST_EA(insn, opsize, dest, &addr);
} else {
- tcg_gen_mov_i32(reg, dest);
+ gen_partset_reg(opsize, reg, dest);
}
}
@@ -1070,7 +1599,7 @@ DISAS_INSN(sats)
reg = DREG(insn, 0);
gen_flush_flags(s);
gen_helper_sats(reg, reg, QREG_CC_DEST);
- gen_logic_cc(s, reg);
+ gen_logic_cc(s, reg, OS_LONG);
}
static void gen_push(DisasContext *s, TCGv val)
@@ -1091,9 +1620,10 @@ DISAS_INSN(movem)
TCGv reg;
TCGv tmp;
int is_load;
+ int opsize;
+ int32_t incr;
- mask = lduw_code(s->pc);
- s->pc += 2;
+ mask = read_im16(s);
tmp = gen_lea(s, insn, OS_LONG);
if (IS_NULL_QREG(tmp)) {
gen_addr_fault(s);
@@ -1102,21 +1632,40 @@ DISAS_INSN(movem)
addr = tcg_temp_new();
tcg_gen_mov_i32(addr, tmp);
is_load = ((insn & 0x0400) != 0);
- for (i = 0; i < 16; i++, mask >>= 1) {
- if (mask & 1) {
- if (i < 8)
- reg = DREG(i, 0);
- else
- reg = AREG(i, 0);
- if (is_load) {
- tmp = gen_load(s, OS_LONG, addr, 0);
- tcg_gen_mov_i32(reg, tmp);
- } else {
- gen_store(s, OS_LONG, addr, reg);
- }
- if (mask != 1)
- tcg_gen_addi_i32(addr, addr, 4);
- }
+ opsize = (insn & 0x40) != 0 ? OS_LONG : OS_WORD;
+ incr = opsize_bytes(opsize);
+ if (!is_load && (insn & 070) == 040) {
+ for (i = 15; i >= 0; i--, mask >>= 1) {
+ if (mask & 1) {
+ if (i < 8)
+ reg = DREG(i, 0);
+ else
+ reg = AREG(i, 0);
+ gen_store(s, opsize, addr, reg);
+ if (mask != 1)
+ tcg_gen_subi_i32(addr, addr, incr);
+ }
+ }
+ tcg_gen_mov_i32(AREG(insn, 0), addr);
+ } else {
+ for (i = 0; i < 16; i++, mask >>= 1) {
+ if (mask & 1) {
+ if (i < 8)
+ reg = DREG(i, 0);
+ else
+ reg = AREG(i, 0);
+ if (is_load) {
+ tmp = gen_load(s, opsize, addr, 1);
+ tcg_gen_mov_i32(reg, tmp);
+ } else {
+ gen_store(s, opsize, addr, reg);
+ }
+ if (mask != 1 || (insn & 070) == 030)
+ tcg_gen_addi_i32(addr, addr, incr);
+ }
+ }
+ if ((insn & 070) == 030)
+ tcg_gen_mov_i32(AREG(insn, 0), addr);
}
}
@@ -1136,8 +1685,7 @@ DISAS_INSN(bitop_im)
opsize = OS_LONG;
op = (insn >> 6) & 3;
- bitnum = lduw_code(s->pc);
- s->pc += 2;
+ bitnum = read_im16(s);
if (bitnum & 0xff00) {
disas_undef(s, insn);
return;
@@ -1189,50 +1737,128 @@ DISAS_INSN(arith_im)
TCGv src1;
TCGv dest;
TCGv addr;
+ int opsize;
op = (insn >> 9) & 7;
- SRC_EA(src1, OS_LONG, 0, (op == 6) ? NULL : &addr);
- im = read_im32(s);
+ opsize = insn_opsize(insn, 6);
+ switch (opsize) {
+ case OS_BYTE:
+ im = read_im8(s);
+ break;
+ case OS_WORD:
+ im = read_im16(s);
+ break;
+ case OS_LONG:
+ im = read_im32(s);
+ break;
+ default:
+ abort();
+ }
+ SRC_EA(src1, opsize, -1, (op == 6) ? NULL : &addr);
dest = tcg_temp_new();
switch (op) {
case 0: /* ori */
tcg_gen_ori_i32(dest, src1, im);
- gen_logic_cc(s, dest);
+ gen_logic_cc(s, dest, opsize);
break;
case 1: /* andi */
tcg_gen_andi_i32(dest, src1, im);
- gen_logic_cc(s, dest);
+ gen_logic_cc(s, dest, opsize);
break;
case 2: /* subi */
tcg_gen_mov_i32(dest, src1);
- gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im));
+ SET_X_FLAG(opsize, dest, tcg_const_i32(im));
tcg_gen_subi_i32(dest, dest, im);
gen_update_cc_add(dest, tcg_const_i32(im));
- s->cc_op = CC_OP_SUB;
+ SET_CC_OP(opsize, SUB);
break;
case 3: /* addi */
tcg_gen_mov_i32(dest, src1);
tcg_gen_addi_i32(dest, dest, im);
gen_update_cc_add(dest, tcg_const_i32(im));
- gen_helper_xflag_lt(QREG_CC_X, dest, tcg_const_i32(im));
- s->cc_op = CC_OP_ADD;
+ SET_X_FLAG(opsize, dest, tcg_const_i32(im));
+ SET_CC_OP(opsize, ADD);
break;
case 5: /* eori */
tcg_gen_xori_i32(dest, src1, im);
- gen_logic_cc(s, dest);
+ gen_logic_cc(s, dest, opsize);
break;
case 6: /* cmpi */
tcg_gen_mov_i32(dest, src1);
tcg_gen_subi_i32(dest, dest, im);
gen_update_cc_add(dest, tcg_const_i32(im));
- s->cc_op = CC_OP_SUB;
+ SET_CC_OP(opsize, SUB);
break;
default:
abort();
}
if (op != 6) {
- DEST_EA(insn, OS_LONG, dest, &addr);
+ DEST_EA(insn, opsize, dest, &addr);
+ }
+}
+
+DISAS_INSN(cas)
+{
+ int opsize;
+ TCGv dest;
+ TCGv tmp;
+ TCGv cmp;
+ TCGv update;
+ TCGv taddr;
+ TCGv addr;
+ TCGv res;
+ uint16_t ext;
+ int l1, l2;
+
+ if ((insn & 0x3f) == 0x3c) {
+ /* CAS2: Not yet implemented */
+ gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+ }
+
+ switch((insn >> 9) & 3) {
+ case 1:
+ opsize = OS_BYTE;
+ break;
+ case 2:
+ opsize = OS_WORD;
+ break;
+ case 3:
+ opsize = OS_LONG;
+ break;
+ default:
+ abort();
+ }
+
+ ext = read_im16(s);
+ taddr = gen_lea(s, insn, opsize);
+ if (IS_NULL_QREG(taddr)) {
+ gen_addr_fault(s);
+ return;
}
+
+ cmp = DREG(ext, 0);
+ update = DREG(ext, 6);
+ tmp = gen_load(s, opsize, taddr, 0);
+ dest = tcg_temp_local_new();
+ tcg_gen_mov_i32(dest, tmp);
+ addr = tcg_temp_local_new ();
+ tcg_gen_mov_i32(addr, taddr);
+
+ res = tcg_temp_new();
+ tcg_gen_sub_i32(res, dest, cmp);
+ gen_logic_cc(s, res, opsize);
+
+ l1 = gen_new_label();
+ l2 = gen_new_label();
+
+ gen_jmpcc(s, 6 /* !Z */, l1);
+ gen_store(s, opsize, addr, update);
+ tcg_gen_br(l2);
+ gen_set_label(l1);
+ tcg_gen_mov_i32(cmp, dest);
+ gen_set_label(l2);
+ tcg_temp_free(dest);
+ tcg_temp_free(addr);
}
DISAS_INSN(byterev)
@@ -1276,17 +1902,34 @@ DISAS_INSN(move)
dest_ea = ((insn >> 9) & 7) | (op << 3);
DEST_EA(dest_ea, opsize, src, NULL);
/* This will be correct because loads sign extend. */
- gen_logic_cc(s, src);
+ gen_logic_cc(s, src, opsize);
}
}
DISAS_INSN(negx)
{
- TCGv reg;
+ TCGv src;
+ TCGv dest;
+ TCGv addr;
+ int opsize;
+ opsize = insn_opsize(insn, 6);
gen_flush_flags(s);
- reg = DREG(insn, 0);
- gen_helper_subx_cc(reg, cpu_env, tcg_const_i32(0), reg);
+ SRC_EA(src, opsize, -1, &addr);
+ dest = tcg_temp_new();
+ switch(opsize) {
+ case OS_BYTE:
+ gen_helper_subx8_cc(dest, cpu_env, tcg_const_i32(0), src);
+ break;
+ case OS_WORD:
+ gen_helper_subx16_cc(dest, cpu_env, tcg_const_i32(0), src);
+ break;
+ case OS_LONG:
+ gen_helper_subx32_cc(dest, cpu_env, tcg_const_i32(0), src);
+ break;
+ }
+ s->cc_op = CC_OP_FLAGS;
+ DEST_EA(insn, opsize, dest, &addr);
}
DISAS_INSN(lea)
@@ -1307,21 +1950,9 @@ DISAS_INSN(clr)
{
int opsize;
- switch ((insn >> 6) & 3) {
- case 0: /* clr.b */
- opsize = OS_BYTE;
- break;
- case 1: /* clr.w */
- opsize = OS_WORD;
- break;
- case 2: /* clr.l */
- opsize = OS_LONG;
- break;
- default:
- abort();
- }
+ opsize = insn_opsize(insn, 6);
DEST_EA(insn, opsize, tcg_const_i32(0), NULL);
- gen_logic_cc(s, tcg_const_i32(0));
+ gen_logic_cc(s, tcg_const_i32(0), opsize);
}
static TCGv gen_get_ccr(DisasContext *s)
@@ -1347,17 +1978,19 @@ DISAS_INSN(move_from_ccr)
DISAS_INSN(neg)
{
- TCGv reg;
TCGv src1;
+ TCGv dest;
+ TCGv addr;
+ int opsize;
- reg = DREG(insn, 0);
- src1 = tcg_temp_new();
- tcg_gen_mov_i32(src1, reg);
- tcg_gen_neg_i32(reg, src1);
- s->cc_op = CC_OP_SUB;
- gen_update_cc_add(reg, src1);
- gen_helper_xflag_lt(QREG_CC_X, tcg_const_i32(0), src1);
- s->cc_op = CC_OP_SUB;
+ opsize = insn_opsize(insn, 6);
+ SRC_EA(src1, opsize, -1, &addr);
+ dest = tcg_temp_new();
+ tcg_gen_neg_i32(dest, src1);
+ SET_CC_OP(opsize, SUB);
+ gen_update_cc_add(dest, src1);
+ SET_X_FLAG(opsize, tcg_const_i32(0), dest);
+ DEST_EA(insn, opsize, dest, &addr);
}
static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
@@ -1389,8 +2022,7 @@ static void gen_set_sr(DisasContext *s, uint16_t
insn, int ccr_only)
else if ((insn & 0x3f) == 0x3c)
{
uint16_t val;
- val = lduw_code(s->pc);
- s->pc += 2;
+ val = read_im16(s);
gen_set_sr_im(s, val, ccr_only);
}
else
@@ -1404,11 +2036,17 @@ DISAS_INSN(move_to_ccr)
DISAS_INSN(not)
{
- TCGv reg;
+ TCGv src1;
+ TCGv dest;
+ TCGv addr;
+ int opsize;
- reg = DREG(insn, 0);
- tcg_gen_not_i32(reg, reg);
- gen_logic_cc(s, reg);
+ opsize = insn_opsize(insn, 6);
+ SRC_EA(src1, opsize, -1, &addr);
+ dest = tcg_temp_new();
+ tcg_gen_not_i32(dest, src1);
+ DEST_EA(insn, opsize, dest, &addr);
+ gen_logic_cc(s, dest, opsize);
}
DISAS_INSN(swap)
@@ -1423,7 +2061,12 @@ DISAS_INSN(swap)
tcg_gen_shli_i32(src1, reg, 16);
tcg_gen_shri_i32(src2, reg, 16);
tcg_gen_or_i32(reg, src1, src2);
- gen_logic_cc(s, reg);
+ gen_logic_cc(s, reg, OS_LONG);
+}
+
+DISAS_INSN(bkpt)
+{
+ gen_exception(s, s->pc - 2, EXCP_DEBUG);
}
DISAS_INSN(pea)
@@ -1455,7 +2098,7 @@ DISAS_INSN(ext)
gen_partset_reg(OS_WORD, reg, tmp);
else
tcg_gen_mov_i32(reg, tmp);
- gen_logic_cc(s, tmp);
+ gen_logic_cc(s, tmp, OS_LONG);
}
DISAS_INSN(tst)
@@ -1463,21 +2106,9 @@ DISAS_INSN(tst)
int opsize;
TCGv tmp;
- switch ((insn >> 6) & 3) {
- case 0: /* tst.b */
- opsize = OS_BYTE;
- break;
- case 1: /* tst.w */
- opsize = OS_WORD;
- break;
- case 2: /* tst.l */
- opsize = OS_LONG;
- break;
- default:
- abort();
- }
- SRC_EA(tmp, opsize, 1, NULL);
- gen_logic_cc(s, tmp);
+ opsize = insn_opsize(insn, 6);
+ SRC_EA(tmp, opsize, -1, NULL);
+ gen_logic_cc(s, tmp, opsize);
}
DISAS_INSN(pulse)
@@ -1487,6 +2118,7 @@ DISAS_INSN(pulse)
DISAS_INSN(illegal)
{
+ fprintf(stderr,"test\n");
gen_exception(s, s->pc - 2, EXCP_ILLEGAL);
}
@@ -1499,7 +2131,7 @@ DISAS_INSN(tas)
dest = tcg_temp_new();
SRC_EA(src1, OS_BYTE, 1, &addr);
- gen_logic_cc(s, src1);
+ gen_logic_cc(s, src1, OS_BYTE);
tcg_gen_ori_i32(dest, src1, 0x80);
DEST_EA(insn, OS_BYTE, dest, &addr);
}
@@ -1510,22 +2142,43 @@ DISAS_INSN(mull)
TCGv reg;
TCGv src1;
TCGv dest;
+ TCGv regh;
/* The upper 32 bits of the product are discarded, so
muls.l and mulu.l are functionally equivalent. */
- ext = lduw_code(s->pc);
- s->pc += 2;
- if (ext & 0x87ff) {
- gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
- return;
+ ext = read_im16(s);
+ if (ext & 0x400) {
+ if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
+ gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+ return;
+ }
+ reg = DREG(ext, 12);
+ regh = DREG(ext, 0);
+ SRC_EA(src1, OS_LONG, 0, NULL);
+ dest = tcg_temp_new();
+ if (ext & 0x800)
+ gen_helper_muls64(dest, cpu_env, src1, reg);
+ else
+ gen_helper_mulu64(dest, cpu_env, src1, reg);
+ tcg_gen_mov_i32(reg, dest);
+ tcg_gen_mov_i32(regh, QREG_QUADH);
+ s->cc_op = CC_OP_FLAGS;
+ return;
}
reg = DREG(ext, 12);
SRC_EA(src1, OS_LONG, 0, NULL);
dest = tcg_temp_new();
- tcg_gen_mul_i32(dest, src1, reg);
+ if (m68k_feature(s->env, M68K_FEATURE_M68000)) {
+ if (ext & 0x800)
+ gen_helper_muls32_cc(dest, cpu_env, src1, reg);
+ else
+ gen_helper_mulu32_cc(dest, cpu_env, src1, reg);
+ s->cc_op = CC_OP_FLAGS;
+ } else {
+ tcg_gen_mul_i32(dest, src1, reg);
+ }
+ gen_logic_cc(s, dest, OS_LONG);
tcg_gen_mov_i32(reg, dest);
- /* Unlike m68k, coldfire always clears the overflow bit. */
- gen_logic_cc(s, dest);
}
DISAS_INSN(link)
@@ -1534,8 +2187,23 @@ DISAS_INSN(link)
TCGv reg;
TCGv tmp;
- offset = ldsw_code(s->pc);
- s->pc += 2;
+ offset = read_im16(s);
+ reg = AREG(insn, 0);
+ tmp = tcg_temp_new();
+ tcg_gen_subi_i32(tmp, QREG_SP, 4);
+ gen_store(s, OS_LONG, tmp, reg);
+ if ((insn & 7) != 7)
+ tcg_gen_mov_i32(reg, tmp);
+ tcg_gen_addi_i32(QREG_SP, tmp, offset);
+}
+
+DISAS_INSN(linkl)
+{
+ int32_t offset;
+ TCGv reg;
+ TCGv tmp;
+
+ offset = read_im32(s);
reg = AREG(insn, 0);
tmp = tcg_temp_new();
tcg_gen_subi_i32(tmp, QREG_SP, 4);
@@ -1597,8 +2265,14 @@ DISAS_INSN(addsubq)
TCGv dest;
int val;
TCGv addr;
+ int opsize;
- SRC_EA(src1, OS_LONG, 0, &addr);
+ if ((insn & 070) == 010) {
+ /* Operation on address register is always long. */
+ opsize = OS_LONG;
+ } else
+ opsize = insn_opsize(insn, 6);
+ SRC_EA(src1, opsize, -1, &addr);
val = (insn >> 9) & 7;
if (val == 0)
val = 8;
@@ -1615,17 +2289,17 @@ DISAS_INSN(addsubq)
} else {
src2 = tcg_const_i32(val);
if (insn & 0x0100) {
- gen_helper_xflag_lt(QREG_CC_X, dest, src2);
+ SET_X_FLAG(opsize, dest, src2);
tcg_gen_subi_i32(dest, dest, val);
- s->cc_op = CC_OP_SUB;
+ SET_CC_OP(opsize, SUB);
} else {
tcg_gen_addi_i32(dest, dest, val);
- gen_helper_xflag_lt(QREG_CC_X, dest, src2);
- s->cc_op = CC_OP_ADD;
+ SET_X_FLAG(opsize, dest, src2);
+ SET_CC_OP(opsize, ADD);
}
gen_update_cc_add(dest, src2);
}
- DEST_EA(insn, OS_LONG, dest, &addr);
+ DEST_EA(insn, opsize, dest, &addr);
}
DISAS_INSN(tpf)
@@ -1684,7 +2358,7 @@ DISAS_INSN(moveq)
val = (int8_t)insn;
tcg_gen_movi_i32(DREG(insn, 9), val);
- gen_logic_cc(s, tcg_const_i32(val));
+ gen_logic_cc(s, tcg_const_i32(val), OS_LONG);
}
DISAS_INSN(mvzs)
@@ -1700,7 +2374,7 @@ DISAS_INSN(mvzs)
SRC_EA(src, opsize, (insn & 0x80) == 0, NULL);
reg = DREG(insn, 9);
tcg_gen_mov_i32(reg, src);
- gen_logic_cc(s, src);
+ gen_logic_cc(s, src, opsize);
}
DISAS_INSN(or)
@@ -1709,19 +2383,21 @@ DISAS_INSN(or)
TCGv dest;
TCGv src;
TCGv addr;
+ int opsize;
+ opsize = insn_opsize(insn, 6);
reg = DREG(insn, 9);
dest = tcg_temp_new();
if (insn & 0x100) {
- SRC_EA(src, OS_LONG, 0, &addr);
+ SRC_EA(src, opsize, -1, &addr);
tcg_gen_or_i32(dest, src, reg);
- DEST_EA(insn, OS_LONG, dest, &addr);
+ DEST_EA(insn, opsize, dest, &addr);
} else {
- SRC_EA(src, OS_LONG, 0, NULL);
+ SRC_EA(src, opsize, -1, NULL);
tcg_gen_or_i32(dest, src, reg);
- tcg_gen_mov_i32(reg, dest);
+ gen_partset_reg(opsize, reg, dest);
}
- gen_logic_cc(s, dest);
+ gen_logic_cc(s, dest, opsize);
}
DISAS_INSN(suba)
@@ -1729,65 +2405,99 @@ DISAS_INSN(suba)
TCGv src;
TCGv reg;
- SRC_EA(src, OS_LONG, 0, NULL);
+ SRC_EA(src, (insn & 0x100) ? OS_LONG : OS_WORD, -1, NULL);
reg = AREG(insn, 9);
tcg_gen_sub_i32(reg, reg, src);
}
-DISAS_INSN(subx)
+DISAS_INSN(subx_reg)
{
TCGv reg;
TCGv src;
+ int opsize;
+
+ opsize = insn_opsize(insn, 6);
gen_flush_flags(s);
reg = DREG(insn, 9);
src = DREG(insn, 0);
- gen_helper_subx_cc(reg, cpu_env, reg, src);
-}
-
-DISAS_INSN(mov3q)
-{
- TCGv src;
- int val;
-
- val = (insn >> 9) & 7;
+ switch(opsize) {
+ case OS_BYTE:
+ gen_helper_subx8_cc(reg, cpu_env, reg, src);
+ break;
+ case OS_WORD:
+ gen_helper_subx16_cc(reg, cpu_env, reg, src);
+ break;
+ case OS_LONG:
+ gen_helper_subx32_cc(reg, cpu_env, reg, src);
+ break;
+ }
+ s->cc_op = CC_OP_FLAGS;
+}
+
+DISAS_INSN(subx_mem)
+{
+ TCGv src;
+ TCGv addr_src;
+ TCGv reg;
+ TCGv addr_reg;
+ int opsize;
+
+ opsize = insn_opsize(insn, 6);
+
+ gen_flush_flags(s);
+
+ addr_src = AREG(insn, 0);
+ tcg_gen_subi_i32(addr_src, addr_src, opsize);
+ src = gen_load(s, opsize, addr_src, 0);
+
+ addr_reg = AREG(insn, 9);
+ tcg_gen_subi_i32(addr_reg, addr_reg, opsize);
+ reg = gen_load(s, opsize, addr_reg, 0);
+
+ switch(opsize) {
+ case OS_BYTE:
+ gen_helper_subx8_cc(reg, cpu_env, reg, src);
+ break;
+ case OS_WORD:
+ gen_helper_subx16_cc(reg, cpu_env, reg, src);
+ break;
+ case OS_LONG:
+ gen_helper_subx32_cc(reg, cpu_env, reg, src);
+ break;
+ }
+ s->cc_op = CC_OP_FLAGS;
+
+ gen_store(s, opsize, addr_reg, reg);
+}
+
+DISAS_INSN(mov3q)
+{
+ TCGv src;
+ int val;
+
+ val = (insn >> 9) & 7;
if (val == 0)
val = -1;
src = tcg_const_i32(val);
- gen_logic_cc(s, src);
+ gen_logic_cc(s, src, OS_LONG);
DEST_EA(insn, OS_LONG, src, NULL);
}
DISAS_INSN(cmp)
{
- int op;
TCGv src;
TCGv reg;
TCGv dest;
int opsize;
- op = (insn >> 6) & 3;
- switch (op) {
- case 0: /* cmp.b */
- opsize = OS_BYTE;
- s->cc_op = CC_OP_CMPB;
- break;
- case 1: /* cmp.w */
- opsize = OS_WORD;
- s->cc_op = CC_OP_CMPW;
- break;
- case 2: /* cmp.l */
- opsize = OS_LONG;
- s->cc_op = CC_OP_SUB;
- break;
- default:
- abort();
- }
- SRC_EA(src, opsize, 1, NULL);
+ opsize = insn_opsize(insn, 6);
+ SRC_EA(src, opsize, -1, NULL);
reg = DREG(insn, 9);
dest = tcg_temp_new();
tcg_gen_sub_i32(dest, reg, src);
gen_update_cc_add(dest, src);
+ SET_CC_OP(opsize, SUB);
}
DISAS_INSN(cmpa)
@@ -1807,7 +2517,7 @@ DISAS_INSN(cmpa)
dest = tcg_temp_new();
tcg_gen_sub_i32(dest, reg, src);
gen_update_cc_add(dest, src);
- s->cc_op = CC_OP_SUB;
+ SET_CC_OP(OS_LONG, SUB);
}
DISAS_INSN(eor)
@@ -1816,13 +2526,34 @@ DISAS_INSN(eor)
TCGv reg;
TCGv dest;
TCGv addr;
+ int opsize;
+
+ opsize = insn_opsize(insn, 6);
+
+ if (((insn >> 3) & 7) == 1 ) {
+ /* cmpm */
+ reg = AREG(insn, 0);
+ src = gen_load(s, opsize, reg, 1);
+ tcg_gen_addi_i32(reg, reg, opsize_bytes(opsize));
+
+ reg = AREG(insn, 9);
+ dest = gen_load(s, opsize, reg, 1);
+ tcg_gen_addi_i32(reg, reg, opsize_bytes(opsize));
- SRC_EA(src, OS_LONG, 0, &addr);
+ reg = tcg_temp_new();
+ tcg_gen_sub_i32(reg, dest, src);
+ gen_update_cc_add(reg, src);
+ SET_CC_OP(opsize, SUB);
+
+ return;
+ }
+
+ SRC_EA(src, opsize, -1, &addr);
reg = DREG(insn, 9);
dest = tcg_temp_new();
tcg_gen_xor_i32(dest, src, reg);
- gen_logic_cc(s, dest);
- DEST_EA(insn, OS_LONG, dest, &addr);
+ gen_logic_cc(s, dest, opsize);
+ DEST_EA(insn, opsize, dest, &addr);
}
DISAS_INSN(and)
@@ -1831,19 +2562,52 @@ DISAS_INSN(and)
TCGv reg;
TCGv dest;
TCGv addr;
+ int opsize;
+ int exg_mode;
- reg = DREG(insn, 9);
dest = tcg_temp_new();
+
+ /* exg */
+
+ exg_mode = insn & 0x1f8;
+ if (exg_mode == 0x140) {
+ /* exchange Dx and Dy */
+ src = DREG(insn, 9);
+ reg = DREG(insn, 0);
+ tcg_gen_mov_i32(dest, src);
+ tcg_gen_mov_i32(src, reg);
+ tcg_gen_mov_i32(reg, dest);
+ return;
+ } else if (exg_mode == 0x148) {
+ /* exchange Ax and Ay */
+ src = AREG(insn, 9);
+ reg = AREG(insn, 0);
+ tcg_gen_mov_i32(dest, src);
+ tcg_gen_mov_i32(src, reg);
+ tcg_gen_mov_i32(reg, dest);
+ return;
+ } else if (exg_mode == 0x188) {
+ /* exchange Dx and Ay */
+ src = DREG(insn, 9);
+ reg = AREG(insn, 0);
+ tcg_gen_mov_i32(dest, src);
+ tcg_gen_mov_i32(src, reg);
+ tcg_gen_mov_i32(reg, dest);
+ return;
+ }
+ /* and */
+ opsize = insn_opsize(insn, 6);
+ reg = DREG(insn, 9);
if (insn & 0x100) {
- SRC_EA(src, OS_LONG, 0, &addr);
+ SRC_EA(src, opsize, -1, &addr);
tcg_gen_and_i32(dest, src, reg);
- DEST_EA(insn, OS_LONG, dest, &addr);
+ DEST_EA(insn, opsize, dest, &addr);
} else {
- SRC_EA(src, OS_LONG, 0, NULL);
+ SRC_EA(src, opsize, -1, NULL);
tcg_gen_and_i32(dest, src, reg);
- tcg_gen_mov_i32(reg, dest);
+ gen_partset_reg(opsize, reg, dest);
}
- gen_logic_cc(s, dest);
+ gen_logic_cc(s, dest, opsize);
}
DISAS_INSN(adda)
@@ -1851,24 +2615,138 @@ DISAS_INSN(adda)
TCGv src;
TCGv reg;
- SRC_EA(src, OS_LONG, 0, NULL);
+ SRC_EA(src, (insn & 0x100) ? OS_LONG : OS_WORD, -1, NULL);
reg = AREG(insn, 9);
tcg_gen_add_i32(reg, reg, src);
}
-DISAS_INSN(addx)
+DISAS_INSN(addx_reg)
{
TCGv reg;
TCGv src;
+ int opsize;
+
+ opsize = insn_opsize(insn, 6);
gen_flush_flags(s);
reg = DREG(insn, 9);
src = DREG(insn, 0);
- gen_helper_addx_cc(reg, cpu_env, reg, src);
+ switch(opsize) {
+ case OS_BYTE:
+ gen_helper_addx8_cc(reg, cpu_env, reg, src);
+ break;
+ case OS_WORD:
+ gen_helper_addx16_cc(reg, cpu_env, reg, src);
+ break;
+ case OS_LONG:
+ gen_helper_addx32_cc(reg, cpu_env, reg, src);
+ break;
+ }
+ s->cc_op = CC_OP_FLAGS;
+}
+
+DISAS_INSN(addx_mem)
+{
+ TCGv src;
+ TCGv addr_src;
+ TCGv reg;
+ TCGv addr_reg;
+ int opsize;
+
+ opsize = insn_opsize(insn, 6);
+
+ gen_flush_flags(s);
+
+ addr_src = AREG(insn, 0);
+ tcg_gen_subi_i32(addr_src, addr_src, opsize);
+ src = gen_load(s, opsize, addr_src, 0);
+
+ addr_reg = AREG(insn, 9);
+ tcg_gen_subi_i32(addr_reg, addr_reg, opsize);
+ reg = gen_load(s, opsize, addr_reg, 0);
+
+ switch(opsize) {
+ case OS_BYTE:
+ gen_helper_addx8_cc(reg, cpu_env, reg, src);
+ break;
+ case OS_WORD:
+ gen_helper_addx16_cc(reg, cpu_env, reg, src);
+ break;
+ case OS_LONG:
+ gen_helper_addx32_cc(reg, cpu_env, reg, src);
+ break;
+ }
s->cc_op = CC_OP_FLAGS;
+
+ gen_store(s, opsize, addr_reg, reg);
+}
+
+/* TODO: This could be implemented without helper functions. */
+DISAS_INSN(shift8_im)
+{
+ TCGv reg;
+ int tmp;
+ TCGv shift;
+ TCGv dest;
+
+ reg = DREG(insn, 0);
+ tmp = (insn >> 9) & 7;
+ if (tmp == 0)
+ tmp = 8;
+ shift = tcg_const_i32(tmp);
+ dest = tcg_temp_new_i32();
+ /* No need to flush flags becuse we know we will set C flag. */
+ if (insn & 0x100) {
+ if (insn & 8) {
+ gen_helper_shl8_cc(dest, cpu_env, reg, shift);
+ } else {
+ gen_helper_sal8_cc(dest, cpu_env, reg, shift);
+ }
+ } else {
+ if (insn & 8) {
+ gen_helper_shr8_cc(dest, cpu_env, reg, shift);
+ } else {
+ gen_helper_sar8_cc(dest, cpu_env, reg, shift);
+ }
+ }
+ s->cc_op = CC_OP_SHIFTB;
+ gen_partset_reg(OS_BYTE, reg, dest);
}
/* TODO: This could be implemented without helper functions. */
+DISAS_INSN(shift16_im)
+{
+ TCGv reg;
+ int tmp;
+ TCGv shift;
+ TCGv dest;
+
+ reg = DREG(insn, 0);
+ tmp = (insn >> 9) & 7;
+ if (tmp == 0)
+ tmp = 8;
+ shift = tcg_const_i32(tmp);
+ dest = tcg_temp_new_i32();
+ /* No need to flush flags becuse we know we will set C flag. */
+ if (insn & 0x100) {
+ if (insn & 8) {
+ gen_helper_shl16_cc(dest, cpu_env, reg, shift);
+ } else {
+ gen_helper_sal16_cc(dest, cpu_env, reg, shift);
+ }
+ } else {
+ if (insn & 8) {
+ gen_helper_shr16_cc(dest, cpu_env, reg, shift);
+ } else {
+ gen_helper_sar16_cc(dest, cpu_env, reg, shift);
+ }
+ }
+ s->cc_op = CC_OP_SHIFTW;
+ gen_partset_reg(OS_WORD, reg, dest);
+}
+
+
+/* TODO: This could be implemented without helper functions. */
DISAS_INSN(shift_im)
{
TCGv reg;
@@ -1882,43 +2760,662 @@ DISAS_INSN(shift_im)
shift = tcg_const_i32(tmp);
/* No need to flush flags becuse we know we will set C flag. */
if (insn & 0x100) {
- gen_helper_shl_cc(reg, cpu_env, reg, shift);
+ if (insn & 8) {
+ gen_helper_shl32_cc(reg, cpu_env, reg, shift);
+ } else {
+ gen_helper_sal32_cc(reg, cpu_env, reg, shift);
+ }
+ } else {
+ if (insn & 8) {
+ gen_helper_shr32_cc(reg, cpu_env, reg, shift);
+ } else {
+ gen_helper_sar32_cc(reg, cpu_env, reg, shift);
+ }
+ }
+ s->cc_op = CC_OP_SHIFT;
+}
+
+DISAS_INSN(shift8_reg)
+{
+ TCGv reg;
+ TCGv shift;
+ TCGv dest;
+ TCGv tmp;
+
+ reg = DREG(insn, 0);
+ shift = DREG(insn, 9);
+ tmp = tcg_temp_new_i32();
+ tcg_gen_andi_i32(tmp, shift, 63);
+ dest = tcg_temp_new_i32();
+ /* Shift by zero leaves C flag unmodified. */
+ gen_flush_flags(s);
+ if (insn & 0x100) {
+ if (insn & 8) {
+ gen_helper_shl8_cc(dest, cpu_env, reg, tmp);
+ } else {
+ gen_helper_sal8_cc(dest, cpu_env, reg, tmp);
+ }
+ } else {
+ if (insn & 8) {
+ gen_helper_shr8_cc(dest, cpu_env, reg, tmp);
+ } else {
+ gen_helper_sar8_cc(dest, cpu_env, reg, tmp);
+ }
+ }
+ s->cc_op = CC_OP_SHIFTB;
+ gen_partset_reg(OS_BYTE, reg, dest);
+}
+
+DISAS_INSN(shift16_reg)
+{
+ TCGv reg;
+ TCGv shift;
+ TCGv dest;
+ TCGv tmp;
+
+ reg = DREG(insn, 0);
+ shift = DREG(insn, 9);
+ tmp = tcg_temp_new_i32();
+ tcg_gen_andi_i32(tmp, shift, 63);
+ dest = tcg_temp_new_i32();
+ /* Shift by zero leaves C flag unmodified. */
+ gen_flush_flags(s);
+ if (insn & 0x100) {
+ if (insn & 8) {
+ gen_helper_shl16_cc(dest, cpu_env, reg, tmp);
+ } else {
+ gen_helper_sal16_cc(dest, cpu_env, reg, tmp);
+ }
+ } else {
+ if (insn & 8) {
+ gen_helper_shr16_cc(dest, cpu_env, reg, tmp);
+ } else {
+ gen_helper_sar16_cc(dest, cpu_env, reg, tmp);
+ }
+ }
+ s->cc_op = CC_OP_SHIFTW;
+ gen_partset_reg(OS_WORD, reg, dest);
+}
+
+DISAS_INSN(shift_reg)
+{
+ TCGv reg;
+ TCGv shift;
+
+ reg = DREG(insn, 0);
+ shift = DREG(insn, 9);
+ /* Shift by zero leaves C flag unmodified. */
+ gen_flush_flags(s);
+ if (insn & 0x100) {
+ if (insn & 8) {
+ gen_helper_shl32_cc(reg, cpu_env, reg, shift);
+ } else {
+ gen_helper_sal32_cc(reg, cpu_env, reg, shift);
+ }
+ } else {
+ if (insn & 8) {
+ gen_helper_shr32_cc(reg, cpu_env, reg, shift);
+ } else {
+ gen_helper_sar32_cc(reg, cpu_env, reg, shift);
+ }
+ }
+ s->cc_op = CC_OP_SHIFT;
+}
+
+DISAS_INSN(shift_mem)
+{
+ TCGv src;
+ TCGv dest;
+ TCGv addr;
+ TCGv shift;
+
+ SRC_EA(src, OS_WORD, 0, &addr);
+ dest = tcg_temp_new_i32();
+ shift = tcg_const_i32(1);
+ if (insn & 0x100) {
+ gen_helper_shl16_cc(dest, cpu_env, src, shift);
} else {
if (insn & 8) {
- gen_helper_shr_cc(reg, cpu_env, reg, shift);
+ gen_helper_shr16_cc(dest, cpu_env, src, shift);
+ } else {
+ gen_helper_sar16_cc(dest, cpu_env, src, shift);
+ }
+ }
+ s->cc_op = CC_OP_SHIFTW;
+ DEST_EA(insn, OS_WORD, dest, &addr);
+}
+
+DISAS_INSN(rotate_im)
+{
+ TCGv reg;
+ TCGv shift;
+ int tmp;
+
+ reg = DREG(insn, 0);
+ tmp = (insn >> 9) & 7;
+ if (tmp == 0)
+ tmp = 8;
+ shift = tcg_const_i32(tmp);
+ if (insn & 8) {
+ if (insn & 0x100) {
+ gen_helper_rol32_cc(reg, cpu_env, reg, shift);
+ } else {
+ gen_helper_ror32_cc(reg, cpu_env, reg, shift);
+ }
+ } else {
+ if (insn & 0x100) {
+ gen_helper_roxl32_cc(reg, cpu_env, reg, shift);
+ } else {
+ gen_helper_roxr32_cc(reg, cpu_env, reg, shift);
+ }
+ }
+ s->cc_op = CC_OP_FLAGS;
+}
+
+DISAS_INSN(rotate8_im)
+{
+ TCGv reg;
+ TCGv dest;
+ TCGv shift;
+ int tmp;
+
+ reg = DREG(insn, 0);
+ tmp = (insn >> 9) & 7;
+ if (tmp == 0)
+ tmp = 8;
+ dest = tcg_temp_new_i32();
+ shift = tcg_const_i32(tmp);
+ if (insn & 8) {
+ if (insn & 0x100) {
+ gen_helper_rol8_cc(dest, cpu_env, reg, shift);
+ } else {
+ gen_helper_ror8_cc(dest, cpu_env, reg, shift);
+ }
+ } else {
+ if (insn & 0x100) {
+ gen_helper_roxl8_cc(dest, cpu_env, reg, shift);
+ } else {
+ gen_helper_roxr8_cc(dest, cpu_env, reg, shift);
+ }
+ }
+ s->cc_op = CC_OP_FLAGS;
+ gen_partset_reg(OS_BYTE, reg, dest);
+}
+
+DISAS_INSN(rotate16_im)
+{
+ TCGv reg;
+ TCGv dest;
+ TCGv shift;
+ int tmp;
+
+ reg = DREG(insn, 0);
+ tmp = (insn >> 9) & 7;
+ if (tmp == 0)
+ tmp = 8;
+ dest = tcg_temp_new_i32();
+ shift = tcg_const_i32(tmp);
+ if (insn & 8) {
+ if (insn & 0x100) {
+ gen_helper_rol16_cc(dest, cpu_env, reg, shift);
+ } else {
+ gen_helper_ror16_cc(dest, cpu_env, reg, shift);
+ }
+ } else {
+ if (insn & 0x100) {
+ gen_helper_roxl16_cc(dest, cpu_env, reg, shift);
+ } else {
+ gen_helper_roxr16_cc(dest, cpu_env, reg, shift);
+ }
+ }
+ s->cc_op = CC_OP_FLAGS;
+ gen_partset_reg(OS_WORD, reg, dest);
+}
+
+DISAS_INSN(rotate_reg)
+{
+ TCGv reg;
+ TCGv src;
+ TCGv tmp;
+
+ reg = DREG(insn, 0);
+ src = DREG(insn, 9);
+ tmp = tcg_temp_new_i32();
+ tcg_gen_andi_i32(tmp, src, 63);
+ if (insn & 8) {
+ if (insn & 0x100) {
+ gen_helper_rol32_cc(reg, cpu_env, reg, tmp);
+ } else {
+ gen_helper_ror32_cc(reg, cpu_env, reg, tmp);
+ }
+ } else {
+ if (insn & 0x100) {
+ gen_helper_roxl32_cc(reg, cpu_env, reg, tmp);
+ } else {
+ gen_helper_roxr32_cc(reg, cpu_env, reg, tmp);
+ }
+ }
+ s->cc_op = CC_OP_FLAGS;
+}
+
+DISAS_INSN(rotate8_reg)
+{
+ TCGv reg;
+ TCGv src;
+ TCGv dest;
+ TCGv tmp;
+
+ reg = DREG(insn, 0);
+ src = DREG(insn, 9);
+ tmp = tcg_temp_new_i32();
+ tcg_gen_andi_i32(tmp, src, 63);
+ dest = tcg_temp_new_i32();
+ if (insn & 8) {
+ if (insn & 0x100) {
+ gen_helper_rol8_cc(dest, cpu_env, reg, tmp);
+ } else {
+ gen_helper_ror8_cc(dest, cpu_env, reg, tmp);
+ }
+ } else {
+ if (insn & 0x100) {
+ gen_helper_roxl8_cc(dest, cpu_env, reg, tmp);
+ } else {
+ gen_helper_roxr8_cc(dest, cpu_env, reg, tmp);
+ }
+ }
+ s->cc_op = CC_OP_FLAGS;
+ gen_partset_reg(OS_BYTE, reg, dest);
+}
+
+DISAS_INSN(rotate16_reg)
+{
+ TCGv reg;
+ TCGv src;
+ TCGv dest;
+ TCGv tmp;
+
+ reg = DREG(insn, 0);
+ src = DREG(insn, 9);
+ tmp = tcg_temp_new_i32();
+ tcg_gen_andi_i32(tmp, src, 63);
+ dest = tcg_temp_new_i32();
+ if (insn & 8) {
+ if (insn & 0x100) {
+ gen_helper_rol16_cc(dest, cpu_env, reg, tmp);
+ } else {
+ gen_helper_ror16_cc(dest, cpu_env, reg, tmp);
+ }
+ } else {
+ if (insn & 0x100) {
+ gen_helper_roxl16_cc(dest, cpu_env, reg, tmp);
+ } else {
+ gen_helper_roxr16_cc(dest, cpu_env, reg, tmp);
+ }
+ }
+ s->cc_op = CC_OP_FLAGS;
+ gen_partset_reg(OS_WORD, reg, dest);
+}
+
+DISAS_INSN(rotate_mem)
+{
+ TCGv src;
+ TCGv dest;
+ TCGv addr;
+ TCGv shift;
+
+ SRC_EA(src, OS_WORD, 0, &addr);
+ dest = tcg_temp_new_i32();
+ shift = tcg_const_i32(1);
+ if (insn & 8) {
+ if (insn & 0x100) {
+ gen_helper_rol16_cc(dest, cpu_env, src, shift);
+ } else {
+ gen_helper_ror16_cc(dest, cpu_env, src, shift);
+ }
+ } else {
+ if (insn & 0x100) {
+ gen_helper_roxl16_cc(dest, cpu_env, src, shift);
} else {
- gen_helper_sar_cc(reg, cpu_env, reg, shift);
+ gen_helper_roxr16_cc(dest, cpu_env, src, shift);
}
}
- s->cc_op = CC_OP_SHIFT;
-}
+ s->cc_op = CC_OP_FLAGS;
+ DEST_EA(insn, OS_WORD, dest, &addr);
+}
+
+static void bitfield_param(uint16_t ext, TCGv *offset, TCGv *width, TCGv *mask)
+{
+ TCGv tmp;
+
+ /* offset */
+
+ if (ext & 0x0800) {
+ *offset = tcg_temp_new_i32();
+ tcg_gen_mov_i32(*offset, DREG(ext, 6));
+ } else {
+ *offset = tcg_temp_new_i32();
+ tcg_gen_movi_i32(*offset, (ext >> 6) & 31);
+ }
+
+ /* width */
+
+ if (ext & 0x0020) {
+ *width = tcg_temp_new_i32();
+ tcg_gen_subi_i32(*width, DREG(ext, 0), 1);
+ tcg_gen_andi_i32(*width, *width, 31);
+ tcg_gen_addi_i32(*width, *width, 1);
+ } else {
+ *width = tcg_temp_new_i32();
+ tcg_gen_movi_i32(*width, ((ext - 1) & 31) + 1);
+ }
+
+ /* mask */
+
+ tmp = tcg_temp_new_i32();
+ tcg_gen_sub_i32(tmp, tcg_const_i32(32), *width);
+ *mask = tcg_temp_new_i32();
+ tcg_gen_shl_i32(*mask, tcg_const_i32(0xffffffff), tmp);
+}
+
+DISAS_INSN(bitfield_reg)
+{
+ uint16_t ext;
+ TCGv tmp;
+ TCGv tmp1;
+ TCGv reg;
+ TCGv offset;
+ TCGv width;
+ int op;
+ TCGv reg2;
+ TCGv mask;
+
+ reg = DREG(insn, 0);
+ op = (insn >> 8) & 7;
+ ext = read_im16(s);
+
+ bitfield_param(ext, &offset, &width, &mask);
+
+ if (ext & 0x0800)
+ tcg_gen_andi_i32(offset, offset, 31);
+ gen_helper_ror32(mask, mask, offset);
+
+ /* reg & mask */
+
+ tmp = tcg_temp_new_i32();
+ tcg_gen_and_i32(tmp, reg, mask);
+
+ tmp1 = tcg_temp_new_i32();
+ gen_helper_rol32(tmp1, tmp, offset);
+
+ reg2 = DREG(ext, 12);
+ if (op == 7) {
+ TCGv tmp2;
+
+ tmp2 = tcg_temp_new_i32();
+ tcg_gen_sub_i32(tmp2, tcg_const_i32(32), width);
+ tcg_gen_shl_i32(tmp2, reg2, tmp2);
+ tcg_gen_and_i32(tmp2, tmp2, mask);
+ gen_logic_cc(s, tmp2, OS_LONG);
+
+ tcg_temp_free_i32(tmp1);
+ } else {
+ gen_logic_cc(s, tmp1, OS_LONG);
+ }
+
+ switch (op) {
+ case 0: /* bftst */
+ break;
+ case 1: /* bfextu */
+ tcg_gen_add_i32(tmp1, offset, width);
+ tcg_gen_andi_i32(tmp1, tmp1, 31);
+ gen_helper_rol32(reg2, tmp, tmp1);
+ break;
+ case 2: /* bfchg */
+ tcg_gen_xor_i32(reg, reg, mask);
+ break;
+ case 3: /* bfexts */
+ gen_helper_rol32(reg2, tmp, offset);
+ tcg_gen_sub_i32(width, tcg_const_i32(32), width);
+ tcg_gen_sar_i32(reg2, reg2, width);
+ break;
+ case 4: /* bfclr */
+ tcg_gen_not_i32(mask, mask);
+ tcg_gen_and_i32(reg, reg, mask);
+ break;
+ case 5: /* bfffo */
+ gen_helper_rol32(reg2, tmp, offset);
+ gen_helper_bfffo(tmp, tmp, width);
+ tcg_gen_add_i32(reg2, tmp, offset);
+ break;
+ case 6: /* bfset */
+ tcg_gen_or_i32(reg, reg, mask);
+ break;
+ case 7: /* bfins */
+ tcg_gen_shl_i32(tmp1, tcg_const_i32(1), width);
+ tcg_gen_subi_i32(tmp1, tmp1, 1);
+ tcg_gen_and_i32(tmp, reg2, tmp1);
+ tcg_gen_add_i32(tmp1, offset, width);
+ tcg_gen_andi_i32(tmp1, tmp1, 31);
+ gen_helper_ror32(tmp, tmp, tmp1);
+ tcg_gen_not_i32(mask, mask);
+ tcg_gen_and_i32(reg, reg, mask);
+ tcg_gen_or_i32(reg, reg, tmp);
+ break;
+ }
+}
+
+static TCGv gen_bitfield_cc(DisasContext *s,
+ TCGv offset, TCGv mask_cc, TCGv_i64 bitfield)
+{
+ TCGv dest;
+ TCGv_i64 tmp64;
+
+ /* move bitfield to a 32bit */
+
+ tmp64 = tcg_temp_new_i64();
+
+ tcg_gen_extu_i32_i64(tmp64, offset);
+
+ /* tmp64 = bitfield << offset */
+
+ tcg_gen_shl_i64(tmp64, bitfield, tmp64);
+
+ /* tmp = (bitfield << offset) >> 32 */
+
+ tcg_gen_shri_i64(tmp64, tmp64, 32ULL);
+ dest = tcg_temp_new_i32();
+ tcg_gen_trunc_i64_i32(dest, tmp64);
+ tcg_gen_and_i32(dest, dest, mask_cc);
+
+ return dest;
+}
+
+static TCGv_i64 gen_bitfield_mask(TCGv offset, TCGv width)
+{
+ TCGv tmp;
+ TCGv_i64 mask;
+ TCGv_i64 shift;
+
+ mask = tcg_temp_new_i64();
+
+ /* mask = (1u << width) - 1; */
+
+ tcg_gen_extu_i32_i64(mask, width);
+ tcg_gen_shl_i64(mask, tcg_const_i64(1), mask);
+ tcg_gen_subi_i64(mask, mask, 1);
+
+ /* shift = 64 - (width + offset); */
+
+ tmp = tcg_temp_new_i32();
+ tcg_gen_add_i32(tmp, offset, width);
+ tcg_gen_sub_i32(tmp, tcg_const_i32(64), tmp);
+ shift = tcg_temp_new_i64();
+ tcg_gen_extu_i32_i64(shift, tmp);
+
+ /* mask <<= shift */
+
+ tcg_gen_shl_i64(mask, mask, shift);
+
+ return mask;
+}
+
+static void gen_bitfield_ins(TCGv offset, TCGv width, TCGv src,
+ TCGv_i64 val)
+{
+ TCGv_i64 insert;
+ TCGv_i64 shift;
+ TCGv tmp;
+
+ tmp = tcg_temp_new_i32();
+
+ /* tmp = (1u << width) - 1; */
+
+ /* width is between 1 and 32
+ * tcg_gen_shl_i32() cannot manage value 32
+ */
+ tcg_gen_subi_i32(tmp, width, 1);
+ tcg_gen_shl_i32(tmp, tcg_const_i32(2), tmp);
+ tcg_gen_subi_i32(tmp, tmp, 1);
+
+ /* tmp = tmp & src; */
+
+ tcg_gen_and_i32(tmp, tmp, src);
+
+ /* insert = (i64)tmp; */
+
+ insert = tcg_temp_new_i64();
+ tcg_gen_extu_i32_i64(insert, tmp);
+
+ /* tmp = 64 - (width + offset); */
+
+ tcg_gen_add_i32(tmp, offset, width);
+ tcg_gen_sub_i32(tmp, tcg_const_i32(64), tmp);
+ shift = tcg_temp_new_i64();
+ tcg_gen_extu_i32_i64(shift, tmp);
+
+ /* insert <<= shift */
+
+ tcg_gen_shl_i64(insert, insert, shift);
+
+ /* val |= select */
+
+ tcg_gen_or_i64(val, val, insert);
+}
+
+DISAS_INSN(bitfield_mem)
+{
+ uint16_t ext;
+ int op;
+ TCGv_i64 bitfield;
+ TCGv_i64 mask_bitfield;
+ TCGv mask_cc;
+ TCGv shift;
+ TCGv val;
+ TCGv src;
+ TCGv offset;
+ TCGv width;
+ TCGv reg;
+ TCGv tmp;
+
+ op = (insn >> 8) & 7;
+ ext = read_im16(s);
+ src = gen_lea(s, insn, OS_LONG);
+ if (IS_NULL_QREG(src)) {
+ gen_addr_fault(s);
+ return;
+ }
-DISAS_INSN(shift_reg)
-{
- TCGv reg;
- TCGv shift;
+ bitfield_param(ext, &offset, &width, &mask_cc);
- reg = DREG(insn, 0);
- shift = DREG(insn, 9);
- /* Shift by zero leaves C flag unmodified. */
- gen_flush_flags(s);
- if (insn & 0x100) {
- gen_helper_shl_cc(reg, cpu_env, reg, shift);
+ /* adjust src and offset */
+
+ /* src += offset >> 3; */
+
+ tmp = tcg_temp_new_i32();
+ tcg_gen_shri_i32(tmp, offset, 3);
+ tcg_gen_add_i32(src, src, tmp);
+
+ /* offset &= 7; */
+
+ tcg_gen_andi_i32(offset, offset, 7);
+
+ /* load */
+
+ bitfield = tcg_temp_new_i64();
+ gen_helper_bitfield_load(bitfield, src, offset, width);
+
+ /* compute CC and move bitfield into a 32bit */
+
+ val = gen_bitfield_cc(s, offset, mask_cc, bitfield);
+
+ /* execute operation */
+
+ reg = DREG(ext, 12);
+
+ if (op == 7) {
+ TCGv tmp1;
+
+ tmp1 = tcg_temp_new_i32();
+ tcg_gen_sub_i32(tmp1, tcg_const_i32(32), width);
+ tcg_gen_shl_i32(tmp1, reg, tmp1);
+ tcg_gen_and_i32(tmp1, tmp1, mask_cc);
+ gen_logic_cc(s, tmp1, OS_LONG);
+
+ tcg_temp_free_i32(tmp1);
} else {
- if (insn & 8) {
- gen_helper_shr_cc(reg, cpu_env, reg, shift);
- } else {
- gen_helper_sar_cc(reg, cpu_env, reg, shift);
- }
+ gen_logic_cc(s, val, OS_LONG);
+ }
+
+ switch (op) {
+ case 0: /* bftst */
+ break;
+ case 1: /* bfextu */
+ shift = tcg_temp_new_i32();
+ tcg_gen_sub_i32(shift, tcg_const_i32(32), width);
+ tcg_gen_shr_i32(reg, val, shift);
+ break;
+ case 2: /* bfchg */
+ mask_bitfield = gen_bitfield_mask(offset, width);
+ tcg_gen_xor_i64(bitfield, bitfield, mask_bitfield);
+ gen_helper_bitfield_store(src, offset, width, bitfield);
+ break;
+ case 3: /* bfexts */
+ shift = tcg_temp_new_i32();
+ tcg_gen_sub_i32(shift, tcg_const_i32(32), width);
+ tcg_gen_sar_i32(reg, val, shift);
+ break;
+ case 4: /* bfclr */
+ mask_bitfield = gen_bitfield_mask(offset, width);
+ tcg_gen_not_i64(mask_bitfield, mask_bitfield);
+ tcg_gen_and_i64(bitfield, bitfield, mask_bitfield);
+ gen_helper_bitfield_store(src, offset, width, bitfield);
+ break;
+ case 5: /* bfffo */
+ gen_helper_bfffo(val, val, width);
+ tcg_gen_add_i32(reg, val, offset);
+ break;
+ case 6: /* bfset */
+ mask_bitfield = gen_bitfield_mask(offset, width);
+ tcg_gen_or_i64(bitfield, bitfield, mask_bitfield);
+ gen_helper_bitfield_store(src, offset, width, bitfield);
+ break;
+ case 7: /* bfins */
+ /* clear */
+ mask_bitfield = gen_bitfield_mask(offset, width);
+ tcg_gen_not_i64(mask_bitfield, mask_bitfield);
+ tcg_gen_and_i64(bitfield, bitfield, mask_bitfield);
+ /* insert */
+ gen_bitfield_ins(offset, width, reg, bitfield);
+ gen_helper_bitfield_store(src, offset, width, bitfield);
+ break;
}
- s->cc_op = CC_OP_SHIFT;
}
DISAS_INSN(ff1)
{
TCGv reg;
reg = DREG(insn, 0);
- gen_logic_cc(s, reg);
+ gen_logic_cc(s, reg, OS_LONG);
gen_helper_ff1(reg, reg);
}
@@ -1940,14 +3437,12 @@ DISAS_INSN(strldsr)
uint32_t addr;
addr = s->pc - 2;
- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);
if (ext != 0x46FC) {
gen_exception(s, addr, EXCP_UNSUPPORTED);
return;
}
- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);
if (IS_USER(s) || (ext & SR_S) == 0) {
gen_exception(s, addr, EXCP_PRIVILEGE);
return;
@@ -1958,7 +3453,6 @@ DISAS_INSN(strldsr)
DISAS_INSN(move_from_sr)
{
- TCGv reg;
TCGv sr;
if (IS_USER(s)) {
@@ -1966,8 +3460,7 @@ DISAS_INSN(move_from_sr)
return;
}
sr = gen_get_sr(s);
- reg = DREG(insn, 0);
- gen_partset_reg(OS_WORD, reg, sr);
+ DEST_EA(insn, OS_WORD, sr, NULL);
}
DISAS_INSN(move_to_sr)
@@ -2014,8 +3507,7 @@ DISAS_INSN(stop)
return;
}
- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);
gen_set_sr_im(s, ext, 0);
tcg_gen_movi_i32(QREG_HALTED, 1);
@@ -2041,15 +3533,18 @@ DISAS_INSN(movec)
return;
}
- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);
if (ext & 0x8000) {
reg = AREG(ext, 12);
} else {
reg = DREG(ext, 12);
}
- gen_helper_movec(cpu_env, tcg_const_i32(ext & 0xfff), reg);
+ if (insn & 1) {
+ gen_helper_movec_to(cpu_env, tcg_const_i32(ext & 0xfff), reg);
+ } else {
+ gen_helper_movec_from(reg, cpu_env, tcg_const_i32(ext & 0xfff));
+ }
gen_lookup_tb(s);
}
@@ -2088,7 +3583,71 @@ DISAS_INSN(wdebug)
DISAS_INSN(trap)
{
- gen_exception(s, s->pc - 2, EXCP_TRAP0 + (insn & 0xf));
+ gen_exception(s, s->pc - 2, EXCP_TRAP0 + (insn & 0xf));
+}
+
+static void gen_op_fmovem(DisasContext *s, uint32_t insn, uint32_t ext)
+{
+ int opsize;
+ uint16_t mask;
+ int i;
+ uint32_t mode;
+ int32_t incr;
+ TCGv addr, tmp;
+ int is_load;
+
+ if (m68k_feature(s->env, M68K_FEATURE_FPU))
+ opsize = OS_EXTENDED;
+ else
+ opsize = OS_DOUBLE; // FIXME
+
+ mode = (ext >> 11) & 0x3;
+ if ((mode & 0x1) == 1) {
+ gen_helper_fmovem(cpu_env, tcg_const_i32(opsize),
+ tcg_const_i32(mode), DREG(ext, 0));
+ return;
+ }
+
+ tmp = gen_lea(s, insn, opsize);
+ if (IS_NULL_QREG(tmp)) {
+ gen_addr_fault(s);
+ return;
+ }
+
+ addr = tcg_temp_new();
+ tcg_gen_mov_i32(addr, tmp);
+ is_load = ((ext & 0x2000) == 0);
+ incr = opsize_bytes(opsize);
+ mask = ext & 0x00FF;
+
+ if (!is_load && (mode & 2) == 0) {
+ for (i = 7; i >= 0; i--, mask <<= 1) {
+ if (mask & 0x80) {
+ gen_op_load_fpr_FP0(i);
+ gen_store_FP0(s, opsize, addr);
+ if ((mask & 0xff) != 0x80)
+ tcg_gen_subi_i32(addr, addr, incr);
+ }
+ }
+ tcg_gen_mov_i32(AREG(insn, 0), addr);
+ } else{
+ for (i = 0; i < 8; i++, mask <<=1) {
+ if (mask & 0x80) {
+ if (is_load) {
+ gen_load_FP0(s, opsize, addr);
+ gen_op_store_fpr_FP0(i);
+ } else {
+ gen_op_load_fpr_FP0(i);
+ gen_store_FP0(s, opsize, addr);
+ }
+ if ((mask & 0xff) != 0x80 || (insn & 070) == 030)
+ tcg_gen_addi_i32(addr, addr, incr);
+ }
+ }
+ if ((insn & 070) == 030)
+ tcg_gen_mov_i32(AREG(insn, 0), addr);
+ }
+ tcg_temp_free_i32(addr);
}
/* ??? FP exceptions are not implemented. Most exceptions are deferred until
@@ -2096,86 +3655,40 @@ DISAS_INSN(trap)
DISAS_INSN(fpu)
{
uint16_t ext;
- int32_t offset;
+ uint8_t rom_offset;
int opmode;
- TCGv_i64 src;
- TCGv_i64 dest;
- TCGv_i64 res;
- TCGv tmp32;
int round;
int set_dest;
int opsize;
+ TCGv val;
- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);
opmode = ext & 0x7f;
switch ((ext >> 13) & 7) {
- case 0: case 2:
+ case 0:
break;
case 1:
goto undef;
- case 3: /* fmove out */
- src = FREG(ext, 7);
- tmp32 = tcg_temp_new_i32();
- /* fmove */
- /* ??? TODO: Proper behavior on overflow. */
- switch ((ext >> 10) & 7) {
- case 0:
- opsize = OS_LONG;
- gen_helper_f64_to_i32(tmp32, cpu_env, src);
- break;
- case 1:
- opsize = OS_SINGLE;
- gen_helper_f64_to_f32(tmp32, cpu_env, src);
- break;
- case 4:
- opsize = OS_WORD;
- gen_helper_f64_to_i32(tmp32, cpu_env, src);
- break;
- case 5: /* OS_DOUBLE */
- tcg_gen_mov_i32(tmp32, AREG(insn, 0));
- switch ((insn >> 3) & 7) {
- case 2:
- case 3:
- break;
- case 4:
- tcg_gen_addi_i32(tmp32, tmp32, -8);
- break;
- case 5:
- offset = ldsw_code(s->pc);
- s->pc += 2;
- tcg_gen_addi_i32(tmp32, tmp32, offset);
- break;
- default:
- goto undef;
- }
- gen_store64(s, tmp32, src);
- switch ((insn >> 3) & 7) {
- case 3:
- tcg_gen_addi_i32(tmp32, tmp32, 8);
- tcg_gen_mov_i32(AREG(insn, 0), tmp32);
- break;
- case 4:
- tcg_gen_mov_i32(AREG(insn, 0), tmp32);
- break;
- }
- tcg_temp_free_i32(tmp32);
+ case 2:
+ if ( insn == 0xf200 && (ext & 0xfc00) == 0x5c00) {
+ /* fmovecr */
+ rom_offset = ext & 0x7f;
+ gen_helper_const_FP0(cpu_env, tcg_const_i32(rom_offset));
+ gen_op_store_fpr_FP0(REG(ext, 7));
return;
- case 6:
- opsize = OS_BYTE;
- gen_helper_f64_to_i32(tmp32, cpu_env, src);
- break;
- default:
- goto undef;
}
- DEST_EA(insn, opsize, tmp32, NULL);
- tcg_temp_free_i32(tmp32);
+ break;
+ case 3: /* fmove out */
+ opsize = ext_opsize(ext, 10);
+ gen_op_load_fpr_FP0(REG(ext, 7));
+ gen_op_store_ea_FP0(s, insn, opsize);
return;
case 4: /* fmove to control register. */
switch ((ext >> 10) & 7) {
case 4: /* FPCR */
- /* Not implemented. Ignore writes. */
- break;
+ SRC_EA(val, OS_LONG, 0, NULL);
+ gen_helper_set_fpcr(cpu_env, val);
+ return;
case 1: /* FPIAR */
case 2: /* FPSR */
default:
@@ -2186,173 +3699,162 @@ DISAS_INSN(fpu)
case 5: /* fmove from control register. */
switch ((ext >> 10) & 7) {
case 4: /* FPCR */
- /* Not implemented. Always return zero. */
- tmp32 = tcg_const_i32(0);
- break;
+ DEST_EA(insn, OS_LONG, QEMU_FPCR, NULL);
+ return;
case 1: /* FPIAR */
+ cpu_abort(NULL, "Unimplemented: fmove from control FPIAR");
+ goto undef;
case 2: /* FPSR */
+ DEST_EA(insn, OS_LONG, QEMU_FPSR, NULL);
+ return;
default:
cpu_abort(NULL, "Unimplemented: fmove from control %d",
(ext >> 10) & 7);
goto undef;
}
- DEST_EA(insn, OS_LONG, tmp32, NULL);
break;
case 6: /* fmovem */
case 7:
- {
- TCGv addr;
- uint16_t mask;
- int i;
- if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
- goto undef;
- tmp32 = gen_lea(s, insn, OS_LONG);
- if (IS_NULL_QREG(tmp32)) {
- gen_addr_fault(s);
- return;
- }
- addr = tcg_temp_new_i32();
- tcg_gen_mov_i32(addr, tmp32);
- mask = 0x80;
- for (i = 0; i < 8; i++) {
- if (ext & mask) {
- s->is_mem = 1;
- dest = FREG(i, 0);
- if (ext & (1 << 13)) {
- /* store */
- tcg_gen_qemu_stf64(dest, addr, IS_USER(s));
- } else {
- /* load */
- tcg_gen_qemu_ldf64(dest, addr, IS_USER(s));
- }
- if (ext & (mask - 1))
- tcg_gen_addi_i32(addr, addr, 8);
- }
- mask >>= 1;
- }
- tcg_temp_free_i32(addr);
- }
+ if ((ext & 0xf00) != 0 || (ext & 0xff) == 0)
+ goto undef;
+ if ((ext & 0x1000) == 0 && !m68k_feature(s->env, M68K_FEATURE_FPU))
+ goto undef;
+ gen_op_fmovem(s, insn, ext);
return;
}
if (ext & (1 << 14)) {
- /* Source effective address. */
- switch ((ext >> 10) & 7) {
- case 0: opsize = OS_LONG; break;
- case 1: opsize = OS_SINGLE; break;
- case 4: opsize = OS_WORD; break;
- case 5: opsize = OS_DOUBLE; break;
- case 6: opsize = OS_BYTE; break;
- default:
- goto undef;
- }
- if (opsize == OS_DOUBLE) {
- tmp32 = tcg_temp_new_i32();
- tcg_gen_mov_i32(tmp32, AREG(insn, 0));
- switch ((insn >> 3) & 7) {
- case 2:
- case 3:
- break;
- case 4:
- tcg_gen_addi_i32(tmp32, tmp32, -8);
- break;
- case 5:
- offset = ldsw_code(s->pc);
- s->pc += 2;
- tcg_gen_addi_i32(tmp32, tmp32, offset);
- break;
- case 7:
- offset = ldsw_code(s->pc);
- offset += s->pc - 2;
- s->pc += 2;
- tcg_gen_addi_i32(tmp32, tmp32, offset);
- break;
- default:
- goto undef;
- }
- src = gen_load64(s, tmp32);
- switch ((insn >> 3) & 7) {
- case 3:
- tcg_gen_addi_i32(tmp32, tmp32, 8);
- tcg_gen_mov_i32(AREG(insn, 0), tmp32);
- break;
- case 4:
- tcg_gen_mov_i32(AREG(insn, 0), tmp32);
- break;
- }
- tcg_temp_free_i32(tmp32);
- } else {
- SRC_EA(tmp32, opsize, 1, NULL);
- src = tcg_temp_new_i64();
- switch (opsize) {
- case OS_LONG:
- case OS_WORD:
- case OS_BYTE:
- gen_helper_i32_to_f64(src, cpu_env, tmp32);
- break;
- case OS_SINGLE:
- gen_helper_f32_to_f64(src, cpu_env, tmp32);
- break;
- }
- }
+ opsize = ext_opsize(ext, 10);
+ gen_op_load_ea_FP0(s, insn, opsize);
} else {
/* Source register. */
- src = FREG(ext, 10);
+ opsize = OS_EXTENDED;
+ gen_op_load_fpr_FP0(REG(ext, 10));
}
- dest = FREG(ext, 7);
- res = tcg_temp_new_i64();
- if (opmode != 0x3a)
- tcg_gen_mov_f64(res, dest);
round = 1;
set_dest = 1;
switch (opmode) {
case 0: case 0x40: case 0x44: /* fmove */
- tcg_gen_mov_f64(res, src);
break;
case 1: /* fint */
- gen_helper_iround_f64(res, cpu_env, src);
+ gen_helper_iround_FP0(cpu_env);
round = 0;
break;
+ case 2: /* fsinh */
+ gen_helper_sinh_FP0(cpu_env);
+ break;
case 3: /* fintrz */
- gen_helper_itrunc_f64(res, cpu_env, src);
+ gen_helper_itrunc_FP0(cpu_env);
round = 0;
break;
case 4: case 0x41: case 0x45: /* fsqrt */
- gen_helper_sqrt_f64(res, cpu_env, src);
+ gen_helper_sqrt_FP0(cpu_env);
+ break;
+ case 6: /* flognp1 */
+ gen_helper_lognp1_FP0(cpu_env);
+ break;
+ case 0x09: /* ftanh */
+ gen_helper_tanh_FP0(cpu_env);
+ break;
+ case 0x0a: /* fatan */
+ gen_helper_atan_FP0(cpu_env);
+ break;
+ case 0x0c: /* fasin */
+ gen_helper_asin_FP0(cpu_env);
+ break;
+ case 0x0d: /* fatanh */
+ gen_helper_atanh_FP0(cpu_env);
+ break;
+ case 0x0e: /* fsin */
+ gen_helper_sin_FP0(cpu_env);
+ break;
+ case 0x0f: /* ftan */
+ gen_helper_tan_FP0(cpu_env);
+ break;
+ case 0x10: /* fetox */
+ gen_helper_exp_FP0(cpu_env);
+ break;
+ case 0x11: /* ftwotox */
+ gen_helper_exp2_FP0(cpu_env);
+ break;
+ case 0x12: /* ftentox */
+ gen_helper_exp10_FP0(cpu_env);
+ break;
+ case 0x14: /* flogn */
+ gen_helper_ln_FP0(cpu_env);
+ break;
+ case 0x15: /* flog10 */
+ gen_helper_log10_FP0(cpu_env);
break;
case 0x18: case 0x58: case 0x5c: /* fabs */
- gen_helper_abs_f64(res, src);
+ gen_helper_abs_FP0(cpu_env);
+ break;
+ case 0x19:
+ gen_helper_cosh_FP0(cpu_env);
break;
case 0x1a: case 0x5a: case 0x5e: /* fneg */
- gen_helper_chs_f64(res, src);
+ gen_helper_chs_FP0(cpu_env);
+ break;
+ case 0x1c: /* facos */
+ gen_helper_acos_FP0(cpu_env);
+ break;
+ case 0x1d: /* fcos */
+ gen_helper_cos_FP0(cpu_env);
+ break;
+ case 0x1e: /* fgetexp */
+ gen_helper_getexp_FP0(cpu_env);
break;
case 0x20: case 0x60: case 0x64: /* fdiv */
- gen_helper_div_f64(res, cpu_env, res, src);
+ gen_op_load_fpr_FP1(REG(ext, 7));
+ gen_helper_div_FP0_FP1(cpu_env);
+ break;
+ case 0x21: /* fmod */
+ gen_op_load_fpr_FP1(REG(ext, 7));
+ gen_helper_mod_FP0_FP1(cpu_env);
break;
case 0x22: case 0x62: case 0x66: /* fadd */
- gen_helper_add_f64(res, cpu_env, res, src);
+ gen_op_load_fpr_FP1(REG(ext, 7));
+ gen_helper_add_FP0_FP1(cpu_env);
break;
case 0x23: case 0x63: case 0x67: /* fmul */
- gen_helper_mul_f64(res, cpu_env, res, src);
+ gen_op_load_fpr_FP1(REG(ext, 7));
+ gen_helper_mul_FP0_FP1(cpu_env);
+ break;
+ case 0x24: /* fsgldiv */
+ gen_op_load_fpr_FP1(REG(ext, 7));
+ gen_helper_div_FP0_FP1(cpu_env);
+ break;
+ case 0x26: /* fscale */
+ gen_op_load_fpr_FP1(REG(ext, 7));
+ gen_helper_scale_FP0_FP1(cpu_env);
+ break;
+ case 0x27: /* fsglmul */
+ gen_op_load_fpr_FP1(REG(ext, 7));
+ gen_helper_mul_FP0_FP1(cpu_env);
break;
case 0x28: case 0x68: case 0x6c: /* fsub */
- gen_helper_sub_f64(res, cpu_env, res, src);
+ gen_op_load_fpr_FP1(REG(ext, 7));
+ gen_helper_sub_FP0_FP1(cpu_env);
+ break;
+ case 0x30: case 0x31: case 0x32:
+ case 0x33: case 0x34: case 0x35:
+ case 0x36: case 0x37:
+ gen_helper_sincos_FP0_FP1(cpu_env);
+ gen_op_store_fpr_FP0(REG(ext, 7)); /* sin */
+ gen_op_store_fpr_FP1(REG(ext, 0)); /* cos */
break;
case 0x38: /* fcmp */
- gen_helper_sub_cmp_f64(res, cpu_env, res, src);
+ gen_op_load_fpr_FP1(REG(ext, 7));
+ gen_helper_fcmp_FP0_FP1(cpu_env);
set_dest = 0;
round = 0;
break;
case 0x3a: /* ftst */
- tcg_gen_mov_f64(res, src);
set_dest = 0;
round = 0;
break;
default:
goto undef;
}
- if (ext & (1 << 14)) {
- tcg_temp_free_i64(src);
- }
if (round) {
if (opmode & 0x40) {
if ((opmode & 0x4) != 0)
@@ -2362,16 +3864,16 @@ DISAS_INSN(fpu)
}
}
if (round) {
+#if 0
TCGv tmp = tcg_temp_new_i32();
gen_helper_f64_to_f32(tmp, cpu_env, res);
gen_helper_f32_to_f64(res, cpu_env, tmp);
tcg_temp_free_i32(tmp);
+#endif
}
- tcg_gen_mov_f64(QREG_FP_RESULT, res);
if (set_dest) {
- tcg_gen_mov_f64(dest, res);
+ gen_op_store_fpr_FP0(REG(ext, 7));
}
- tcg_temp_free_i64(res);
return;
undef:
/* FIXME: Is this right for offset addressing modes? */
@@ -2379,27 +3881,15 @@ undef:
disas_undef_fpu(s, insn);
}
-DISAS_INSN(fbcc)
+static void gen_fjmpcc(DisasContext *s, int cond, int l1)
{
- uint32_t offset;
- uint32_t addr;
TCGv flag;
- int l1;
-
- addr = s->pc;
- offset = ldsw_code(s->pc);
- s->pc += 2;
- if (insn & (1 << 6)) {
- offset = (offset << 16) | lduw_code(s->pc);
- s->pc += 2;
- }
- l1 = gen_new_label();
/* TODO: Raise BSUN exception. */
flag = tcg_temp_new();
- gen_helper_compare_f64(flag, cpu_env, QREG_FP_RESULT);
+ gen_helper_compare_FP0(flag, cpu_env);
/* Jump to l1 if condition is true. */
- switch (insn & 0xf) {
+ switch (cond) {
case 0: /* f */
break;
case 1: /* eq (=0) */
@@ -2421,12 +3911,12 @@ DISAS_INSN(fbcc)
tcg_gen_andi_i32(flag, flag, 1);
tcg_gen_brcond_i32(TCG_COND_NE, flag, tcg_const_i32(0), l1);
break;
- case 7: /* or (=2) */
- tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(2), l1);
- break;
- case 8: /* un (<2) */
+ case 7: /* or (<2) */
tcg_gen_brcond_i32(TCG_COND_LT, flag, tcg_const_i32(2), l1);
break;
+ case 8: /* un (=2) */
+ tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(2), l1);
+ break;
case 9: /* ueq (=0 or =2) */
tcg_gen_andi_i32(flag, flag, 1);
tcg_gen_brcond_i32(TCG_COND_EQ, flag, tcg_const_i32(0), l1);
@@ -2450,21 +3940,91 @@ DISAS_INSN(fbcc)
tcg_gen_br(l1);
break;
}
+}
+
+DISAS_INSN(fbcc)
+{
+ uint32_t offset;
+ uint32_t addr;
+ int l1;
+
+ addr = s->pc;
+ offset = ldsw_code(s->pc);
+ s->pc += 2;
+ if (insn & (1 << 6)) {
+ offset = (offset << 16) | lduw_code(s->pc);
+ s->pc += 2;
+ }
+
+ l1 = gen_new_label();
+ gen_fjmpcc(s, insn & 0xf, l1);
gen_jmp_tb(s, 0, s->pc);
gen_set_label(l1);
gen_jmp_tb(s, 1, addr + offset);
}
+DISAS_INSN(fscc_mem)
+{
+ int l1, l2;
+ TCGv taddr;
+ TCGv addr;
+ uint16_t ext;
+
+ ext = read_im16(s);
+
+ taddr = gen_lea(s, insn, OS_BYTE);
+ if (IS_NULL_QREG(taddr)) {
+ gen_addr_fault(s);
+ return;
+ }
+ addr = tcg_temp_local_new ();
+ tcg_gen_mov_i32(addr, taddr);
+ l1 = gen_new_label();
+ l2 = gen_new_label();
+ gen_fjmpcc(s, ext & 0xf, l1);
+ gen_store(s, OS_BYTE, addr, tcg_const_i32(0x00));
+ tcg_gen_br(l2);
+ gen_set_label(l1);
+ gen_store(s, OS_BYTE, addr, tcg_const_i32(0xff));
+ gen_set_label(l2);
+ tcg_temp_free(addr);
+}
+
+DISAS_INSN(fscc_reg)
+{
+ int l1;
+ TCGv reg;
+ uint16_t ext;
+
+ ext = read_im16(s);
+
+ reg = DREG(insn, 0);
+
+ l1 = gen_new_label();
+ tcg_gen_ori_i32(reg, reg, 0x000000ff);
+ gen_fjmpcc(s, ext & 0xf, l1);
+ tcg_gen_andi_i32(reg, reg, 0xffffff00);
+ gen_set_label(l1);
+}
+
DISAS_INSN(frestore)
{
/* TODO: Implement frestore. */
- qemu_assert(0, "FRESTORE not implemented");
+ // qemu_assert(0, "FRESTORE not implemented");
+ // cpu_abort(cpu_single_env, "Illegal instruction: %04x @ %08x",
+ // insn, s->pc - 2);
+
+
}
DISAS_INSN(fsave)
{
/* TODO: Implement fsave. */
- qemu_assert(0, "FSAVE not implemented");
+ // qemu_assert(0, "FSAVE not implemented");
+ // cpu_abort(cpu_single_env, "Illegal instruction: %04x @ %08x",
+ // insn, s->pc - 2);
+
+
}
static inline TCGv gen_mac_extract_word(DisasContext *s, TCGv val, int upper)
@@ -2512,8 +4072,7 @@ DISAS_INSN(mac)
s->done_mac = 1;
}
- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);
acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
@@ -2780,6 +4339,13 @@ DISAS_INSN(to_mext)
gen_helper_set_mac_extu(cpu_env, val, acc);
}
+#ifdef CONFIG_EMULOP
+DISAS_INSN(emulop_exec_return)
+{
+ gen_exception(s, s->pc - 2, EXCP_EXEC_RETURN);
+}
+#endif
+
static disas_proc opcode_table[65536];
static void
@@ -2815,6 +4381,71 @@ register_opcode (disas_proc proc, uint16_t
opcode, uint16_t mask)
}
}
+/* my instructions start here */
+DISAS_INSN(cinva)
+{
+/* Cache invalidate (NOP)*/
+}
+
+DISAS_INSN(pflush)
+{
+ int opmode = (insn>>3) & 0x3;
+ switch(opmode)
+ {
+ case 0x0:
+ case 0x1:
+ fprintf(stderr,"entry\n");
+ break;
+ case 0x2:
+ case 0x3:
+ fprintf(stderr,"all\n");
+ break;
+
+ }
+
+
+}
+DISAS_INSN(move16)
+{
+ TCGv src;
+ TCGv s_addr;
+ TCGv d_addr;
+ uint16_t im;
+ if(insn & 0x8){
+
+ vm_stop(VMSTOP_DEBUG);
+ //abort();
+ }else if(insn & 0x10){
+
+ vm_stop(VMSTOP_DEBUG);
+ //abort();
+
+ }else{
+
+ d_addr = tcg_temp_new();
+ s_addr = tcg_temp_new();
+
+ s_addr = AREG(insn,0);
+ src = gen_load(s, OS_LONG, s_addr, 0);
+
+ im = read_im16(s);
+ d_addr = AREG(im,12);
+
+ gen_store(s, OS_LONG, d_addr, src);
+
+ int i = 0;
+ for(;i <3; i++)
+ {
+ tcg_gen_addi_i32(d_addr,d_addr,4);
+ tcg_gen_addi_i32(s_addr,s_addr,4);
+
+ src = gen_load(s, OS_LONG, s_addr, 0);
+ gen_store(s, OS_LONG, d_addr, src);
+ }
+ }
+}
+
+
/* Register m68k opcode handlers. Order is important.
Later insn override earlier ones. */
void register_m68k_insns (CPUM68KState *env)
@@ -2824,85 +4455,163 @@ void register_m68k_insns (CPUM68KState *env)
register_opcode(disas_##name, 0x##opcode, 0x##mask); \
} while(0)
INSN(undef, 0000, 0000, CF_ISA_A);
+ INSN(undef, 0000, 0000, M68000);
INSN(arith_im, 0080, fff8, CF_ISA_A);
+ INSN(arith_im, 0000, ff00, M68000);
+ INSN(undef, 00c0, ffc0, M68000);
INSN(bitrev, 00c0, fff8, CF_ISA_APLUSC);
INSN(bitop_reg, 0100, f1c0, CF_ISA_A);
+ INSN(bitop_reg, 0100, f1c0, M68000);
INSN(bitop_reg, 0140, f1c0, CF_ISA_A);
+ INSN(bitop_reg, 0140, f1c0, M68000);
INSN(bitop_reg, 0180, f1c0, CF_ISA_A);
+ INSN(bitop_reg, 0180, f1c0, M68000);
INSN(bitop_reg, 01c0, f1c0, CF_ISA_A);
+ INSN(bitop_reg, 01c0, f1c0, M68000);
INSN(arith_im, 0280, fff8, CF_ISA_A);
+ INSN(arith_im, 0200, ff00, M68000);
+ INSN(undef, 02c0, ffc0, M68000);
INSN(byterev, 02c0, fff8, CF_ISA_APLUSC);
INSN(arith_im, 0480, fff8, CF_ISA_A);
+ INSN(arith_im, 0400, ff00, M68000);
+ INSN(undef, 04c0, ffc0, M68000);
+ INSN(arith_im, 0600, ff00, M68000);
+ INSN(undef, 06c0, ffc0, M68000);
INSN(ff1, 04c0, fff8, CF_ISA_APLUSC);
INSN(arith_im, 0680, fff8, CF_ISA_A);
INSN(bitop_im, 0800, ffc0, CF_ISA_A);
+ INSN(bitop_im, 0800, ffc0, M68000);
INSN(bitop_im, 0840, ffc0, CF_ISA_A);
+ INSN(bitop_im, 0840, ffc0, M68000);
INSN(bitop_im, 0880, ffc0, CF_ISA_A);
+ INSN(bitop_im, 0880, ffc0, M68000);
+ INSN(cas, 08c0, f9c0, CAS);
INSN(bitop_im, 08c0, ffc0, CF_ISA_A);
+ INSN(bitop_im, 08c0, ffc0, M68000);
INSN(arith_im, 0a80, fff8, CF_ISA_A);
+ INSN(arith_im, 0a00, ff00, M68000);
+ INSN(undef, 0ac0, ffc0, M68000);
INSN(arith_im, 0c00, ff38, CF_ISA_A);
+ INSN(arith_im, 0c00, ff00, M68000);
+ INSN(undef, 0cc0, ffc0, M68000);
INSN(move, 1000, f000, CF_ISA_A);
+ INSN(move, 1000, f000, M68000);
INSN(move, 2000, f000, CF_ISA_A);
+ INSN(move, 2000, f000, M68000);
INSN(move, 3000, f000, CF_ISA_A);
+ INSN(move, 3000, f000, M68000);
INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC);
INSN(negx, 4080, fff8, CF_ISA_A);
+ INSN(negx, 4000, ff00, M68000);
+ INSN(undef, 40c0, ffc0, M68000);
INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
+ INSN(move_from_sr, 40c0, ffc0, M68000);
INSN(lea, 41c0, f1c0, CF_ISA_A);
+ INSN(lea, 41c0, f1c0, M68000);
INSN(clr, 4200, ff00, CF_ISA_A);
+ INSN(clr, 4200, ff00, M68000);
INSN(undef, 42c0, ffc0, CF_ISA_A);
+ INSN(undef, 42c0, ffc0, M68000);
INSN(move_from_ccr, 42c0, fff8, CF_ISA_A);
INSN(neg, 4480, fff8, CF_ISA_A);
+ INSN(neg, 4400, ff00, M68000);
+ INSN(undef, 44c0, ffc0, M68000);
INSN(move_to_ccr, 44c0, ffc0, CF_ISA_A);
+ INSN(move_to_ccr, 44c0, ffc0, M68000);
INSN(not, 4680, fff8, CF_ISA_A);
+ INSN(not, 4600, ff00, M68000);
+ INSN(move_to_sr, 46c0, ffc0, M68000);
INSN(move_to_sr, 46c0, ffc0, CF_ISA_A);
+ INSN(nbcd, 4800, ffc0, M68000);
+ INSN(linkl, 4808, fff8, M68000);
INSN(pea, 4840, ffc0, CF_ISA_A);
+ INSN(pea, 4840, ffc0, M68000);
INSN(swap, 4840, fff8, CF_ISA_A);
+ INSN(swap, 4840, fff8, M68000);
+ INSN(bkpt, 4848, fff8, M68000);
INSN(movem, 48c0, fbc0, CF_ISA_A);
+ INSN(movem, 48c0, fbc0, M68000);
INSN(ext, 4880, fff8, CF_ISA_A);
+ INSN(ext, 4880, fff8, M68000);
INSN(ext, 48c0, fff8, CF_ISA_A);
+ INSN(ext, 48c0, fff8, M68000);
INSN(ext, 49c0, fff8, CF_ISA_A);
+ INSN(ext, 49c0, fff8, M68000);
INSN(tst, 4a00, ff00, CF_ISA_A);
+ INSN(tst, 4a00, ff00, M68000);
INSN(tas, 4ac0, ffc0, CF_ISA_B);
+ INSN(tas, 4ac0, ffc0, M68000);
INSN(halt, 4ac8, ffff, CF_ISA_A);
INSN(pulse, 4acc, ffff, CF_ISA_A);
INSN(illegal, 4afc, ffff, CF_ISA_A);
+ INSN(illegal, 4afc, ffff, M68000);
INSN(mull, 4c00, ffc0, CF_ISA_A);
+ INSN(mull, 4c00, ffc0, LONG_MULDIV);
INSN(divl, 4c40, ffc0, CF_ISA_A);
+ INSN(divl, 4c40, ffc0, LONG_MULDIV);
INSN(sats, 4c80, fff8, CF_ISA_B);
INSN(trap, 4e40, fff0, CF_ISA_A);
+ INSN(trap, 4e40, fff0, M68000);
INSN(link, 4e50, fff8, CF_ISA_A);
+ INSN(link, 4e50, fff8, M68000);
INSN(unlk, 4e58, fff8, CF_ISA_A);
+ INSN(unlk, 4e58, fff8, M68000);
INSN(move_to_usp, 4e60, fff8, USP);
INSN(move_from_usp, 4e68, fff8, USP);
INSN(nop, 4e71, ffff, CF_ISA_A);
+ INSN(nop, 4e71, ffff, M68000);
INSN(stop, 4e72, ffff, CF_ISA_A);
+ INSN(stop, 4e72, ffff, M68000);
INSN(rte, 4e73, ffff, CF_ISA_A);
+ INSN(rte, 4e73, ffff, M68000);
INSN(rts, 4e75, ffff, CF_ISA_A);
- INSN(movec, 4e7b, ffff, CF_ISA_A);
+ INSN(rts, 4e75, ffff, M68000);
+ INSN(movec, 4e7a, fffe, CF_ISA_A);
+ INSN(movec, 4e7a, fffe, M68000);
INSN(jump, 4e80, ffc0, CF_ISA_A);
+ INSN(jump, 4e80, ffc0, M68000);
INSN(jump, 4ec0, ffc0, CF_ISA_A);
- INSN(addsubq, 5180, f1c0, CF_ISA_A);
+ INSN(jump, 4ec0, ffc0, M68000);
+ INSN(addsubq, 5080, f0c0, CF_ISA_A);
+ INSN(addsubq, 5000, f080, M68000);
+ INSN(addsubq, 5080, f0c0, M68000);
INSN(scc, 50c0, f0f8, CF_ISA_A);
- INSN(addsubq, 5080, f1c0, CF_ISA_A);
+ INSN(scc_mem, 50c0, f0c0, M68000);
+ INSN(scc, 50c0, f0f8, M68000);
+ INSN(dbcc, 50c8, f0f8, M68000);
INSN(tpf, 51f8, fff8, CF_ISA_A);
/* Branch instructions. */
INSN(branch, 6000, f000, CF_ISA_A);
+ INSN(branch, 6000, f000, M68000);
/* Disable long branch instructions, then add back the ones we want. */
INSN(undef, 60ff, f0ff, CF_ISA_A); /* All long branches. */
+ INSN(undef, 60ff, f0ff, M68000); /* All long branches. */
INSN(branch, 60ff, f0ff, CF_ISA_B);
INSN(undef, 60ff, ffff, CF_ISA_B); /* bra.l */
INSN(branch, 60ff, ffff, BRAL);
+ INSN(branch, 60ff, f0ff, BCCL);
INSN(moveq, 7000, f100, CF_ISA_A);
+ INSN(moveq, 7000, f100, M68000);
INSN(mvzs, 7100, f100, CF_ISA_B);
INSN(or, 8000, f000, CF_ISA_A);
+ INSN(or, 8000, f000, M68000);
INSN(divw, 80c0, f0c0, CF_ISA_A);
+ INSN(divw, 80c0, f0c0, M68000);
+ INSN(sbcd_reg, 8100, f1f8, M68000);
+ INSN(sbcd_mem, 8108, f1f8, M68000);
INSN(addsub, 9000, f000, CF_ISA_A);
- INSN(subx, 9180, f1f8, CF_ISA_A);
+ INSN(addsub, 9000, f000, M68000);
+ INSN(undef, 90c0, f0c0, CF_ISA_A);
+ INSN(subx_reg, 9180, f1f8, CF_ISA_A);
+ INSN(subx_reg, 9100, f138, M68000);
+ INSN(subx_mem, 9108, f138, M68000);
INSN(suba, 91c0, f1c0, CF_ISA_A);
+ INSN(suba, 90c0, f0c0, M68000);
INSN(undef_mac, a000, f000, CF_ISA_A);
+ INSN(undef_mac, a000, f000, M68000);
INSN(mac, a000, f100, CF_EMAC);
INSN(from_mac, a180, f9b0, CF_EMAC);
INSN(move_mac, a110, f9fc, CF_EMAC);
@@ -2921,23 +4630,69 @@ void register_m68k_insns (CPUM68KState *env)
INSN(cmpa, b0c0, f1c0, CF_ISA_B); /* cmpa.w */
INSN(cmp, b080, f1c0, CF_ISA_A);
INSN(cmpa, b1c0, f1c0, CF_ISA_A);
+ INSN(cmp, b000, f100, M68000);
+ INSN(eor, b100, f100, M68000);
+ INSN(cmpa, b0c0, f0c0, M68000);
INSN(eor, b180, f1c0, CF_ISA_A);
INSN(and, c000, f000, CF_ISA_A);
+ INSN(and, c000, f000, M68000);
INSN(mulw, c0c0, f0c0, CF_ISA_A);
+ INSN(mulw, c0c0, f0c0, M68000);
+ INSN(abcd_reg, c100, f1f8, M68000);
+ INSN(abcd_mem, c108, f1f8, M68000);
INSN(addsub, d000, f000, CF_ISA_A);
- INSN(addx, d180, f1f8, CF_ISA_A);
+ INSN(addsub, d000, f000, M68000);
+ INSN(undef, d0c0, f0c0, CF_ISA_A);
+ INSN(addx_reg, d180, f1f8, CF_ISA_A);
+ INSN(addx_reg, d100, f138, M68000);
+ INSN(addx_mem, d108, f138, M68000);
INSN(adda, d1c0, f1c0, CF_ISA_A);
+ INSN(adda, d0c0, f0c0, M68000);
+ /* Bit ops */
INSN(shift_im, e080, f0f0, CF_ISA_A);
INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
+ INSN(shift8_im, e000, f0f0, M68000);
+ INSN(shift16_im, e040, f0f0, M68000);
+ INSN(shift_im, e080, f0f0, M68000);
+ INSN(shift8_reg, e020, f0f0, M68000);
+ INSN(shift16_reg, e060, f0f0, M68000);
+ INSN(shift_reg, e0a0, f0f0, M68000);
+ INSN(shift_mem, e0c0, fcc0, M68000);
+ INSN(rotate_im, e090, f0f0, M68000);
+ INSN(rotate8_im, e010, f0f0, M68000);
+ INSN(rotate16_im, e050, f0f0, M68000);
+ INSN(rotate_reg, e0b0, f0f0, M68000);
+ INSN(rotate8_reg, e030, f0f0, M68000);
+ INSN(rotate16_reg,e070, f0f0, M68000);
+ INSN(rotate_mem, e4c0, fcc0, M68000);
+ INSN(bitfield_mem,e8c0, f8c0, BITFIELD);
+ INSN(bitfield_reg,e8c0, f8f8, BITFIELD);
+ /* FPU */
INSN(undef_fpu, f000, f000, CF_ISA_A);
+ INSN(undef_fpu, f000, f000, M68000);
INSN(fpu, f200, ffc0, CF_FPU);
INSN(fbcc, f280, ffc0, CF_FPU);
INSN(frestore, f340, ffc0, CF_FPU);
INSN(fsave, f340, ffc0, CF_FPU);
- INSN(intouch, f340, ffc0, CF_ISA_A);
+ INSN(fpu, f200, ffc0, FPU);
+ INSN(fscc_mem, f240, ffc0, FPU);
+ INSN(fscc_reg, f240, fff8, FPU);
+ INSN(fbcc, f280, ffc0, FPU);
+ INSN(frestore, f300, ffc0, FPU);
+ INSN(fsave, f340, ffc0, FPU);
+ INSN(intouch, f340, ffc0, CF_ISA_A);
+ /* MMU */
INSN(cpushl, f428, ff38, CF_ISA_A);
- INSN(wddata, fb00, ff00, CF_ISA_A);
+ INSN(cpushl, f478, ff78, M68000);
+ INSN(cinva, f4d8, f4d8, M68000);
+ INSN(pflush, f500, f500, M68000);
+
+ INSN(move16, f600, f600, M68000);
+ INSN(wddata, fb00, ff00, CF_ISA_A);
INSN(wdebug, fbc0, ffc0, CF_ISA_A);
+#ifdef CONFIG_EMULOP
+ INSN(emulop_exec_return, 7100, ffff, M68000);
+#endif
#undef INSN
}
@@ -2947,8 +4702,10 @@ static void disas_m68k_insn(CPUState * env,
DisasContext *s)
{
uint16_t insn;
- insn = lduw_code(s->pc);
- s->pc += 2;
+ if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
+ tcg_gen_debug_insn_start(s->pc);
+
+ insn = read_im16(s);
opcode_table[insn](s, insn);
}
@@ -3073,9 +4830,6 @@ gen_intermediate_code_internal(CPUState *env,
TranslationBlock *tb,
tb->size = dc->pc - pc_start;
tb->icount = num_insns;
}
-
- //optimize_flags();
- //expand_target_qops();
}
void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
@@ -3093,20 +4847,18 @@ void cpu_dump_state(CPUState *env, FILE *f,
fprintf_function cpu_fprintf,
{
int i;
uint16_t sr;
- CPU_DoubleU u;
for (i = 0; i < 8; i++)
{
- u.d = env->fregs[i];
- cpu_fprintf (f, "D%d = %08x A%d = %08x F%d = %08x%08x (%12g)\n",
+ cpu_fprintf (f, "D%d = %08x A%d = %08x "
+ "F%d = %" PRIxFPH " %" PRIxFPL "\n",
i, env->dregs[i], i, env->aregs[i],
- i, u.l.upper, u.l.lower, *(double *)&u.d);
+ i, env->fregs[i].d.high, env->fregs[i].d.low);
}
cpu_fprintf (f, "PC = %08x ", env->pc);
sr = env->sr;
cpu_fprintf (f, "SR = %04x %c%c%c%c%c ", sr, (sr & 0x10) ? 'X' : '-',
(sr & CCF_N) ? 'N' : '-', (sr & CCF_Z) ? 'Z' : '-',
(sr & CCF_V) ? 'V' : '-', (sr & CCF_C) ? 'C' : '-');
- cpu_fprintf (f, "FPRESULT = %12g\n", *(double *)&env->fp_result);
}
void restore_state_to_opc(CPUState *env, TranslationBlock *tb, int pc_pos)
diff --git tests/m68k/Makefile tests/m68k/Makefile
new file mode 100644
index 0000000..27525d3
--- /dev/null
+++ tests/m68k/Makefile
@@ -0,0 +1,12 @@
+TESTS=fmovecr fmove fmovem fsub fdiv fmul fabs fgetexp fscale flogn fetox \
+ bfins inf
+
+all: $(TESTS)
+
+%: %.S
+ m68k-linux-gnu-gcc -m68040 -nostartfiles -nodefaultlibs -nostdlib -o
$@ $<
+
+.PHONY: clean
+
+clean:
+ rm -f $(TESTS)
diff --git tests/m68k/bfins.S tests/m68k/bfins.S
new file mode 100644
index 0000000..a0b27f9
--- /dev/null
+++ tests/m68k/bfins.S
@@ -0,0 +1,23 @@
+ .include "trap.i"
+
+ .data
+.A: .long 0
+ .text
+ .globl _start
+_start:
+ move.l #0,%d1
+ move.l #1,%d0
+ bfins %d0,%d1,4,4
+ move.l #3,%d0
+ bfins %d0,%d1,8,2
+ move.l #0,%d0
+ bfins %d0,%d1,8,16
+
+ move.l #1,%d0
+ lea .A,%a0
+ bfins %d0,(%a0),4,4
+ move.l #3,%d0
+ bfins %d0,(%a0),8,2
+ move.l #0,%d0
+ bfins %d0,(%a0),8,16
+ exit 0
diff --git tests/m68k/fabs.S tests/m68k/fabs.S
new file mode 100644
index 0000000..cbe2a4a
--- /dev/null
+++ tests/m68k/fabs.S
@@ -0,0 +1,9 @@
+ .include "trap.i"
+
+ .text
+ .globl _start
+_start:
+ fabs.b #-55, %fp0
+ fmove.l #-1024, %fp1
+ fabs.x %fp1
+ exit 0
diff --git tests/m68k/fdiv.S tests/m68k/fdiv.S
new file mode 100644
index 0000000..a5e3656
--- /dev/null
+++ tests/m68k/fdiv.S
@@ -0,0 +1,10 @@
+ .include "trap.i"
+
+ .text
+ .globl _start
+_start:
+# Pi
+ fmove.b #10, %fp0
+ fmove.b #3, %fp1
+ fdiv.x %fp1, %fp0
+ exit 0
diff --git tests/m68k/fetox.S tests/m68k/fetox.S
new file mode 100644
index 0000000..302072b
--- /dev/null
+++ tests/m68k/fetox.S
@@ -0,0 +1,8 @@
+ .include "trap.i"
+
+ .text
+ .globl _start
+_start:
+ fmove.l #1,%fp0 // 1
+ fetox.x %fp0,%fp0 // e
+ exit 0
diff --git tests/m68k/fgetexp.S tests/m68k/fgetexp.S
new file mode 100644
index 0000000..d17f7ab
--- /dev/null
+++ tests/m68k/fgetexp.S
@@ -0,0 +1,8 @@
+ .include "trap.i"
+
+ .text
+ .globl _start
+_start:
+ fmove.l #4096, %fp0
+ fgetexp.x %fp0, %fp1
+ exit 0
diff --git tests/m68k/flogn.S tests/m68k/flogn.S
new file mode 100644
index 0000000..a27835e
--- /dev/null
+++ tests/m68k/flogn.S
@@ -0,0 +1,8 @@
+ .include "trap.i"
+
+ .text
+ .globl _start
+_start:
+ fmovecr.x #0x0C,%fp0 // e
+ flogn.x %fp0,%fp0 // 1
+ exit 0
diff --git tests/m68k/fmove.S tests/m68k/fmove.S
new file mode 100644
index 0000000..d08c866
--- /dev/null
+++ tests/m68k/fmove.S
@@ -0,0 +1,60 @@
+ .include "trap.i"
+
+ .data
+tmp: .long 0x88776655
+pi: .long 0x40000000, 0xc90fdaa2, 0x2168C235
+store: .long 0, 0, 0
+
+ .text
+ .globl _start
+_start:
+ lea pi,%a0
+ move.l (%a0), %d0
+ fmove.x (%a0), %fp4
+ fmove.b %fp4, store
+ fmove.w %fp4, store
+ fmove.l %fp4, store
+ fmove.s %fp4, store
+ fmove.d %fp4, store
+ fmove.x %fp4, store
+ # Dn
+
+ move.l #-1, %d3
+ fmove.b %d3, %fp0
+ fmove.w %d3, %fp1
+ fmove.l %d3, %fp2
+ fmove.s %d3, %fp3
+
+ move.l #1, %d1
+ fmove.b %d1, %fp0
+ fmove.w %d1, %fp1
+ fmove.l %d1, %fp2
+ fmove.s %d1, %fp3
+
+ move.l #0x11223344, %d1
+ fmove.b %d1, %fp1
+ fmove.w %d1, %fp2
+ fmove.l %d1, %fp3
+ fmove.s %d1, %fp4
+
+ # (A0)
+
+ lea tmp,%a0
+ fmove.b (%a0), %fp0
+ fmove.w (%a0), %fp1
+ fmove.l (%a0), %fp2
+ fmove.l (%a0), %fp3
+ lea pi,%a0
+ fmove.x (%a0), %fp4
+
+ # immediate values
+
+ fmove.b #0xFF,%fp0
+ fmove.w #0xFABC,%fp1
+ fmove.l #0xFABCDEFA,%fp2
+ fmove.s #0xDEADBEAF,%fp3
+ fmove.d #0f4.29497E+09,%fp4
+ fmove.x #0xFABCDEFADEADBEAF12345678,%fp5
+ fmove.p #0xFABCDEFADEADBEAF12345678,%fp6
+
+ exit 0
diff --git tests/m68k/fmovecr.S tests/m68k/fmovecr.S
new file mode 100644
index 0000000..c6cd82b
--- /dev/null
+++ tests/m68k/fmovecr.S
@@ -0,0 +1,29 @@
+ .include "trap.i"
+
+ .text
+ .globl _start
+_start:
+ fmovecr.x #0x00,%fp0
+ fmovecr.x #0x0B,%fp0
+ fmovecr.x #0x0C,%fp0
+ fmovecr.x #0x0D,%fp0
+ fmovecr.x #0x0E,%fp0
+ fmovecr.x #0x0F,%fp0
+ fmovecr.x #0x30,%fp0
+ fmovecr.x #0x31,%fp0
+ fmovecr.x #0x32,%fp0
+ fmovecr.x #0x33,%fp0
+ fmovecr.x #0x34,%fp0
+ fmovecr.x #0x35,%fp0
+ fmovecr.x #0x36,%fp0
+ fmovecr.x #0x37,%fp0
+ fmovecr.x #0x38,%fp0
+ fmovecr.x #0x39,%fp0
+ fmovecr.x #0x3A,%fp0
+ fmovecr.x #0x3B,%fp0
+ fmovecr.x #0x3c,%fp0
+ fmovecr.x #0x3d,%fp0
+ fmovecr.x #0x3e,%fp0
+ fmovecr.x #0x3f,%fp0
+
+ exit 0
diff --git tests/m68k/fmovem.S tests/m68k/fmovem.S
new file mode 100644
index 0000000..35da35f
--- /dev/null
+++ tests/m68k/fmovem.S
@@ -0,0 +1,17 @@
+ .include "trap.i"
+
+ .data
+pi: .long 0x40000000
+ .long 0xc90fdaa2
+ .long 0x2168C235
+ln2: .long 0x3ffe0000
+ .long 0xb17217f7
+ .long 0xd1cf79ac
+
+ .text
+ .globl _start
+_start:
+ lea pi,%a0
+ fmovem.x (%a0), %fp2-%fp3
+ fmovem.x (%a0)+, %fp0-%fp1
+ exit 0
diff --git tests/m68k/fmul.S tests/m68k/fmul.S
new file mode 100644
index 0000000..1b989fc
--- /dev/null
+++ tests/m68k/fmul.S
@@ -0,0 +1,9 @@
+ .include "trap.i"
+
+ .text
+ .globl _start
+_start:
+ fmove.b #255, %fp0
+ fmove.w #1023, %fp1
+ fmul.x %fp1, %fp0
+ exit 0
diff --git tests/m68k/fscale.S tests/m68k/fscale.S
new file mode 100644
index 0000000..f6a5c62
--- /dev/null
+++ tests/m68k/fscale.S
@@ -0,0 +1,9 @@
+ .include "trap.i"
+
+ .text
+ .globl _start
+_start:
+ fmove.l #2, %fp0
+ fmovecr.x #0x00,%fp1
+ fscale.x %fp0, %fp1
+ exit 0
diff --git tests/m68k/fsub.S tests/m68k/fsub.S
new file mode 100644
index 0000000..cf1a77a
--- /dev/null
+++ tests/m68k/fsub.S
@@ -0,0 +1,11 @@
+ .include "trap.i"
+
+ .text
+ .globl _start
+_start:
+# Pi
+ fmovecr.x #0x00, %fp0
+ fmove.b #3, %fp1
+# 0.1415926535897932
+ fsub.x %fp1, %fp0
+ exit 0
diff --git tests/m68k/inf.S tests/m68k/inf.S
new file mode 100644
index 0000000..2b2de84
--- /dev/null
+++ tests/m68k/inf.S
@@ -0,0 +1,17 @@
+ .include "trap.i"
+
+ .data
+X: .long 0x7ffe0000, 0x80000000, 0x00000000
+
+ .text
+ .globl _start
+_start:
+ fmove.x X, %fp0
+ fmove.x X, %fp1
+ fadd.x %fp0, %fp1
+ fmul.l #2,%fp0
+ fcmp.x %fp0, %fp1
+ fbeq a
+ nop
+a:
+ exit 0
diff --git tests/m68k/trap.i tests/m68k/trap.i
new file mode 100644
index 0000000..ce7aa1e
--- /dev/null
+++ tests/m68k/trap.i
@@ -0,0 +1,5 @@
+.macro exit value
+ move.l #\value,%d1
+ move.l #1, %d0
+ trap #0
+.endm
- [Qemu-devel] [RFC][PATCH] NeXT emulation on QEMU,
Bryce Lanham <=