Discussion:
[RFC][PATCH 000/111] QEMU m68k core additions
Bryce Lanham
2011-08-17 20:46:05 UTC
Permalink
These patches greatly expand Motorola 68k emulation within qemu, and are what I used as a basis for my
Google Summer of Code project to add NeXT hardware support to QEMU.

Bryce Lanham

Alexander Paramonov (1):
linux-user: Signals processing is not thread-safe.

Andreas Schwab (3):
m68k: add cas
m68k: define fcntl constants
m68k: add DBcc instruction.

Laurent Vivier (106):
linux-user: add qemu-wrapper
linux-user: define default cpu model in configure instead of
linux-user/main.c
linux-user: specify the cpu model during configure
linux-user,m68k: display default cpu
linux-user: define new environment variables
linux-user: define a script to set binfmt using debian flavored tools
linux-user: define default cpu model in configure instead of
linux-user/main.c
m68k: add tcg_gen_debug_insn_start()
m68k: define m680x0 CPUs and features
m68k: add missing accessing modes for some instructions.
m68k: add Motorola 680x0 family common instructions.
m68k: add Scc instruction with memory operand.
m68k: add DBcc instruction.
m68k: modify movem instruction to manage word
m68k: add 64bit divide.
m68k: add 32bit and 64bit multiply
m68k: add word data size for suba/adda
m68k: add fpu
m68k: add "byte", "word" and memory shift
m68k: add "byte", "word" and memory rotate.
m68k: add bitfield_mem, bitfield_reg
m68k: add variable offset/width to bitfield_reg/bitfield_mem
m68k: add cas
m68k: allow fpu to manage double data type.
m68k: allow fpu to manage double data type with fmove to <ea>
m68k: add FScc instruction
m68k: add single data type to gen_ea
m68k: add linkl instruction
m68k: Add fmovecr
m68k: correct typo on f64_to_i32() return type.
m68k: improve CC_OP_LOGIC
m68k: correct neg condition code flags computation
Correct invalid use of "const void *" with "const uint8_t *"
m68k: add EA support for negx
m68k: add abcd instruction
m68k: add sbcd instruction
mm68k: add nbcd instruction
m68k: set X flag according size of operand Set X flag correctly
for addsub, arith_im, addsubq.
m68k: on 0 bit shift, don't update X flag
m68k: improve addx instructions Add (byte, word) opsize Add
memory access
m68k: improve subx,negx instructions Add (byte, word) opsize
Add memory access (subx)
m68k: improve asl/asr evaluate correclty the missing V flag
m68k: use read_imm1() when it is possible
m68k: correct shift side effect for roxrl and roxll
m68k: asl/asr, clear C flag if shift count is 0
m68k: lsl/lsr, clear C flag if shift count is 0
m68k: correct divs.w and divu.w
m68k: correct flags with negl
m68k: for bitfield opcodes, correct operands corruption
m68k: Correct bfclr in register case.
m68k-linux-user: add '--enable-emulop'
m68k: correctly compute divsl
m68k: correctly compute divul
m68k: add m68030 definition
m68k: remove dead code
m68k: remove useless file m68k-qreg.h
m68k: FPU rework (draft)
m68k: some FPU debugging macros
m68k: more tests
m68k: correct compute gen_bitfield_cc()
m68k: add fgetexp
m68k: add fscale
m68k: correct addsubq
m68k: add fetox and flogn
m68k: initialize FRegs, define pickNaN()
m68k: correct cmpa comparison datatype
m68k: add flog10
m68k: add cmpm instruction
m68k: add ftwotox instruction
m68k: better fpu traces
m68k: register source operand is always in extended size
m68k: add facos instruction
m68k: add ftan instruction
m68k: add fsin instruction
m68k: add fcos instruction
m68k: correct fpcr update
m68k: add fmod instruction
m68k: flush flags before negx instruction.
m68k: correct fmovemx FP registers order.
m68k: add fatan instruction
m68k: correct bfins instruction
m68k: fcmp correctly compares infinity.
m68k: allows bfins to manage correctly width = 32
m68k: add ftentox instruction
m68k: correctly define and manage NaN
m68k: don't call gdb_register_coprocessor() twice.
m68k: gdb FP registers are 96 bits
m68k: add exg instruction
m68k: define floatx80_default_inf_high and floatx80_default_inf_low
m68k: add bkpt instruction
m68k: correctly convert floatx80<->long double
m68k: use expl() to compute exp_FP0()
m68k: use exp2l() to compute exp2_FP0()
m68k: use logl() to compute ln_FP0()
m68k: use log10l() to compute log10_FP0()
m68k: correctly load signed word into floating point register
m68k: add fcosh instruction
m68k: add fasin instruction
m68k: add fsincos instruction
m68k: add fsinh instruction
m68k: add ftanh instruction
m68k: add flognp1 instruction
m68k: add fatanh instruction
m68k: first draft of q800 emulation (not working)
m68k: add movec instruction
m68k: move from sr can use effective addresse on m68k

Peter Bjørn Jørgensen (1):
m68k: Added ULL to 64 bit integer in helper.c
Bryce Lanham
2011-08-17 20:46:06 UTC
Permalink
From: Alexander Paramonov <***@gmail.com>

Signed-off-by: Alexander Paramonov <***@gmail.com>
Signed-off-by: Laurent Vivier <***@Vivier.EU>
---
linux-user/qemu.h | 1 +
linux-user/signal.c | 39 +++++++++++++++++++++++++++++++--------
2 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index 627c8b3..ae87149 100644
--- a/linux-user/qemu.h
+++ b/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 a/linux-user/signal.c b/linux-user/signal.c
index 07ad07a..0ba11bd 100644
--- a/linux-user/signal.c
+++ b/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);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:07 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
Makefile.target | 8 +++-
configure | 9 ++++
linux-user/qemu-wrapper.c | 97 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 113 insertions(+), 1 deletions(-)
create mode 100644 linux-user/qemu-wrapper.c

diff --git a/Makefile.target b/Makefile.target
index 4aacc67..a486aa9 100644
--- a/Makefile.target
+++ b/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
diff --git a/configure b/configure
index 0c67a4a..e85d2ca 100755
--- a/configure
+++ b/configure
@@ -2636,6 +2636,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=
@@ -3079,6 +3087,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
diff --git a/linux-user/qemu-wrapper.c b/linux-user/qemu-wrapper.c
new file mode 100644
index 0000000..6926a6c
--- /dev/null
+++ b/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);
+}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:20 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch modifies "movem" to manage "word" and "long" register size
instead of only "word". Attach it to M68000 feature.

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 52 +++++++++++++++++++++++++++++++++-------------
1 files changed, 37 insertions(+), 15 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index e0edc6d..0f9b4eb 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1173,6 +1173,8 @@ DISAS_INSN(movem)
TCGv reg;
TCGv tmp;
int is_load;
+ int opsize;
+ int32_t incr;

mask = lduw_code(s->pc);
s->pc += 2;
@@ -1184,21 +1186,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);
}
}

@@ -2972,6 +2993,7 @@ void register_m68k_insns (CPUM68KState *env)
INSN(swap, 4840, fff8, CF_ISA_A);
INSN(swap, 4840, 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);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:34 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch allows to manage instructions like "fmoved %fp0,%fp@(-512)".

Original function manages double data only through an address register.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 73 +++++++++++++++++-----------------------------
1 files changed, 27 insertions(+), 46 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index a91f557..01dea9c 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2933,7 +2933,6 @@ DISAS_INSN(trap)
DISAS_INSN(fpu)
{
uint16_t ext;
- int32_t offset;
int opmode;
TCGv_i64 src;
TCGv_i64 dest;
@@ -2944,8 +2943,7 @@ DISAS_INSN(fpu)
int set_dest;
int opsize;

- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);
opmode = ext & 0x7f;
switch ((ext >> 13) & 7) {
case 0: case 2:
@@ -2958,55 +2956,38 @@ DISAS_INSN(fpu)
/* 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;
+ 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 = gen_lea(s, insn, opsize);
+ if (IS_NULL_QREG(tmp32)) {
+ gen_addr_fault(s);
+ return;
}
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);
+ if ( ((insn >> 3) & 7) == 3) { /* post-increment */
+ reg = AREG(insn, 0);
+ tcg_gen_addi_i32(reg, reg, opsize_bytes(opsize));
+ }
+ } else {
+ switch (opsize) {
+ case OS_LONG:
+ case OS_WORD:
+ case OS_BYTE:
+ gen_helper_f64_to_i32(tmp32, cpu_env, src);
break;
- case 4:
- tcg_gen_mov_i32(AREG(insn, 0), tmp32);
+ case OS_SINGLE:
+ gen_helper_f64_to_f32(tmp32, cpu_env, src);
break;
}
- tcg_temp_free_i32(tmp32);
- 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);
}
- DEST_EA(insn, opsize, tmp32, NULL);
tcg_temp_free_i32(tmp32);
return;
case 4: /* fmove to control register. */
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:09 UTC
Permalink
From: Laurent Vivier <***@Vivier.EU>

This patch allows to set the default cpu model for a given architecture,
for instance:

configure --target-list=m68k-linux-user --m68k-default-cpu=m68040

Signed-off-by: Laurent Vivier <***@Vivier.EU>
---
configure | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/configure b/configure
index 1b9da9e..46b49e0 100755
--- a/configure
+++ b/configure
@@ -530,6 +530,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"
@@ -926,6 +930,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]"
@@ -3360,6 +3365,10 @@ 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
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:55 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 5800a4f..21dfcc7 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -739,7 +739,7 @@ uint32_t HELPER(glue(glue(shl, bits),_cc))(CPUState *env, uint32_t val, uint32_t
shift &= 63; \
if (shift == 0) { \
result = (type)val; \
- cf = env->cc_src & CCF_C; \
+ cf = 0; \
} else if (shift < bits) { \
result = (type)val << shift; \
cf = ((type)val >> (bits - shift)) & 1; \
@@ -768,7 +768,7 @@ uint32_t HELPER(glue(glue(shr, bits), _cc))(CPUState *env, uint32_t val, uint32_
shift &= 63; \
if (shift == 0) { \
result = (type)val; \
- cf = env->cc_src & CCF_C; \
+ cf = 0; \
} else if (shift < bits) { \
result = (type)val >> shift; \
cf = ((type)val >> (shift - 1)) & 1; \
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:42 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

When cpu-all.h is used with m68k-tester (an m68k testsuite),
the header is compiled with g++ and reports the following errors:

../qemu-m68k/cpu-all.h: In function ‘int lduw_be_p(const void*)’:
../qemu-m68k/cpu-all.h:414: error: invalid conversion from ‘const void*’ to ‘const uint8_t*’
../qemu-m68k/cpu-all.h: In function ‘int ldsw_be_p(const void*)’:
../qemu-m68k/cpu-all.h:429: error: invalid conversion from ‘const void*’ to ‘const uint8_t*’

This patch casts the variable to "const uint8_t*"

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
bswap.h | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/bswap.h b/bswap.h
index f41bebe..13fd5cf 100644
--- a/bswap.h
+++ b/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
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:44 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 38 ++++++++++++++++++++++++++++++++++++++
target-m68k/helpers.h | 2 ++
target-m68k/translate.c | 32 ++++++++++++++++++++++++++++++++
3 files changed, 72 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index dfa7c10..7d99326 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -1286,3 +1286,41 @@ void HELPER(bitfield_store)(uint32_t addr, uint32_t offset, uint32_t width,
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;
+}
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 4bfb149..f299752 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -81,4 +81,6 @@ 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);
#include "def-helper.h"
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index ab2073a..231d87a 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1065,6 +1065,36 @@ DISAS_INSN(divl)
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(addsub)
{
TCGv reg;
@@ -3915,6 +3945,8 @@ void register_m68k_insns (CPUM68KState *env)
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(addsub, d000, f000, M68000);
INSN(undef, d0c0, f0c0, CF_ISA_A);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:48 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 451b02a..1c3dd72 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -660,7 +660,7 @@ uint32_t HELPER(glue(glue(shl, bits),_cc))(CPUState *env, uint32_t val, uint32_t
cf = 0; \
} \
env->cc_src = cf; \
- env->cc_x = (cf != 0); \
+ if (shift) env->cc_x = (cf != 0); \
env->cc_dest = result; \
return result; \
}
@@ -689,7 +689,7 @@ uint32_t HELPER(glue(glue(shr, bits), _cc))(CPUState *env, uint32_t val, uint32_
cf = 0; \
} \
env->cc_src = cf; \
- env->cc_x = (cf != 0); \
+ if (shift) env->cc_x = (cf != 0); \
env->cc_dest = result; \
return result; \
}
@@ -715,7 +715,7 @@ uint32_t HELPER(glue(glue(sar, bits), _cc))(CPUState *env, uint32_t val, uint32_
cf = (type)val >> (bits - 1); \
} \
env->cc_src = cf; \
- env->cc_x = cf; \
+ if (shift) env->cc_x = (cf != 0); \
env->cc_dest = result; \
return result; \
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:20 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 136 +++++++++++++++++++++++++++++++------------------
1 files changed, 86 insertions(+), 50 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 3f6a0a0..cccae97 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -30,12 +30,22 @@
#include "helpers.h"

#if 0
-#define DBG_FPU(...) do { fprintf(stderr, "0x%08x: ", env->pc); fprintf(stderr, __VA_ARGS__); } while(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)
+static inline float FLOAT(float32 x)
+{
+ return *(float *)&x;
+}
+static inline double DOUBLE(float64 x)
+{
+ return *(double *)&x;
+}
static inline long double LDOUBLE(floatx80 x)
{
return *(long double *)&x;
}
#else
+#define DBG_FPUH(...)
#define DBG_FPU(...)
#define LDOUBLE(x)
#endif
@@ -1092,7 +1102,7 @@ void HELPER(const_FP0)(CPUState *env, uint32_t offset)
{
env->fp0h = fpu_rom[offset].high;
env->fp0l = fpu_rom[offset].low;
- DBG_FPU("ROM[0x%02x] %"PRIxFPH" %"PRIxFPL" %.17Lg\n",
+ DBG_FPUH("ROM[0x%02x] %"PRIxFPH" %"PRIxFPL" %.17Lg\n",
offset, env->fp0h, env->fp0l, LDOUBLE(FP0_to_floatx80(env)));
}

@@ -1142,7 +1152,7 @@ static inline void restore_rounding_mode(CPUState *env)

void HELPER(set_fpcr)(CPUState *env, uint32_t val)
{
- DBG_FPU("set_fpcr %04x\n", val);
+ DBG_FPUH("set_fpcr %04x\n", val);

env->fpcr = val & 0xffff;

@@ -1154,11 +1164,11 @@ void HELPER(exts32_FP0)(CPUState *env)
{
floatx80 res;

- DBG_FPU("exts32_FP0 %d\n", FP0_to_int32(env));
+ DBG_FPUH("exts32_FP0 %d", FP0_to_int32(env));

res = int32_to_floatx80(FP0_to_int32(env), &env->fp_status);

- DBG_FPU(" = %Lg\n", LDOUBLE(res));
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));
floatx80_to_FP0(env, res);
}

@@ -1166,8 +1176,9 @@ void HELPER(extf32_FP0)(CPUState *env)
{
floatx80 res;

- DBG_FPU("extf32_FP0\n");
+ 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", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1178,9 +1189,9 @@ void HELPER(extf64_FP0)(CPUState *env)
uint64_t val;

val = FP0_to_float64(env);
- DBG_FPU("extf64_FP0 0x%016"PRIx64", %g\n", val, *(double*)&val);
+ DBG_FPUH("extf64_FP0 0x%016"PRIx64", %g", val, *(double*)&val);
res = float64_to_floatx80(val, &env->fp_status);
- DBG_FPU(" = %Lg\n", LDOUBLE(res));
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1195,9 +1206,9 @@ void HELPER(reds32_FP0)(CPUState *env)
int32_t res;

val = FP0_to_floatx80(env);
- DBG_FPU("reds32_FP0 %Lg\n", LDOUBLE(val));
+ DBG_FPUH("reds32_FP0 %Lg", LDOUBLE(val));
res = floatx80_to_int32(val, &env->fp_status);
- DBG_FPU(" = %d\n", res);
+ DBG_FPU(" = %d\n", res);

int32_to_FP0(env, res);
}
@@ -1207,9 +1218,10 @@ void HELPER(redf32_FP0)(CPUState *env)
floatx80 val;
float32 res;

- DBG_FPU("redf32_FP0\n");
val = FP0_to_floatx80(env);
+ DBG_FPUH("redf32_FP0 %Lg", LDOUBLE(val));
res = floatx80_to_float32(val, &env->fp_status);
+ DBG_FPU(" = %f\n", FLOAT(res));

float32_to_FP0(env, res);
}
@@ -1220,25 +1232,29 @@ void HELPER(redf64_FP0)(CPUState *env)
float64 res;

val = FP0_to_floatx80(env);
- DBG_FPU("redf64_FP0 %Lg\n", LDOUBLE(val));
+ DBG_FPUH("redf64_FP0 %Lg", LDOUBLE(val));
res = floatx80_to_float64(val, &env->fp_status);
- DBG_FPU(" = %g\n", *(double*)&res);
+ DBG_FPU(" = %g\n", *(double*)&res);

float64_to_FP0(env, res);
}

void HELPER(redp96_FP0)(CPUState *env)
{
- DBG_FPU("redp96_FP0\n");
+ DBG_FPUH("redp96_FP0\n");
}

void HELPER(iround_FP0)(CPUState *env)
{
floatx80 res;

- DBG_FPU("iround_FP0\n");
+ res = FP0_to_floatx80(env);

- res = floatx80_round_to_int(FP0_to_floatx80(env), &env->fp_status);
+ DBG_FPUH("iround_FP0 %Lg", LDOUBLE(res));
+
+ res = floatx80_round_to_int(res, &env->fp_status);
+
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1247,12 +1263,15 @@ void HELPER(itrunc_FP0)(CPUState *env)
{
floatx80 res;

- DBG_FPU("itrunc_FP0\n");
+ res = FP0_to_floatx80(env);
+ DBG_FPUH("itrunc_FP0 %Lg", LDOUBLE(res));

set_float_rounding_mode(float_round_to_zero, &env->fp_status);
- res = floatx80_round_to_int(FP0_to_floatx80(env), &env->fp_status);
+ res = floatx80_round_to_int(res, &env->fp_status);
restore_rounding_mode(env);

+ DBG_FPU(" = %Lg\n", LDOUBLE(res));
+
floatx80_to_FP0(env, res);
}

@@ -1260,8 +1279,10 @@ void HELPER(sqrt_FP0)(CPUState *env)
{
floatx80 res;

- DBG_FPU("sqrt_FP0\n");
- res = floatx80_sqrt(FP0_to_floatx80(env), &env->fp_status);
+ res = FP0_to_floatx80(env);
+ DBG_FPUH("sqrt_FP0 %Lg", LDOUBLE(res));
+ res = floatx80_sqrt(res, &env->fp_status);
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1273,13 +1294,15 @@ void HELPER(ln_FP0)(CPUState *env)

/* ln(x) = log2(x) / log2(e) */

- DBG_FPU("ln_FP0\n");
+ res = FP0_to_floatx80(env);
+ DBG_FPUH("ln_FP0 %Lg", LDOUBLE(res));

- f = floatx80_to_float64(FP0_to_floatx80(env), &env->fp_status);
+ f = floatx80_to_float64(res, &env->fp_status);

log2 = float64_log2(f, &env->fp_status);
res = floatx80_div(float64_to_floatx80(log2, &env->fp_status),
floatx80_log2e, &env->fp_status);
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1291,7 +1314,7 @@ void HELPER(log10_FP0)(CPUState *env)

/* log10(x) = log2(x) / log2(10) */

- DBG_FPU("log10_FP0(%Lg)\n", LDOUBLE(FP0_to_floatx80(env)));
+ DBG_FPUH("log10_FP0 %Lg", LDOUBLE(FP0_to_floatx80(env)));
f = floatx80_to_float64(FP0_to_floatx80(env), &env->fp_status);

log2 = float64_log2(f, &env->fp_status);
@@ -1300,7 +1323,7 @@ void HELPER(log10_FP0)(CPUState *env)
res = floatx80_div(float64_to_floatx80(log2, &env->fp_status),
float64_to_floatx80(log210, &env->fp_status),
&env->fp_status);
- DBG_FPU(" = %Lg\n", LDOUBLE(res));
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1312,23 +1335,29 @@ void HELPER(exp_FP0)(CPUState *env)

/* exp(x) = exp2(x * log2(e)) */

- DBG_FPU("exp_FP0\n");
+ f = FP0_to_floatx80(env);
+
+ DBG_FPUH("exp_FP0 %Lg", LDOUBLE(f));

- f = floatx80_mul(FP0_to_floatx80(env), floatx80_log2e, &env->fp_status);
+ f = floatx80_mul(f, floatx80_log2e, &env->fp_status);
res = float32_exp2(floatx80_to_float32(f, &env->fp_status),
&env->fp_status);

+ DBG_FPU(" = %f\n", FLOAT(res));
floatx80_to_FP0(env, float32_to_floatx80(res, &env->fp_status));
}

void HELPER(exp2_FP0)(CPUState *env)
{
float32 res;
+ floatx80 f;

- DBG_FPU("exp_FP0\n");
+ f = FP0_to_floatx80(env);
+ DBG_FPUH("exp2_FP0 %Lg", LDOUBLE(f));

- res = float32_exp2(floatx80_to_float32(FP0_to_floatx80(env),
- &env->fp_status), &env->fp_status);
+ res = float32_exp2(floatx80_to_float32(f, &env->fp_status),
+ &env->fp_status);
+ DBG_FPU(" = %f\n", FLOAT(res));

floatx80_to_FP0(env, float32_to_floatx80(res, &env->fp_status));
}
@@ -1337,8 +1366,10 @@ void HELPER(abs_FP0)(CPUState *env)
{
floatx80 res;

- DBG_FPU("abs_FP0\n");
- res = floatx80_abs(FP0_to_floatx80(env));
+ res = FP0_to_floatx80(env);
+ DBG_FPUH("abs_FP0 %Lg", LDOUBLE(res));
+ res = floatx80_abs(res);
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1347,8 +1378,10 @@ void HELPER(chs_FP0)(CPUState *env)
{
floatx80 res;

- DBG_FPU("chs_FP0\n");
- res = floatx80_chs(FP0_to_floatx80(env));
+ res = FP0_to_floatx80(env);
+ DBG_FPUH("chs_FP0 %Lg", LDOUBLE(res));
+ res = floatx80_chs(res);
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1358,15 +1391,15 @@ void HELPER(getexp_FP0)(CPUState *env)
int32_t exp;
floatx80 res;

- DBG_FPU("getexp_FP0(%Lg)\n", LDOUBLE(FP0_to_floatx80(env)));
+ DBG_FPUH("getexp_FP0 %Lg", LDOUBLE(FP0_to_floatx80(env)));

- DBG_FPU(" fp0h 0x%08x fp0l 0x%016" PRIx64 "\n", env->fp0h, env->fp0l);
+ 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\n", LDOUBLE(res));
+ DBG_FPU(" = %Lg", LDOUBLE(res));
floatx80_to_FP0(env, res);
}

@@ -1375,9 +1408,9 @@ void HELPER(scale_FP0_FP1)(CPUState *env)
int32_t scale;
int32_t exp;

- DBG_FPU("getexp_FP0(%Lg)\n", LDOUBLE(FP0_to_floatx80(env)));
+ DBG_FPUH("scale_FP0 %Lg", LDOUBLE(FP0_to_floatx80(env)));

- DBG_FPU(" fp0h 0x%08x fp0l 0x%016" PRIx64 "\n", env->fp0h, env->fp0l);
+ DBG_FPU(" fp0h 0x%08x fp0l 0x%016" PRIx64, env->fp0h, env->fp0l);

scale = floatx80_to_int32(FP0_to_floatx80(env), &env->fp_status);

@@ -1385,17 +1418,18 @@ void HELPER(scale_FP0_FP1)(CPUState *env)

env->fp0h = (env->fp1h & 0x8000) | (exp & 0x7fff);
env->fp0l = env->fp1l;
+ DBG_FPU(" = %Lg", LDOUBLE(FP0_to_floatx80(env)));
}

void HELPER(add_FP0_FP1)(CPUState *env)
{
floatx80 res;

- DBG_FPU("add_FP0_FP1(%Lg,%Lg)\n", LDOUBLE(FP0_to_floatx80(env)),
+ DBG_FPUH("add_FP0_FP1 %Lg %Lg", LDOUBLE(FP0_to_floatx80(env)),
LDOUBLE(FP1_to_floatx80(env)));
res = floatx80_add(FP0_to_floatx80(env), FP1_to_floatx80(env),
&env->fp_status);
- DBG_FPU(" = %Lg\n", LDOUBLE(res));
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1404,11 +1438,11 @@ void HELPER(sub_FP0_FP1)(CPUState *env)
{
floatx80 res;

- DBG_FPU("sub_FP0 %Lg %Lg\n", LDOUBLE(FP0_to_floatx80(env)),
+ DBG_FPUH("sub_FP0 %Lg %Lg", LDOUBLE(FP0_to_floatx80(env)),
LDOUBLE(FP1_to_floatx80(env)));
res = floatx80_sub(FP1_to_floatx80(env), FP0_to_floatx80(env),
&env->fp_status);
- DBG_FPU(" = %Lg\n", LDOUBLE(res));
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1417,11 +1451,11 @@ void HELPER(mul_FP0_FP1)(CPUState *env)
{
floatx80 res;

- DBG_FPU("mul_FP0_FP1 %Lg %Lg\n",
+ DBG_FPUH("mul_FP0_FP1 %Lg %Lg",
LDOUBLE(FP0_to_floatx80(env)), LDOUBLE(FP1_to_floatx80(env)));
res = floatx80_mul(FP0_to_floatx80(env), FP1_to_floatx80(env),
&env->fp_status);
- DBG_FPU(" = %Lg\n", LDOUBLE(res));
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1430,9 +1464,11 @@ void HELPER(div_FP0_FP1)(CPUState *env)
{
floatx80 res;

- DBG_FPU("div\n");
+ DBG_FPUH("div_FP0_FP1 %Lg %Lg",
+ LDOUBLE(FP0_to_floatx80(env)), LDOUBLE(FP1_to_floatx80(env)));
res = floatx80_div(FP1_to_floatx80(env), FP0_to_floatx80(env),
&env->fp_status);
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1442,8 +1478,8 @@ void HELPER(fcmp_FP0_FP1)(CPUState *env)
/* ??? This may incorrectly raise exceptions. */
/* ??? Should flush denormals to zero. */
floatx80 res;
- DBG_FPU("cmp_FP0_FP1 %Lg %Lg\n", LDOUBLE(FP1_to_floatx80(env)),
- LDOUBLE(FP0_to_floatx80(env)));
+ DBG_FPUH("cmp_FP0_FP1 %Lg %Lg", LDOUBLE(FP0_to_floatx80(env)),
+ 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)) {
@@ -1455,7 +1491,7 @@ void HELPER(fcmp_FP0_FP1)(CPUState *env)
res = floatx80_chs(res);
}
}
- DBG_FPU(" : %Lg\n", LDOUBLE(res));
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));
floatx80_to_FP0(env, res);
}

@@ -1463,11 +1499,11 @@ uint32_t HELPER(compare_FP0)(CPUState *env)
{
uint32_t res;

- DBG_FPU("compare_FP0 %Lg\n", LDOUBLE(FP0_to_floatx80(env)));
+ DBG_FPUH("compare_FP0 %Lg", 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);
+ DBG_FPU(" = %d\n", res);
return res;
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:22 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch modify "mull" to support 64bit result, and to update
CC on 32bit operands.

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helpers.h | 4 +++
target-m68k/op_helper.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++
target-m68k/translate.c | 36 +++++++++++++++++++++----
3 files changed, 100 insertions(+), 6 deletions(-)

diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index a158aee..ca2bf82 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -7,6 +7,10 @@ DEF_HELPER_2(divu, void, env, i32)
DEF_HELPER_2(divs, void, env, 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(addx_cc, i32, env, i32, i32)
DEF_HELPER_3(subx_cc, i32, env, i32, i32)
DEF_HELPER_3(shl_cc, i32, env, i32, i32)
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index 1bffe5d..a6c8148 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -318,3 +318,69 @@ void HELPER(divs64)(CPUState *env)
}
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 a/target-m68k/translate.c b/target-m68k/translate.c
index 1d84081..74faabf 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1631,22 +1631,45 @@ 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;
+ 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);
+ /* Unlike m68k, coldfire always clears the overflow bit. */
+ gen_logic_cc(s, dest);
+ }
tcg_gen_mov_i32(reg, dest);
- /* Unlike m68k, coldfire always clears the overflow bit. */
- gen_logic_cc(s, dest);
}

DISAS_INSN(link)
@@ -3028,6 +3051,7 @@ void register_m68k_insns (CPUM68KState *env)
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);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:14 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch add debug info by writing the PC of the corresponing CPU
instruction of an TCG opcode.

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 0e7f1fe..b86588c 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2947,6 +2947,9 @@ static void disas_m68k_insn(CPUState * env, DisasContext *s)
{
uint16_t insn;

+ if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
+ tcg_gen_debug_insn_start(s->pc);
+
insn = lduw_code(s->pc);
s->pc += 2;
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:17 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch declares existing ISA instructions belonging to previously
defined 680x0 familty new features:

- modify gen_lea_indexed() to manage scaled index,

- declare M68000 instructions: arith_im, bitop_reg, arith_im, bitop_im,
move, negx, move_from_sr, lea, clr, neg, move_to_ccr, not, pea, swap,
ext, tas, tst, illegal, trap, link, unlk, nop, stop, rte, rts, jump,
addsubq, scc, branch, moveq, or, divw, addsub, subx, cmp, cmpa, eor,
and, mulw, addx, shift_im, shift_reg.

- declare FPU instructions: fbcc, frestore, fsave,

- declare long branch instructions: branch.

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 89 ++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 85 insertions(+), 4 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index a537373..ea92fd6 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -325,6 +325,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))
@@ -333,7 +336,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);
@@ -382,7 +385,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);
@@ -2856,85 +2859,149 @@ 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(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, 4080, fff8, M68000);
+ INSN(undef, 40c0, ffc0, M68000);
INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
+ INSN(move_from_sr, 40c0, fff8, 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(undef, 46c0, ffc0, M68000);
INSN(move_to_sr, 46c0, ffc0, CF_ISA_A);
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(movem, 48c0, fbc0, CF_ISA_A);
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(divl, 4c40, ffc0, CF_ISA_A);
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(rts, 4e75, ffff, M68000);
INSN(movec, 4e7b, ffff, CF_ISA_A);
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, 50c0, 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(addsub, 9000, f000, CF_ISA_A);
+ INSN(addsub, 9000, f000, M68000);
+ INSN(undef, 90c0, f0c0, CF_ISA_A);
INSN(subx, 9180, f1f8, CF_ISA_A);
+ INSN(subx, 9100, f138, M68000);
INSN(suba, 91c0, f1c0, CF_ISA_A);

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);
@@ -2953,19 +3020,33 @@ 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(addsub, d000, f000, CF_ISA_A);
+ INSN(addsub, d000, f000, M68000);
+ INSN(undef, d0c0, f0c0, CF_ISA_A);
INSN(addx, d180, f1f8, CF_ISA_A);
+ INSN(addx, d100, f138, M68000);
INSN(adda, d1c0, f1c0, CF_ISA_A);
INSN(shift_im, e080, f0f0, CF_ISA_A);
INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
+ INSN(shift_im, e080, f0f0, M68000);
+ INSN(shift_reg, e0a0, f0f0, M68000);
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(fbcc, f280, ffc0, FPU);
+ INSN(frestore, f340, ffc0, FPU);
+ INSN(fsave, f340, ffc0, FPU);
INSN(intouch, f340, ffc0, CF_ISA_A);
INSN(cpushl, f428, ff38, CF_ISA_A);
INSN(wddata, fb00, ff00, CF_ISA_A);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:07 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/cpu.h | 53 +++-
target-m68k/helper.c | 345 +++++++++++++++++----
target-m68k/helpers.h | 39 ++-
target-m68k/qregs.def | 3 +-
target-m68k/translate.c | 776 +++++++++++++++++++++++++++++++----------------
tests/m68k/Makefile | 15 +
tests/m68k/fmove.S | 55 ++++
tests/m68k/fmovecr.S | 29 ++
tests/m68k/fmovem.S | 17 +
tests/m68k/trap.i | 5 +
10 files changed, 978 insertions(+), 359 deletions(-)
create mode 100644 tests/m68k/Makefile
create mode 100644 tests/m68k/fmove.S
create mode 100644 tests/m68k/fmovecr.S
create mode 100644 tests/m68k/fmovem.S
create mode 100644 tests/m68k/trap.i

diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index e316b1e..2587512 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -60,6 +60,36 @@

#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];
@@ -76,8 +106,7 @@ typedef struct CPUM68KState {
uint32_t cc_src;
uint32_t cc_x;

- float64 fregs[8];
- float64 fp_result;
+ FPReg fregs[8];
uint32_t fpcr;
uint32_t fpsr;
float_status fp_status;
@@ -90,6 +119,13 @@ 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;
@@ -228,17 +264,6 @@ void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf);

void register_m68k_insns (CPUM68KState *env);

-#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
-
-#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
@@ -267,8 +292,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)
{
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 1bb0cef..081e1d9 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -23,6 +23,7 @@

#include "config.h"
#include "cpu.h"
+#include "exec.h"
#include "qemu-common.h"
#include "gdbstub.h"

@@ -115,7 +116,8 @@ void m68k_cpu_list(FILE *f, fprintf_function cpu_fprintf)
static int 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) {
@@ -129,7 +131,8 @@ static int fpu_gdb_get_reg(CPUState *env, uint8_t *mem_buf, int n)
static int 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) {
@@ -980,125 +983,335 @@ HELPER_ROXL(uint32_t, 32)
/* FPU helpers. */

static const floatx80 fpu_rom[128] = {
- [0x00] = { .high = 0x4000, .low = 0xc90fdaa22168c235ULL }, /* Pi */
-
- [0x0b] = { .high = 0x3ffd, .low = 0x9a209a84fbcff798ULL }, /* Log10(2) */
- [0x0c] = { .high = 0x4000, .low = 0xadf85458a2bb4a9aULL }, /* e */
- [0x0d] = { .high = 0x3fff, .low = 0xb8aa3b295c17f0bcULL }, /* Log2(e) */
- [0x0e] = { .high = 0x3ffd, .low = 0xde5bd8a937287195ULL }, /* Log10(e) */
- [0x0f] = { .high = 0x0000, .low = 0x0000000000000000ULL }, /* Zero */
-
- [0x30] = { .high = 0x3ffe, .low = 0xb17217f7d1cf79acULL }, /* ln(2) */
- [0x31] = { .high = 0x4000, .low = 0x935d8dddaaa8ac17ULL }, /* ln(10) */
- [0x32] = { .high = 0x3fff, .low = 0x8000000000000000ULL }, /* 10^0 */
- [0x33] = { .high = 0x4002, .low = 0xa000000000000000ULL }, /* 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 */
+ [0x00] = floatx80_pi, /* Pi */
+
+ [0x0b] = { .high = 0x3ffd, .low = 0x9a209a84fbcff798ULL }, /* Log10(2) */
+ [0x0c] = { .high = 0x4000, .low = 0xadf85458a2bb4a9aULL }, /* e */
+ [0x0d] = { .high = 0x3fff, .low = 0xb8aa3b295c17f0bcULL }, /* 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] = { .high = 0x4002, .low = 0xa000000000000000ULL }, /* 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 */
};

-float64 HELPER(const_f64)(CPUState *env, uint32_t offset)
+void HELPER(const_FP0)(CPUState *env, uint32_t offset)
{
- return floatx80_to_float64(fpu_rom[offset], &env->fp_status);
+ env->fp0h = fpu_rom[offset].high;
+ env->fp0l = fpu_rom[offset].low;
}

-uint32_t HELPER(f64_to_i32)(CPUState *env, float64 val)
+static inline floatx80 FP0_to_floatx80(CPUState *env)
{
- return float64_to_int32(val, &env->fp_status);
+ floatx80 res;
+
+ res.high = env->fp0h;
+ res.low = env->fp0l;
+
+ return res;
}

-float32 HELPER(f64_to_f32)(CPUState *env, float64 val)
+static inline void floatx80_to_FP0(CPUState *env, floatx80 res)
{
- return float64_to_float32(val, &env->fp_status);
+ env->fp0h = res.high;
+ env->fp0l = res.low;
}

-float64 HELPER(i32_to_f64)(CPUState *env, uint32_t val)
+static inline int32_t FP0_to_int32(CPUState *env)
{
- return int32_to_float64(val, &env->fp_status);
+ return env->fp0h;
}

-float64 HELPER(f32_to_f64)(CPUState *env, float32 val)
+static inline void int32_to_FP0(CPUState *env, int32_t val)
{
- return float32_to_float64(val, &env->fp_status);
+ env->fp0h = val;
}

-float64 HELPER(iround_f64)(CPUState *env, float64 val)
+static inline float32 FP0_to_float32(CPUState *env)
{
- return float64_round_to_int(val, &env->fp_status);
+ return *(float32*)&env->fp0h;
}

-float64 HELPER(itrunc_f64)(CPUState *env, float64 val)
+static inline void float32_to_FP0(CPUState *env, float32 val)
{
- return float64_trunc_to_int(val, &env->fp_status);
+
+ env->fp0h = *(uint32_t*)&val;
}

-float64 HELPER(sqrt_f64)(CPUState *env, float64 val)
+static inline float64 FP0_to_float64(CPUState *env)
{
- return float64_sqrt(val, &env->fp_status);
+ return *(float64*)&env->fp0l;
}

-float64 HELPER(abs_f64)(float64 val)
+static inline void float64_to_FP0(CPUState *env, float64 val)
{
- return float64_abs(val);
+ env->fp0l = *(uint64_t*)&val;
}

-float64 HELPER(chs_f64)(float64 val)
+static inline floatx80 FP1_to_floatx80(CPUState *env)
{
- return float64_chs(val);
+ floatx80 res;
+
+ res.high = env->fp1h;
+ res.low = env->fp1l;
+
+ return res;
}

-float64 HELPER(add_f64)(CPUState *env, float64 a, float64 b)
+static inline void restore_precision_mode(CPUState *env)
{
- return float64_add(a, b, &env->fp_status);
+ 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;
+ }
}

-float64 HELPER(sub_f64)(CPUState *env, float64 a, float64 b)
+static inline void restore_rounding_mode(CPUState *env)
{
- return float64_sub(a, b, &env->fp_status);
+ 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;
+ }
}

-float64 HELPER(mul_f64)(CPUState *env, float64 a, float64 b)
+void HELPER(set_fpcr)(CPUState *env, uint32_t val)
{
- return float64_mul(a, b, &env->fp_status);
+ env->fpcr = val & 0xffff;
+
+ restore_precision_mode(env);
+ restore_rounding_mode(env);
}

-float64 HELPER(div_f64)(CPUState *env, float64 a, float64 b)
+void HELPER(exts32_FP0)(CPUState *env)
{
- return float64_div(a, b, &env->fp_status);
+ floatx80 res;
+
+ res = int32_to_floatx80(FP0_to_int32(env), &env->fp_status);
+
+ floatx80_to_FP0(env, res);
}

-float64 HELPER(sub_cmp_f64)(CPUState *env, float64 a, float64 b)
+void HELPER(extf32_FP0)(CPUState *env)
+{
+ floatx80 res;
+
+ res = float32_to_floatx80(FP0_to_float32(env), &env->fp_status);
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(extf64_FP0)(CPUState *env)
+{
+ floatx80 res;
+
+ res = float64_to_floatx80(FP0_to_float64(env), &env->fp_status);
+
+ 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);
+ res = floatx80_to_int32(val, &env->fp_status);
+
+ int32_to_FP0(env, res);
+}
+
+void HELPER(redf32_FP0)(CPUState *env)
+{
+ floatx80 val;
+ float32 res;
+
+ val = FP0_to_floatx80(env);
+ res = floatx80_to_float32(val, &env->fp_status);
+
+ float32_to_FP0(env, res);
+}
+
+void HELPER(redf64_FP0)(CPUState *env)
+{
+ floatx80 val;
+ float64 res;
+
+ val = FP0_to_floatx80(env);
+ res = floatx80_to_float64(val, &env->fp_status);
+
+ float64_to_FP0(env, res);
+}
+
+void HELPER(redp96_FP0)(CPUState *env)
+{
+}
+
+void HELPER(iround_FP0)(CPUState *env)
+{
+ floatx80 res;
+
+ res = floatx80_round_to_int(FP0_to_floatx80(env), &env->fp_status);
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(itrunc_FP0)(CPUState *env)
+{
+ floatx80 res;
+
+ set_float_rounding_mode(float_round_to_zero, &env->fp_status);
+ res = floatx80_round_to_int(FP0_to_floatx80(env), &env->fp_status);
+ restore_rounding_mode(env);
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(sqrt_FP0)(CPUState *env)
+{
+ floatx80 res;
+
+ res = floatx80_sqrt(FP0_to_floatx80(env), &env->fp_status);
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(abs_FP0)(CPUState *env)
+{
+ floatx80 res;
+
+ res = floatx80_abs(FP0_to_floatx80(env));
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(chs_FP0)(CPUState *env)
+{
+ floatx80 res;
+
+ res = floatx80_chs(FP0_to_floatx80(env));
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(add_FP0_FP1)(CPUState *env)
+{
+ floatx80 res;
+
+ res = floatx80_add(FP0_to_floatx80(env), FP1_to_floatx80(env),
+ &env->fp_status);
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(sub_FP0_FP1)(CPUState *env)
+{
+ floatx80 res;
+
+ res = floatx80_sub(FP0_to_floatx80(env), FP1_to_floatx80(env),
+ &env->fp_status);
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(mul_FP0_FP1)(CPUState *env)
+{
+ floatx80 res;
+
+ res = floatx80_mul(FP0_to_floatx80(env), FP1_to_floatx80(env),
+ &env->fp_status);
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(div_FP0_FP1)(CPUState *env)
+{
+ floatx80 res;
+
+ res = floatx80_div(FP0_to_floatx80(env), FP1_to_floatx80(env),
+ &env->fp_status);
+
+ floatx80_to_FP0(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;
+ 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))) {
+ if (floatx80_lt_quiet(FP1_to_floatx80(env), floatx80_zero,
+ &env->fp_status))
+ res = floatx80_chs(res);
}
}
- return 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;
+
+ res = float64_compare_quiet(floatx80_to_float64(FP0_to_floatx80(env),
+ &env->fp_status),
+ float64_zero, &env->fp_status);
+ 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
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index aa835eb..6ddd659 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -50,22 +50,29 @@ 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_2(const_f64, f64, env, i32);
-DEF_HELPER_2(f64_to_i32, i32, 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(itrunc_FP0, void, env)
+DEF_HELPER_1(sqrt_FP0, void, env)
+DEF_HELPER_1(abs_FP0, void, env)
+DEF_HELPER_1(chs_FP0, 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(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)
diff --git a/target-m68k/qregs.def b/target-m68k/qregs.def
index 76e0236..13a8e5c 100644
--- a/target-m68k/qregs.def
+++ b/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)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index e394c2d..d4a7074 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -25,6 +25,7 @@

#include "config.h"
#include "cpu.h"
+#include "exec.h"
#include "disas.h"
#include "tcg-op.h"
#include "qemu-log.h"
@@ -35,30 +36,26 @@

//#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 +73,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 +94,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 +102,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 +151,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 +173,64 @@ 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)
+{
+ 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);
+}
+
+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_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 +253,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 +262,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 +275,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 +283,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,
@@ -282,10 +322,17 @@ static inline uint32_t read_im16(DisasContext *s)
static inline uint32_t read_im32(DisasContext *s)
{
uint32_t im;
- im = ((uint32_t)lduw_code(s->pc)) << 16;
- s->pc += 2;
- im |= lduw_code(s->pc);
- s->pc += 2;
+ 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;
}

@@ -414,13 +461,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)
{
@@ -469,6 +509,8 @@ 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;
@@ -485,6 +527,20 @@ static inline int insn_opsize(int insn, int pos)
}
}

+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)
@@ -534,7 +590,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:
@@ -704,7 +759,6 @@ static TCGv gen_ea(DisasContext *s, uint16_t insn, int opsize, TCGv val,
s->pc += 2;
break;
case OS_LONG:
- case OS_SINGLE:
offset = read_im32(s);
break;
default:
@@ -719,6 +773,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_ld16u(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)
{
@@ -848,14 +1190,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)
{
@@ -864,18 +1198,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)) { \
@@ -3159,6 +3481,70 @@ DISAS_INSN(trap)
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 & 1) {
+ gen_op_load_fpr_FP0(i);
+ gen_store_FP0(s, opsize, addr);
+ if (mask != 1)
+ 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 & 1) {
+ 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 != 1 || (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
immediately before the next FP instruction is executed. */
DISAS_INSN(fpu)
@@ -3166,14 +3552,10 @@ DISAS_INSN(fpu)
uint16_t ext;
uint8_t rom_offset;
int opmode;
- TCGv_i64 src;
- TCGv_i64 dest;
- TCGv_i64 res;
- TCGv tmp32;
- TCGv reg;
int round;
int set_dest;
int opsize;
+ TCGv val;

ext = read_im16(s);
opmode = ext & 0x7f;
@@ -3186,55 +3568,21 @@ DISAS_INSN(fpu)
if ( insn == 0xf200 && (ext & 0xfc00) == 0x5c00) {
/* fmovecr */
rom_offset = ext & 0x7f;
- dest = FREG(ext, 7);
- gen_helper_const_f64(dest, cpu_env, tcg_const_i32(rom_offset));
+ gen_helper_const_FP0(cpu_env, tcg_const_i32(rom_offset));
+ gen_op_store_fpr_FP0(REG(ext, 7));
return;
}
break;
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; 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 = gen_lea(s, insn, opsize);
- if (IS_NULL_QREG(tmp32)) {
- gen_addr_fault(s);
- return;
- }
- gen_store64(s, tmp32, src);
- if ( ((insn >> 3) & 7) == 3) { /* post-increment */
- reg = AREG(insn, 0);
- tcg_gen_addi_i32(reg, reg, opsize_bytes(opsize));
- }
- } else {
- switch (opsize) {
- case OS_LONG:
- case OS_WORD:
- case OS_BYTE:
- gen_helper_f64_to_i32(tmp32, cpu_env, src);
- break;
- case OS_SINGLE:
- gen_helper_f64_to_f32(tmp32, cpu_env, src);
- break;
- }
- DEST_EA(insn, opsize, tmp32, NULL);
- }
- tcg_temp_free_i32(tmp32);
+ 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. */
+ SRC_EA(val, OS_LONG, 0, NULL);
+ gen_helper_set_fpcr(cpu_env, val);
break;
case 1: /* FPIAR */
case 2: /* FPSR */
@@ -3247,187 +3595,95 @@ DISAS_INSN(fpu)
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;
- int incr;
- uint16_t mask;
- int i;
- if ((ext & 0xf00) != 0 || (ext & 0xff) == 0)
- goto undef;
- if ((ext & 0x1000) == 0 && !m68k_feature(s->env, M68K_FEATURE_FPU))
- goto undef;
- if ((insn & 070) == 040)
- tmp32 = AREG(insn, 0);
- else {
- 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;
- if (m68k_feature(s->env, M68K_FEATURE_FPU))
- incr = 12;
- else
- incr = 8;
- if ((ext & (1 << 13)) && (insn & 070) == 040) {
- for (i = 0; i < 8; i++) {
- if (ext & mask) {
- s->is_mem = 1;
- dest = FREG(i, 7);
- tcg_gen_subi_i32(addr, addr, incr);
- tcg_gen_mov_i32(AREG(insn, 0), addr);
- tcg_gen_qemu_stf64(dest, addr, IS_USER(s));
- }
- mask >>= 1;
- }
- tcg_temp_free_i32(addr);
- return;
- }
- 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) || (insn & 070) == 030) {
- tcg_gen_addi_i32(addr, addr, incr);
- if ((insn & 070) == 030)
- tcg_gen_mov_i32(AREG(insn, 0), addr);
- }
- }
- 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;
}
+ opsize = ext_opsize(ext, 10);
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) {
- if ((insn & 0x3f) == 0x3c) {
- src = gen_load64(s, tcg_const_i32(s->pc));
- s->pc += 8;
- } else {
- tmp32 = gen_lea(s, insn, opsize);
- if (IS_NULL_QREG(tmp32)) {
- gen_addr_fault(s);
- return;
- }
- src = gen_load64(s, tmp32);
- if ( ((insn >> 3) & 7) == 3) { /* post-increment */
- reg = AREG(insn, 0);
- tcg_gen_addi_i32(reg, reg, opsize_bytes(opsize));
- }
- }
- } 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;
- }
- }
+ gen_op_load_ea_FP0(s, insn, opsize);
} else {
/* Source register. */
- src = FREG(ext, 10);
+ 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 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 0x18: case 0x58: case 0x5c: /* fabs */
- gen_helper_abs_f64(res, src);
+ gen_helper_abs_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 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 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_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 0x27: /* fsglmul */
- 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 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 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)
@@ -3437,16 +3693,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? */
@@ -3460,7 +3716,7 @@ static void gen_fjmpcc(DisasContext *s, int cond, int l1)

/* 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 (cond) {
case 0: /* f */
@@ -3484,12 +3740,12 @@ static void gen_fjmpcc(DisasContext *s, int cond, int l1)
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);
@@ -4337,20 +4593,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 a/tests/m68k/Makefile b/tests/m68k/Makefile
new file mode 100644
index 0000000..8f09805
--- /dev/null
+++ b/tests/m68k/Makefile
@@ -0,0 +1,15 @@
+TESTS=fmovecr fmove fmovem
+
+all: $(TESTS)
+
+%: %.S
+ m68k-linux-gnu-gcc -m68040 -nostartfiles -nodefaultlibs -nostdlib -o $@ $<
+
+fmovecr: fmovecr.S
+fmove: fmove.S
+fmovem: fmovem.S
+
+.PHONY: clean
+
+clean:
+ rm -f $(TESTS)
diff --git a/tests/m68k/fmove.S b/tests/m68k/fmove.S
new file mode 100644
index 0000000..3f2daba
--- /dev/null
+++ b/tests/m68k/fmove.S
@@ -0,0 +1,55 @@
+ .include "trap.i"
+
+ .data
+tmp: .long 0x88776655
+pi: .long 0x40000000
+ .long 0xc90fdaa2
+ .long 0x2168C235
+
+ .text
+ .globl _start
+_start:
+ lea pi,%a0
+ move.l (%a0), %d0
+ fmove.x (%a0), %fp4
+ # 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 #0xFABCDEFADEADBEAF,%fp4
+ fmove.x #0xFABCDEFADEADBEAF12345678,%fp5
+ fmove.p #0xFABCDEFADEADBEAF12345678,%fp6
+
+ exit 0
diff --git a/tests/m68k/fmovecr.S b/tests/m68k/fmovecr.S
new file mode 100644
index 0000000..c6cd82b
--- /dev/null
+++ b/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 a/tests/m68k/fmovem.S b/tests/m68k/fmovem.S
new file mode 100644
index 0000000..35da35f
--- /dev/null
+++ b/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 a/tests/m68k/trap.i b/tests/m68k/trap.i
new file mode 100644
index 0000000..ce7aa1e
--- /dev/null
+++ b/tests/m68k/trap.i
@@ -0,0 +1,5 @@
+.macro exit value
+ move.l #\value,%d1
+ move.l #1, %d0
+ trap #0
+.endm
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:21 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Allow Xvnc4 to run.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 61ec317..4f73bf8 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3637,11 +3637,12 @@ DISAS_INSN(fpu)
gen_op_fmovem(s, insn, ext);
return;
}
- opsize = ext_opsize(ext, 10);
if (ext & (1 << 14)) {
+ opsize = ext_opsize(ext, 10);
gen_op_load_ea_FP0(s, insn, opsize);
} else {
/* Source register. */
+ opsize = OS_EXTENDED;
gen_op_load_fpr_FP0(REG(ext, 10));
}
round = 1;
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:19 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Used by "gconf-schemas --register metacity.schemas" via libm

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 12 ++++++++++++
target-m68k/helpers.h | 1 +
target-m68k/translate.c | 3 +++
3 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index f6e446a..3f6a0a0 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -1321,6 +1321,18 @@ void HELPER(exp_FP0)(CPUState *env)
floatx80_to_FP0(env, float32_to_floatx80(res, &env->fp_status));
}

+void HELPER(exp2_FP0)(CPUState *env)
+{
+ float32 res;
+
+ DBG_FPU("exp_FP0\n");
+
+ res = float32_exp2(floatx80_to_float32(FP0_to_floatx80(env),
+ &env->fp_status), &env->fp_status);
+
+ floatx80_to_FP0(env, float32_to_floatx80(res, &env->fp_status));
+}
+
void HELPER(abs_FP0)(CPUState *env)
{
floatx80 res;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 138b4a4..184ceef 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -66,6 +66,7 @@ DEF_HELPER_1(iround_FP0, void, env)
DEF_HELPER_1(itrunc_FP0, void, env)
DEF_HELPER_1(sqrt_FP0, void, env)
DEF_HELPER_1(exp_FP0, void, env)
+DEF_HELPER_1(exp2_FP0, void, env)
DEF_HELPER_1(ln_FP0, void, env)
DEF_HELPER_1(log10_FP0, void, env)
DEF_HELPER_1(abs_FP0, void, env)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 252e610..61ec317 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3663,6 +3663,9 @@ DISAS_INSN(fpu)
case 0x10: /* fetox */
gen_helper_exp_FP0(cpu_env);
break;
+ case 0x11: /* ftwotox */
+ gen_helper_exp2_FP0(cpu_env);
+ break;
case 0x14: /* flogn */
gen_helper_ln_FP0(cpu_env);
break;
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:05 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 0808673..e394c2d 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -4320,9 +4320,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)
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:50 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 48 ++++++++++++++++++++++++++++++-
target-m68k/helpers.h | 4 ++-
target-m68k/translate.c | 72 +++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 117 insertions(+), 7 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 60021d7..8bf4920 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -573,7 +573,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;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 11f1c0b..8f6d333 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -17,7 +17,9 @@ 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(subx_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)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index f2d0fae..bc1cf04 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1572,7 +1572,18 @@ DISAS_INSN(negx)
opsize = insn_opsize(insn, 6);
SRC_EA(src, opsize, -1, &addr);
dest = tcg_temp_new();
- gen_helper_subx_cc(dest, cpu_env, tcg_const_i32(0), src);
+ 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);
}

@@ -2050,15 +2061,65 @@ DISAS_INSN(suba)
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);
+ 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)
@@ -4015,8 +4076,9 @@ void register_m68k_insns (CPUM68KState *env)
INSN(addsub, 9000, f000, CF_ISA_A);
INSN(addsub, 9000, f000, M68000);
INSN(undef, 90c0, f0c0, CF_ISA_A);
- INSN(subx, 9180, f1f8, CF_ISA_A);
- INSN(subx, 9100, f138, M68000);
+ 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);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:36 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch allows to have instructions like "fcmps #0.1,%fp1".

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 3917243..38be7ab 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -696,6 +696,7 @@ static TCGv gen_ea(DisasContext *s, uint16_t insn, int opsize, TCGv val,
s->pc += 2;
break;
case OS_LONG:
+ case OS_SINGLE:
offset = read_im32(s);
break;
default:
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:15 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
fpu/softfloat-specialize.h | 20 ++++++++++++++++++++
target-m68k/helper.c | 13 ++++++++++++-
2 files changed, 32 insertions(+), 1 deletions(-)

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index c165205..e051549 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -387,6 +387,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 a/target-m68k/helper.c b/target-m68k/helper.c
index f67bfba..14a6ae6 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -244,6 +244,8 @@ static int cpu_m68k_set_model(CPUM68KState *env, const char *name)

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);
@@ -254,7 +256,16 @@ void cpu_reset(CPUM68KState *env)
env->sr = 0x2700;
#endif
m68k_switch_sp(env);
- /* ??? FP regs should be initialized to NaN. */
+
+ for (i = 0; i < 8; i++) {
+ env->fregs[i].l.upper = floatx80_default_nan_high;
+ env->fregs[i].l.lower = 0xffffffffffffffffULL;
+ }
+ env->fp0h = floatx80_default_nan_high;
+ env->fp0l = 0xffffffffffffffffULL;
+ env->fp1h = floatx80_default_nan_high;
+ env->fp1l = 0xffffffffffffffffULL;
+
env->cc_op = CC_OP_FLAGS;
/* TODO: We should set PC from the interrupt vector. */
env->pc = 0;
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:47 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 12 +++++++++++-
target-m68k/helpers.h | 4 +++-
target-m68k/translate.c | 23 ++++++++++++++++-------
3 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 0fa59c8..451b02a 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -619,7 +619,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;
}
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 76d3063..2e5b8f8 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -37,7 +37,9 @@ 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, i32, 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)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 56000eb..f743fd2 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -440,6 +440,15 @@ static inline void gen_flush_flags(DisasContext *s)
} \
} 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);
@@ -1160,10 +1169,10 @@ DISAS_INSN(addsub)
}
if (add) {
tcg_gen_add_i32(dest, tmp, src);
- gen_helper_xflag_lt(QREG_CC_X, dest, src);
+ 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);
SET_CC_OP(opsize, SUB);
}
@@ -1413,7 +1422,7 @@ DISAS_INSN(arith_im)
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));
SET_CC_OP(opsize, SUB);
@@ -1422,7 +1431,7 @@ DISAS_INSN(arith_im)
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));
+ SET_X_FLAG(opsize, dest, tcg_const_i32(im));
SET_CC_OP(opsize, ADD);
break;
case 5: /* eori */
@@ -1625,7 +1634,7 @@ DISAS_INSN(neg)
DEST_EA(insn, opsize, dest, &addr);
SET_CC_OP(opsize, SUB);
gen_update_cc_add(dest, src1);
- gen_helper_xflag_lt(QREG_CC_X, tcg_const_i32(0), dest);
+ SET_X_FLAG(opsize, tcg_const_i32(0), dest);
}

static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
@@ -1920,12 +1929,12 @@ 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);
SET_CC_OP(opsize, SUB);
} else {
tcg_gen_addi_i32(dest, dest, val);
- gen_helper_xflag_lt(QREG_CC_X, dest, src2);
+ SET_X_FLAG(opsize, dest, src2);
SET_CC_OP(opsize, ADD);
}
gen_update_cc_add(dest, src2);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:30 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

allow to run gtk-demo/Color Selector/Change the above color

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 15 +++++++++++++++
target-m68k/helpers.h | 1 +
target-m68k/translate.c | 3 +++
3 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 70e7053..62aadfd 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -1332,6 +1332,21 @@ void HELPER(log10_FP0)(CPUState *env)
floatx80_to_FP0(env, res);
}

+void HELPER(atan_FP0)(CPUState *env)
+{
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = LDOUBLE(res);
+
+ DBG_FPUH("atan_FP0 %Lg", val);
+ val = atanl(val);
+ DBG_FPU(" = %Lg", val);
+ res = FLOATx80(val);
+ floatx80_to_FP0(env, res);
+}
+
void HELPER(sin_FP0)(CPUState *env)
{
floatx80 res;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index c3c5eb2..46e71d2 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -65,6 +65,7 @@ DEF_HELPER_2(const_FP0, void, env, i32)
DEF_HELPER_1(iround_FP0, void, env)
DEF_HELPER_1(itrunc_FP0, void, env)
DEF_HELPER_1(sqrt_FP0, void, env)
+DEF_HELPER_1(atan_FP0, void, env)
DEF_HELPER_1(sin_FP0, void, env)
DEF_HELPER_1(tan_FP0, void, env)
DEF_HELPER_1(exp_FP0, void, env)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 14ce1f9..d4445fe 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3661,6 +3661,9 @@ DISAS_INSN(fpu)
case 4: case 0x41: case 0x45: /* fsqrt */
gen_helper_sqrt_FP0(cpu_env);
break;
+ case 0x0a: /* fatan */
+ gen_helper_atan_FP0(cpu_env);
+ break;
case 0x0e: /* fsin */
gen_helper_sin_FP0(cpu_env);
break;
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:18 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Allow to run 'flex'.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 19 +++++++++++++++++++
1 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 1196508..252e610 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2504,6 +2504,25 @@ DISAS_INSN(eor)
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));
+
+ 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();
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:00 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Apply a "not" on the mask to really clear bits with the "and"...
(as it is done for bfclr in the memory case)

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index e0c6fa3..f93ad02 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2769,6 +2769,7 @@ DISAS_INSN(bitfield_reg)
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 */
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:59 UTC
Permalink
From: Peter Bjørn Jørgensen <***@gmail.com>

Signed-off-by: Peter Bjørn Jørgensen <***@gmail.com>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 48 ++++++++++++++++++++++++------------------------
1 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 21dfcc7..875ff45 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -977,30 +977,30 @@ HELPER_ROXL(uint32_t, 32)
/* FPU helpers. */

static const floatx80 fpu_rom[128] = {
- [0x00] = { .high = 0x4000, .low = 0xc90fdaa22168c235 }, /* Pi */
-
- [0x0b] = { .high = 0x3ffd, .low = 0x9a209a84fbcff798 }, /* Log10(2) */
- [0x0c] = { .high = 0x4000, .low = 0xadf85458a2bb4a9a }, /* e */
- [0x0d] = { .high = 0x3fff, .low = 0xb8aa3b295c17f0bc }, /* Log2(e) */
- [0x0e] = { .high = 0x3ffd, .low = 0xde5bd8a937287195 }, /* Log10(e) */
- [0x0f] = { .high = 0x0000, .low = 0x0000000000000000 }, /* Zero */
-
- [0x30] = { .high = 0x3ffe, .low = 0xb17217f7d1cf79ac }, /* ln(2) */
- [0x31] = { .high = 0x4000, .low = 0x935d8dddaaa8ac17 }, /* ln(10) */
- [0x32] = { .high = 0x3fff, .low = 0x8000000000000000 }, /* 10^0 */
- [0x33] = { .high = 0x4002, .low = 0xa000000000000000 }, /* 10^1 */
- [0x34] = { .high = 0x4005, .low = 0xc800000000000000 }, /* 10^2 */
- [0x35] = { .high = 0x400c, .low = 0x9c40000000000000 }, /* 10^4 */
- [0x36] = { .high = 0x4019, .low = 0xbebc200000000000 }, /* 10^8 */
- [0x37] = { .high = 0x4034, .low = 0x8e1bc9bf04000000 }, /* 10^16 */
- [0x38] = { .high = 0x4069, .low = 0x9dc5ada82b70b59e }, /* 10^32 */
- [0x39] = { .high = 0x40d3, .low = 0xc2781f49ffcfa6d5 }, /* 10^64 */
- [0x3a] = { .high = 0x41a8, .low = 0x93ba47c980e98ce0 }, /* 10^128 */
- [0x3b] = { .high = 0x4351, .low = 0xaa7eebfb9df9de8e }, /* 10^256 */
- [0x3c] = { .high = 0x46a3, .low = 0xe319a0aea60e91c7 }, /* 10^512 */
- [0x3d] = { .high = 0x4d48, .low = 0xc976758681750c17 }, /* 10^1024 */
- [0x3e] = { .high = 0x5a92, .low = 0x9e8b3b5dc53d5de5 }, /* 10^2048 */
- [0x3f] = { .high = 0x7525, .low = 0xc46052028a20979b }, /* 10^4096 */
+ [0x00] = { .high = 0x4000, .low = 0xc90fdaa22168c235ULL }, /* Pi */
+
+ [0x0b] = { .high = 0x3ffd, .low = 0x9a209a84fbcff798ULL }, /* Log10(2) */
+ [0x0c] = { .high = 0x4000, .low = 0xadf85458a2bb4a9aULL }, /* e */
+ [0x0d] = { .high = 0x3fff, .low = 0xb8aa3b295c17f0bcULL }, /* Log2(e) */
+ [0x0e] = { .high = 0x3ffd, .low = 0xde5bd8a937287195ULL }, /* Log10(e) */
+ [0x0f] = { .high = 0x0000, .low = 0x0000000000000000ULL }, /* Zero */
+
+ [0x30] = { .high = 0x3ffe, .low = 0xb17217f7d1cf79acULL }, /* ln(2) */
+ [0x31] = { .high = 0x4000, .low = 0x935d8dddaaa8ac17ULL }, /* ln(10) */
+ [0x32] = { .high = 0x3fff, .low = 0x8000000000000000ULL }, /* 10^0 */
+ [0x33] = { .high = 0x4002, .low = 0xa000000000000000ULL }, /* 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 */
};

float64 HELPER(const_f64)(CPUState *env, uint32_t offset)
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:08 UTC
Permalink
From: Laurent Vivier <***@Vivier.EU>

Signed-off-by: Laurent Vivier <***@Vivier.EU>
---
configure | 14 ++++++++++++++
linux-user/main.c | 34 +---------------------------------
2 files changed, 15 insertions(+), 33 deletions(-)

diff --git a/configure b/configure
index e85d2ca..1b9da9e 100755
--- a/configure
+++ b/configure
@@ -3145,6 +3145,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)
@@ -3221,11 +3222,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
@@ -3268,12 +3271,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
@@ -3281,12 +3286,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
@@ -3295,6 +3302,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
@@ -3303,6 +3311,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
@@ -3312,6 +3321,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
@@ -3321,11 +3331,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
@@ -3333,6 +3345,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"
@@ -3351,6 +3364,7 @@ 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
diff --git a/linux-user/main.c b/linux-user/main.c
index 8e15474..68b5681 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3083,39 +3083,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();
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:45 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
target-m68k/helpers.h | 1 +
target-m68k/translate.c | 32 ++++++++++++++++++++++++++++++++
3 files changed, 78 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 7d99326..0fa59c8 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -1324,3 +1324,48 @@ uint32_t HELPER(abcd_cc)(CPUState *env, uint32_t src, uint32_t dest)

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 a/target-m68k/helpers.h b/target-m68k/helpers.h
index f299752..76d3063 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -83,4 +83,5 @@ 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 a/target-m68k/translate.c b/target-m68k/translate.c
index 231d87a..7aef2f6 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1095,6 +1095,36 @@ DISAS_INSN(abcd_mem)
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(addsub)
{
TCGv reg;
@@ -3909,6 +3939,8 @@ void register_m68k_insns (CPUM68KState *env)
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(addsub, 9000, f000, M68000);
INSN(undef, 90c0, f0c0, CF_ISA_A);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:27 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

used by gnome-system-monitor.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 16 ++++++++++++++++
target-m68k/helpers.h | 1 +
target-m68k/translate.c | 4 ++++
3 files changed, 21 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 79e6a28..70e7053 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -1537,6 +1537,22 @@ void HELPER(div_FP0_FP1)(CPUState *env)
floatx80_to_FP0(env, res);
}

+void HELPER(mod_FP0_FP1)(CPUState *env)
+{
+ floatx80 res;
+ long double src, dst;
+
+ src = LDOUBLE(FP0_to_floatx80(env));
+ dst = LDOUBLE(FP1_to_floatx80(env));
+
+ DBG_FPUH("mod_FP0_FP1 %Lg %Lg", src, dst);
+ dst = fmodl(dst, src);
+ DBG_FPU(" = %Lg\n", dst);
+
+ res = FLOATx80(dst);
+ floatx80_to_FP0(env, res);
+}
+
void HELPER(fcmp_FP0_FP1)(CPUState *env)
{
/* ??? This may incorrectly raise exceptions. */
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index e6465cd..c3c5eb2 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -81,6 +81,7 @@ 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(fcmp_FP0_FP1, void, env)
DEF_HELPER_1(compare_FP0, i32, env)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 91355ba..7d0b790 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3697,6 +3697,10 @@ DISAS_INSN(fpu)
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_op_load_fpr_FP1(REG(ext, 7));
gen_helper_add_FP0_FP1(cpu_env);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:16 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch modifies following instructions to allow them to manage data
size other than "long", by adding "byte" and "word" data size: "addsub",
"arith_im", "addsubq", "or", "eor", "and".

This patch modifies following instructions to use EA to access data:
"neg", "not".

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/cpu.h | 10 ++-
target-m68k/helper.c | 78 +++++++++++++------
target-m68k/translate.c | 202 +++++++++++++++++++++++++++--------------------
3 files changed, 179 insertions(+), 111 deletions(-)

diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index 0f216c2..688642f 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -132,11 +132,17 @@ enum {
CC_OP_DYNAMIC, /* Use env->cc_op */
CC_OP_FLAGS, /* CC_DEST = CVZN, 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_SHIFT, /* CC_DEST = result, CC_SRC = carry */
};
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index f226e4a..dd9079f 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -242,7 +242,7 @@ 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) \
@@ -256,7 +256,34 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
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((type)dest); \
+ 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((type)dest); \
+ 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((type)dest); \
+ tmp = dest + src + 1; \
+ if ((utype) tmp <= (utype) src) \
+ flags |= CCF_C; \
+ if (HIGHBIT(type) & (tmp ^ dest) & (tmp ^ src)) \
flags |= CCF_V; \
} while (0)

@@ -270,38 +297,41 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
case CC_OP_LOGIC:
SET_NZ(dest);
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_SHIFT:
SET_NZ(dest);
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index b86588c..a537373 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -262,6 +262,22 @@ static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val,
}
}

+/* Read an 8-bit immediate constant */
+static inline uint32_t read_im8(DisasContext *s)
+{
+ uint32_t im;
+ im = ldsb_code(s->pc + 1);
+ s->pc += 2;
+ 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)
{
@@ -438,6 +454,25 @@ static inline int opsize_bytes(int opsize)
}
}

+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();
+ }
+}
+
+#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)
+
/* 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)
@@ -974,31 +1009,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_CC_OP(opsize, ADD);
} else {
gen_helper_xflag_lt(QREG_CC_X, 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);
}
}

@@ -1189,10 +1226,24 @@ 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 */
@@ -1208,14 +1259,14 @@ DISAS_INSN(arith_im)
gen_helper_xflag_lt(QREG_CC_X, 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_CC_OP(opsize, ADD);
break;
case 5: /* eori */
tcg_gen_xori_i32(dest, src1, im);
@@ -1225,13 +1276,13 @@ DISAS_INSN(arith_im)
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);
}
}

@@ -1307,19 +1358,7 @@ 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));
}
@@ -1347,17 +1386,20 @@ 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);
+ DEST_EA(insn, opsize, dest, &addr);
+ SET_CC_OP(opsize, SUB);
+ gen_update_cc_add(src1, dest);
+ gen_helper_xflag_lt(QREG_CC_X, tcg_const_i32(0), dest);
+ SET_CC_OP(opsize, SUB);
}

static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
@@ -1404,11 +1446,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);
}

DISAS_INSN(swap)
@@ -1463,20 +1511,8 @@ 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);
+ opsize = insn_opsize(insn, 6);
+ SRC_EA(tmp, opsize, -1, NULL);
gen_logic_cc(s, tmp);
}

@@ -1597,8 +1633,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;
@@ -1617,11 +1659,11 @@ DISAS_INSN(addsubq)
if (insn & 0x0100) {
gen_helper_xflag_lt(QREG_CC_X, 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_CC_OP(opsize, ADD);
}
gen_update_cc_add(dest, src2);
}
@@ -1709,17 +1751,19 @@ 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);
}
@@ -1760,34 +1804,18 @@ DISAS_INSN(mov3q)

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 +1835,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(opsize, SUB);
}

DISAS_INSN(eor)
@@ -1816,13 +1844,15 @@ DISAS_INSN(eor)
TCGv reg;
TCGv dest;
TCGv addr;
+ int opsize;

- SRC_EA(src, OS_LONG, 0, &addr);
+ opsize = insn_opsize(insn, 6);
+ 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);
+ DEST_EA(insn, opsize, dest, &addr);
}

DISAS_INSN(and)
@@ -1831,17 +1861,19 @@ DISAS_INSN(and)
TCGv reg;
TCGv dest;
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_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);
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:12 UTC
Permalink
From: Laurent Vivier <***@Vivier.EU>

Signed-off-by: Laurent Vivier <***@Vivier.EU>
---
scripts/set_binfmt_m68k | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
create mode 100755 scripts/set_binfmt_m68k

diff --git a/scripts/set_binfmt_m68k b/scripts/set_binfmt_m68k
new file mode 100755
index 0000000..fb3d720
--- /dev/null
+++ b/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
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:13 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

DEST_EA() must use same opsize as SRC_EA().

This allows to run nano and vim.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 93f9973..fb12f3b 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2274,7 +2274,7 @@ DISAS_INSN(addsubq)
}
gen_update_cc_add(dest, src2);
}
- DEST_EA(insn, OS_LONG, dest, &addr);
+ DEST_EA(insn, opsize, dest, &addr);
}

DISAS_INSN(tpf)
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:58 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch doesn't modify values inside operand "shift" and "offset",
instead copy them in a TCG temp.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 7 ++++---
1 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 4f2a5ee..e0c6fa3 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2693,7 +2693,8 @@ static void bitfield_param(uint16_t ext, TCGv *offset, TCGv *width, TCGv *mask)
/* offset */

if (ext & 0x0800) {
- *offset = DREG(ext, 6);
+ *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);
@@ -2702,8 +2703,8 @@ static void bitfield_param(uint16_t ext, TCGv *offset, TCGv *width, TCGv *mask)
/* width */

if (ext & 0x0020) {
- *width = DREG(ext, 0);
- tcg_gen_subi_i32(*width, *width, 1);
+ *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 {
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:32 UTC
Permalink
+ 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, 0, l1);
The counter needs to be compared with -1, not 0.

Andreas.
---
target-m68k/translate.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 218210c..d4d2f44 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -939,7 +939,7 @@ DISAS_INSN(dbcc)
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, 0, l1);
+ 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);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:02 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

- put results in QUADH and DIV1
- correctly compute overflow flag (idea from aranym/UAE)

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/op_helper.c | 34 ++++++++++++++++++----------------
target-m68k/translate.c | 2 +-
2 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index c270259..d180c80 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -290,37 +290,39 @@ void HELPER(divu64)(CPUState *env)
/* Don't modify destination if overflow occured. */
if ((flags & CCF_V) == 0) {
env->div1 = quot;
- env->div2 = rem;
+ env->quadh = rem;
}
env->cc_dest = flags;
}

void HELPER(divs64)(CPUState *env)
{
- int32_t num;
+ uint32_t num;
int32_t den;
- int32_t quot;
+ 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);
- quot = (num | ((int64_t)env->quadh << 32)) / den;
- rem = (num | ((int64_t)env->quadh << 32)) % den;
- rem = num % den;
- flags = 0;
- if (quot != (int32_t)quot)
- flags |= CCF_V;
- if (quot == 0)
- flags |= CCF_Z;
- else if (quot < 0)
- flags |= CCF_N;
- /* Don't modify destination if overflow occured. */
- if ((flags & CCF_V) == 0) {
+ 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->div2 = rem;
+ env->quadh = rem;
}
env->cc_dest = flags;
}
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index b011a5e..0808673 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1055,7 +1055,7 @@ DISAS_INSN(divl)
}
tcg_gen_mov_i32(num, QREG_DIV1);
if (!TCGV_EQUAL(num, reg))
- tcg_gen_mov_i32(reg, QREG_DIV2);
+ tcg_gen_mov_i32(reg, QREG_QUADH);
s->cc_op = CC_OP_FLAGS;
return;
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:24 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Modify "fpu" instruction to be compatible with 680x0 family and attach
it to FPU feature (in addition to CF_FPU).

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 49 ++++++++++++++++++++++++++++++++++++++++------
1 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 0321349..8fb71b8 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2342,18 +2342,43 @@ DISAS_INSN(fpu)
case 7:
{
TCGv addr;
+ int incr;
uint16_t mask;
int i;
- if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
+ if ((ext & 0xf00) != 0 || (ext & 0xff) == 0)
goto undef;
- tmp32 = gen_lea(s, insn, OS_LONG);
- if (IS_NULL_QREG(tmp32)) {
- gen_addr_fault(s);
- return;
+ if ((ext & 0x1000) == 0 && !m68k_feature(s->env, M68K_FEATURE_FPU))
+ goto undef;
+ if ((insn & 070) == 040)
+ tmp32 = AREG(insn, 0);
+ else {
+ 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;
+ if (m68k_feature(s->env, M68K_FEATURE_FPU))
+ incr = 12;
+ else
+ incr = 8;
+ if ((ext & (1 << 13)) && (insn & 070) == 040) {
+ for (i = 0; i < 8; i++) {
+ if (ext & mask) {
+ s->is_mem = 1;
+ dest = FREG(i, 7);
+ tcg_gen_subi_i32(addr, addr, incr);
+ tcg_gen_mov_i32(AREG(insn, 0), addr);
+ tcg_gen_qemu_stf64(dest, addr, IS_USER(s));
+ }
+ mask >>= 1;
+ }
+ tcg_temp_free_i32(addr);
+ return;
+ }
for (i = 0; i < 8; i++) {
if (ext & mask) {
s->is_mem = 1;
@@ -2365,8 +2390,11 @@ DISAS_INSN(fpu)
/* load */
tcg_gen_qemu_ldf64(dest, addr, IS_USER(s));
}
- if (ext & (mask - 1))
- tcg_gen_addi_i32(addr, addr, 8);
+ if (ext & (mask - 1) || (insn & 070) == 030) {
+ tcg_gen_addi_i32(addr, addr, incr);
+ if ((insn & 070) == 030)
+ tcg_gen_mov_i32(AREG(insn, 0), addr);
+ }
}
mask >>= 1;
}
@@ -2474,6 +2502,12 @@ DISAS_INSN(fpu)
case 0x23: case 0x63: case 0x67: /* fmul */
gen_helper_mul_f64(res, cpu_env, res, src);
break;
+ case 0x24: /* fsgldiv */
+ gen_helper_div_f64(res, cpu_env, res, src);
+ break;
+ case 0x27: /* fsglmul */
+ gen_helper_mul_f64(res, cpu_env, res, src);
+ break;
case 0x28: case 0x68: case 0x6c: /* fsub */
gen_helper_sub_f64(res, cpu_env, res, src);
break;
@@ -3156,6 +3190,7 @@ void register_m68k_insns (CPUM68KState *env)
INSN(fbcc, f280, ffc0, CF_FPU);
INSN(frestore, f340, ffc0, CF_FPU);
INSN(fsave, f340, ffc0, CF_FPU);
+ INSN(fpu, f200, ffc0, FPU);
INSN(fbcc, f280, ffc0, FPU);
INSN(frestore, f340, ffc0, FPU);
INSN(fsave, f340, ffc0, FPU);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:40 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Add support for all opsize (byte, word) instead of only long.
On 680x0, don't clear/modify the X flag.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/cpu.h | 2 +
target-m68k/helper.c | 31 +++++++++++++++------
target-m68k/translate.c | 70 +++++++++++++++++++++++------------------------
3 files changed, 58 insertions(+), 45 deletions(-)

diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index ae4f6fa..0d5e3d3 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -134,6 +134,8 @@ 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 */
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 914147a..dfa7c10 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -282,15 +282,15 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)

#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; \
@@ -299,7 +299,7 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
} while (0)

#define SET_FLAGS_ADD(type, utype) do { \
- SET_NZ((type)dest); \
+ SET_NZ(dest, type); \
if ((utype) dest < (utype) src) \
flags |= CCF_C; \
tmp = dest - src; \
@@ -308,7 +308,7 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
} while (0)

#define SET_FLAGS_ADDX(type, utype) do { \
- SET_NZ((type)dest); \
+ SET_NZ(dest, type); \
if ((utype) dest <= (utype) src) \
flags |= CCF_C; \
tmp = dest - src - 1; \
@@ -317,7 +317,7 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
} while (0)

#define SET_FLAGS_SUBX(type, utype) do { \
- SET_NZ((type)dest); \
+ SET_NZ(dest, type); \
tmp = dest + src + 1; \
if ((utype) tmp <= (utype) src) \
flags |= CCF_C; \
@@ -326,7 +326,7 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
} while (0)

#define SET_FLAGS_SHIFT(type) do { \
- SET_NZ((type)dest); \
+ SET_NZ(dest, type); \
if (src) \
flags |= CCF_C; \
} while(0)
@@ -338,8 +338,21 @@ 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);
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 3ce5f53..cad2e26 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -431,10 +431,19 @@ 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)
+
+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)
@@ -467,15 +476,6 @@ static inline int insn_opsize(int insn, int pos)
}
}

-#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)
-
/* 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)
@@ -980,8 +980,7 @@ 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)
@@ -1172,7 +1171,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)
@@ -1334,11 +1333,11 @@ DISAS_INSN(arith_im)
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);
@@ -1356,7 +1355,7 @@ DISAS_INSN(arith_im)
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);
@@ -1422,7 +1421,7 @@ DISAS_INSN(cas)

res = tcg_temp_new();
tcg_gen_sub_i32(res, dest, cmp);
- gen_logic_cc(s, res);
+ gen_logic_cc(s, res, opsize);

l1 = gen_new_label();
l2 = gen_new_label();
@@ -1478,7 +1477,7 @@ 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);
}
}

@@ -1511,7 +1510,7 @@ DISAS_INSN(clr)

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)
@@ -1607,7 +1606,7 @@ DISAS_INSN(not)
dest = tcg_temp_new();
tcg_gen_not_i32(dest, src1);
DEST_EA(insn, opsize, dest, &addr);
- gen_logic_cc(s, dest);
+ gen_logic_cc(s, dest, opsize);
}

DISAS_INSN(swap)
@@ -1622,7 +1621,7 @@ 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(pea)
@@ -1654,7 +1653,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)
@@ -1664,7 +1663,7 @@ DISAS_INSN(tst)

opsize = insn_opsize(insn, 6);
SRC_EA(tmp, opsize, -1, NULL);
- gen_logic_cc(s, tmp);
+ gen_logic_cc(s, tmp, opsize);
}

DISAS_INSN(pulse)
@@ -1686,7 +1685,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);
}
@@ -1732,9 +1731,8 @@ DISAS_INSN(mull)
s->cc_op = CC_OP_FLAGS;
} else {
tcg_gen_mul_i32(dest, src1, reg);
- /* Unlike m68k, coldfire always clears the overflow bit. */
- gen_logic_cc(s, dest);
}
+ gen_logic_cc(s, dest, OS_LONG);
tcg_gen_mov_i32(reg, dest);
}

@@ -1915,7 +1913,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)
@@ -1931,7 +1929,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)
@@ -1954,7 +1952,7 @@ DISAS_INSN(or)
tcg_gen_or_i32(dest, src, reg);
gen_partset_reg(opsize, reg, dest);
}
- gen_logic_cc(s, dest);
+ gen_logic_cc(s, dest, opsize);
}

DISAS_INSN(suba)
@@ -1987,7 +1985,7 @@ DISAS_INSN(mov3q)
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);
}

@@ -2040,7 +2038,7 @@ DISAS_INSN(eor)
reg = DREG(insn, 9);
dest = tcg_temp_new();
tcg_gen_xor_i32(dest, src, reg);
- gen_logic_cc(s, dest);
+ gen_logic_cc(s, dest, opsize);
DEST_EA(insn, opsize, dest, &addr);
}

@@ -2064,7 +2062,7 @@ DISAS_INSN(and)
tcg_gen_and_i32(dest, src, reg);
gen_partset_reg(opsize, reg, dest);
}
- gen_logic_cc(s, dest);
+ gen_logic_cc(s, dest, opsize);
}

DISAS_INSN(adda)
@@ -2530,7 +2528,7 @@ DISAS_INSN(bitfield_reg)

tmp1 = tcg_temp_new_i32();
gen_helper_rol32(tmp1, tmp, offset);
- gen_logic_cc(s, tmp1);
+ gen_logic_cc(s, tmp1, OS_LONG);

reg2 = DREG(ext, 12);
switch (op) {
@@ -2599,7 +2597,7 @@ static TCGv gen_bitfield_cc(DisasContext *s,
/* compute cc */

tcg_gen_and_i32(dest, dest, mask_cc);
- gen_logic_cc(s, dest);
+ gen_logic_cc(s, dest, OS_LONG);

return dest;
}
@@ -2771,7 +2769,7 @@ 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);
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:10 UTC
Permalink
From: Laurent Vivier <***@Vivier.EU>

Signed-off-by: Laurent Vivier <***@Vivier.EU>
---
target-m68k/helper.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 7ca75fb..8a8b4f8 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -57,6 +57,11 @@ 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);
}
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:28 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Force the computing of the flags before negx as
negx will keep Z flag from previous instructions
if result is non zero.

Seen with gcc testsuite,
gcc.c-torture/execute/builtin-bitops-1.c

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 7d0b790..e9b6abc 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1896,6 +1896,7 @@ DISAS_INSN(negx)
int opsize;

opsize = insn_opsize(insn, 6);
+ gen_flush_flags(s);
SRC_EA(src, opsize, -1, &addr);
dest = tcg_temp_new();
switch(opsize) {
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:13 UTC
Permalink
From: Laurent Vivier <***@Vivier.EU>

Signed-off-by: Laurent Vivier <***@Vivier.EU>
---
configure | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/configure b/configure
index 46b49e0..40b1fa9 100755
--- a/configure
+++ b/configure
@@ -3251,6 +3251,7 @@ case "$target_arch2" in
cris)
target_nptl="yes"
target_phys_bits=32
+ target_default_cpu=""
;;
lm32)
target_phys_bits=32
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:29 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

seen with gcc testsuite,
gcc-4.1.2/gcc/testsuite/gcc.c-torture/execute/930622-2.c

allow to run gtk-demo, gimp ...

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index e9b6abc..14ce1f9 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3536,18 +3536,18 @@ static void gen_op_fmovem(DisasContext *s, uint32_t insn, uint32_t ext)
mask = ext & 0x00FF;

if (!is_load && (mode & 2) == 0) {
- for (i = 7; i >= 0; i--, mask >>= 1) {
- if (mask & 1) {
+ 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 != 1)
+ 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 & 1) {
+ 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);
@@ -3555,7 +3555,7 @@ static void gen_op_fmovem(DisasContext *s, uint32_t insn, uint32_t ext)
gen_op_load_fpr_FP0(i);
gen_store_FP0(s, opsize, addr);
}
- if (mask != 1 || (insn & 070) == 030)
+ if ((mask & 0xff) != 0x80 || (insn & 070) == 030)
tcg_gen_addi_i32(addr, addr, incr);
}
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:35 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch allows to manage instructions like "fsge %d0".

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 82 +++++++++++++++++++++++++++++++++++++++--------
1 files changed, 68 insertions(+), 14 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 01dea9c..3917243 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3213,27 +3213,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);
/* Jump to l1 if condition is true. */
- switch (insn & 0xf) {
+ switch (cond) {
case 0: /* f */
break;
case 1: /* eq (=0) */
@@ -3284,11 +3272,75 @@ 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 = lduw_code(s->pc);
+ s->pc += 2;
+
+ 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 = lduw_code(s->pc);
+ s->pc += 2;
+
+ 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. */
@@ -3866,6 +3918,8 @@ void register_m68k_insns (CPUM68KState *env)
INSN(frestore, f340, ffc0, CF_FPU);
INSN(fsave, f340, ffc0, CF_FPU);
INSN(fpu, f200, ffc0, FPU);
+ INSN(fscc_mem, f240, ffc0, FPU);
+ INSN(fscc_reg, f240, fff8, FPU);
INSN(fbcc, f280, ffc0, FPU);
INSN(frestore, f340, ffc0, FPU);
INSN(fsave, f340, ffc0, FPU);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:52 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 48 +++++++++++++++-------------------------------
1 files changed, 16 insertions(+), 32 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 37ee841..f5e56bc 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -567,8 +567,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. */
@@ -1276,8 +1275,7 @@ DISAS_INSN(movem)
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);
@@ -1339,8 +1337,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;
@@ -1484,8 +1481,7 @@ DISAS_INSN(cas)
abort();
}

- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);
taddr = gen_lea(s, insn, opsize);
if (IS_NULL_QREG(taddr)) {
gen_addr_fault(s);
@@ -1677,8 +1673,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
@@ -1796,8 +1791,7 @@ DISAS_INSN(mull)

/* 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;
+ ext = read_im16(s);
if (ext & 0x400) {
if (!m68k_feature(s->env, M68K_FEATURE_QUAD_MULDIV)) {
gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
@@ -2731,8 +2725,7 @@ DISAS_INSN(bitfield_reg)

reg = DREG(insn, 0);
op = (insn >> 8) & 7;
- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);

bitfield_param(ext, &offset, &width, &mask);

@@ -2905,8 +2898,7 @@ DISAS_INSN(bitfield_mem)
TCGv tmp;

op = (insn >> 8) & 7;
- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);
src = gen_lea(s, insn, OS_LONG);
if (IS_NULL_QREG(src)) {
gen_addr_fault(s);
@@ -3010,14 +3002,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;
@@ -3084,8 +3074,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);
@@ -3111,8 +3100,7 @@ DISAS_INSN(movec)
return;
}

- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);

if (ext & 0x8000) {
reg = AREG(ext, 12);
@@ -3545,8 +3533,7 @@ DISAS_INSN(fscc_mem)
TCGv addr;
uint16_t ext;

- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);

taddr = gen_lea(s, insn, OS_BYTE);
if (IS_NULL_QREG(taddr)) {
@@ -3572,8 +3559,7 @@ DISAS_INSN(fscc_reg)
TCGv reg;
uint16_t ext;

- ext = lduw_code(s->pc);
- s->pc += 2;
+ ext = read_im16(s);

reg = DREG(insn, 0);

@@ -3641,8 +3627,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);
@@ -4190,8 +4175,7 @@ static void disas_m68k_insn(CPUState * env, DisasContext *s)
if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
tcg_gen_debug_insn_start(s->pc);

- insn = lduw_code(s->pc);
- s->pc += 2;
+ insn = read_im16(s);

opcode_table[insn](s, insn);
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:24 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 15 +++++++++++++++
target-m68k/helpers.h | 1 +
target-m68k/translate.c | 3 +++
3 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 319723e..699f28a 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -1332,6 +1332,21 @@ void HELPER(log10_FP0)(CPUState *env)
floatx80_to_FP0(env, res);
}

+void HELPER(sin_FP0)(CPUState *env)
+{
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = LDOUBLE(res);
+
+ DBG_FPUH("sin_FP0 %Lg", val);
+ val = sinl(val);
+ DBG_FPU(" = %Lg", val);
+ res = FLOATx80(val);
+ floatx80_to_FP0(env, res);
+}
+
void HELPER(tan_FP0)(CPUState *env)
{
floatx80 res;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index ec51ce0..c704953 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -65,6 +65,7 @@ DEF_HELPER_2(const_FP0, void, env, i32)
DEF_HELPER_1(iround_FP0, void, env)
DEF_HELPER_1(itrunc_FP0, void, env)
DEF_HELPER_1(sqrt_FP0, void, env)
+DEF_HELPER_1(sin_FP0, void, env)
DEF_HELPER_1(tan_FP0, void, env)
DEF_HELPER_1(exp_FP0, void, env)
DEF_HELPER_1(exp2_FP0, void, env)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index b69cac9..0fafa3b 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3661,6 +3661,9 @@ DISAS_INSN(fpu)
case 4: case 0x41: case 0x45: /* fsqrt */
gen_helper_sqrt_FP0(cpu_env);
break;
+ case 0x0e: /* fsin */
+ gen_helper_sin_FP0(cpu_env);
+ break;
case 0x0f: /* ftan */
gen_helper_tan_FP0(cpu_env);
break;
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:32 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

seen with gcc testsuite,
gcc-4.1.2/gcc/testsuite/gcc.c-torture/execute/960405-1.c

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 4 ++--
tests/m68k/Makefile | 2 +-
tests/m68k/inf.S | 17 +++++++++++++++++
3 files changed, 20 insertions(+), 3 deletions(-)
create mode 100644 tests/m68k/inf.S

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 62aadfd..6cc4202 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -1581,8 +1581,8 @@ void HELPER(fcmp_FP0_FP1)(CPUState *env)
/* +/-inf compares equal against itself, but sub returns nan. */
if (!floatx80_is_any_nan(FP0_to_floatx80(env))
&& !floatx80_is_any_nan(FP1_to_floatx80(env))) {
- if (floatx80_lt_quiet(FP1_to_floatx80(env), floatx80_zero,
- &env->fp_status))
+ res = floatx80_zero;
+ if (floatx80_lt_quiet(FP1_to_floatx80(env), res, &env->fp_status))
res = floatx80_chs(res);
}
}
diff --git a/tests/m68k/Makefile b/tests/m68k/Makefile
index d043aeb..27525d3 100644
--- a/tests/m68k/Makefile
+++ b/tests/m68k/Makefile
@@ -1,5 +1,5 @@
TESTS=fmovecr fmove fmovem fsub fdiv fmul fabs fgetexp fscale flogn fetox \
- bfins
+ bfins inf

all: $(TESTS)

diff --git a/tests/m68k/inf.S b/tests/m68k/inf.S
new file mode 100644
index 0000000..2b2de84
--- /dev/null
+++ b/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
--
1.7.2.3
Anthony Liguori
2011-08-17 22:35:01 UTC
Permalink
Post by Bryce Lanham
These patches greatly expand Motorola 68k emulation within qemu, and are what I used as a basis for my
Google Summer of Code project to add NeXT hardware support to QEMU.
Please don't crap flood the list with a series of 100 patches.

Split things into logical chunks such that a series can be reasonably
reviewed and applied.

Regards,

Anthony Liguori
Post by Bryce Lanham
Bryce Lanham
linux-user: Signals processing is not thread-safe.
m68k: add cas
m68k: define fcntl constants
m68k: add DBcc instruction.
linux-user: add qemu-wrapper
linux-user: define default cpu model in configure instead of
linux-user/main.c
linux-user: specify the cpu model during configure
linux-user,m68k: display default cpu
linux-user: define new environment variables
linux-user: define a script to set binfmt using debian flavored tools
linux-user: define default cpu model in configure instead of
linux-user/main.c
m68k: add tcg_gen_debug_insn_start()
m68k: define m680x0 CPUs and features
m68k: add missing accessing modes for some instructions.
m68k: add Motorola 680x0 family common instructions.
m68k: add Scc instruction with memory operand.
m68k: add DBcc instruction.
m68k: modify movem instruction to manage word
m68k: add 64bit divide.
m68k: add 32bit and 64bit multiply
m68k: add word data size for suba/adda
m68k: add fpu
m68k: add "byte", "word" and memory shift
m68k: add "byte", "word" and memory rotate.
m68k: add bitfield_mem, bitfield_reg
m68k: add variable offset/width to bitfield_reg/bitfield_mem
m68k: add cas
m68k: allow fpu to manage double data type.
m68k: allow fpu to manage double data type with fmove to<ea>
m68k: add FScc instruction
m68k: add single data type to gen_ea
m68k: add linkl instruction
m68k: Add fmovecr
m68k: correct typo on f64_to_i32() return type.
m68k: improve CC_OP_LOGIC
m68k: correct neg condition code flags computation
Correct invalid use of "const void *" with "const uint8_t *"
m68k: add EA support for negx
m68k: add abcd instruction
m68k: add sbcd instruction
mm68k: add nbcd instruction
m68k: set X flag according size of operand Set X flag correctly
for addsub, arith_im, addsubq.
m68k: on 0 bit shift, don't update X flag
m68k: improve addx instructions Add (byte, word) opsize Add
memory access
m68k: improve subx,negx instructions Add (byte, word) opsize
Add memory access (subx)
m68k: improve asl/asr evaluate correclty the missing V flag
m68k: use read_imm1() when it is possible
m68k: correct shift side effect for roxrl and roxll
m68k: asl/asr, clear C flag if shift count is 0
m68k: lsl/lsr, clear C flag if shift count is 0
m68k: correct divs.w and divu.w
m68k: correct flags with negl
m68k: for bitfield opcodes, correct operands corruption
m68k: Correct bfclr in register case.
m68k-linux-user: add '--enable-emulop'
m68k: correctly compute divsl
m68k: correctly compute divul
m68k: add m68030 definition
m68k: remove dead code
m68k: remove useless file m68k-qreg.h
m68k: FPU rework (draft)
m68k: some FPU debugging macros
m68k: more tests
m68k: correct compute gen_bitfield_cc()
m68k: add fgetexp
m68k: add fscale
m68k: correct addsubq
m68k: add fetox and flogn
m68k: initialize FRegs, define pickNaN()
m68k: correct cmpa comparison datatype
m68k: add flog10
m68k: add cmpm instruction
m68k: add ftwotox instruction
m68k: better fpu traces
m68k: register source operand is always in extended size
m68k: add facos instruction
m68k: add ftan instruction
m68k: add fsin instruction
m68k: add fcos instruction
m68k: correct fpcr update
m68k: add fmod instruction
m68k: flush flags before negx instruction.
m68k: correct fmovemx FP registers order.
m68k: add fatan instruction
m68k: correct bfins instruction
m68k: fcmp correctly compares infinity.
m68k: allows bfins to manage correctly width = 32
m68k: add ftentox instruction
m68k: correctly define and manage NaN
m68k: don't call gdb_register_coprocessor() twice.
m68k: gdb FP registers are 96 bits
m68k: add exg instruction
m68k: define floatx80_default_inf_high and floatx80_default_inf_low
m68k: add bkpt instruction
m68k: correctly convert floatx80<->long double
m68k: use expl() to compute exp_FP0()
m68k: use exp2l() to compute exp2_FP0()
m68k: use logl() to compute ln_FP0()
m68k: use log10l() to compute log10_FP0()
m68k: correctly load signed word into floating point register
m68k: add fcosh instruction
m68k: add fasin instruction
m68k: add fsincos instruction
m68k: add fsinh instruction
m68k: add ftanh instruction
m68k: add flognp1 instruction
m68k: add fatanh instruction
m68k: first draft of q800 emulation (not working)
m68k: add movec instruction
m68k: move from sr can use effective addresse on m68k
m68k: Added ULL to 64 bit integer in helper.c
Bryce Lanham
2011-08-17 23:30:06 UTC
Permalink
Ugh, I'm sorry about that. This is why I should test before using
unfamiliar tools. Someone suggested using git format-patch/git
send-email instead of a big patch.

Apologies,
Bryce Lanham
Post by Anthony Liguori
Post by Bryce Lanham
These patches greatly expand Motorola 68k emulation within qemu, and are
what I used as a basis for my
Google Summer of Code project to add NeXT hardware support to QEMU.
Please don't crap flood the list with a series of 100 patches.
Split things into logical chunks such that a series can be reasonably
reviewed and applied.
Regards,
Anthony Liguori
Post by Bryce Lanham
Bryce Lanham
  linux-user: Signals processing is not thread-safe.
  m68k: add cas
  m68k: define fcntl constants
  m68k: add DBcc instruction.
  linux-user: add qemu-wrapper
  linux-user: define default cpu model in configure instead of
    linux-user/main.c
  linux-user: specify the cpu model during configure
  linux-user,m68k: display default cpu
  linux-user: define new environment variables
  linux-user: define a script to set binfmt using debian flavored tools
  linux-user: define default cpu model in configure instead of
    linux-user/main.c
  m68k: add tcg_gen_debug_insn_start()
  m68k: define m680x0 CPUs and features
  m68k: add missing accessing modes for some instructions.
  m68k: add Motorola 680x0 family common instructions.
  m68k: add Scc instruction with memory operand.
  m68k: add DBcc instruction.
  m68k: modify movem instruction to manage word
  m68k: add 64bit divide.
  m68k: add 32bit and 64bit multiply
  m68k: add word data size for suba/adda
  m68k: add fpu
  m68k: add "byte", "word" and memory shift
  m68k: add "byte", "word" and memory rotate.
  m68k: add bitfield_mem, bitfield_reg
  m68k: add variable offset/width to bitfield_reg/bitfield_mem
  m68k: add cas
  m68k: allow fpu to manage double data type.
  m68k: allow fpu to manage double data type with fmove to<ea>
  m68k: add FScc instruction
  m68k: add single data type to gen_ea
  m68k: add linkl instruction
  m68k: Add fmovecr
  m68k: correct typo on f64_to_i32() return type.
  m68k: improve CC_OP_LOGIC
  m68k: correct neg condition code flags computation
  Correct invalid use of "const void *" with "const uint8_t *"
  m68k: add EA support for negx
  m68k: add abcd instruction
  m68k: add sbcd instruction
  mm68k: add nbcd instruction
  m68k: set X flag according size of operand     Set X flag correctly
    for addsub, arith_im, addsubq.
  m68k: on 0 bit shift, don't update X flag
  m68k: improve addx instructions     Add (byte, word) opsize     Add
    memory access
  m68k: improve subx,negx instructions     Add (byte, word) opsize
    Add memory access (subx)
  m68k: improve asl/asr     evaluate correclty the missing V flag
  m68k: use read_imm1() when it is possible
  m68k: correct shift side effect for roxrl and roxll
  m68k: asl/asr, clear C flag if shift count is 0
  m68k: lsl/lsr, clear C flag if shift count is 0
  m68k: correct divs.w and divu.w
  m68k: correct flags with negl
  m68k: for bitfield opcodes, correct operands corruption
  m68k: Correct bfclr in register case.
  m68k-linux-user: add '--enable-emulop'
  m68k: correctly compute divsl
  m68k: correctly compute divul
  m68k: add m68030 definition
  m68k: remove dead code
  m68k: remove useless file m68k-qreg.h
  m68k: FPU rework (draft)
  m68k: some FPU debugging macros
  m68k: more tests
  m68k: correct compute gen_bitfield_cc()
  m68k: add fgetexp
  m68k: add fscale
  m68k: correct addsubq
  m68k: add fetox and flogn
  m68k: initialize FRegs, define pickNaN()
  m68k: correct cmpa comparison datatype
  m68k: add flog10
  m68k: add cmpm instruction
  m68k: add ftwotox instruction
  m68k: better fpu traces
  m68k: register source operand is always in extended size
  m68k: add facos instruction
  m68k: add ftan instruction
  m68k: add fsin instruction
  m68k: add fcos instruction
  m68k: correct fpcr update
  m68k: add fmod instruction
  m68k: flush flags before negx instruction.
  m68k: correct fmovemx FP registers order.
  m68k: add fatan instruction
  m68k: correct bfins instruction
  m68k: fcmp correctly compares infinity.
  m68k: allows bfins to manage correctly width = 32
  m68k: add ftentox instruction
  m68k: correctly define and manage NaN
  m68k: don't call gdb_register_coprocessor() twice.
  m68k: gdb FP registers are 96 bits
  m68k: add exg instruction
  m68k: define floatx80_default_inf_high and floatx80_default_inf_low
  m68k: add bkpt instruction
  m68k: correctly convert floatx80<->long double
  m68k: use expl() to compute exp_FP0()
  m68k: use exp2l() to compute exp2_FP0()
  m68k: use logl() to compute ln_FP0()
  m68k: use log10l() to compute log10_FP0()
  m68k: correctly load signed word into floating point register
  m68k: add fcosh instruction
  m68k: add fasin instruction
  m68k: add fsincos instruction
  m68k: add fsinh instruction
  m68k: add ftanh instruction
  m68k: add flognp1 instruction
  m68k: add fatanh instruction
  m68k: first draft of q800 emulation (not working)
  m68k: add movec instruction
  m68k: move from sr can use effective addresse on m68k
  m68k: Added ULL to 64 bit integer in helper.c
Peter Maydell
2011-08-17 23:36:37 UTC
Permalink
Post by Bryce Lanham
Ugh, I'm sorry about that. This is why I should test before using
unfamiliar tools. Someone suggested using git format-patch/git
send-email instead of a big patch.
git send-email has a "--dry-run" option which I commend to
your attention :-)

-- PMM
Michael Roth
2011-08-18 16:05:20 UTC
Permalink
Post by Bryce Lanham
Ugh, I'm sorry about that. This is why I should test before using
unfamiliar tools. Someone suggested using git format-patch/git
send-email instead of a big patch.
That's definitely preferred actually, but you should look at breaking
this into multiple logical/self-contained series for easier review/testing.
Post by Bryce Lanham
Apologies,
Bryce Lanham
Post by Anthony Liguori
Post by Bryce Lanham
These patches greatly expand Motorola 68k emulation within qemu, and are
what I used as a basis for my
Google Summer of Code project to add NeXT hardware support to QEMU.
Please don't crap flood the list with a series of 100 patches.
Split things into logical chunks such that a series can be reasonably
reviewed and applied.
Regards,
Anthony Liguori
Post by Bryce Lanham
Bryce Lanham
linux-user: Signals processing is not thread-safe.
m68k: add cas
m68k: define fcntl constants
m68k: add DBcc instruction.
linux-user: add qemu-wrapper
linux-user: define default cpu model in configure instead of
linux-user/main.c
linux-user: specify the cpu model during configure
linux-user,m68k: display default cpu
linux-user: define new environment variables
linux-user: define a script to set binfmt using debian flavored tools
linux-user: define default cpu model in configure instead of
linux-user/main.c
m68k: add tcg_gen_debug_insn_start()
m68k: define m680x0 CPUs and features
m68k: add missing accessing modes for some instructions.
m68k: add Motorola 680x0 family common instructions.
m68k: add Scc instruction with memory operand.
m68k: add DBcc instruction.
m68k: modify movem instruction to manage word
m68k: add 64bit divide.
m68k: add 32bit and 64bit multiply
m68k: add word data size for suba/adda
m68k: add fpu
m68k: add "byte", "word" and memory shift
m68k: add "byte", "word" and memory rotate.
m68k: add bitfield_mem, bitfield_reg
m68k: add variable offset/width to bitfield_reg/bitfield_mem
m68k: add cas
m68k: allow fpu to manage double data type.
m68k: allow fpu to manage double data type with fmove to<ea>
m68k: add FScc instruction
m68k: add single data type to gen_ea
m68k: add linkl instruction
m68k: Add fmovecr
m68k: correct typo on f64_to_i32() return type.
m68k: improve CC_OP_LOGIC
m68k: correct neg condition code flags computation
Correct invalid use of "const void *" with "const uint8_t *"
m68k: add EA support for negx
m68k: add abcd instruction
m68k: add sbcd instruction
mm68k: add nbcd instruction
m68k: set X flag according size of operand Set X flag correctly
for addsub, arith_im, addsubq.
m68k: on 0 bit shift, don't update X flag
m68k: improve addx instructions Add (byte, word) opsize Add
memory access
m68k: improve subx,negx instructions Add (byte, word) opsize
Add memory access (subx)
m68k: improve asl/asr evaluate correclty the missing V flag
m68k: use read_imm1() when it is possible
m68k: correct shift side effect for roxrl and roxll
m68k: asl/asr, clear C flag if shift count is 0
m68k: lsl/lsr, clear C flag if shift count is 0
m68k: correct divs.w and divu.w
m68k: correct flags with negl
m68k: for bitfield opcodes, correct operands corruption
m68k: Correct bfclr in register case.
m68k-linux-user: add '--enable-emulop'
m68k: correctly compute divsl
m68k: correctly compute divul
m68k: add m68030 definition
m68k: remove dead code
m68k: remove useless file m68k-qreg.h
m68k: FPU rework (draft)
m68k: some FPU debugging macros
m68k: more tests
m68k: correct compute gen_bitfield_cc()
m68k: add fgetexp
m68k: add fscale
m68k: correct addsubq
m68k: add fetox and flogn
m68k: initialize FRegs, define pickNaN()
m68k: correct cmpa comparison datatype
m68k: add flog10
m68k: add cmpm instruction
m68k: add ftwotox instruction
m68k: better fpu traces
m68k: register source operand is always in extended size
m68k: add facos instruction
m68k: add ftan instruction
m68k: add fsin instruction
m68k: add fcos instruction
m68k: correct fpcr update
m68k: add fmod instruction
m68k: flush flags before negx instruction.
m68k: correct fmovemx FP registers order.
m68k: add fatan instruction
m68k: correct bfins instruction
m68k: fcmp correctly compares infinity.
m68k: allows bfins to manage correctly width = 32
m68k: add ftentox instruction
m68k: correctly define and manage NaN
m68k: don't call gdb_register_coprocessor() twice.
m68k: gdb FP registers are 96 bits
m68k: add exg instruction
m68k: define floatx80_default_inf_high and floatx80_default_inf_low
m68k: add bkpt instruction
m68k: correctly convert floatx80<->long double
m68k: use expl() to compute exp_FP0()
m68k: use exp2l() to compute exp2_FP0()
m68k: use logl() to compute ln_FP0()
m68k: use log10l() to compute log10_FP0()
m68k: correctly load signed word into floating point register
m68k: add fcosh instruction
m68k: add fasin instruction
m68k: add fsincos instruction
m68k: add fsinh instruction
m68k: add ftanh instruction
m68k: add flognp1 instruction
m68k: add fatanh instruction
m68k: first draft of q800 emulation (not working)
m68k: add movec instruction
m68k: move from sr can use effective addresse on m68k
m68k: Added ULL to 64 bit integer in helper.c
Laurent Vivier
2011-08-18 07:02:29 UTC
Permalink
Post by Anthony Liguori
Post by Bryce Lanham
These patches greatly expand Motorola 68k emulation within qemu, and are what I used as a basis for my
Google Summer of Code project to add NeXT hardware support to QEMU.
Please don't crap flood the list with a series of 100 patches.
Split things into logical chunks such that a series can be reasonably
reviewed and applied.
And I'm not sure this series of patches is ready for inclusion in qemu
mainline as it should break existing m68k emulation...

Bryce, you should only post your patches, refering to the repository on
which they apply, i.e. git://gitorious.org/qemu-m68k/qemu-m68k.git ,
master branch.

Regards,
Laurent
Post by Anthony Liguori
Regards,
Anthony Liguori
Post by Bryce Lanham
Bryce Lanham
linux-user: Signals processing is not thread-safe.
m68k: add cas
m68k: define fcntl constants
m68k: add DBcc instruction.
linux-user: add qemu-wrapper
linux-user: define default cpu model in configure instead of
linux-user/main.c
linux-user: specify the cpu model during configure
linux-user,m68k: display default cpu
linux-user: define new environment variables
linux-user: define a script to set binfmt using debian flavored tools
linux-user: define default cpu model in configure instead of
linux-user/main.c
m68k: add tcg_gen_debug_insn_start()
m68k: define m680x0 CPUs and features
m68k: add missing accessing modes for some instructions.
m68k: add Motorola 680x0 family common instructions.
m68k: add Scc instruction with memory operand.
m68k: add DBcc instruction.
m68k: modify movem instruction to manage word
m68k: add 64bit divide.
m68k: add 32bit and 64bit multiply
m68k: add word data size for suba/adda
m68k: add fpu
m68k: add "byte", "word" and memory shift
m68k: add "byte", "word" and memory rotate.
m68k: add bitfield_mem, bitfield_reg
m68k: add variable offset/width to bitfield_reg/bitfield_mem
m68k: add cas
m68k: allow fpu to manage double data type.
m68k: allow fpu to manage double data type with fmove to<ea>
m68k: add FScc instruction
m68k: add single data type to gen_ea
m68k: add linkl instruction
m68k: Add fmovecr
m68k: correct typo on f64_to_i32() return type.
m68k: improve CC_OP_LOGIC
m68k: correct neg condition code flags computation
Correct invalid use of "const void *" with "const uint8_t *"
m68k: add EA support for negx
m68k: add abcd instruction
m68k: add sbcd instruction
mm68k: add nbcd instruction
m68k: set X flag according size of operand Set X flag correctly
for addsub, arith_im, addsubq.
m68k: on 0 bit shift, don't update X flag
m68k: improve addx instructions Add (byte, word) opsize Add
memory access
m68k: improve subx,negx instructions Add (byte, word) opsize
Add memory access (subx)
m68k: improve asl/asr evaluate correclty the missing V flag
m68k: use read_imm1() when it is possible
m68k: correct shift side effect for roxrl and roxll
m68k: asl/asr, clear C flag if shift count is 0
m68k: lsl/lsr, clear C flag if shift count is 0
m68k: correct divs.w and divu.w
m68k: correct flags with negl
m68k: for bitfield opcodes, correct operands corruption
m68k: Correct bfclr in register case.
m68k-linux-user: add '--enable-emulop'
m68k: correctly compute divsl
m68k: correctly compute divul
m68k: add m68030 definition
m68k: remove dead code
m68k: remove useless file m68k-qreg.h
m68k: FPU rework (draft)
m68k: some FPU debugging macros
m68k: more tests
m68k: correct compute gen_bitfield_cc()
m68k: add fgetexp
m68k: add fscale
m68k: correct addsubq
m68k: add fetox and flogn
m68k: initialize FRegs, define pickNaN()
m68k: correct cmpa comparison datatype
m68k: add flog10
m68k: add cmpm instruction
m68k: add ftwotox instruction
m68k: better fpu traces
m68k: register source operand is always in extended size
m68k: add facos instruction
m68k: add ftan instruction
m68k: add fsin instruction
m68k: add fcos instruction
m68k: correct fpcr update
m68k: add fmod instruction
m68k: flush flags before negx instruction.
m68k: correct fmovemx FP registers order.
m68k: add fatan instruction
m68k: correct bfins instruction
m68k: fcmp correctly compares infinity.
m68k: allows bfins to manage correctly width = 32
m68k: add ftentox instruction
m68k: correctly define and manage NaN
m68k: don't call gdb_register_coprocessor() twice.
m68k: gdb FP registers are 96 bits
m68k: add exg instruction
m68k: define floatx80_default_inf_high and floatx80_default_inf_low
m68k: add bkpt instruction
m68k: correctly convert floatx80<->long double
m68k: use expl() to compute exp_FP0()
m68k: use exp2l() to compute exp2_FP0()
m68k: use logl() to compute ln_FP0()
m68k: use log10l() to compute log10_FP0()
m68k: correctly load signed word into floating point register
m68k: add fcosh instruction
m68k: add fasin instruction
m68k: add fsincos instruction
m68k: add fsinh instruction
m68k: add ftanh instruction
m68k: add flognp1 instruction
m68k: add fatanh instruction
m68k: first draft of q800 emulation (not working)
m68k: add movec instruction
m68k: move from sr can use effective addresse on m68k
m68k: Added ULL to 64 bit integer in helper.c
François Revol
2011-08-18 11:12:32 UTC
Permalink
Post by Laurent Vivier
Post by Anthony Liguori
Post by Bryce Lanham
These patches greatly expand Motorola 68k emulation within qemu, and are what I used as a basis for my
Google Summer of Code project to add NeXT hardware support to QEMU.
Please don't crap flood the list with a series of 100 patches.
Split things into logical chunks such that a series can be reasonably
reviewed and applied.
And I'm not sure this series of patches is ready for inclusion in qemu
mainline as it should break existing m68k emulation...
Bryce, you should only post your patches, refering to the repository on
which they apply, i.e. git://gitorious.org/qemu-m68k/qemu-m68k.git ,
master branch.
Btw, are you planning on merging it back someday?

François.
Laurent Vivier
2011-08-18 14:02:20 UTC
Permalink
 
Post by François Revol
Post by Laurent Vivier
Post by Anthony Liguori
Post by Bryce Lanham
These patches greatly expand Motorola 68k emulation within qemu, and are
what I used as a basis for my
Google Summer of Code project to add NeXT hardware support to QEMU.
Please don't crap flood the list with a series of 100 patches.
Split things into logical chunks such that a series can be reasonably
reviewed and applied.
And I'm not sure this series of patches is ready for inclusion in qemu
mainline as it should break existing m68k emulation...
Bryce, you should only post your patches, refering to the repository on
which they apply, i.e. git://gitorious.org/qemu-m68k/qemu-m68k.git ,
master branch.
Btw, are you planning on merging it back someday?
 
Yes... when it will work correctly.
 
I have at least, to rework 680x0 FPU part (80bit fpu) to not break the existing
one (64bit fpu).
I have to check modified instructions don't break existing m68k emulation.
 
Currently, I'm trying to port some parts of BasiliskII into Qemu to be able to
boot MacOS 7.6.
 
Regards,
Laurent
Natalia Portillo
2011-08-18 19:42:12 UTC
Permalink
Hi Laurent,
Post by Laurent Vivier
Post by François Revol
Post by Laurent Vivier
Post by Anthony Liguori
Post by Bryce Lanham
These patches greatly expand Motorola 68k emulation within qemu, and are what I used as a basis for my
Google Summer of Code project to add NeXT hardware support to QEMU.
Please don't crap flood the list with a series of 100 patches.
Split things into logical chunks such that a series can be reasonably
reviewed and applied.
And I'm not sure this series of patches is ready for inclusion in qemu
mainline as it should break existing m68k emulation...
Bryce, you should only post your patches, refering to the repository on
which they apply, i.e. git://gitorious.org/qemu-m68k/qemu-m68k.git ,
master branch.
Btw, are you planning on merging it back someday?
Yes... when it will work correctly.
I have at least, to rework 680x0 FPU part (80bit fpu) to not break the existing one (64bit fpu).
I have to check modified instructions don't break existing m68k emulation.
Maybe Bryce can help you
Post by Laurent Vivier
Currently, I'm trying to port some parts of BasiliskII into Qemu to be able to boot MacOS 7.6.
Why are you planning to port a hack instead of making a full machine emulation?
Post by Laurent Vivier
Regards,
Laurent
Laurent Vivier
2011-08-18 19:57:34 UTC
Permalink
Post by Natalia Portillo
Hi Laurent,
Hi Natalia,
Post by Natalia Portillo
Post by Bryce Lanham
Post by François Revol
Le mercredi 17 août 2011 à 17:35 -0500, Anthony Liguori a
Post by Anthony Liguori
Post by Bryce Lanham
These patches greatly expand Motorola 68k emulation within
qemu, and are what I used as a basis for my
Post by François Revol
Post by Anthony Liguori
Post by Bryce Lanham
Google Summer of Code project to add NeXT hardware support to
QEMU.
Post by François Revol
Post by Anthony Liguori
Please don't crap flood the list with a series of 100 patches.
Split things into logical chunks such that a series can be
reasonably
Post by François Revol
Post by Anthony Liguori
reviewed and applied.
And I'm not sure this series of patches is ready for inclusion
in qemu
Post by François Revol
mainline as it should break existing m68k emulation...
Bryce, you should only post your patches, refering to the
repository on
Post by François Revol
which they apply, i.e.
git://gitorious.org/qemu-m68k/qemu-m68k.git ,
Post by François Revol
master branch.
Btw, are you planning on merging it back someday?
Yes... when it will work correctly.
I have at least, to rework 680x0 FPU part (80bit fpu) to not break
the existing one (64bit fpu).
I have to check modified instructions don't break existing m68k emulation.
Maybe Bryce can help you
I don't know if he is courageous enough to review and push 111
patches ;-)
Post by Natalia Portillo
Post by Bryce Lanham
Currently, I'm trying to port some parts of BasiliskII into Qemu to
be able to boot MacOS 7.6.
Why are you planning to port a hack instead of making a full machine emulation?
Because I'm lazy and dumb: the work is already done, I like cut'n'paste.

Regards,
Laurent
Natalia Portillo
2011-08-18 20:13:44 UTC
Permalink
Hi Laurent,
Post by Laurent Vivier
Post by Natalia Portillo
Hi Laurent,
Hi Natalia,
Post by Natalia Portillo
Post by Bryce Lanham
Post by François Revol
Le mercredi 17 août 2011 à 17:35 -0500, Anthony Liguori a
Post by Anthony Liguori
Post by Bryce Lanham
These patches greatly expand Motorola 68k emulation within
qemu, and are what I used as a basis for my
Post by François Revol
Post by Anthony Liguori
Post by Bryce Lanham
Google Summer of Code project to add NeXT hardware support to
QEMU.
Post by François Revol
Post by Anthony Liguori
Please don't crap flood the list with a series of 100 patches.
Split things into logical chunks such that a series can be
reasonably
Post by François Revol
Post by Anthony Liguori
reviewed and applied.
And I'm not sure this series of patches is ready for inclusion
in qemu
Post by François Revol
mainline as it should break existing m68k emulation...
Bryce, you should only post your patches, refering to the
repository on
Post by François Revol
which they apply, i.e.
git://gitorious.org/qemu-m68k/qemu-m68k.git ,
Post by François Revol
master branch.
Btw, are you planning on merging it back someday?
Yes... when it will work correctly.
I have at least, to rework 680x0 FPU part (80bit fpu) to not break
the existing one (64bit fpu).
I have to check modified instructions don't break existing m68k emulation.
Maybe Bryce can help you
I don't know if he is courageous enough to review and push 111
patches ;-)
He worked on emulating an abandoned, strange, difficult to get, and undocumented hardware, using your 111 patches, and finished it before the wholy more experienced MESS team.

He is! xD
Post by Laurent Vivier
Post by Natalia Portillo
Post by Bryce Lanham
Currently, I'm trying to port some parts of BasiliskII into Qemu to
be able to boot MacOS 7.6.
Why are you planning to port a hack instead of making a full machine emulation?
Because I'm lazy and dumb: the work is already done, I like cut'n'paste.
Yeah, you said it!
The work is already done, we have all the hardware emulation that Basilisk substitutes for hacks.
We only lack the 68k cpu (oh! your patches!!!) and the glue :p

Please don't port Basilisk on top of TCG, I beg to you in the name of some god of your own choice :(
(1000 Mb floppies patching .sony instead of implementing SCSI and SWIM, no ethernet controller but a working TCP/IP, oh hell, it's not a Mac, it's a Match!)
Laurent Vivier
2011-08-18 20:51:00 UTC
Permalink
Post by Natalia Portillo
Hi Laurent,
Post by Laurent Vivier
Post by Natalia Portillo
Hi Laurent,
Hi Natalia,
Post by Natalia Portillo
Post by Bryce Lanham
Post by François Revol
Le mercredi 17 août 2011 à 17:35 -0500, Anthony Liguori a
Post by Anthony Liguori
Post by Bryce Lanham
These patches greatly expand Motorola 68k emulation within
qemu, and are what I used as a basis for my
Post by François Revol
Post by Anthony Liguori
Post by Bryce Lanham
Google Summer of Code project to add NeXT hardware support to
QEMU.
Post by François Revol
Post by Anthony Liguori
Please don't crap flood the list with a series of 100 patches.
Split things into logical chunks such that a series can be
reasonably
Post by François Revol
Post by Anthony Liguori
reviewed and applied.
And I'm not sure this series of patches is ready for inclusion
in qemu
Post by François Revol
mainline as it should break existing m68k emulation...
Bryce, you should only post your patches, refering to the
repository on
Post by François Revol
which they apply, i.e.
git://gitorious.org/qemu-m68k/qemu-m68k.git ,
Post by François Revol
master branch.
Btw, are you planning on merging it back someday?
Yes... when it will work correctly.
I have at least, to rework 680x0 FPU part (80bit fpu) to not break
the existing one (64bit fpu).
I have to check modified instructions don't break existing m68k emulation.
Maybe Bryce can help you
I don't know if he is courageous enough to review and push 111
patches ;-)
He worked on emulating an abandoned, strange, difficult to get, and undocumented hardware, using your 111 patches, and finished it before the wholy more experienced MESS team.
The next-cube emulation is really working ?
Post by Natalia Portillo
He is! xD
There is no problem for me, he can do...
Post by Natalia Portillo
Post by Laurent Vivier
Post by Natalia Portillo
Post by Bryce Lanham
Currently, I'm trying to port some parts of BasiliskII into Qemu to
be able to boot MacOS 7.6.
Why are you planning to port a hack instead of making a full machine emulation?
Because I'm lazy and dumb: the work is already done, I like cut'n'paste.
Yeah, you said it!
The work is already done, we have all the hardware emulation that Basilisk substitutes for hacks.
I'm not sure of that... no MMU emulation, no Nubus, no ethernet card, no
video card, no SWIM, no SCSI, ... useless with a patched ROM.

You know, nights are not long enough...
Post by Natalia Portillo
We only lack the 68k cpu (oh! your patches!!!) and the glue :p
this part is not working well as well ... gcc cannot compile linux
kernel, some demos fail in gtk-demo, ...
Post by Natalia Portillo
Please don't port Basilisk on top of TCG, I beg to you in the name of some god of your own choice :(
I believe only in Santa Claus, and it's not Christmas.
Post by Natalia Portillo
(1000 Mb floppies patching .sony instead of implementing SCSI and SWIM, no ethernet controller but a working TCP/IP, oh hell, it's not a Mac, it's a Match!)
Regards,
Laurent
Natalia Portillo
2011-08-19 02:14:42 UTC
Permalink
Hi,
Post by Laurent Vivier
Post by Natalia Portillo
Hi Laurent,
Post by Laurent Vivier
Post by Natalia Portillo
Hi Laurent,
Hi Natalia,
Post by Natalia Portillo
Post by Bryce Lanham
Post by François Revol
Le mercredi 17 août 2011 à 17:35 -0500, Anthony Liguori a
Post by Anthony Liguori
Post by Bryce Lanham
These patches greatly expand Motorola 68k emulation within
qemu, and are what I used as a basis for my
Post by François Revol
Post by Anthony Liguori
Post by Bryce Lanham
Google Summer of Code project to add NeXT hardware support to
QEMU.
Post by François Revol
Post by Anthony Liguori
Please don't crap flood the list with a series of 100 patches.
Split things into logical chunks such that a series can be
reasonably
Post by François Revol
Post by Anthony Liguori
reviewed and applied.
And I'm not sure this series of patches is ready for inclusion
in qemu
Post by François Revol
mainline as it should break existing m68k emulation...
Bryce, you should only post your patches, refering to the
repository on
Post by François Revol
which they apply, i.e.
git://gitorious.org/qemu-m68k/qemu-m68k.git ,
Post by François Revol
master branch.
Btw, are you planning on merging it back someday?
Yes... when it will work correctly.
I have at least, to rework 680x0 FPU part (80bit fpu) to not break
the existing one (64bit fpu).
I have to check modified instructions don't break existing m68k emulation.
Maybe Bryce can help you
I don't know if he is courageous enough to review and push 111
patches ;-)
He worked on emulating an abandoned, strange, difficult to get, and undocumented hardware, using your 111 patches, and finished it before the wholy more experienced MESS team.
The next-cube emulation is really working ?
Yes, it is, absolutely.
Post by Laurent Vivier
Post by Natalia Portillo
He is! xD
There is no problem for me, he can do...
Post by Natalia Portillo
Post by Laurent Vivier
Post by Natalia Portillo
Post by Bryce Lanham
Currently, I'm trying to port some parts of BasiliskII into Qemu to
be able to boot MacOS 7.6.
Why are you planning to port a hack instead of making a full machine emulation?
Because I'm lazy and dumb: the work is already done, I like cut'n'paste.
Yeah, you said it!
The work is already done, we have all the hardware emulation that Basilisk substitutes for hacks.
I'm not sure of that... no MMU emulation, no Nubus, no ethernet card, no
video card, no SWIM, no SCSI, ... useless with a patched ROM.
Macs do not have videocards :p, only the Mac II and we're not forced to emulate that one.
SWIM is a piece of cake that can be even implemented without ICs, just some logical arrays.
NuBus is not required for almost anything, only the video card uses it, and it's present only on the Mac II, a stub will suffice to make Toolbox be happy.
Most m68k didn't include a network card, third party ones are stock chips (probably almost all are NE2000, 3COM and PCNET), and Apple integrated ones are also stock, easy to do :p
The MMU is your part I won't discuss on it.

But porting BasiliskII will not make qemu have an m68k-system, but a macos7-wrapper.
And that's the problem with Basilisk, that's why you cannot partition a disk, try MachTen, don't even think on A/UX.

If you insist, please name it "basilisk2" and let Bryce (he wants to in the future) do the real machines (-M quadra, -M centris, -M IIcx)
Post by Laurent Vivier
You know, nights are not long enough...
Move to North Pole, I've heard nights are six month long there ^^
Post by Laurent Vivier
Post by Natalia Portillo
We only lack the 68k cpu (oh! your patches!!!) and the glue :p
this part is not working well as well ... gcc cannot compile linux
kernel, some demos fail in gtk-demo, ...
I know it's not perfect, but right now, it's better than nothing.
There is no 68k cpu emulation complete afaik, I discussed with Ray Arachelian a lot on that when he was working on LisaEm.
However emulators are live, Aranym, UAE, LisaEm, BasiliskII.

qemu-m68k is quite complete to go live (when it does not break mcoldfire) right now.
Bugs are easy to be corrected by more people when they are in main than in a developer's own clone.

Leave your little kid go wild, it's old and big enough :p
Post by Laurent Vivier
Post by Natalia Portillo
Please don't port Basilisk on top of TCG, I beg to you in the name of some god of your own choice :(
I believe only in Santa Claus, and it's not Christmas.
Post by Natalia Portillo
(1000 Mb floppies patching .sony instead of implementing SCSI and SWIM, no ethernet controller but a working TCP/IP, oh hell, it's not a Mac, it's a Match!)
Regards,
Laurent
Bryce Lanham
2011-08-17 20:47:31 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

correctly update generated condition code.

seen with gcc testsuite,
gcc-4.1.2/gcc/testsuite/gcc.c-torture/execute/960301-1.c

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 34 +++++++++++++++++++++++++++++-----
tests/m68k/Makefile | 3 ++-
tests/m68k/bfins.S | 23 +++++++++++++++++++++++
3 files changed, 54 insertions(+), 6 deletions(-)
create mode 100644 tests/m68k/bfins.S

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index d4445fe..96ea93f 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3091,9 +3091,22 @@ DISAS_INSN(bitfield_reg)

tmp1 = tcg_temp_new_i32();
gen_helper_rol32(tmp1, tmp, offset);
- gen_logic_cc(s, tmp1, OS_LONG);

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;
@@ -3157,11 +3170,7 @@ static TCGv gen_bitfield_cc(DisasContext *s,
tcg_gen_shri_i64(tmp64, tmp64, 32ULL);
dest = tcg_temp_new_i32();
tcg_gen_trunc_i64_i32(dest, tmp64);
-
- /* compute cc */
-
tcg_gen_and_i32(dest, dest, mask_cc);
- gen_logic_cc(s, dest, OS_LONG);

return dest;
}
@@ -3283,6 +3292,21 @@ DISAS_INSN(bitfield_mem)
/* 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 {
+ gen_logic_cc(s, val, OS_LONG);
+ }
+
switch (op) {
case 0: /* bftst */
break;
diff --git a/tests/m68k/Makefile b/tests/m68k/Makefile
index 8e90986..d043aeb 100644
--- a/tests/m68k/Makefile
+++ b/tests/m68k/Makefile
@@ -1,4 +1,5 @@
-TESTS=fmovecr fmove fmovem fsub fdiv fmul fabs fgetexp fscale flogn fetox
+TESTS=fmovecr fmove fmovem fsub fdiv fmul fabs fgetexp fscale flogn fetox \
+ bfins

all: $(TESTS)

diff --git a/tests/m68k/bfins.S b/tests/m68k/bfins.S
new file mode 100644
index 0000000..a0b27f9
--- /dev/null
+++ b/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
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:30 UTC
Permalink
+ cmp = DREG(ext, 0);
+ update = DREG(ext, 6);
+ tmp = gen_load(s, opsize, addr, 0);
+ dest = tcg_temp_local_new();
+ tcg_gen_mov_i32(dest, tmp);
+
+ res = tcg_temp_new();
+ tcg_gen_sub_i32(res, dest, cmp);
+ gen_logic_cc(s, res);
+
+ l1 = gen_new_label();
+ l2 = gen_new_label();
+
+ gen_jmpcc(s, 6 /* !Z */, l1);
+ gen_store(s, opsize, addr, update);
This has a bug: addr is used around a jump.

Andreas.
---
target-m68k/translate.c | 10 +++++++---
1 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index c186fe1..218210c 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1378,6 +1378,7 @@ DISAS_INSN(cas)
TCGv tmp;
TCGv cmp;
TCGv update;
+ TCGv taddr;
TCGv addr;
TCGv res;
uint16_t ext;
@@ -1404,17 +1405,19 @@ DISAS_INSN(cas)

ext = lduw_code(s->pc);
s->pc += 2;
- addr = gen_lea(s, insn, opsize);
- if (IS_NULL_QREG(addr)) {
+ 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, addr, 0);
+ 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);
@@ -1430,6 +1433,7 @@ DISAS_INSN(cas)
tcg_gen_mov_i32(cmp, dest);
gen_set_label(l2);
tcg_temp_free(dest);
+ tcg_temp_free(addr);
}

DISAS_INSN(byterev)
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:12 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
.gitignore | 1 +
target-m68k/helper.c | 17 +++++++++++++++++
target-m68k/helpers.h | 1 +
target-m68k/translate.c | 4 ++++
tests/m68k/Makefile | 2 +-
tests/m68k/fscale.S | 9 +++++++++
6 files changed, 33 insertions(+), 1 deletions(-)
create mode 100644 tests/m68k/fscale.S

diff --git a/.gitignore b/.gitignore
index ef339f5..fed07c5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,3 +79,4 @@ tests/m68k/fmovem
tests/m68k/fmul
tests/m68k/fsub
tests/m68k/fgetexp
+tests/m68k/fscale
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 2be3355..77d88e7 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -1292,6 +1292,23 @@ void HELPER(getexp_FP0)(CPUState *env)
floatx80_to_FP0(env, res);
}

+void HELPER(scale_FP0_FP1)(CPUState *env)
+{
+ int32_t scale;
+ int32_t exp;
+
+ DBG_FPU("getexp_FP0(%Lg)\n", LDOUBLE(FP0_to_floatx80(env)));
+
+ DBG_FPU(" fp0h 0x%08x fp0l 0x%016" PRIx64 "\n", 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;
+}
+
void HELPER(add_FP0_FP1)(CPUState *env)
{
floatx80 res;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 0b4c0cb..f6578ee 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -68,6 +68,7 @@ DEF_HELPER_1(sqrt_FP0, void, env)
DEF_HELPER_1(abs_FP0, void, env)
DEF_HELPER_1(chs_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)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index d09e325..93f9973 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3666,6 +3666,10 @@ DISAS_INSN(fpu)
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);
diff --git a/tests/m68k/Makefile b/tests/m68k/Makefile
index a7a59ac..28a998f 100644
--- a/tests/m68k/Makefile
+++ b/tests/m68k/Makefile
@@ -1,4 +1,4 @@
-TESTS=fmovecr fmove fmovem fsub fdiv fmul fabs fgetexp
+TESTS=fmovecr fmove fmovem fsub fdiv fmul fabs fgetexp fscale

all: $(TESTS)

diff --git a/tests/m68k/fscale.S b/tests/m68k/fscale.S
new file mode 100644
index 0000000..f6a5c62
--- /dev/null
+++ b/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
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:38 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch allows to read constant from the FPU ROM.
It implements instructions like "fmovecrx #0,%fp0" (which loads
Pi to %fp0).

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 33 +++++++++++++++++++++++++++++++++
target-m68k/helpers.h | 1 +
target-m68k/translate.c | 12 +++++++++++-
3 files changed, 45 insertions(+), 1 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index d0fc155..914147a 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -815,6 +815,39 @@ HELPER_ROXL(uint16_t, 16)
HELPER_ROXL(uint32_t, 32)

/* FPU helpers. */
+
+static const floatx80 fpu_rom[128] = {
+ [0x00] = { .high = 0x4000, .low = 0xc90fdaa22168c235 }, /* Pi */
+
+ [0x0b] = { .high = 0x3ffd, .low = 0x9a209a84fbcff798 }, /* Log10(2) */
+ [0x0c] = { .high = 0x4000, .low = 0xadf85458a2bb4a9a }, /* e */
+ [0x0d] = { .high = 0x3fff, .low = 0xb8aa3b295c17f0bc }, /* Log2(e) */
+ [0x0e] = { .high = 0x3ffd, .low = 0xde5bd8a937287195 }, /* Log10(e) */
+ [0x0f] = { .high = 0x0000, .low = 0x0000000000000000 }, /* Zero */
+
+ [0x30] = { .high = 0x3ffe, .low = 0xb17217f7d1cf79ac }, /* ln(2) */
+ [0x31] = { .high = 0x4000, .low = 0x935d8dddaaa8ac17 }, /* ln(10) */
+ [0x32] = { .high = 0x3fff, .low = 0x8000000000000000 }, /* 10^0 */
+ [0x33] = { .high = 0x4002, .low = 0xa000000000000000 }, /* 10^1 */
+ [0x34] = { .high = 0x4005, .low = 0xc800000000000000 }, /* 10^2 */
+ [0x35] = { .high = 0x400c, .low = 0x9c40000000000000 }, /* 10^4 */
+ [0x36] = { .high = 0x4019, .low = 0xbebc200000000000 }, /* 10^8 */
+ [0x37] = { .high = 0x4034, .low = 0x8e1bc9bf04000000 }, /* 10^16 */
+ [0x38] = { .high = 0x4069, .low = 0x9dc5ada82b70b59e }, /* 10^32 */
+ [0x39] = { .high = 0x40d3, .low = 0xc2781f49ffcfa6d5 }, /* 10^64 */
+ [0x3a] = { .high = 0x41a8, .low = 0x93ba47c980e98ce0 }, /* 10^128 */
+ [0x3b] = { .high = 0x4351, .low = 0xaa7eebfb9df9de8e }, /* 10^256 */
+ [0x3c] = { .high = 0x46a3, .low = 0xe319a0aea60e91c7 }, /* 10^512 */
+ [0x3d] = { .high = 0x4d48, .low = 0xc976758681750c17 }, /* 10^1024 */
+ [0x3e] = { .high = 0x5a92, .low = 0x9e8b3b5dc53d5de5 }, /* 10^2048 */
+ [0x3f] = { .high = 0x7525, .low = 0xc46052028a20979b }, /* 10^4096 */
+};
+
+float64 HELPER(const_f64)(CPUState *env, uint32_t offset)
+{
+ return floatx80_to_float64(fpu_rom[offset], &env->fp_status);
+}
+
uint32_t HELPER(f64_to_i32)(CPUState *env, float64 val)
{
return float64_to_int32(val, &env->fp_status);
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index d71ed26..50f5486 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -41,6 +41,7 @@ DEF_HELPER_2(xflag_lt, i32, i32, i32)
DEF_HELPER_2(set_sr, void, env, i32)
DEF_HELPER_3(movec, void, env, i32, i32)

+DEF_HELPER_2(const_f64, f64, 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)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 896e187..3ce5f53 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2949,6 +2949,7 @@ DISAS_INSN(trap)
DISAS_INSN(fpu)
{
uint16_t ext;
+ uint8_t rom_offset;
int opmode;
TCGv_i64 src;
TCGv_i64 dest;
@@ -2962,10 +2963,19 @@ DISAS_INSN(fpu)
ext = read_im16(s);
opmode = ext & 0x7f;
switch ((ext >> 13) & 7) {
- case 0: case 2:
+ case 0:
break;
case 1:
goto undef;
+ case 2:
+ if ( insn == 0xf200 && (ext & 0xfc00) == 0x5c00) {
+ /* fmovecr */
+ rom_offset = ext & 0x7f;
+ dest = FREG(ext, 7);
+ gen_helper_const_f64(dest, cpu_env, tcg_const_i32(rom_offset));
+ return;
+ }
+ break;
case 3: /* fmove out */
src = FREG(ext, 7);
tmp32 = tcg_temp_new_i32();
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:03 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/op_helper.c | 28 +++++++++++++---------------
1 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index d180c80..6c3144e 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -266,29 +266,27 @@ void HELPER(divu64)(CPUState *env)
{
uint32_t num;
uint32_t den;
- uint32_t quot;
+ 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);
- quot = (num | ((uint64_t)env->quadh << 32)) / den;
- rem = (num | ((uint64_t)env->quadh << 32)) % den;
- flags = 0;
- /* 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 (quot > 0xffffffff)
- flags |= CCF_V;
- if (quot == 0)
- flags |= CCF_Z;
- else if ((int32_t)quot < 0)
- flags |= CCF_N;
- /* Don't modify destination if overflow occured. */
- if ((flags & CCF_V) == 0) {
+ 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;
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:14 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
fpu/softfloat.h | 2 ++
target-m68k/helper.c | 38 ++++++++++++++++++++++++++++++++++++--
target-m68k/helpers.h | 2 ++
target-m68k/translate.c | 6 ++++++
tests/m68k/Makefile | 2 +-
tests/m68k/fetox.S | 8 ++++++++
tests/m68k/flogn.S | 8 ++++++++
7 files changed, 63 insertions(+), 3 deletions(-)
create mode 100644 tests/m68k/fetox.S
create mode 100644 tests/m68k/flogn.S

diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 3bb7d8f..f6d5fce 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -532,6 +532,8 @@ 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)

/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN.
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 77d88e7..f67bfba 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -997,8 +997,8 @@ static const floatx80 fpu_rom[128] = {
[0x00] = floatx80_pi, /* Pi */

[0x0b] = { .high = 0x3ffd, .low = 0x9a209a84fbcff798ULL }, /* Log10(2) */
- [0x0c] = { .high = 0x4000, .low = 0xadf85458a2bb4a9aULL }, /* e */
- [0x0d] = { .high = 0x3fff, .low = 0xb8aa3b295c17f0bcULL }, /* Log2(e) */
+ [0x0c] = floatx80_e, /* e */
+ [0x0d] = floatx80_log2e, /* Log2(e) */
[0x0e] = { .high = 0x3ffd, .low = 0xde5bd8a937287195ULL }, /* Log10(e) */
[0x0f] = floatx80_zero, /* Zero */

@@ -1255,6 +1255,40 @@ void HELPER(sqrt_FP0)(CPUState *env)
floatx80_to_FP0(env, res);
}

+void HELPER(ln_FP0)(CPUState *env)
+{
+ float64 f, log2;
+ floatx80 res;
+
+ /* ln(x) = log2(x) / log2(e) */
+
+ DBG_FPU("ln_FP0\n");
+
+ f = floatx80_to_float64(FP0_to_floatx80(env), &env->fp_status);
+
+ log2 = float64_log2(f, &env->fp_status);
+ res = floatx80_div(float64_to_floatx80(log2, &env->fp_status),
+ floatx80_log2e, &env->fp_status);
+
+ floatx80_to_FP0(env, res);
+}
+
+void HELPER(exp_FP0)(CPUState *env)
+{
+ floatx80 f;
+ float32 res;
+
+ /* exp(x) = exp2(x * log2(e)) */
+
+ DBG_FPU("exp_FP0\n");
+
+ f = floatx80_mul(FP0_to_floatx80(env), floatx80_log2e, &env->fp_status);
+ res = float32_exp2(floatx80_to_float32(f, &env->fp_status),
+ &env->fp_status);
+
+ floatx80_to_FP0(env, float32_to_floatx80(res, &env->fp_status));
+}
+
void HELPER(abs_FP0)(CPUState *env)
{
floatx80 res;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index f6578ee..53ab1a9 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -65,6 +65,8 @@ DEF_HELPER_2(const_FP0, void, env, i32)
DEF_HELPER_1(iround_FP0, void, env)
DEF_HELPER_1(itrunc_FP0, void, env)
DEF_HELPER_1(sqrt_FP0, void, env)
+DEF_HELPER_1(exp_FP0, void, env)
+DEF_HELPER_1(ln_FP0, void, env)
DEF_HELPER_1(abs_FP0, void, env)
DEF_HELPER_1(chs_FP0, void, env)
DEF_HELPER_1(getexp_FP0, void, env)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index fb12f3b..1901b1b 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3641,6 +3641,12 @@ DISAS_INSN(fpu)
case 4: case 0x41: case 0x45: /* fsqrt */
gen_helper_sqrt_FP0(cpu_env);
break;
+ case 0x10: /* fetox */
+ gen_helper_exp_FP0(cpu_env);
+ break;
+ case 0x14: /* flogn */
+ gen_helper_ln_FP0(cpu_env);
+ break;
case 0x18: case 0x58: case 0x5c: /* fabs */
gen_helper_abs_FP0(cpu_env);
break;
diff --git a/tests/m68k/Makefile b/tests/m68k/Makefile
index 28a998f..8e90986 100644
--- a/tests/m68k/Makefile
+++ b/tests/m68k/Makefile
@@ -1,4 +1,4 @@
-TESTS=fmovecr fmove fmovem fsub fdiv fmul fabs fgetexp fscale
+TESTS=fmovecr fmove fmovem fsub fdiv fmul fabs fgetexp fscale flogn fetox

all: $(TESTS)

diff --git a/tests/m68k/fetox.S b/tests/m68k/fetox.S
new file mode 100644
index 0000000..302072b
--- /dev/null
+++ b/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 a/tests/m68k/flogn.S b/tests/m68k/flogn.S
new file mode 100644
index 0000000..a27835e
--- /dev/null
+++ b/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
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:18 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch defines Scc instruction for M68000 feature accessing
destination operand using an effective address (existing Scc instruction
manages only data registers).

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index ea92fd6..8cf49d8 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -903,6 +903,23 @@ 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(undef_mac)
{
gen_exception(s, s->pc - 2, EXCP_LINEA);
@@ -2972,6 +2989,7 @@ void register_m68k_insns (CPUM68KState *env)
INSN(addsubq, 5000, f080, M68000);
INSN(addsubq, 5080, f0c0, M68000);
INSN(scc, 50c0, f0f8, CF_ISA_A);
+ INSN(scc_mem, 50c0, f0c0, M68000);
INSN(scc, 50c0, f0f8, M68000);
INSN(tpf, 51f8, fff8, CF_ISA_A);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:53 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 10 ++++++++--
1 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index bdfe9aa..a3a6108 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -915,7 +915,10 @@ uint32_t HELPER(glue(glue(roxr,bits),_cc))(CPUState *env, uint32_t val, uint32_t
if (bits == 16) count = rox16_table[count]; \
if (bits == 32) count = rox32_table[count]; \
if (count) { \
- result = ((type)val >> count) | ((type)env->cc_x << (bits - 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; \
@@ -947,7 +950,10 @@ uint32_t HELPER(glue(glue(roxl,bits),_cc))(CPUState *env, uint32_t val, uint32_t
if (bits == 16) count = rox16_table[count]; \
if (bits == 32) count = rox32_table[count]; \
if (count) { \
- result = ((type)val << count) | ((type)env->cc_x << (count - 1)); \
+ 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; \
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:27 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch implements bitfields instructions: bftst, bfextu, bfexts,
bfffo, bfchg, bfclr, bfset, bfins and attach them to BITFIELD feature.

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 27 ++++
target-m68k/helpers.h | 3 +
target-m68k/translate.c | 323 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 353 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 7f83d20..d6c92bf 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -519,6 +519,33 @@ 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;
+ result = (val << shift) | (val >> (32 - shift));
+ return result;
+}
+
+uint32_t HELPER(ror32)(uint32_t val, uint32_t shift)
+{
+ uint32_t result;
+ 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. */
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 07d1f82..949d5d5 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -2,6 +2,9 @@

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)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index cf59ffe..334681b 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2386,6 +2386,327 @@ DISAS_INSN(rotate_mem)
DEST_EA(insn, OS_WORD, dest, &addr);
}

+DISAS_INSN(bitfield_reg)
+{
+ uint16_t ext;
+ TCGv tmp;
+ TCGv tmp1;
+ TCGv reg;
+ int offset;
+ int width;
+ int op;
+ TCGv reg2;
+ uint32_t mask;
+
+ reg = DREG(insn, 0);
+ op = (insn >> 8) & 7;
+ ext = lduw_code(s->pc);
+ s->pc += 2;
+ if ((ext & 0x820) == 0) {
+ /* constant offset and width */
+ offset = (ext >> 6) & 31;
+ width = (ext & 31);
+ if (width == 0)
+ width = 32;
+ reg2 = DREG(ext, 12);
+ mask = 0xffffffff << (32 - width);
+ if (offset > 0)
+ mask = (mask >> offset) | (mask << (32 - offset));
+ tmp = tcg_temp_new_i32();
+ tcg_gen_andi_i32(tmp, reg, mask);
+ if (offset > 0) {
+ tmp1 = tcg_temp_new_i32();
+ gen_helper_rol32(tmp1, tmp, tcg_const_i32(offset));
+ } else
+ tmp1 = tmp;
+ gen_logic_cc(s, tmp1);
+ switch (op) {
+ case 0: /* bftst */
+ break;
+ case 1: /* bfextu */
+ if (offset + width != 32)
+ gen_helper_rol32(reg2, tmp, tcg_const_i32((offset + width) & 31));
+ else
+ tcg_gen_mov_i32(reg2, tmp);
+ break;
+ case 2: /* bfchg */
+ tcg_gen_xor_i32(reg, reg, tcg_const_i32(mask));
+ break;
+ case 3: /* bfexts */
+ if (offset > 0)
+ gen_helper_rol32(reg2, tmp, tcg_const_i32(offset));
+ if (width < 32)
+ tcg_gen_sari_i32(reg2, reg2, 32 - width);
+ break;
+ case 4: /* bfclr */
+ tcg_gen_and_i32(reg, reg, tcg_const_i32(mask));
+ break;
+ case 5: /* bfffo */
+ if (offset > 0)
+ gen_helper_rol32(reg2, tmp, tcg_const_i32(offset));
+ gen_helper_bfffo(tmp, tmp, tcg_const_i32(width));
+ tcg_gen_addi_i32(reg2, tmp, offset);
+ break;
+ case 6: /* bfset */
+ tcg_gen_ori_i32(reg, reg, mask);
+ break;
+ case 7: /* bfins */
+ if (width == 32) {
+ if (offset > 0)
+ gen_helper_ror32(reg, reg2, tcg_const_i32(offset));
+ else
+ tcg_gen_mov_i32(reg, reg2);
+ } else {
+ tcg_gen_andi_i32(tmp, reg2, (1u << width) - 1);
+ if (offset + width != 32)
+ gen_helper_ror32(tmp, tmp, tcg_const_i32((offset + width) & 31));
+ tcg_gen_andi_i32(reg, reg, ~mask);
+ tcg_gen_or_i32(reg, reg, tmp);
+ }
+ break;
+ }
+ return;
+ }
+ /* Not yet implemented */
+ gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+}
+
+/* Generate a load from a bitfield. */
+static void gen_bitfield_load(DisasContext *s, TCGv addr, int endpos,
+ TCGv *val1, TCGv *val2)
+{
+ TCGv tmp;
+
+ if (endpos <= 8)
+ *val1 = gen_load(s, OS_BYTE, addr, 0);
+ else if (endpos <= 24) {
+ *val1 = gen_load(s, OS_WORD, addr, 0);
+ if (endpos > 16) {
+ tmp = tcg_temp_new_i32();
+ tcg_gen_addi_i32(tmp, addr, 2);
+ *val2 = gen_load(s, OS_BYTE, tmp, 0);
+ }
+ } else {
+ *val1 = gen_load(s, OS_LONG, addr, 0);
+ if (endpos > 32) {
+ tmp = tcg_temp_new_i32();
+ tcg_gen_addi_i32(tmp, addr, 4);
+ *val2 = gen_load(s, OS_BYTE, tmp, 0);
+ }
+ }
+}
+
+/* Generate a store to a bitfield. */
+static void gen_bitfield_store(DisasContext *s, TCGv addr, int endpos,
+ TCGv val1, TCGv val2)
+{
+ TCGv tmp;
+
+ if (endpos <= 8)
+ gen_store(s, OS_BYTE, addr, val1);
+ else if (endpos <= 24) {
+ gen_store(s, OS_WORD, addr, val1);
+ if (endpos > 16) {
+ tmp = tcg_temp_new_i32();
+ tcg_gen_addi_i32(tmp, addr, 2);
+ gen_store(s, OS_BYTE, tmp, val2);
+ }
+ } else {
+ gen_store(s, OS_LONG, addr, val1);
+ if (endpos > 32) {
+ tmp = tcg_temp_new_i32();
+ tcg_gen_addi_i32(tmp, addr, 4);
+ gen_store(s, OS_BYTE, tmp, val2);
+ }
+ }
+}
+
+static TCGv gen_bitfield_cc(DisasContext *s, int offset, int width,
+ TCGv val1, TCGv val2)
+{
+ TCGv dest;
+ TCGv tmp;
+
+ dest = tcg_temp_new_i32();
+
+ if (offset + width <= 8)
+ tcg_gen_shli_i32(dest, val1, 24 + offset);
+ else if (offset + width <= 24) {
+ tcg_gen_shli_i32(dest, val1, 16 + offset);
+ if (offset + width > 16) {
+ tmp = tcg_temp_new_i32();
+ tcg_gen_shli_i32(tmp, val2, 8 + offset);
+ tcg_gen_or_i32(dest, dest, tmp);
+ }
+ } else {
+ tcg_gen_shli_i32(dest, val1, offset);
+ if (offset + width > 32) {
+ tmp = tcg_temp_new_i32();
+ tcg_gen_shri_i32(tmp, val2, offset);
+ tcg_gen_or_i32(dest, dest, tmp);
+ }
+ }
+ tcg_gen_andi_i32(dest, dest, 0xffffffff << (32 - width));
+ gen_logic_cc(s, dest);
+ return dest;
+}
+
+static void gen_bitfield_op(int offset, int width, int op, TCGv val1, TCGv val2)
+{
+ uint32_t mask1;
+ uint32_t mask2;
+ int endpos = offset + width;
+
+ if (endpos <= 8) {
+ mask1 = (0xff >> offset) & (0xff << (8 - endpos));
+ mask2 = 0;
+ } else if (endpos <= 16) {
+ mask1 = (0xffff >> offset) & (0xffff << (16 - endpos));
+ mask2 = 0;
+ } else if (endpos <= 24) {
+ mask1 = 0xffffff >> offset;
+ mask2 = 0xff & (0xff << (24 - endpos));
+ } else if (endpos <= 32) {
+ mask1 = (0xffffffff >> offset) & (0xffffffff << (32 - endpos));
+ mask2 = 0;
+ } else {
+ mask1 = 0xffffffff >> offset;
+ mask2 = 0xff & (0xff << (40 - endpos));
+ }
+ switch (op) {
+ case 2: /* bfchg */
+ tcg_gen_xori_i32(val1, val1, mask1);
+ if (mask2)
+ tcg_gen_xori_i32(val2, val2, mask2);
+ break;
+ case 4: /* bfclr */
+ tcg_gen_andi_i32(val1, val1, ~mask1);
+ if (mask2)
+ tcg_gen_andi_i32(val2, val2, ~mask2);
+ break;
+ case 6: /* bfset */
+ tcg_gen_ori_i32(val1, val1, mask1);
+ if (mask2)
+ tcg_gen_ori_i32(val2, val2, mask2);
+ break;
+ }
+}
+
+static void gen_bitfield_ins(int offset, int width, TCGv src,
+ TCGv val1, TCGv val2)
+{
+ TCGv tmp;
+ int endpos = offset + width;
+
+ tmp = tcg_temp_new_i32();
+ if (width < 32) {
+ tcg_gen_andi_i32(tmp, src, (1u << width) - 1);
+ } else
+ tcg_gen_mov_i32(tmp, src);
+ if (endpos <= 8) {
+ if (endpos < 8)
+ tcg_gen_shli_i32(tmp, tmp, 8 - endpos);
+ tcg_gen_or_i32(val1, val1, tmp);
+ } else if (endpos <= 16) {
+ if (endpos < 16)
+ tcg_gen_shli_i32(tmp, tmp, 16 - endpos);
+ tcg_gen_or_i32(val1, val1, tmp);
+ } else if (endpos <= 24) {
+ tcg_gen_shri_i32(tmp, tmp, endpos - 16);
+ tcg_gen_or_i32(val1, val1, tmp);
+ tcg_gen_andi_i32(tmp, src, (1u << (endpos - 16)) - 1);
+ if (endpos < 24)
+ tcg_gen_shli_i32(tmp, tmp, 24 - endpos);
+ tcg_gen_or_i32(val2, val2, tmp);
+ } else if (endpos <= 32) {
+ if (endpos < 32)
+ tcg_gen_shli_i32(tmp, tmp, 32 - endpos);
+ tcg_gen_or_i32(val1, val1, tmp);
+ } else {
+ tcg_gen_shri_i32(tmp, tmp, endpos - 32);
+ tcg_gen_or_i32(val1, val1, tmp);
+ tcg_gen_andi_i32(tmp, src, (1u << (endpos - 32)) - 1);
+ tcg_gen_shri_i32(tmp, tmp, 32 - endpos);
+ tcg_gen_or_i32(val2, val2, tmp);
+ }
+}
+
+DISAS_INSN(bitfield_mem)
+{
+ uint16_t ext;
+ TCGv val;
+ TCGv val1, val2;
+ TCGv src;
+ int offset;
+ int width;
+ int op;
+ TCGv reg;
+ TCGv addr;
+ uint32_t mask;
+
+ op = (insn >> 8) & 7;
+ ext = lduw_code(s->pc);
+ s->pc += 2;
+ src = gen_lea(s, insn, OS_LONG);
+ if (IS_NULL_QREG(src)) {
+ gen_addr_fault(s);
+ return;
+ }
+ if ((ext & 0x820) == 0) {
+ /* constant offset and width */
+ offset = (ext >> 6) & 31;
+ width = (ext & 31);
+ if (width == 0)
+ width = 32;
+ reg = DREG(ext, 12);
+ mask = 0xffffffff << (32 - width);
+ addr = tcg_temp_new_i32();
+ if (offset > 7) {
+ tcg_gen_addi_i32(addr, src, offset >> 3);
+ offset &= 7;
+ } else
+ tcg_gen_mov_i32(addr, src);
+ if (offset > 0)
+ mask <<= 32 - offset;
+ gen_bitfield_load(s, addr, offset + width, &val1, &val2);
+ val = gen_bitfield_cc(s, offset, width, val1, val2);
+ switch (op) {
+ case 0: /* bftst */
+ break;
+ case 1: /* bfextu */
+ if (width < 32)
+ tcg_gen_shri_i32(reg, val, 32 - width);
+ else
+ tcg_gen_mov_i32(reg, val);
+ break;
+ case 3: /* bfexts */
+ if (width < 32)
+ tcg_gen_sari_i32(reg, val, 32 - width);
+ else
+ tcg_gen_mov_i32(reg, val);
+ break;
+ case 5: /* bfffo */
+ gen_helper_bfffo(val, val, tcg_const_i32(width));
+ tcg_gen_addi_i32(reg, val, offset);
+ break;
+ case 2: /* bfchg */
+ case 4: /* bfclr */
+ case 6: /* bfset */
+ gen_bitfield_op(offset, width, op, val1, val2);
+ gen_bitfield_store(s, addr, offset + width, val1, val2);
+ break;
+ case 7: /* bfins */
+ gen_bitfield_op(offset, width, 4, val1, val2);
+ gen_bitfield_ins(offset, width, reg, val1, val2);
+ gen_bitfield_store(s, addr, offset + width, val1, val2);
+ break;
+ }
+ return;
+ }
+ /* Not yet implemented */
+ gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
+}
+
DISAS_INSN(ff1)
{
TCGv reg;
@@ -3528,6 +3849,8 @@ void register_m68k_insns (CPUM68KState *env)
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);
INSN(undef_fpu, f000, f000, CF_ISA_A);
INSN(undef_fpu, f000, f000, M68000);
INSN(fpu, f200, ffc0, CF_FPU);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:10 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index d4a7074..6bba2c9 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3134,7 +3134,7 @@ static TCGv gen_bitfield_cc(DisasContext *s,

/* tmp = (bitfield << offset) >> 32 */

- tcg_gen_shri_i64(tmp64, bitfield, 32ULL);
+ tcg_gen_shri_i64(tmp64, tmp64, 32ULL);
dest = tcg_temp_new_i32();
tcg_gen_trunc_i64_i32(dest, tmp64);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:46 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 7aef2f6..56000eb 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1125,6 +1125,18 @@ DISAS_INSN(sbcd_mem)
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;
@@ -3865,6 +3877,7 @@ void register_m68k_insns (CPUM68KState *env)
INSN(not, 4600, ff00, M68000);
INSN(undef, 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);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:54 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index a3a6108..5800a4f 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -808,7 +808,7 @@ uint32_t HELPER(glue(glue(sal, bits),_cc))(CPUState *env, uint32_t val, uint32_t
}\
if (shift == 0) { \
result = (type)val; \
- cf = env->cc_src & CCF_C; \
+ cf = 0; \
} else if (shift < bits) { \
result = (type)val << shift; \
cf = ((type)val >> (bits - shift)) & 1; \
@@ -837,7 +837,7 @@ uint32_t HELPER(glue(glue(sar, bits), _cc))(CPUState *env, uint32_t val, uint32_
shift &= 63; \
if (shift == 0) { \
result = (type)val; \
- cf = (env->cc_src & CCF_C) != 0; \
+ cf = 0; \
} else if (shift < bits) { \
result = (type)val >> shift; \
cf = ((type)val >> (shift - 1)) & 1; \
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:11 UTC
Permalink
From: Laurent Vivier <***@Vivier.EU>

QEMU_GDB=port allows to define gdb server port to wait on.
QEMU_DEBUG=options allows to activate log file (like -d options)

Signed-off-by: Laurent Vivier <***@Vivier.EU>
---
linux-user/main.c | 14 +++++++++++---
qemu-doc.texi | 4 ++++
2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/linux-user/main.c b/linux-user/main.c
index 68b5681..62aa983 100644
--- a/linux-user/main.c
+++ b/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 = &regs1;
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(;;) {
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 31199f6..2193463 100644
--- a/qemu-doc.texi
+++ b/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.
+@item QEMU_DEBUG=options
+Activate log. Use same options as '-d' options.
+@item QEMU_GDB=port
+Wait gdb connection to port.
@end table

@node Other binaries
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:49 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 48 ++++++++++++++++++++++++++++++++++++++-
target-m68k/helpers.h | 4 ++-
target-m68k/translate.c | 58 +++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 104 insertions(+), 6 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 1c3dd72..60021d7 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -596,7 +596,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;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 2e5b8f8..11f1c0b 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -14,7 +14,9 @@ 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(addx_cc, 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(subx_cc, i32, env, i32, i32)
DEF_HELPER_3(shl8_cc, i32, env, i32, i32)
DEF_HELPER_3(shl16_cc, i32, env, i32, i32)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index f743fd2..f2d0fae 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2160,16 +2160,65 @@ DISAS_INSN(adda)
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. */
@@ -4004,8 +4053,9 @@ void register_m68k_insns (CPUM68KState *env)
INSN(addsub, d000, f000, CF_ISA_A);
INSN(addsub, d000, f000, M68000);
INSN(undef, d0c0, f0c0, CF_ISA_A);
- INSN(addx, d180, f1f8, CF_ISA_A);
- INSN(addx, d100, f138, M68000);
+ 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);
INSN(shift_im, e080, f0f0, CF_ISA_A);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:51 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 49 ++++++++++++++++++++++++++++++++++++++++++----
target-m68k/helpers.h | 3 ++
target-m68k/translate.c | 36 ++++++++++++++++++++++++++++-----
3 files changed, 77 insertions(+), 11 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 8bf4920..bdfe9aa 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -327,8 +327,7 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)

#define SET_FLAGS_SHIFT(type) do { \
SET_NZ(dest, type); \
- if (src) \
- flags |= CCF_C; \
+ flags |= src; \
} while(0)

flags = 0;
@@ -751,7 +750,7 @@ uint32_t HELPER(glue(glue(shl, bits),_cc))(CPUState *env, uint32_t val, uint32_t
result = 0; \
cf = 0; \
} \
- env->cc_src = cf; \
+ env->cc_src = cf ? CCF_C : 0; \
if (shift) env->cc_x = (cf != 0); \
env->cc_dest = result; \
return result; \
@@ -780,7 +779,7 @@ uint32_t HELPER(glue(glue(shr, bits), _cc))(CPUState *env, uint32_t val, uint32_
result = 0; \
cf = 0; \
} \
- env->cc_src = cf; \
+ env->cc_src = cf ? CCF_C : 0; \
if (shift) env->cc_x = (cf != 0); \
env->cc_dest = result; \
return result; \
@@ -790,6 +789,46 @@ 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 = env->cc_src & CCF_C; \
+ } 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) \
{ \
@@ -806,7 +845,7 @@ uint32_t HELPER(glue(glue(sar, bits), _cc))(CPUState *env, uint32_t val, uint32_
result = (type)val >> (bits - 1); \
cf = (type)val >> (bits - 1); \
} \
- env->cc_src = cf; \
+ env->cc_src = cf ? CCF_C : 0; \
if (shift) env->cc_x = (cf != 0); \
env->cc_dest = result; \
return result; \
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 8f6d333..aa835eb 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -26,6 +26,9 @@ 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)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index bc1cf04..37ee841 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2298,7 +2298,11 @@ DISAS_INSN(shift8_im)
dest = tcg_temp_new_i32();
/* No need to flush flags becuse we know we will set C flag. */
if (insn & 0x100) {
- gen_helper_shl8_cc(dest, cpu_env, reg, shift);
+ 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);
@@ -2326,7 +2330,11 @@ DISAS_INSN(shift16_im)
dest = tcg_temp_new_i32();
/* No need to flush flags becuse we know we will set C flag. */
if (insn & 0x100) {
- gen_helper_shl16_cc(dest, cpu_env, reg, shift);
+ 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);
@@ -2353,7 +2361,11 @@ 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_shl32_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);
@@ -2379,7 +2391,11 @@ DISAS_INSN(shift8_reg)
/* Shift by zero leaves C flag unmodified. */
gen_flush_flags(s);
if (insn & 0x100) {
- gen_helper_shl8_cc(dest, cpu_env, reg, tmp);
+ 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);
@@ -2406,7 +2422,11 @@ DISAS_INSN(shift16_reg)
/* Shift by zero leaves C flag unmodified. */
gen_flush_flags(s);
if (insn & 0x100) {
- gen_helper_shl16_cc(dest, cpu_env, reg, tmp);
+ 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);
@@ -2428,7 +2448,11 @@ DISAS_INSN(shift_reg)
/* Shift by zero leaves C flag unmodified. */
gen_flush_flags(s);
if (insn & 0x100) {
- gen_helper_shl32_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);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:28 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch allows bitfield instructions to read bit offset and field
size from a register instead of an immediat value.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 50 +++++
target-m68k/helpers.h | 2 +
target-m68k/translate.c | 515 +++++++++++++++++++++++------------------------
3 files changed, 299 insertions(+), 268 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index d6c92bf..fd9867d 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -535,6 +535,8 @@ uint32_t HELPER(bfffo)(uint32_t arg, uint32_t width)
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;
}
@@ -542,6 +544,8 @@ uint32_t HELPER(rol32)(uint32_t val, uint32_t shift)
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;
}
@@ -1188,3 +1192,49 @@ 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
+}
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 949d5d5..d71ed26 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -78,4 +78,6 @@ 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);
#include "def-helper.h"
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 334681b..fa67ff9 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2386,263 +2386,225 @@ DISAS_INSN(rotate_mem)
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 = DREG(ext, 6);
+ } else {
+ *offset = tcg_temp_new_i32();
+ tcg_gen_movi_i32(*offset, (ext >> 6) & 31);
+ }
+
+ /* width */
+
+ if (ext & 0x0020) {
+ *width = DREG(ext, 0);
+ tcg_gen_subi_i32(*width, *width, 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;
- int offset;
- int width;
+ TCGv offset;
+ TCGv width;
int op;
TCGv reg2;
- uint32_t mask;
+ TCGv mask;

reg = DREG(insn, 0);
op = (insn >> 8) & 7;
ext = lduw_code(s->pc);
s->pc += 2;
- if ((ext & 0x820) == 0) {
- /* constant offset and width */
- offset = (ext >> 6) & 31;
- width = (ext & 31);
- if (width == 0)
- width = 32;
- reg2 = DREG(ext, 12);
- mask = 0xffffffff << (32 - width);
- if (offset > 0)
- mask = (mask >> offset) | (mask << (32 - offset));
- tmp = tcg_temp_new_i32();
- tcg_gen_andi_i32(tmp, reg, mask);
- if (offset > 0) {
- tmp1 = tcg_temp_new_i32();
- gen_helper_rol32(tmp1, tmp, tcg_const_i32(offset));
- } else
- tmp1 = tmp;
- gen_logic_cc(s, tmp1);
- switch (op) {
- case 0: /* bftst */
- break;
- case 1: /* bfextu */
- if (offset + width != 32)
- gen_helper_rol32(reg2, tmp, tcg_const_i32((offset + width) & 31));
- else
- tcg_gen_mov_i32(reg2, tmp);
- break;
- case 2: /* bfchg */
- tcg_gen_xor_i32(reg, reg, tcg_const_i32(mask));
- break;
- case 3: /* bfexts */
- if (offset > 0)
- gen_helper_rol32(reg2, tmp, tcg_const_i32(offset));
- if (width < 32)
- tcg_gen_sari_i32(reg2, reg2, 32 - width);
- break;
- case 4: /* bfclr */
- tcg_gen_and_i32(reg, reg, tcg_const_i32(mask));
- break;
- case 5: /* bfffo */
- if (offset > 0)
- gen_helper_rol32(reg2, tmp, tcg_const_i32(offset));
- gen_helper_bfffo(tmp, tmp, tcg_const_i32(width));
- tcg_gen_addi_i32(reg2, tmp, offset);
- break;
- case 6: /* bfset */
- tcg_gen_ori_i32(reg, reg, mask);
- break;
- case 7: /* bfins */
- if (width == 32) {
- if (offset > 0)
- gen_helper_ror32(reg, reg2, tcg_const_i32(offset));
- else
- tcg_gen_mov_i32(reg, reg2);
- } else {
- tcg_gen_andi_i32(tmp, reg2, (1u << width) - 1);
- if (offset + width != 32)
- gen_helper_ror32(tmp, tmp, tcg_const_i32((offset + width) & 31));
- tcg_gen_andi_i32(reg, reg, ~mask);
- tcg_gen_or_i32(reg, reg, tmp);
- }
- break;
- }
- return;
- }
- /* Not yet implemented */
- gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
-}

-/* Generate a load from a bitfield. */
-static void gen_bitfield_load(DisasContext *s, TCGv addr, int endpos,
- TCGv *val1, TCGv *val2)
-{
- TCGv tmp;
+ bitfield_param(ext, &offset, &width, &mask);

- if (endpos <= 8)
- *val1 = gen_load(s, OS_BYTE, addr, 0);
- else if (endpos <= 24) {
- *val1 = gen_load(s, OS_WORD, addr, 0);
- if (endpos > 16) {
- tmp = tcg_temp_new_i32();
- tcg_gen_addi_i32(tmp, addr, 2);
- *val2 = gen_load(s, OS_BYTE, tmp, 0);
- }
- } else {
- *val1 = gen_load(s, OS_LONG, addr, 0);
- if (endpos > 32) {
- tmp = tcg_temp_new_i32();
- tcg_gen_addi_i32(tmp, addr, 4);
- *val2 = gen_load(s, OS_BYTE, tmp, 0);
- }
- }
-}
+ if (ext & 0x0800)
+ tcg_gen_andi_i32(offset, offset, 31);
+ gen_helper_ror32(mask, mask, offset);

-/* Generate a store to a bitfield. */
-static void gen_bitfield_store(DisasContext *s, TCGv addr, int endpos,
- TCGv val1, TCGv val2)
-{
- TCGv tmp;
+ /* reg & mask */

- if (endpos <= 8)
- gen_store(s, OS_BYTE, addr, val1);
- else if (endpos <= 24) {
- gen_store(s, OS_WORD, addr, val1);
- if (endpos > 16) {
- tmp = tcg_temp_new_i32();
- tcg_gen_addi_i32(tmp, addr, 2);
- gen_store(s, OS_BYTE, tmp, val2);
- }
- } else {
- gen_store(s, OS_LONG, addr, val1);
- if (endpos > 32) {
- tmp = tcg_temp_new_i32();
- tcg_gen_addi_i32(tmp, addr, 4);
- gen_store(s, OS_BYTE, tmp, val2);
- }
+ tmp = tcg_temp_new_i32();
+ tcg_gen_and_i32(tmp, reg, mask);
+
+ tmp1 = tcg_temp_new_i32();
+ gen_helper_rol32(tmp1, tmp, offset);
+ gen_logic_cc(s, tmp1);
+
+ reg2 = DREG(ext, 12);
+ 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_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, int offset, int width,
- TCGv val1, TCGv val2)
+static TCGv gen_bitfield_cc(DisasContext *s,
+ TCGv offset, TCGv mask_cc, TCGv_i64 bitfield)
{
TCGv dest;
- TCGv tmp;
+ 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, bitfield, 32ULL);
dest = tcg_temp_new_i32();
+ tcg_gen_trunc_i64_i32(dest, tmp64);

- if (offset + width <= 8)
- tcg_gen_shli_i32(dest, val1, 24 + offset);
- else if (offset + width <= 24) {
- tcg_gen_shli_i32(dest, val1, 16 + offset);
- if (offset + width > 16) {
- tmp = tcg_temp_new_i32();
- tcg_gen_shli_i32(tmp, val2, 8 + offset);
- tcg_gen_or_i32(dest, dest, tmp);
- }
- } else {
- tcg_gen_shli_i32(dest, val1, offset);
- if (offset + width > 32) {
- tmp = tcg_temp_new_i32();
- tcg_gen_shri_i32(tmp, val2, offset);
- tcg_gen_or_i32(dest, dest, tmp);
- }
- }
- tcg_gen_andi_i32(dest, dest, 0xffffffff << (32 - width));
+ /* compute cc */
+
+ tcg_gen_and_i32(dest, dest, mask_cc);
gen_logic_cc(s, dest);
+
return dest;
}

-static void gen_bitfield_op(int offset, int width, int op, TCGv val1, TCGv val2)
-{
- uint32_t mask1;
- uint32_t mask2;
- int endpos = offset + width;
-
- if (endpos <= 8) {
- mask1 = (0xff >> offset) & (0xff << (8 - endpos));
- mask2 = 0;
- } else if (endpos <= 16) {
- mask1 = (0xffff >> offset) & (0xffff << (16 - endpos));
- mask2 = 0;
- } else if (endpos <= 24) {
- mask1 = 0xffffff >> offset;
- mask2 = 0xff & (0xff << (24 - endpos));
- } else if (endpos <= 32) {
- mask1 = (0xffffffff >> offset) & (0xffffffff << (32 - endpos));
- mask2 = 0;
- } else {
- mask1 = 0xffffffff >> offset;
- mask2 = 0xff & (0xff << (40 - endpos));
- }
- switch (op) {
- case 2: /* bfchg */
- tcg_gen_xori_i32(val1, val1, mask1);
- if (mask2)
- tcg_gen_xori_i32(val2, val2, mask2);
- break;
- case 4: /* bfclr */
- tcg_gen_andi_i32(val1, val1, ~mask1);
- if (mask2)
- tcg_gen_andi_i32(val2, val2, ~mask2);
- break;
- case 6: /* bfset */
- tcg_gen_ori_i32(val1, val1, mask1);
- if (mask2)
- tcg_gen_ori_i32(val2, val2, mask2);
- break;
- }
-}
-
-static void gen_bitfield_ins(int offset, int width, TCGv src,
- TCGv val1, TCGv val2)
+static TCGv_i64 gen_bitfield_mask(TCGv offset, TCGv width)
{
TCGv tmp;
- int endpos = offset + width;
+ 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();
- if (width < 32) {
- tcg_gen_andi_i32(tmp, src, (1u << width) - 1);
- } else
- tcg_gen_mov_i32(tmp, src);
- if (endpos <= 8) {
- if (endpos < 8)
- tcg_gen_shli_i32(tmp, tmp, 8 - endpos);
- tcg_gen_or_i32(val1, val1, tmp);
- } else if (endpos <= 16) {
- if (endpos < 16)
- tcg_gen_shli_i32(tmp, tmp, 16 - endpos);
- tcg_gen_or_i32(val1, val1, tmp);
- } else if (endpos <= 24) {
- tcg_gen_shri_i32(tmp, tmp, endpos - 16);
- tcg_gen_or_i32(val1, val1, tmp);
- tcg_gen_andi_i32(tmp, src, (1u << (endpos - 16)) - 1);
- if (endpos < 24)
- tcg_gen_shli_i32(tmp, tmp, 24 - endpos);
- tcg_gen_or_i32(val2, val2, tmp);
- } else if (endpos <= 32) {
- if (endpos < 32)
- tcg_gen_shli_i32(tmp, tmp, 32 - endpos);
- tcg_gen_or_i32(val1, val1, tmp);
- } else {
- tcg_gen_shri_i32(tmp, tmp, endpos - 32);
- tcg_gen_or_i32(val1, val1, tmp);
- tcg_gen_andi_i32(tmp, src, (1u << (endpos - 32)) - 1);
- tcg_gen_shri_i32(tmp, tmp, 32 - endpos);
- tcg_gen_or_i32(val2, val2, tmp);
- }
+ 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; */
+
+ tcg_gen_shl_i32(tmp, tcg_const_i32(1), width);
+ 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 val1, val2;
TCGv src;
- int offset;
- int width;
- int op;
+ TCGv offset;
+ TCGv width;
TCGv reg;
- TCGv addr;
- uint32_t mask;
+ TCGv tmp;

op = (insn >> 8) & 7;
ext = lduw_code(s->pc);
@@ -2652,59 +2614,76 @@ DISAS_INSN(bitfield_mem)
gen_addr_fault(s);
return;
}
- if ((ext & 0x820) == 0) {
- /* constant offset and width */
- offset = (ext >> 6) & 31;
- width = (ext & 31);
- if (width == 0)
- width = 32;
- reg = DREG(ext, 12);
- mask = 0xffffffff << (32 - width);
- addr = tcg_temp_new_i32();
- if (offset > 7) {
- tcg_gen_addi_i32(addr, src, offset >> 3);
- offset &= 7;
- } else
- tcg_gen_mov_i32(addr, src);
- if (offset > 0)
- mask <<= 32 - offset;
- gen_bitfield_load(s, addr, offset + width, &val1, &val2);
- val = gen_bitfield_cc(s, offset, width, val1, val2);
- switch (op) {
- case 0: /* bftst */
- break;
- case 1: /* bfextu */
- if (width < 32)
- tcg_gen_shri_i32(reg, val, 32 - width);
- else
- tcg_gen_mov_i32(reg, val);
- break;
- case 3: /* bfexts */
- if (width < 32)
- tcg_gen_sari_i32(reg, val, 32 - width);
- else
- tcg_gen_mov_i32(reg, val);
- break;
- case 5: /* bfffo */
- gen_helper_bfffo(val, val, tcg_const_i32(width));
- tcg_gen_addi_i32(reg, val, offset);
- break;
- case 2: /* bfchg */
- case 4: /* bfclr */
- case 6: /* bfset */
- gen_bitfield_op(offset, width, op, val1, val2);
- gen_bitfield_store(s, addr, offset + width, val1, val2);
- break;
- case 7: /* bfins */
- gen_bitfield_op(offset, width, 4, val1, val2);
- gen_bitfield_ins(offset, width, reg, val1, val2);
- gen_bitfield_store(s, addr, offset + width, val1, val2);
- break;
- }
- return;
+
+ bitfield_param(ext, &offset, &width, &mask_cc);
+
+ /* 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);
+ 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;
}
- /* Not yet implemented */
- gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED);
}

DISAS_INSN(ff1)
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:26 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

allow to run metacity

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 96586ae..91355ba 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3602,7 +3602,7 @@ DISAS_INSN(fpu)
case 4: /* FPCR */
SRC_EA(val, OS_LONG, 0, NULL);
gen_helper_set_fpcr(cpu_env, val);
- break;
+ return;
case 1: /* FPIAR */
case 2: /* FPSR */
default:
@@ -3613,7 +3613,6 @@ DISAS_INSN(fpu)
case 5: /* fmove from control register. */
switch ((ext >> 10) & 7) {
case 4: /* FPCR */
- /* Not implemented. Always return zero. */
DEST_EA(insn, OS_LONG, QEMU_FPCR, NULL);
return;
case 1: /* FPIAR */
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:08 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 69 +++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 60 insertions(+), 9 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 081e1d9..7dcac61 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -29,6 +29,17 @@

#include "helpers.h"

+#if 0
+#define DBG_FPU(...) do { fprintf(stderr, "0x%08x: ", env->pc); fprintf(stderr, __VA_ARGS__); } while(0)
+static inline long double LDOUBLE(floatx80 x)
+{
+ return *(long double *)&x;
+}
+#else
+#define DBG_FPU(...)
+#define LDOUBLE(x)
+#endif
+
#define SIGNBIT (1u << 31)

enum m68k_cpuid {
@@ -1009,12 +1020,6 @@ static const floatx80 fpu_rom[128] = {
[0x3f] = { .high = 0x7525, .low = 0xc46052028a20979bULL }, /* 10^4096 */
};

-void HELPER(const_FP0)(CPUState *env, uint32_t offset)
-{
- env->fp0h = fpu_rom[offset].high;
- env->fp0l = fpu_rom[offset].low;
-}
-
static inline floatx80 FP0_to_floatx80(CPUState *env)
{
floatx80 res;
@@ -1072,6 +1077,14 @@ static inline floatx80 FP1_to_floatx80(CPUState *env)
return res;
}

+void HELPER(const_FP0)(CPUState *env, uint32_t offset)
+{
+ env->fp0h = fpu_rom[offset].high;
+ env->fp0l = fpu_rom[offset].low;
+ DBG_FPU("ROM[0x%02x] %"PRIxFPH" %"PRIxFPL" %.17Lg\n",
+ offset, env->fp0h, env->fp0l, LDOUBLE(FP0_to_floatx80(env)));
+}
+
static inline void restore_precision_mode(CPUState *env)
{
int rounding_precision;
@@ -1118,6 +1131,8 @@ static inline void restore_rounding_mode(CPUState *env)

void HELPER(set_fpcr)(CPUState *env, uint32_t val)
{
+ DBG_FPU("set_fpcr %04x\n", val);
+
env->fpcr = val & 0xffff;

restore_precision_mode(env);
@@ -1128,8 +1143,11 @@ void HELPER(exts32_FP0)(CPUState *env)
{
floatx80 res;

+ DBG_FPU("exts32_FP0 %d\n", FP0_to_int32(env));
+
res = int32_to_floatx80(FP0_to_int32(env), &env->fp_status);

+ DBG_FPU(" = %Lg\n", LDOUBLE(res));
floatx80_to_FP0(env, res);
}

@@ -1137,6 +1155,7 @@ void HELPER(extf32_FP0)(CPUState *env)
{
floatx80 res;

+ DBG_FPU("extf32_FP0\n");
res = float32_to_floatx80(FP0_to_float32(env), &env->fp_status);

floatx80_to_FP0(env, res);
@@ -1145,8 +1164,12 @@ void HELPER(extf32_FP0)(CPUState *env)
void HELPER(extf64_FP0)(CPUState *env)
{
floatx80 res;
+ uint64_t val;

- res = float64_to_floatx80(FP0_to_float64(env), &env->fp_status);
+ val = FP0_to_float64(env);
+ DBG_FPU("extf64_FP0 0x%016"PRIx64", %g\n", val, *(double*)&val);
+ res = float64_to_floatx80(val, &env->fp_status);
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1161,7 +1184,9 @@ void HELPER(reds32_FP0)(CPUState *env)
int32_t res;

val = FP0_to_floatx80(env);
+ DBG_FPU("reds32_FP0 %Lg\n", LDOUBLE(val));
res = floatx80_to_int32(val, &env->fp_status);
+ DBG_FPU(" = %d\n", res);

int32_to_FP0(env, res);
}
@@ -1171,6 +1196,7 @@ void HELPER(redf32_FP0)(CPUState *env)
floatx80 val;
float32 res;

+ DBG_FPU("redf32_FP0\n");
val = FP0_to_floatx80(env);
res = floatx80_to_float32(val, &env->fp_status);

@@ -1183,19 +1209,24 @@ void HELPER(redf64_FP0)(CPUState *env)
float64 res;

val = FP0_to_floatx80(env);
+ DBG_FPU("redf64_FP0 %Lg\n", 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_FPU("redp96_FP0\n");
}

void HELPER(iround_FP0)(CPUState *env)
{
floatx80 res;

+ DBG_FPU("iround_FP0\n");
+
res = floatx80_round_to_int(FP0_to_floatx80(env), &env->fp_status);

floatx80_to_FP0(env, res);
@@ -1205,6 +1236,8 @@ void HELPER(itrunc_FP0)(CPUState *env)
{
floatx80 res;

+ DBG_FPU("itrunc_FP0\n");
+
set_float_rounding_mode(float_round_to_zero, &env->fp_status);
res = floatx80_round_to_int(FP0_to_floatx80(env), &env->fp_status);
restore_rounding_mode(env);
@@ -1216,6 +1249,7 @@ void HELPER(sqrt_FP0)(CPUState *env)
{
floatx80 res;

+ DBG_FPU("sqrt_FP0\n");
res = floatx80_sqrt(FP0_to_floatx80(env), &env->fp_status);

floatx80_to_FP0(env, res);
@@ -1225,6 +1259,7 @@ void HELPER(abs_FP0)(CPUState *env)
{
floatx80 res;

+ DBG_FPU("abs_FP0\n");
res = floatx80_abs(FP0_to_floatx80(env));

floatx80_to_FP0(env, res);
@@ -1234,6 +1269,7 @@ void HELPER(chs_FP0)(CPUState *env)
{
floatx80 res;

+ DBG_FPU("chs_FP0\n");
res = floatx80_chs(FP0_to_floatx80(env));

floatx80_to_FP0(env, res);
@@ -1243,8 +1279,11 @@ void HELPER(add_FP0_FP1)(CPUState *env)
{
floatx80 res;

+ DBG_FPU("add_FP0_FP1(%Lg,%Lg)\n", LDOUBLE(FP0_to_floatx80(env)),
+ LDOUBLE(FP1_to_floatx80(env)));
res = floatx80_add(FP0_to_floatx80(env), FP1_to_floatx80(env),
&env->fp_status);
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1253,8 +1292,11 @@ void HELPER(sub_FP0_FP1)(CPUState *env)
{
floatx80 res;

- res = floatx80_sub(FP0_to_floatx80(env), FP1_to_floatx80(env),
+ DBG_FPU("sub_FP0 %Lg %Lg\n", LDOUBLE(FP0_to_floatx80(env)),
+ LDOUBLE(FP1_to_floatx80(env)));
+ res = floatx80_sub(FP1_to_floatx80(env), FP0_to_floatx80(env),
&env->fp_status);
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1263,8 +1305,11 @@ void HELPER(mul_FP0_FP1)(CPUState *env)
{
floatx80 res;

+ DBG_FPU("mul_FP0_FP1 %Lg %Lg\n",
+ LDOUBLE(FP0_to_floatx80(env)), LDOUBLE(FP1_to_floatx80(env)));
res = floatx80_mul(FP0_to_floatx80(env), FP1_to_floatx80(env),
&env->fp_status);
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));

floatx80_to_FP0(env, res);
}
@@ -1273,7 +1318,8 @@ void HELPER(div_FP0_FP1)(CPUState *env)
{
floatx80 res;

- res = floatx80_div(FP0_to_floatx80(env), FP1_to_floatx80(env),
+ DBG_FPU("div\n");
+ res = floatx80_div(FP1_to_floatx80(env), FP0_to_floatx80(env),
&env->fp_status);

floatx80_to_FP0(env, res);
@@ -1284,6 +1330,8 @@ void HELPER(fcmp_FP0_FP1)(CPUState *env)
/* ??? This may incorrectly raise exceptions. */
/* ??? Should flush denormals to zero. */
floatx80 res;
+ DBG_FPU("cmp_FP0_FP1 %Lg %Lg\n", LDOUBLE(FP1_to_floatx80(env)),
+ LDOUBLE(FP0_to_floatx80(env)));
res = floatx80_sub(FP1_to_floatx80(env), FP0_to_floatx80(env),
&env->fp_status);
if (floatx80_is_any_nan(res)) {
@@ -1295,6 +1343,7 @@ void HELPER(fcmp_FP0_FP1)(CPUState *env)
res = floatx80_chs(res);
}
}
+ DBG_FPU(" : %Lg\n", LDOUBLE(res));
floatx80_to_FP0(env, res);
}

@@ -1302,9 +1351,11 @@ uint32_t HELPER(compare_FP0)(CPUState *env)
{
uint32_t res;

+ DBG_FPU("compare_FP0 %Lg\n", 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;
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:11 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
.gitignore | 1 +
target-m68k/helper.c | 17 +++++++++++++++++
target-m68k/helpers.h | 1 +
target-m68k/translate.c | 3 +++
tests/m68k/Makefile | 2 +-
tests/m68k/fgetexp.S | 8 ++++++++
6 files changed, 31 insertions(+), 1 deletions(-)
create mode 100644 tests/m68k/fgetexp.S

diff --git a/.gitignore b/.gitignore
index 08819c2..ef339f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -78,3 +78,4 @@ tests/m68k/fmovecr
tests/m68k/fmovem
tests/m68k/fmul
tests/m68k/fsub
+tests/m68k/fgetexp
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 7dcac61..2be3355 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -1275,6 +1275,23 @@ void HELPER(chs_FP0)(CPUState *env)
floatx80_to_FP0(env, res);
}

+void HELPER(getexp_FP0)(CPUState *env)
+{
+ int32_t exp;
+ floatx80 res;
+
+ DBG_FPU("getexp_FP0(%Lg)\n", LDOUBLE(FP0_to_floatx80(env)));
+
+ DBG_FPU(" fp0h 0x%08x fp0l 0x%016" PRIx64 "\n", env->fp0h, env->fp0l);
+
+ exp = (env->fp0h & 0x7fff) - 0x3fff;
+
+ res = int32_to_floatx80(exp, &env->fp_status);
+
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));
+ floatx80_to_FP0(env, res);
+}
+
void HELPER(add_FP0_FP1)(CPUState *env)
{
floatx80 res;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 6ddd659..0b4c0cb 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -67,6 +67,7 @@ DEF_HELPER_1(itrunc_FP0, void, env)
DEF_HELPER_1(sqrt_FP0, void, env)
DEF_HELPER_1(abs_FP0, void, env)
DEF_HELPER_1(chs_FP0, void, env)
+DEF_HELPER_1(getexp_FP0, 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)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 6bba2c9..d09e325 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3647,6 +3647,9 @@ DISAS_INSN(fpu)
case 0x1a: case 0x5a: case 0x5e: /* fneg */
gen_helper_chs_FP0(cpu_env);
break;
+ case 0x1e: /* fgetexp */
+ gen_helper_getexp_FP0(cpu_env);
+ break;
case 0x20: case 0x60: case 0x64: /* fdiv */
gen_op_load_fpr_FP1(REG(ext, 7));
gen_helper_div_FP0_FP1(cpu_env);
diff --git a/tests/m68k/Makefile b/tests/m68k/Makefile
index 8b0d8a7..a7a59ac 100644
--- a/tests/m68k/Makefile
+++ b/tests/m68k/Makefile
@@ -1,4 +1,4 @@
-TESTS=fmovecr fmove fmovem fsub fdiv fmul fabs
+TESTS=fmovecr fmove fmovem fsub fdiv fmul fabs fgetexp

all: $(TESTS)

diff --git a/tests/m68k/fgetexp.S b/tests/m68k/fgetexp.S
new file mode 100644
index 0000000..d17f7ab
--- /dev/null
+++ b/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
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:56 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

- the source register to be divided is a 32bit,
so don't extend the 16bit value sign
- don't modify the destination operand on overflow
- don't modify N and Z flags on overflow
(documentation says "undefined" but real 68040 is
doing like this)

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/op_helper.c | 46 ++++++++++++++++++++++++++--------------------
target-m68k/translate.c | 26 +++++++++++++++++---------
2 files changed, 43 insertions(+), 29 deletions(-)

diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index a6c8148..c270259 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -213,17 +213,20 @@ 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;
- /* Don't modify destination if overflow occured. */
- if ((flags & CCF_V) == 0) {
- env->div1 = quot;
- env->div2 = rem;
+ 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;
}

@@ -242,17 +245,20 @@ 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;
- /* Don't modify destination if overflow occured. */
- if ((flags & CCF_V) == 0) {
- env->div1 = quot;
- env->div2 = rem;
+ 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;
}

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index f5e56bc..52da485 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -993,32 +993,40 @@ DISAS_INSN(mulw)

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)
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:16 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Even if cmpa uses an 16 bits source data, the comparison with the register is
done on 32 bits.

This allows to run "gcc hello.c" without segfault.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 1901b1b..5591873 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2492,7 +2492,7 @@ DISAS_INSN(cmpa)
dest = tcg_temp_new();
tcg_gen_sub_i32(dest, reg, src);
gen_update_cc_add(dest, src);
- SET_CC_OP(opsize, SUB);
+ SET_CC_OP(OS_LONG, SUB);
}

DISAS_INSN(eor)
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:06 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/m68k-qreg.h | 11 -----------
1 files changed, 0 insertions(+), 11 deletions(-)
delete mode 100644 target-m68k/m68k-qreg.h

diff --git a/target-m68k/m68k-qreg.h b/target-m68k/m68k-qreg.h
deleted file mode 100644
index c224d5e..0000000
--- a/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
-};
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:04 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 875ff45..1bb0cef 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -33,6 +33,7 @@
enum m68k_cpuid {
M68K_CPUID_M68000,
M68K_CPUID_M68020,
+ M68K_CPUID_M68030,
M68K_CPUID_M68040,
M68K_CPUID_M68060,
M68K_CPUID_M5206,
@@ -51,6 +52,7 @@ 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},
@@ -155,6 +157,7 @@ static int cpu_m68k_set_model(CPUM68KState *env, const char *name)

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:
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:39 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

It returns i32, not f32.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helpers.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 50f5486..4bfb149 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -42,7 +42,7 @@ DEF_HELPER_2(set_sr, void, env, i32)
DEF_HELPER_3(movec, void, env, i32, i32)

DEF_HELPER_2(const_f64, f64, env, i32);
-DEF_HELPER_2(f64_to_i32, f32, env, f64)
+DEF_HELPER_2(f64_to_i32, i32, 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)
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:57 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 52da485..4f2a5ee 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1646,10 +1646,10 @@ DISAS_INSN(neg)
SRC_EA(src1, opsize, -1, &addr);
dest = tcg_temp_new();
tcg_gen_neg_i32(dest, src1);
- DEST_EA(insn, opsize, dest, &addr);
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)
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:25 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch defines shift8_im, shift16_im, shift8_reg, shift16_reg,
shift_mem and attach them to M68000 feature.

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/cpu.h | 2 +
target-m68k/helper.c | 160 +++++++++++++++++++++++++++--------------------
target-m68k/helpers.h | 12 +++-
target-m68k/translate.c | 155 +++++++++++++++++++++++++++++++++++++++++++---
4 files changed, 249 insertions(+), 80 deletions(-)

diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index ff57564..91d3141 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -147,6 +147,8 @@ enum {
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 */
};

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index dd9079f..0025ab5 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -287,6 +287,12 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
flags |= CCF_V; \
} while (0)

+#define SET_FLAGS_SHIFT(type) do { \
+ SET_NZ((type)dest); \
+ if (src) \
+ flags |= CCF_C; \
+ } while(0)
+
flags = 0;
src = env->cc_src;
dest = env->cc_dest;
@@ -333,10 +339,14 @@ void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
case CC_OP_SUBX:
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);
@@ -538,77 +548,89 @@ 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)
-{
- 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;
-}
-
-uint32_t HELPER(shr_cc)(CPUState *env, uint32_t val, uint32_t shift)
-{
- 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;
-}
-
-uint32_t HELPER(sar_cc)(CPUState *env, uint32_t val, uint32_t shift)
-{
- 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;
-}
+#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 = env->cc_src & CCF_C; \
+ } 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; \
+ 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 = env->cc_src & CCF_C; \
+ } 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; \
+ 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_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 = (env->cc_src & CCF_C) != 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; \
+ env->cc_x = cf; \
+ env->cc_dest = result; \
+ return result; \
+}
+
+HELPER_SAR(int8_t, 8)
+HELPER_SAR(int16_t, 16)
+HELPER_SAR(int32_t, 32)

/* FPU helpers. */
uint32_t HELPER(f64_to_i32)(CPUState *env, float64 val)
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index ca2bf82..d1993ab 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -13,9 +13,15 @@ DEF_HELPER_3(mulu64, i32, env, i32, i32)
DEF_HELPER_3(muls64, i32, env, i32, 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_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(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_2(xflag_lt, i32, i32, i32)
DEF_HELPER_2(set_sr, void, env, i32)
DEF_HELPER_3(movec, void, env, i32, i32)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 8fb71b8..ecbd516 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2009,6 +2009,63 @@ DISAS_INSN(addx)
}

/* 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) {
+ gen_helper_shl8_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) {
+ gen_helper_shl16_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;
@@ -2022,17 +2079,71 @@ 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);
+ gen_helper_shl32_cc(reg, cpu_env, reg, shift);
} else {
if (insn & 8) {
- gen_helper_shr_cc(reg, cpu_env, reg, shift);
+ gen_helper_shr32_cc(reg, cpu_env, reg, shift);
} else {
- gen_helper_sar_cc(reg, cpu_env, reg, shift);
+ 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) {
+ gen_helper_shl8_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) {
+ gen_helper_shl16_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;
@@ -2043,17 +2154,40 @@ DISAS_INSN(shift_reg)
/* Shift by zero leaves C flag unmodified. */
gen_flush_flags(s);
if (insn & 0x100) {
- gen_helper_shl_cc(reg, cpu_env, reg, shift);
+ gen_helper_shl32_cc(reg, cpu_env, reg, shift);
} else {
if (insn & 8) {
- gen_helper_shr_cc(reg, cpu_env, reg, shift);
+ gen_helper_shr32_cc(reg, cpu_env, reg, shift);
} else {
- gen_helper_sar_cc(reg, cpu_env, reg, shift);
+ 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_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(ff1)
{
TCGv reg;
@@ -3182,8 +3316,13 @@ void register_m68k_insns (CPUM68KState *env)
INSN(adda, d0c0, f0c0, M68000);
INSN(shift_im, e080, f0f0, CF_ISA_A);
INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
- INSN(shift_im, e080, f0f0, M68000);
- INSN(shift_reg, e0a0, f0f0, M68000);
+ 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(undef_fpu, f000, f000, CF_ISA_A);
INSN(undef_fpu, f000, f000, M68000);
INSN(fpu, f200, ffc0, CF_FPU);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:43 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index f2bdef0..ab2073a 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1483,11 +1483,16 @@ DISAS_INSN(move)

DISAS_INSN(negx)
{
- TCGv reg;
+ TCGv src;
+ TCGv dest;
+ TCGv addr;
+ int opsize;

- gen_flush_flags(s);
- reg = DREG(insn, 0);
- gen_helper_subx_cc(reg, cpu_env, tcg_const_i32(0), reg);
+ opsize = insn_opsize(insn, 6);
+ SRC_EA(src, opsize, -1, &addr);
+ dest = tcg_temp_new();
+ gen_helper_subx_cc(dest, cpu_env, tcg_const_i32(0), src);
+ DEST_EA(insn, opsize, dest, &addr);
}

DISAS_INSN(lea)
@@ -3780,7 +3785,7 @@ void register_m68k_insns (CPUM68KState *env)
INSN(move, 3000, f000, M68000);
INSN(strldsr, 40e7, ffff, CF_ISA_APLUSC);
INSN(negx, 4080, fff8, CF_ISA_A);
- INSN(negx, 4080, fff8, M68000);
+ INSN(negx, 4000, ff00, M68000);
INSN(undef, 40c0, ffc0, M68000);
INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
INSN(move_from_sr, 40c0, fff8, M68000);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:21 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch modifies "divl" to support 64bit operands (QUAD_MULDIV
feature).

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/cpu.h | 3 ++
target-m68k/helpers.h | 2 +
target-m68k/op_helper.c | 77 ++++++++++++++++++++++++++++++++++++++++++++--
target-m68k/qregs.def | 1 +
target-m68k/translate.c | 34 ++++++++++++++++----
5 files changed, 106 insertions(+), 11 deletions(-)

diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index 688642f..ff57564 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -91,6 +91,9 @@ typedef struct CPUM68KState {
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;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index cb8a0c7..a158aee 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -5,6 +5,8 @@ DEF_HELPER_1(ff1, 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_1(divu64, void, env)
+DEF_HELPER_1(divs64, void, env)
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)
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
index c66fa0c..1bffe5d 100644
--- a/target-m68k/op_helper.c
+++ b/target-m68k/op_helper.c
@@ -219,8 +219,11 @@ void HELPER(divu)(CPUState *env, uint32_t word)
flags |= CCF_Z;
else if ((int32_t)quot < 0)
flags |= CCF_N;
- env->div1 = quot;
- env->div2 = rem;
+ /* Don't modify destination if overflow occured. */
+ if ((flags & CCF_V) == 0) {
+ env->div1 = quot;
+ env->div2 = rem;
+ }
env->cc_dest = flags;
}

@@ -245,7 +248,73 @@ void HELPER(divs)(CPUState *env, uint32_t word)
flags |= CCF_Z;
else if (quot < 0)
flags |= CCF_N;
- env->div1 = quot;
- env->div2 = rem;
+ /* Don't modify destination if overflow occured. */
+ if ((flags & CCF_V) == 0) {
+ env->div1 = quot;
+ env->div2 = rem;
+ }
+ env->cc_dest = flags;
+}
+
+void HELPER(divu64)(CPUState *env)
+{
+ uint32_t num;
+ uint32_t den;
+ uint32_t quot;
+ uint32_t rem;
+ uint32_t flags;
+
+ num = env->div1;
+ den = env->div2;
+ /* ??? This needs to make sure the throwing location is accurate. */
+ if (den == 0)
+ raise_exception(EXCP_DIV0);
+ quot = (num | ((uint64_t)env->quadh << 32)) / den;
+ rem = (num | ((uint64_t)env->quadh << 32)) % den;
+ flags = 0;
+ /* 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 (quot > 0xffffffff)
+ flags |= CCF_V;
+ if (quot == 0)
+ flags |= CCF_Z;
+ else if ((int32_t)quot < 0)
+ flags |= CCF_N;
+ /* Don't modify destination if overflow occured. */
+ if ((flags & CCF_V) == 0) {
+ env->div1 = quot;
+ env->div2 = rem;
+ }
+ env->cc_dest = flags;
+}
+
+void HELPER(divs64)(CPUState *env)
+{
+ int32_t num;
+ int32_t den;
+ int32_t quot;
+ int32_t rem;
+ int32_t flags;
+
+ num = env->div1;
+ den = env->div2;
+ if (den == 0)
+ raise_exception(EXCP_DIV0);
+ quot = (num | ((int64_t)env->quadh << 32)) / den;
+ rem = (num | ((int64_t)env->quadh << 32)) % den;
+ rem = num % den;
+ flags = 0;
+ if (quot != (int32_t)quot)
+ flags |= CCF_V;
+ if (quot == 0)
+ flags |= CCF_Z;
+ else if (quot < 0)
+ flags |= CCF_N;
+ /* Don't modify destination if overflow occured. */
+ if ((flags & CCF_V) == 0) {
+ env->div1 = quot;
+ env->div2 = rem;
+ }
env->cc_dest = flags;
}
diff --git a/target-m68k/qregs.def b/target-m68k/qregs.def
index 49400c4..76e0236 100644
--- a/target-m68k/qregs.def
+++ b/target-m68k/qregs.def
@@ -7,6 +7,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 a/target-m68k/translate.c b/target-m68k/translate.c
index 0f9b4eb..1d84081 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1020,10 +1020,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_DIV2);
+ s->cc_op = CC_OP_FLAGS;
return;
}
num = DREG(ext, 12);
@@ -1036,10 +1053,12 @@ 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);
}
@@ -3010,6 +3029,7 @@ void register_m68k_insns (CPUM68KState *env)
INSN(illegal, 4afc, ffff, M68000);
INSN(mull, 4c00, ffc0, CF_ISA_A);
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);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:01 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Allow to configure if the m68k emulator must implement
fake operation to allow returning from the emulator when
the emulator is used with the m68k-tester tool.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
configure | 11 +++++++++++
target-m68k/cpu.h | 3 +++
target-m68k/translate.c | 10 ++++++++++
3 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/configure b/configure
index 40b1fa9..23ec821 100755
--- a/configure
+++ b/configure
@@ -135,6 +135,7 @@ kvm="no"
gprof="no"
debug_tcg="no"
debug_mon="no"
+emulop="no"
debug="no"
strip_opt="yes"
bigendian="no"
@@ -582,6 +583,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"
@@ -1046,6 +1051,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
@@ -2684,6 +2691,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"
@@ -3449,6 +3457,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 a/target-m68k/cpu.h b/target-m68k/cpu.h
index 0d5e3d3..e316b1e 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -54,6 +54,9 @@

#define EXCP_RTE 0x100
#define EXCP_HALT_INSN 0x101
+#ifdef CONFIG_EMULOP
+#define EXCP_EXEC_RETURN 0x20000
+#endif

#define NB_MMU_MODES 2

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index f93ad02..b011a5e 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3904,6 +3904,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
@@ -4173,6 +4180,9 @@ void register_m68k_insns (CPUM68KState *env)
INSN(cpushl, f428, ff38, CF_ISA_A);
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
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:23 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Allows suba and adda to manage word sized effective address, and attach
them to M68000 feature.

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 74faabf..0321349 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1881,7 +1881,7 @@ 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);
}
@@ -1991,7 +1991,7 @@ 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);
}
@@ -3109,6 +3109,7 @@ void register_m68k_insns (CPUM68KState *env)
INSN(subx, 9180, f1f8, CF_ISA_A);
INSN(subx, 9100, 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);
@@ -3144,6 +3145,7 @@ void register_m68k_insns (CPUM68KState *env)
INSN(addx, d180, f1f8, CF_ISA_A);
INSN(addx, d100, f138, M68000);
INSN(adda, d1c0, f1c0, CF_ISA_A);
+ INSN(adda, d0c0, f0c0, M68000);
INSN(shift_im, e080, f0f0, CF_ISA_A);
INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
INSN(shift_im, e080, f0f0, M68000);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:25 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 15 +++++++++++++++
target-m68k/helpers.h | 1 +
target-m68k/translate.c | 3 +++
3 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 699f28a..79e6a28 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -1435,6 +1435,21 @@ void HELPER(acos_FP0)(CPUState *env)
floatx80_to_FP0(env, res);
}

+void HELPER(cos_FP0)(CPUState *env)
+{
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = LDOUBLE(res);
+
+ DBG_FPUH("cos_FP0 %Lg", val);
+ val = cosl(val);
+ DBG_FPU(" = %Lg", val);
+ res = FLOATx80(val);
+ floatx80_to_FP0(env, res);
+}
+
void HELPER(getexp_FP0)(CPUState *env)
{
int32_t exp;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index c704953..e6465cd 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -74,6 +74,7 @@ DEF_HELPER_1(log10_FP0, void, env)
DEF_HELPER_1(abs_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)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 0fafa3b..96586ae 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3688,6 +3688,9 @@ DISAS_INSN(fpu)
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;
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:09 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
.gitignore | 7 +++++++
tests/m68k/Makefile | 6 +-----
tests/m68k/fabs.S | 9 +++++++++
tests/m68k/fdiv.S | 10 ++++++++++
tests/m68k/fmove.S | 13 +++++++++----
tests/m68k/fmul.S | 9 +++++++++
tests/m68k/fsub.S | 11 +++++++++++
7 files changed, 56 insertions(+), 9 deletions(-)
create mode 100644 tests/m68k/fabs.S
create mode 100644 tests/m68k/fdiv.S
create mode 100644 tests/m68k/fmul.S
create mode 100644 tests/m68k/fsub.S

diff --git a/.gitignore b/.gitignore
index 59c343c..08819c2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,3 +71,10 @@ cscope.*
tags
TAGS
*~
+tests/m68k/fabs
+tests/m68k/fdiv
+tests/m68k/fmove
+tests/m68k/fmovecr
+tests/m68k/fmovem
+tests/m68k/fmul
+tests/m68k/fsub
diff --git a/tests/m68k/Makefile b/tests/m68k/Makefile
index 8f09805..8b0d8a7 100644
--- a/tests/m68k/Makefile
+++ b/tests/m68k/Makefile
@@ -1,14 +1,10 @@
-TESTS=fmovecr fmove fmovem
+TESTS=fmovecr fmove fmovem fsub fdiv fmul fabs

all: $(TESTS)

%: %.S
m68k-linux-gnu-gcc -m68040 -nostartfiles -nodefaultlibs -nostdlib -o $@ $<

-fmovecr: fmovecr.S
-fmove: fmove.S
-fmovem: fmovem.S
-
.PHONY: clean

clean:
diff --git a/tests/m68k/fabs.S b/tests/m68k/fabs.S
new file mode 100644
index 0000000..cbe2a4a
--- /dev/null
+++ b/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 a/tests/m68k/fdiv.S b/tests/m68k/fdiv.S
new file mode 100644
index 0000000..a5e3656
--- /dev/null
+++ b/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 a/tests/m68k/fmove.S b/tests/m68k/fmove.S
index 3f2daba..d08c866 100644
--- a/tests/m68k/fmove.S
+++ b/tests/m68k/fmove.S
@@ -2,9 +2,8 @@

.data
tmp: .long 0x88776655
-pi: .long 0x40000000
- .long 0xc90fdaa2
- .long 0x2168C235
+pi: .long 0x40000000, 0xc90fdaa2, 0x2168C235
+store: .long 0, 0, 0

.text
.globl _start
@@ -12,6 +11,12 @@ _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
@@ -48,7 +53,7 @@ _start:
fmove.w #0xFABC,%fp1
fmove.l #0xFABCDEFA,%fp2
fmove.s #0xDEADBEAF,%fp3
- fmove.d #0xFABCDEFADEADBEAF,%fp4
+ fmove.d #0f4.29497E+09,%fp4
fmove.x #0xFABCDEFADEADBEAF12345678,%fp5
fmove.p #0xFABCDEFADEADBEAF12345678,%fp6

diff --git a/tests/m68k/fmul.S b/tests/m68k/fmul.S
new file mode 100644
index 0000000..1b989fc
--- /dev/null
+++ b/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 a/tests/m68k/fsub.S b/tests/m68k/fsub.S
new file mode 100644
index 0000000..cf1a77a
--- /dev/null
+++ b/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
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:19 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Define DBcc instruction and attach it to M68000 feature.

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 26 ++++++++++++++++++++++++++
1 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 8cf49d8..e0edc6d 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -920,6 +920,31 @@ DISAS_INSN(scc_mem)
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, 0, 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);
@@ -2991,6 +3016,7 @@ void register_m68k_insns (CPUM68KState *env)
INSN(scc, 50c0, f0f8, 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. */
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:17 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
fpu/softfloat.h | 1 +
target-m68k/helper.c | 23 ++++++++++++++++++++++-
target-m68k/helpers.h | 1 +
target-m68k/translate.c | 3 +++
4 files changed, 27 insertions(+), 1 deletions(-)

diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index f6d5fce..9ff6b4d 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -534,6 +534,7 @@ INLINE int floatx80_is_any_nan(floatx80 a)
#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.
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 14a6ae6..f6e446a 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -1016,7 +1016,7 @@ static const floatx80 fpu_rom[128] = {
[0x30] = floatx80_ln2, /* ln(2) */
[0x31] = { .high = 0x4000, .low = 0x935d8dddaaa8ac17ULL }, /* ln(10) */
[0x32] = floatx80_one, /* 10^0 */
- [0x33] = { .high = 0x4002, .low = 0xa000000000000000ULL }, /* 10^1 */
+ [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 */
@@ -1284,6 +1284,27 @@ void HELPER(ln_FP0)(CPUState *env)
floatx80_to_FP0(env, res);
}

+void HELPER(log10_FP0)(CPUState *env)
+{
+ float64 f, log2, log210;
+ floatx80 res;
+
+ /* log10(x) = log2(x) / log2(10) */
+
+ DBG_FPU("log10_FP0(%Lg)\n", LDOUBLE(FP0_to_floatx80(env)));
+ f = floatx80_to_float64(FP0_to_floatx80(env), &env->fp_status);
+
+ log2 = float64_log2(f, &env->fp_status);
+ log210 = float64_log2(floatx80_to_float64(floatx80_10, &env->fp_status),
+ &env->fp_status);
+ res = floatx80_div(float64_to_floatx80(log2, &env->fp_status),
+ float64_to_floatx80(log210, &env->fp_status),
+ &env->fp_status);
+ DBG_FPU(" = %Lg\n", LDOUBLE(res));
+
+ floatx80_to_FP0(env, res);
+}
+
void HELPER(exp_FP0)(CPUState *env)
{
floatx80 f;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 53ab1a9..138b4a4 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -67,6 +67,7 @@ DEF_HELPER_1(itrunc_FP0, void, env)
DEF_HELPER_1(sqrt_FP0, void, env)
DEF_HELPER_1(exp_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(chs_FP0, void, env)
DEF_HELPER_1(getexp_FP0, void, env)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 5591873..1196508 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3647,6 +3647,9 @@ DISAS_INSN(fpu)
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_FP0(cpu_env);
break;
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:26 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Add rotate_im, rotate8_im, rotate16_im, rotate_reg, rotate8_reg, rotate16_reg,
rotate_mem and attach them to M68000 feature.

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 149 ++++++++++++++++++++++++++++++++++
target-m68k/helpers.h | 12 +++
target-m68k/translate.c | 205 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 366 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 0025ab5..7f83d20 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -60,6 +60,42 @@ 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;
@@ -632,6 +668,119 @@ 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) { \
+ 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) { \
+ 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. */
uint32_t HELPER(f64_to_i32)(CPUState *env, float64 val)
{
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index d1993ab..07d1f82 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -22,6 +22,18 @@ DEF_HELPER_3(shr32_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, i32, i32, i32)
DEF_HELPER_2(set_sr, void, env, i32)
DEF_HELPER_3(movec, void, env, i32, i32)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index ecbd516..cf59ffe 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2188,6 +2188,204 @@ DISAS_INSN(shift_mem)
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_roxr16_cc(dest, cpu_env, src, shift);
+ }
+ }
+ s->cc_op = CC_OP_FLAGS;
+ DEST_EA(insn, OS_WORD, dest, &addr);
+}
+
DISAS_INSN(ff1)
{
TCGv reg;
@@ -3323,6 +3521,13 @@ void register_m68k_insns (CPUM68KState *env)
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(undef_fpu, f000, f000, CF_ISA_A);
INSN(undef_fpu, f000, f000, M68000);
INSN(fpu, f200, ffc0, CF_FPU);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:23 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 15 +++++++++++++++
target-m68k/helpers.h | 1 +
target-m68k/translate.c | 3 +++
3 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index bba4ae3..319723e 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -1332,6 +1332,21 @@ void HELPER(log10_FP0)(CPUState *env)
floatx80_to_FP0(env, res);
}

+void HELPER(tan_FP0)(CPUState *env)
+{
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = LDOUBLE(res);
+
+ DBG_FPUH("tan_FP0 %Lg", val);
+ val = tanl(val);
+ DBG_FPU(" = %Lg", val);
+ res = FLOATx80(val);
+ floatx80_to_FP0(env, res);
+}
+
void HELPER(exp_FP0)(CPUState *env)
{
floatx80 f;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 1a375c0..ec51ce0 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -65,6 +65,7 @@ DEF_HELPER_2(const_FP0, void, env, i32)
DEF_HELPER_1(iround_FP0, void, env)
DEF_HELPER_1(itrunc_FP0, void, env)
DEF_HELPER_1(sqrt_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(ln_FP0, void, env)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index ece5de3..b69cac9 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3661,6 +3661,9 @@ DISAS_INSN(fpu)
case 4: case 0x41: case 0x45: /* fsqrt */
gen_helper_sqrt_FP0(cpu_env);
break;
+ case 0x0f: /* ftan */
+ gen_helper_tan_FP0(cpu_env);
+ break;
case 0x10: /* fetox */
gen_helper_exp_FP0(cpu_env);
break;
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:15 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch defines four new Motorola 680x0 family CPUs:

- M68K_CPUID_M68000,
- M68K_CPUID_M68020,
- M68K_CPUID_M68040,
- M68K_CPUID_M68060

And six new features:

- M68K_FEATURE_SCALED_INDEX, scaled address index register
- M68K_FEATURE_LONG_MULDIV, 32bit multiply/divide
- M68K_FEATURE_QUAD_MULDIV, 64bit multiply/divide
- M68K_FEATURE_BCCL, long conditional branches
- M68K_FEATURE_BITFIELD, bit field instructions
- M68K_FEATURE_FPU, FPU instructions

Following patches implement them...

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/cpu.h | 13 ++++++++++---
target-m68k/helper.c | 36 +++++++++++++++++++++++++++++++++++-
2 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index 0667f82..0f216c2 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -182,6 +182,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 +193,13 @@ 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
};

static inline int m68k_feature(CPUM68KState *env, int feature)
@@ -205,8 +212,8 @@ 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
+/* Linux uses 4k pages. */
+#define TARGET_PAGE_BITS 12
#else
/* Smallest TLB entry size is 1k. */
#define TARGET_PAGE_BITS 10
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 8a8b4f8..f226e4a 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -31,6 +31,10 @@
#define SIGNBIT (1u << 31)

enum m68k_cpuid {
+ M68K_CPUID_M68000,
+ M68K_CPUID_M68020,
+ M68K_CPUID_M68040,
+ M68K_CPUID_M68060,
M68K_CPUID_M5206,
M68K_CPUID_M5208,
M68K_CPUID_CFV4E,
@@ -45,6 +49,10 @@ struct m68k_def_t {
};

static m68k_def_t m68k_cpu_defs[] = {
+ {"m68000", M68K_CPUID_M68000},
+ {"m68020", M68K_CPUID_M68020},
+ {"m68040", M68K_CPUID_M68040},
+ {"m68060", M68K_CPUID_M68060},
{"m5206", M68K_CPUID_M5206},
{"m5208", M68K_CPUID_M5208},
{"cfv4e", M68K_CPUID_CFV4E},
@@ -110,12 +118,30 @@ static int cpu_m68k_set_model(CPUM68KState *env, const char *name)
return -1;

switch (def->id) {
+ case M68K_CPUID_M68020:
+ 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);
+ 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);
@@ -123,16 +149,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. */
@@ -140,12 +169,17 @@ 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);
break;
}

register_m68k_insns(env);
- if (m68k_feature (env, M68K_FEATURE_CF_FPU)) {
+ if (m68k_feature (env, M68K_FEATURE_CF_FPU) ||
+ m68k_feature (env, M68K_FEATURE_FPU)) {
gdb_register_coprocessor(env, fpu_gdb_get_reg, fpu_gdb_set_reg,
11, "cf-fp.xml", 18);
}
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:37 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch add support for link instruction with 32bit stack frame size

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 20 ++++++++++++++++++--
1 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 38be7ab..896e187 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1744,8 +1744,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);
@@ -3778,6 +3793,7 @@ void register_m68k_insns (CPUM68KState *env)
INSN(not, 4600, ff00, M68000);
INSN(undef, 46c0, ffc0, M68000);
INSN(move_to_sr, 46c0, ffc0, CF_ISA_A);
+ INSN(linkl, 4808, fff8, M68000);
INSN(pea, 4840, ffc0, CF_ISA_A);
INSN(pea, 4840, ffc0, M68000);
INSN(swap, 4840, fff8, CF_ISA_A);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:41 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index cad2e26..f2bdef0 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1547,9 +1547,8 @@ DISAS_INSN(neg)
tcg_gen_neg_i32(dest, src1);
DEST_EA(insn, opsize, dest, &addr);
SET_CC_OP(opsize, SUB);
- gen_update_cc_add(src1, dest);
+ gen_update_cc_add(dest, src1);
gen_helper_xflag_lt(QREG_CC_X, tcg_const_i32(0), dest);
- SET_CC_OP(opsize, SUB);
}

static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only)
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:29 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This instruction is needed to execute commands like "ls" or "date"
(from a debian lenny m68k).

It define a new feaure, CAS, and attach this new instruction to it.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/cpu.h | 3 +-
target-m68k/helper.c | 2 +
target-m68k/translate.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 66 insertions(+), 1 deletions(-)

diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index 91d3141..ae4f6fa 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -210,7 +210,8 @@ enum m68k_features {
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_FPU,
+ M68K_FEATURE_CAS
};

static inline int m68k_feature(CPUM68KState *env, int feature)
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index fd9867d..d0fc155 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -165,6 +165,7 @@ static int cpu_m68k_set_model(CPUM68KState *env, const char *name)
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);
@@ -210,6 +211,7 @@ static int cpu_m68k_set_model(CPUM68KState *env, const char *name)
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;
}

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index fa67ff9..c186fe1 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -1371,6 +1371,67 @@ DISAS_INSN(arith_im)
}
}

+DISAS_INSN(cas)
+{
+ int opsize;
+ TCGv dest;
+ TCGv tmp;
+ TCGv cmp;
+ TCGv update;
+ 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 = lduw_code(s->pc);
+ s->pc += 2;
+ addr = gen_lea(s, insn, opsize);
+ if (IS_NULL_QREG(addr)) {
+ gen_addr_fault(s);
+ return;
+ }
+
+ cmp = DREG(ext, 0);
+ update = DREG(ext, 6);
+ tmp = gen_load(s, opsize, addr, 0);
+ dest = tcg_temp_local_new();
+ tcg_gen_mov_i32(dest, tmp);
+
+ res = tcg_temp_new();
+ tcg_gen_sub_i32(res, dest, cmp);
+ gen_logic_cc(s, res);
+
+ 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);
+}
+
DISAS_INSN(byterev)
{
TCGv reg;
@@ -3660,6 +3721,7 @@ void register_m68k_insns (CPUM68KState *env)
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);
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:33 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

This patch allows to manage instructions like "fcmpd #2.2, %fp0".
Original function manages only data accessed through an address register.

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/translate.c | 48 ++++++++++++++--------------------------------
1 files changed, 15 insertions(+), 33 deletions(-)

diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index d4d2f44..a91f557 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -2939,6 +2939,7 @@ DISAS_INSN(fpu)
TCGv_i64 dest;
TCGv_i64 res;
TCGv tmp32;
+ TCGv reg;
int round;
int set_dest;
int opsize;
@@ -3111,40 +3112,21 @@ DISAS_INSN(fpu)
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;
+ if ((insn & 0x3f) == 0x3c) {
+ src = gen_load64(s, tcg_const_i32(s->pc));
+ s->pc += 8;
+ } else {
+ tmp32 = gen_lea(s, insn, opsize);
+ if (IS_NULL_QREG(tmp32)) {
+ gen_addr_fault(s);
+ return;
+ }
+ src = gen_load64(s, tmp32);
+ if ( ((insn >> 3) & 7) == 3) { /* post-increment */
+ reg = AREG(insn, 0);
+ tcg_gen_addi_i32(reg, reg, opsize_bytes(opsize));
+ }
}
- tcg_temp_free_i32(tmp32);
} else {
SRC_EA(tmp32, opsize, 1, NULL);
src = tcg_temp_new_i64();
--
1.7.2.3
Bryce Lanham
2011-08-17 20:47:22 UTC
Permalink
From: Laurent Vivier <***@vivier.eu>

Signed-off-by: Laurent Vivier <***@vivier.eu>
---
target-m68k/helper.c | 29 ++++++++++++++++++++++++-----
target-m68k/helpers.h | 1 +
target-m68k/translate.c | 3 +++
3 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index cccae97..bba4ae3 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -28,10 +28,15 @@
#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;
@@ -44,11 +49,10 @@ static inline long double LDOUBLE(floatx80 x)
{
return *(long double *)&x;
}
-#else
-#define DBG_FPUH(...)
-#define DBG_FPU(...)
-#define LDOUBLE(x)
-#endif
+static inline floatx80 FLOATx80(long double x)
+{
+ return *(floatx80 *)&x;
+}

#define SIGNBIT (1u << 31)

@@ -1386,6 +1390,21 @@ void HELPER(chs_FP0)(CPUState *env)
floatx80_to_FP0(env, res);
}

+void HELPER(acos_FP0)(CPUState *env)
+{
+ floatx80 res;
+ long double val;
+
+ res = FP0_to_floatx80(env);
+ val = LDOUBLE(res);
+
+ DBG_FPUH("acos_FP0 %Lg", val);
+ val = acosl(val);
+ DBG_FPU(" = %Lg", val);
+ res = FLOATx80(val);
+ floatx80_to_FP0(env, res);
+}
+
void HELPER(getexp_FP0)(CPUState *env)
{
int32_t exp;
diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h
index 184ceef..1a375c0 100644
--- a/target-m68k/helpers.h
+++ b/target-m68k/helpers.h
@@ -71,6 +71,7 @@ DEF_HELPER_1(ln_FP0, void, env)
DEF_HELPER_1(log10_FP0, void, env)
DEF_HELPER_1(abs_FP0, void, env)
DEF_HELPER_1(chs_FP0, void, env)
+DEF_HELPER_1(acos_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)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 4f73bf8..ece5de3 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -3679,6 +3679,9 @@ DISAS_INSN(fpu)
case 0x1a: case 0x5a: case 0x5e: /* fneg */
gen_helper_chs_FP0(cpu_env);
break;
+ case 0x1c: /* facos */
+ gen_helper_acos_FP0(cpu_env);
+ break;
case 0x1e: /* fgetexp */
gen_helper_getexp_FP0(cpu_env);
break;
--
1.7.2.3
Bryce Lanham
2011-08-17 20:46:31 UTC
Permalink
From: Andreas Schwab <***@linux-m68k.org>

Signed-off-by: Andreas Schwab <***@linux-m68k.org>
---
linux-user/syscall_defs.h | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index a117407..aa94a14 100644
--- a/linux-user/syscall_defs.h
+++ b/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
--
1.7.2.3
Loading...